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