bootstat: Add support for logging the boot_reason metric.
This value is read from the ro.boot.bootreason system property.
Bug: 21724738
Change-Id: I43bef3d85ba9c8d87669a91da1aa675d9a86e348
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a83f8ad..31c84c7 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -18,14 +18,15 @@
// timestamp, dump the persisted events, and log all events to EventLog to be
// uploaded to Android log storage via Tron.
-//#define LOG_TAG "bootstat"
-
+#include <getopt.h>
#include <unistd.h>
#include <cstddef>
#include <cstdio>
+#include <map>
#include <memory>
#include <string>
#include <android-base/logging.h>
+#include <cutils/properties.h>
#include <log/log.h>
#include "boot_event_record_store.h"
#include "event_log_list_builder.h"
@@ -35,7 +36,7 @@
// Builds an EventLog buffer named |event| containing |data| and writes
// the log into the Tron histogram logs.
void LogBootEvent(const std::string& event, int32_t data) {
- LOG(INFO) << "Logging boot time: " << event << " " << data;
+ LOG(INFO) << "Logging boot metric: " << event << " " << data;
EventLogListBuilder log_builder;
log_builder.Append(event);
@@ -74,10 +75,11 @@
fprintf(stderr, "Usage: %s [options]\n", cmd);
fprintf(stderr,
"options include:\n"
- " -d Dump the boot event records to the console.\n"
- " -h Show this help.\n"
- " -l Log all metrics to logstorage.\n"
- " -r Record the timestamp of a named boot event.\n");
+ " -h, --help Show this help\n"
+ " -l, --log Log all metrics to logstorage\n"
+ " -p, --print Dump the boot event records to the console\n"
+ " -r, --record Record the timestamp of a named boot event\n"
+ " --record_boot_reason Record the reason why the device booted\n");
}
// Constructs a readable, printable string from the givencommand line
@@ -92,6 +94,61 @@
return cmd;
}
+// Convenience wrapper over the property API that returns an
+// std::string.
+std::string GetProperty(const char* key) {
+ std::vector<char> temp(PROPERTY_VALUE_MAX);
+ const int len = property_get(key, &temp[0], nullptr);
+ if (len < 0) {
+ return "";
+ }
+ return std::string(&temp[0], len);
+}
+
+// A mapping from boot reason string, as read from the ro.boot.bootreason
+// system property, to a unique integer ID. Viewers of log data dashboards for
+// the boot_reason metric may refer to this mapping to discern the histogram
+// values.
+const std::map<std::string, int> kBootReasonMap = {
+ {"normal", 0},
+ {"recovery", 1},
+ {"reboot", 2},
+ {"PowerKey", 3},
+ {"hard_reset", 4},
+ {"kernel_panic", 5},
+ {"rpm_err", 6},
+ {"hw_reset", 7},
+ {"tz_err", 8},
+ {"adsp_err", 9},
+ {"modem_err", 10},
+ {"mba_err", 11},
+ {"Watchdog", 12},
+ {"Panic", 13},
+};
+
+// Converts a string value representing the reason the system booted to an
+// integer representation. This is necessary for logging the boot_reason metric
+// via Tron, which does not accept non-integer buckets in histograms.
+int32_t BootReasonStrToEnum(const std::string& boot_reason) {
+ static const int32_t kUnknownBootReason = -1;
+
+ auto mapping = kBootReasonMap.find(boot_reason);
+ if (mapping != kBootReasonMap.end()) {
+ return mapping->second;
+ }
+
+ LOG(INFO) << "Unknown boot reason: " << boot_reason;
+ return kUnknownBootReason;
+}
+
+// Records the boot_reason metric by querying the ro.boot.bootreason system
+// property.
+void RecordBootReason() {
+ int32_t boot_reason = BootReasonStrToEnum(GetProperty("ro.boot.bootreason"));
+ BootEventRecordStore boot_event_store;
+ boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
+}
+
} // namespace
int main(int argc, char **argv) {
@@ -100,9 +157,31 @@
const std::string cmd_line = GetCommandLine(argc, argv);
LOG(INFO) << "Service started: " << cmd_line;
+ int option_index = 0;
+ static const char boot_reason_str[] = "record_boot_reason";
+ static const struct option long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "log", no_argument, NULL, 'l' },
+ { "print", no_argument, NULL, 'p' },
+ { "record", required_argument, NULL, 'r' },
+ { boot_reason_str, no_argument, NULL, 0 },
+ { NULL, 0, NULL, 0 }
+ };
+
int opt = 0;
- while ((opt = getopt(argc, argv, "hlpr:")) != -1) {
+ while ((opt = getopt_long(argc, argv, "hlpr:", long_options, &option_index)) != -1) {
switch (opt) {
+ // This case handles long options which have no single-character mapping.
+ case 0: {
+ const std::string option_name = long_options[option_index].name;
+ if (option_name == boot_reason_str) {
+ RecordBootReason();
+ } else {
+ LOG(ERROR) << "Invalid option: " << option_name;
+ }
+ break;
+ }
+
case 'h': {
ShowHelp(argv[0]);
break;