Home | History | Annotate | Download | only in otautil
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "otautil/parse_install_logs.h"
     18 
     19 #include <unistd.h>
     20 
     21 #include <optional>
     22 
     23 #include <android-base/file.h>
     24 #include <android-base/logging.h>
     25 #include <android-base/parseint.h>
     26 #include <android-base/properties.h>
     27 #include <android-base/strings.h>
     28 
     29 constexpr const char* OTA_SIDELOAD_METRICS = "ota_sideload";
     30 
     31 // Here is an example of lines in last_install:
     32 // ...
     33 // time_total: 101
     34 // bytes_written_vendor: 51074
     35 // bytes_stashed_vendor: 200
     36 std::map<std::string, int64_t> ParseRecoveryUpdateMetrics(const std::vector<std::string>& lines) {
     37   constexpr unsigned int kMiB = 1024 * 1024;
     38   std::optional<int64_t> bytes_written_in_mib;
     39   std::optional<int64_t> bytes_stashed_in_mib;
     40   std::map<std::string, int64_t> metrics;
     41   for (const auto& line : lines) {
     42     size_t num_index = line.find(':');
     43     if (num_index == std::string::npos) {
     44       LOG(WARNING) << "Skip parsing " << line;
     45       continue;
     46     }
     47 
     48     std::string num_string = android::base::Trim(line.substr(num_index + 1));
     49     int64_t parsed_num;
     50     if (!android::base::ParseInt(num_string, &parsed_num)) {
     51       LOG(ERROR) << "Failed to parse numbers in " << line;
     52       continue;
     53     }
     54 
     55     if (android::base::StartsWith(line, "bytes_written")) {
     56       bytes_written_in_mib = bytes_written_in_mib.value_or(0) + parsed_num / kMiB;
     57     } else if (android::base::StartsWith(line, "bytes_stashed")) {
     58       bytes_stashed_in_mib = bytes_stashed_in_mib.value_or(0) + parsed_num / kMiB;
     59     } else if (android::base::StartsWith(line, "time")) {
     60       metrics.emplace("ota_time_total", parsed_num);
     61     } else if (android::base::StartsWith(line, "uncrypt_time")) {
     62       metrics.emplace("ota_uncrypt_time", parsed_num);
     63     } else if (android::base::StartsWith(line, "source_build")) {
     64       metrics.emplace("ota_source_version", parsed_num);
     65     } else if (android::base::StartsWith(line, "temperature_start")) {
     66       metrics.emplace("ota_temperature_start", parsed_num);
     67     } else if (android::base::StartsWith(line, "temperature_end")) {
     68       metrics.emplace("ota_temperature_end", parsed_num);
     69     } else if (android::base::StartsWith(line, "temperature_max")) {
     70       metrics.emplace("ota_temperature_max", parsed_num);
     71     } else if (android::base::StartsWith(line, "error")) {
     72       metrics.emplace("ota_non_ab_error_code", parsed_num);
     73     } else if (android::base::StartsWith(line, "cause")) {
     74       metrics.emplace("ota_non_ab_cause_code", parsed_num);
     75     }
     76   }
     77 
     78   if (bytes_written_in_mib) {
     79     metrics.emplace("ota_written_in_MiBs", bytes_written_in_mib.value());
     80   }
     81   if (bytes_stashed_in_mib) {
     82     metrics.emplace("ota_stashed_in_MiBs", bytes_stashed_in_mib.value());
     83   }
     84 
     85   return metrics;
     86 }
     87 
     88 std::map<std::string, int64_t> ParseLastInstall(const std::string& file_name) {
     89   if (access(file_name.c_str(), F_OK) != 0) {
     90     return {};
     91   }
     92 
     93   std::string content;
     94   if (!android::base::ReadFileToString(file_name, &content)) {
     95     PLOG(ERROR) << "Failed to read " << file_name;
     96     return {};
     97   }
     98 
     99   if (content.empty()) {
    100     LOG(INFO) << "Empty last_install file";
    101     return {};
    102   }
    103 
    104   std::vector<std::string> lines = android::base::Split(content, "\n");
    105   auto metrics = ParseRecoveryUpdateMetrics(lines);
    106 
    107   // LAST_INSTALL starts with "/sideload/package.zip" after a sideload.
    108   if (android::base::Trim(lines[0]) == "/sideload/package.zip") {
    109     int type = (android::base::GetProperty("ro.build.type", "") == "user") ? 1 : 0;
    110     metrics.emplace(OTA_SIDELOAD_METRICS, type);
    111   }
    112 
    113   return metrics;
    114 }
    115