1 /*
2  * Copyright (C) 2021 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 
18 #include "odr_statslog/odr_statslog.h"
19 
20 #include <cstdint>
21 #include <fstream>
22 #include <istream>
23 #include <string>
24 
25 #include "android-base/logging.h"
26 #include "android-base/stringprintf.h"
27 #include "odr_metrics.h"
28 #include "odr_metrics_record.h"
29 #include "statslog_odrefresh.h"
30 
31 namespace art {
32 namespace odrefresh {
33 
34 using android::base::StringPrintf;
35 
36 namespace {
37 
38 // Convert bare value from art::metrics::Stage to value defined in atoms.proto.
TranslateStage(int32_t art_metrics_stage)39 int32_t TranslateStage(int32_t art_metrics_stage) {
40   switch (static_cast<OdrMetrics::Stage>(art_metrics_stage)) {
41     case OdrMetrics::Stage::kUnknown:
42       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_UNKNOWN;
43     case OdrMetrics::Stage::kCheck:
44       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_CHECK;
45     case OdrMetrics::Stage::kPreparation:
46       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_PREPARATION;
47     case OdrMetrics::Stage::kPrimaryBootClasspath:
48       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_PRIMARY_BOOT_CLASSPATH;
49     case OdrMetrics::Stage::kSecondaryBootClasspath:
50       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_SECONDARY_BOOT_CLASSPATH;
51     case OdrMetrics::Stage::kSystemServerClasspath:
52       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_SYSTEM_SERVER_CLASSPATH;
53     case OdrMetrics::Stage::kComplete:
54       return metrics::statsd::ODREFRESH_REPORTED__STAGE_REACHED__STAGE_COMPLETE;
55   }
56 
57   LOG(ERROR) << "Unknown stage value: " << art_metrics_stage;
58   return -1;
59 }
60 
61 // Convert bare value from art::metrics::Status to value defined in atoms.proto.
TranslateStatus(int32_t art_metrics_status)62 int32_t TranslateStatus(int32_t art_metrics_status) {
63   switch (static_cast<OdrMetrics::Status>(art_metrics_status)) {
64     case OdrMetrics::Status::kUnknown:
65       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_UNKNOWN;
66     case OdrMetrics::Status::kOK:
67       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_OK;
68     case OdrMetrics::Status::kNoSpace:
69       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_NO_SPACE;
70     case OdrMetrics::Status::kIoError:
71       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_IO_ERROR;
72     case OdrMetrics::Status::kDex2OatError:
73       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_DEX2OAT_ERROR;
74     case OdrMetrics::Status::kTimeLimitExceeded:
75       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_TIME_LIMIT_EXCEEDED;
76     case OdrMetrics::Status::kStagingFailed:
77       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_STAGING_FAILED;
78     case OdrMetrics::Status::kInstallFailed:
79       return metrics::statsd::ODREFRESH_REPORTED__STATUS__STATUS_INSTALL_FAILED;
80   }
81 
82   LOG(ERROR) << "Unknown status value: " << art_metrics_status;
83   return -1;
84 }
85 
86 // Convert bare value from art::metrics::Trigger to value defined in atoms.proto.
TranslateTrigger(int32_t art_metrics_trigger)87 int32_t TranslateTrigger(int32_t art_metrics_trigger) {
88   switch (static_cast<OdrMetrics::Trigger>(art_metrics_trigger)) {
89     case OdrMetrics::Trigger::kUnknown:
90       return metrics::statsd::ODREFRESH_REPORTED__TRIGGER__TRIGGER_UNKNOWN;
91     case OdrMetrics::Trigger::kApexVersionMismatch:
92       return metrics::statsd::ODREFRESH_REPORTED__TRIGGER__TRIGGER_APEX_VERSION_MISMATCH;
93     case OdrMetrics::Trigger::kDexFilesChanged:
94       return metrics::statsd::ODREFRESH_REPORTED__TRIGGER__TRIGGER_DEX_FILES_CHANGED;
95     case OdrMetrics::Trigger::kMissingArtifacts:
96       return metrics::statsd::ODREFRESH_REPORTED__TRIGGER__TRIGGER_MISSING_ARTIFACTS;
97   }
98 
99   LOG(ERROR) << "Unknown trigger value: " << art_metrics_trigger;
100   return -1;
101 }
102 
ReadValues(const char * metrics_file,OdrMetricsRecord * record,std::string * error_msg)103 bool ReadValues(const char* metrics_file,
104                 /*out*/ OdrMetricsRecord* record,
105                 /*out*/ std::string* error_msg) {
106   std::ifstream ifs(metrics_file);
107   if (!ifs) {
108     *error_msg = android::base::StringPrintf(
109         "metrics file '%s' could not be opened: %s", metrics_file, strerror(errno));
110     return false;
111   }
112 
113   ifs >> *record;
114   if (!ifs) {
115     *error_msg = "file parsing error.";
116     return false;
117   }
118 
119   //
120   // Convert values defined as enums to their statsd values.
121   //
122 
123   record->trigger = TranslateTrigger(record->trigger);
124   if (record->trigger < 0) {
125     *error_msg = "failed to parse trigger.";
126     return false;
127   }
128 
129   record->stage_reached = TranslateStage(record->stage_reached);
130   if (record->stage_reached < 0) {
131     *error_msg = "failed to parse stage_reached.";
132     return false;
133   }
134 
135   record->status = TranslateStatus(record->status);
136   if (record->status < 0) {
137     *error_msg = "failed to parse status.";
138     return false;
139   }
140 
141   return true;
142 }
143 
144 }  // namespace
145 
UploadStatsIfAvailable(std::string * error_msg)146 bool UploadStatsIfAvailable(/*out*/std::string* error_msg) {
147   OdrMetricsRecord record;
148   if (!ReadValues(kOdrefreshMetricsFile, &record, error_msg)) {
149     return false;
150   }
151 
152   // Write values to statsd. The order of values passed is the same as the order of the
153   // fields in OdrMetricsRecord.
154   int bytes_written = art::metrics::statsd::stats_write(metrics::statsd::ODREFRESH_REPORTED,
155                                                         record.art_apex_version,
156                                                         record.trigger,
157                                                         record.stage_reached,
158                                                         record.status,
159                                                         record.primary_bcp_compilation_seconds,
160                                                         record.secondary_bcp_compilation_seconds,
161                                                         record.system_server_compilation_seconds,
162                                                         record.cache_space_free_start_mib,
163                                                         record.cache_space_free_end_mib);
164   if (bytes_written <= 0) {
165     *error_msg = android::base::StringPrintf("stats_write returned %d", bytes_written);
166     return false;
167   }
168 
169   if (unlink(kOdrefreshMetricsFile) != 0) {
170     *error_msg = StringPrintf("failed to unlink '%s': %s", kOdrefreshMetricsFile, strerror(errno));
171     return false;
172   }
173 
174   return true;
175 }
176 
177 }  // namespace odrefresh
178 }  // namespace art
179