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