• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 // The bootstat command provides options to persist boot events with the current
18 // timestamp, dump the persisted events, and log all events to EventLog to be
19 // uploaded to Android log storage via Tron.
20 
21 #include <getopt.h>
22 #include <unistd.h>
23 
24 #include <cmath>
25 #include <cstddef>
26 #include <cstdio>
27 #include <ctime>
28 #include <map>
29 #include <memory>
30 #include <string>
31 #include <vector>
32 
33 #include <android/log.h>
34 #include <android-base/logging.h>
35 #include <android-base/parseint.h>
36 #include <android-base/strings.h>
37 #include <cutils/properties.h>
38 #include <metricslogger/metrics_logger.h>
39 
40 #include "boot_event_record_store.h"
41 #include "uptime_parser.h"
42 
43 namespace {
44 
45 // Scans the boot event record store for record files and logs each boot event
46 // via EventLog.
LogBootEvents()47 void LogBootEvents() {
48   BootEventRecordStore boot_event_store;
49 
50   auto events = boot_event_store.GetAllBootEvents();
51   for (auto i = events.cbegin(); i != events.cend(); ++i) {
52     android::metricslogger::LogHistogram(i->first, i->second);
53   }
54 }
55 
56 // Records the named boot |event| to the record store. If |value| is non-empty
57 // and is a proper string representation of an integer value, the converted
58 // integer value is associated with the boot event.
RecordBootEventFromCommandLine(const std::string & event,const std::string & value_str)59 void RecordBootEventFromCommandLine(
60     const std::string& event, const std::string& value_str) {
61   BootEventRecordStore boot_event_store;
62   if (!value_str.empty()) {
63     int32_t value = 0;
64     if (android::base::ParseInt(value_str, &value)) {
65       boot_event_store.AddBootEventWithValue(event, value);
66     }
67   } else {
68     boot_event_store.AddBootEvent(event);
69   }
70 }
71 
PrintBootEvents()72 void PrintBootEvents() {
73   printf("Boot events:\n");
74   printf("------------\n");
75 
76   BootEventRecordStore boot_event_store;
77   auto events = boot_event_store.GetAllBootEvents();
78   for (auto i = events.cbegin(); i != events.cend(); ++i) {
79     printf("%s\t%d\n", i->first.c_str(), i->second);
80   }
81 }
82 
ShowHelp(const char * cmd)83 void ShowHelp(const char *cmd) {
84   fprintf(stderr, "Usage: %s [options]\n", cmd);
85   fprintf(stderr,
86           "options include:\n"
87           "  -h, --help            Show this help\n"
88           "  -l, --log             Log all metrics to logstorage\n"
89           "  -p, --print           Dump the boot event records to the console\n"
90           "  -r, --record          Record the timestamp of a named boot event\n"
91           "  --value               Optional value to associate with the boot event\n"
92           "  --record_boot_reason  Record the reason why the device booted\n"
93           "  --record_time_since_factory_reset Record the time since the device was reset\n");
94 }
95 
96 // Constructs a readable, printable string from the givencommand line
97 // arguments.
GetCommandLine(int argc,char ** argv)98 std::string GetCommandLine(int argc, char **argv) {
99   std::string cmd;
100   for (int i = 0; i < argc; ++i) {
101     cmd += argv[i];
102     cmd += " ";
103   }
104 
105   return cmd;
106 }
107 
108 // Convenience wrapper over the property API that returns an
109 // std::string.
GetProperty(const char * key)110 std::string GetProperty(const char* key) {
111   std::vector<char> temp(PROPERTY_VALUE_MAX);
112   const int len = property_get(key, &temp[0], nullptr);
113   if (len < 0) {
114     return "";
115   }
116   return std::string(&temp[0], len);
117 }
118 
119 constexpr int32_t kUnknownBootReason = 1;
120 
121 // A mapping from boot reason string, as read from the ro.boot.bootreason
122 // system property, to a unique integer ID. Viewers of log data dashboards for
123 // the boot_reason metric may refer to this mapping to discern the histogram
124 // values.
125 const std::map<std::string, int32_t> kBootReasonMap = {
126   {"unknown", kUnknownBootReason},
127   {"normal", 2},
128   {"recovery", 3},
129   {"reboot", 4},
130   {"PowerKey", 5},
131   {"hard_reset", 6},
132   {"kernel_panic", 7},
133   {"rpm_err", 8},
134   {"hw_reset", 9},
135   {"tz_err", 10},
136   {"adsp_err", 11},
137   {"modem_err", 12},
138   {"mba_err", 13},
139   {"Watchdog", 14},
140   {"Panic", 15},
141   {"power_key", 16},
142   {"power_on", 17},
143   {"Reboot", 18},
144   {"rtc", 19},
145   {"edl", 20},
146   {"oem_pon1", 21},
147   {"oem_powerkey", 22},
148   {"oem_unknown_reset", 23},
149   {"srto: HWWDT reset SC", 24},
150   {"srto: HWWDT reset platform", 25},
151   {"srto: bootloader", 26},
152   {"srto: kernel panic", 27},
153   {"srto: kernel watchdog reset", 28},
154   {"srto: normal", 29},
155   {"srto: reboot", 30},
156   {"srto: reboot-bootloader", 31},
157   {"srto: security watchdog reset", 32},
158   {"srto: wakesrc", 33},
159   {"srto: watchdog", 34},
160   {"srto:1-1", 35},
161   {"srto:omap_hsmm", 36},
162   {"srto:phy0", 37},
163   {"srto:rtc0", 38},
164   {"srto:touchpad", 39},
165   {"watchdog", 40},
166   {"watchdogr", 41},
167   {"wdog_bark", 42},
168   {"wdog_bite", 43},
169   {"wdog_reset", 44},
170 };
171 
172 // Converts a string value representing the reason the system booted to an
173 // integer representation. This is necessary for logging the boot_reason metric
174 // via Tron, which does not accept non-integer buckets in histograms.
BootReasonStrToEnum(const std::string & boot_reason)175 int32_t BootReasonStrToEnum(const std::string& boot_reason) {
176   auto mapping = kBootReasonMap.find(boot_reason);
177   if (mapping != kBootReasonMap.end()) {
178     return mapping->second;
179   }
180 
181   LOG(INFO) << "Unknown boot reason: " << boot_reason;
182   return kUnknownBootReason;
183 }
184 
185 // Returns the appropriate metric key prefix for the boot_complete metric such
186 // that boot metrics after a system update are labeled as ota_boot_complete;
187 // otherwise, they are labeled as boot_complete.  This method encapsulates the
188 // bookkeeping required to track when a system update has occurred by storing
189 // the UTC timestamp of the system build date and comparing against the current
190 // system build date.
CalculateBootCompletePrefix()191 std::string CalculateBootCompletePrefix() {
192   static const std::string kBuildDateKey = "build_date";
193   std::string boot_complete_prefix = "boot_complete";
194 
195   std::string build_date_str = GetProperty("ro.build.date.utc");
196   int32_t build_date;
197   if (!android::base::ParseInt(build_date_str, &build_date)) {
198     return std::string();
199   }
200 
201   BootEventRecordStore boot_event_store;
202   BootEventRecordStore::BootEventRecord record;
203   if (!boot_event_store.GetBootEvent(kBuildDateKey, &record) ||
204       build_date != record.second) {
205     boot_complete_prefix = "ota_" + boot_complete_prefix;
206     boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
207   }
208 
209   return boot_complete_prefix;
210 }
211 
212 // Records the value of a given ro.boottime.init property in milliseconds.
RecordInitBootTimeProp(BootEventRecordStore * boot_event_store,const char * property)213 void RecordInitBootTimeProp(
214     BootEventRecordStore* boot_event_store, const char* property) {
215   std::string value = GetProperty(property);
216 
217   int32_t time_in_ms;
218   if (android::base::ParseInt(value, &time_in_ms)) {
219     boot_event_store->AddBootEventWithValue(property, time_in_ms);
220   }
221 }
222 
223 // Parses and records the set of bootloader stages and associated boot times
224 // from the ro.boot.boottime system property.
RecordBootloaderTimings(BootEventRecordStore * boot_event_store)225 void RecordBootloaderTimings(BootEventRecordStore* boot_event_store) {
226   // |ro.boot.boottime| is of the form 'stage1:time1,...,stageN:timeN'.
227   std::string value = GetProperty("ro.boot.boottime");
228   if (value.empty()) {
229     // ro.boot.boottime is not reported on all devices.
230     return;
231   }
232 
233   int32_t total_time = 0;
234   auto stages = android::base::Split(value, ",");
235   for (auto const &stageTiming : stages) {
236     // |stageTiming| is of the form 'stage:time'.
237     auto stageTimingValues = android::base::Split(stageTiming, ":");
238     DCHECK_EQ(2, stageTimingValues.size());
239 
240     std::string stageName = stageTimingValues[0];
241     int32_t time_ms;
242     if (android::base::ParseInt(stageTimingValues[1], &time_ms)) {
243       total_time += time_ms;
244       boot_event_store->AddBootEventWithValue(
245           "boottime.bootloader." + stageName, time_ms);
246     }
247   }
248 
249   boot_event_store->AddBootEventWithValue("boottime.bootloader.total", total_time);
250 }
251 
252 // Records several metrics related to the time it takes to boot the device,
253 // including disambiguating boot time on encrypted or non-encrypted devices.
RecordBootComplete()254 void RecordBootComplete() {
255   BootEventRecordStore boot_event_store;
256   BootEventRecordStore::BootEventRecord record;
257 
258   time_t uptime = bootstat::ParseUptime();
259   time_t current_time_utc = time(nullptr);
260 
261   if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
262     time_t last_boot_time_utc = record.second;
263     time_t time_since_last_boot = difftime(current_time_utc,
264                                            last_boot_time_utc);
265     boot_event_store.AddBootEventWithValue("time_since_last_boot",
266                                            time_since_last_boot);
267   }
268 
269   boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc);
270 
271   // The boot_complete metric has two variants: boot_complete and
272   // ota_boot_complete.  The latter signifies that the device is booting after
273   // a system update.
274   std::string boot_complete_prefix = CalculateBootCompletePrefix();
275   if (boot_complete_prefix.empty()) {
276     // The system is hosed because the build date property could not be read.
277     return;
278   }
279 
280   // post_decrypt_time_elapsed is only logged on encrypted devices.
281   if (boot_event_store.GetBootEvent("post_decrypt_time_elapsed", &record)) {
282     // Log the amount of time elapsed until the device is decrypted, which
283     // includes the variable amount of time the user takes to enter the
284     // decryption password.
285     boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime);
286 
287     // Subtract the decryption time to normalize the boot cycle timing.
288     time_t boot_complete = uptime - record.second;
289     boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
290                                            boot_complete);
291 
292 
293   } else {
294     boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
295                                            uptime);
296   }
297 
298   // Record the total time from device startup to boot complete, regardless of
299   // encryption state.
300   boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
301 
302   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
303   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
304   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait");
305 
306   RecordBootloaderTimings(&boot_event_store);
307 }
308 
309 // Records the boot_reason metric by querying the ro.boot.bootreason system
310 // property.
RecordBootReason()311 void RecordBootReason() {
312   int32_t boot_reason = BootReasonStrToEnum(GetProperty("ro.boot.bootreason"));
313   BootEventRecordStore boot_event_store;
314   boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
315 }
316 
317 // Records two metrics related to the user resetting a device: the time at
318 // which the device is reset, and the time since the user last reset the
319 // device.  The former is only set once per-factory reset.
RecordFactoryReset()320 void RecordFactoryReset() {
321   BootEventRecordStore boot_event_store;
322   BootEventRecordStore::BootEventRecord record;
323 
324   time_t current_time_utc = time(nullptr);
325 
326   if (current_time_utc < 0) {
327     // UMA does not display negative values in buckets, so convert to positive.
328     android::metricslogger::LogHistogram(
329         "factory_reset_current_time_failure", std::abs(current_time_utc));
330 
331     // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
332     // is losing records somehow.
333     boot_event_store.AddBootEventWithValue(
334         "factory_reset_current_time_failure", std::abs(current_time_utc));
335     return;
336   } else {
337     android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
338 
339     // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
340     // is losing records somehow.
341     boot_event_store.AddBootEventWithValue(
342         "factory_reset_current_time", current_time_utc);
343   }
344 
345   // The factory_reset boot event does not exist after the device is reset, so
346   // use this signal to mark the time of the factory reset.
347   if (!boot_event_store.GetBootEvent("factory_reset", &record)) {
348     boot_event_store.AddBootEventWithValue("factory_reset", current_time_utc);
349 
350     // Don't log the time_since_factory_reset until some time has elapsed.
351     // The data is not meaningful yet and skews the histogram buckets.
352     return;
353   }
354 
355   // Calculate and record the difference in time between now and the
356   // factory_reset time.
357   time_t factory_reset_utc = record.second;
358   android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
359 
360   // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
361   // is losing records somehow.
362   boot_event_store.AddBootEventWithValue(
363       "factory_reset_record_value", factory_reset_utc);
364 
365   time_t time_since_factory_reset = difftime(current_time_utc,
366                                              factory_reset_utc);
367   boot_event_store.AddBootEventWithValue("time_since_factory_reset",
368                                          time_since_factory_reset);
369 }
370 
371 }  // namespace
372 
main(int argc,char ** argv)373 int main(int argc, char **argv) {
374   android::base::InitLogging(argv);
375 
376   const std::string cmd_line = GetCommandLine(argc, argv);
377   LOG(INFO) << "Service started: " << cmd_line;
378 
379   int option_index = 0;
380   static const char value_str[] = "value";
381   static const char boot_complete_str[] = "record_boot_complete";
382   static const char boot_reason_str[] = "record_boot_reason";
383   static const char factory_reset_str[] = "record_time_since_factory_reset";
384   static const struct option long_options[] = {
385     { "help",            no_argument,       NULL,   'h' },
386     { "log",             no_argument,       NULL,   'l' },
387     { "print",           no_argument,       NULL,   'p' },
388     { "record",          required_argument, NULL,   'r' },
389     { value_str,         required_argument, NULL,   0 },
390     { boot_complete_str, no_argument,       NULL,   0 },
391     { boot_reason_str,   no_argument,       NULL,   0 },
392     { factory_reset_str, no_argument,       NULL,   0 },
393     { NULL,              0,                 NULL,   0 }
394   };
395 
396   std::string boot_event;
397   std::string value;
398   int opt = 0;
399   while ((opt = getopt_long(argc, argv, "hlpr:", long_options, &option_index)) != -1) {
400     switch (opt) {
401       // This case handles long options which have no single-character mapping.
402       case 0: {
403         const std::string option_name = long_options[option_index].name;
404         if (option_name == value_str) {
405           // |optarg| is an external variable set by getopt representing
406           // the option argument.
407           value = optarg;
408         } else if (option_name == boot_complete_str) {
409           RecordBootComplete();
410         } else if (option_name == boot_reason_str) {
411           RecordBootReason();
412         } else if (option_name == factory_reset_str) {
413           RecordFactoryReset();
414         } else {
415           LOG(ERROR) << "Invalid option: " << option_name;
416         }
417         break;
418       }
419 
420       case 'h': {
421         ShowHelp(argv[0]);
422         break;
423       }
424 
425       case 'l': {
426         LogBootEvents();
427         break;
428       }
429 
430       case 'p': {
431         PrintBootEvents();
432         break;
433       }
434 
435       case 'r': {
436         // |optarg| is an external variable set by getopt representing
437         // the option argument.
438         boot_event = optarg;
439         break;
440       }
441 
442       default: {
443         DCHECK_EQ(opt, '?');
444 
445         // |optopt| is an external variable set by getopt representing
446         // the value of the invalid option.
447         LOG(ERROR) << "Invalid option: " << optopt;
448         ShowHelp(argv[0]);
449         return EXIT_FAILURE;
450       }
451     }
452   }
453 
454   if (!boot_event.empty()) {
455     RecordBootEventFromCommandLine(boot_event, value);
456   }
457 
458   return 0;
459 }
460