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 "recovery_utils/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
ParseRecoveryUpdateMetrics(const std::vector<std::string> & lines)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
ParseLastInstall(const std::string & file_name)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