Merge "Tolerate RTM_DELADDR messages from deleted interfaces." into nyc-dev
diff --git a/bootstat/Android.mk b/bootstat/Android.mk
index bbb903d..c6349c1 100644
--- a/bootstat/Android.mk
+++ b/bootstat/Android.mk
@@ -32,6 +32,7 @@
 
 bootstat_shared_libs := \
         libbase \
+        libcutils \
         liblog
 
 bootstat_cflags := \
diff --git a/bootstat/README.md b/bootstat/README.md
index 1b4bf7f..b3964ce 100644
--- a/bootstat/README.md
+++ b/bootstat/README.md
@@ -7,10 +7,11 @@
 
     Usage: bootstat [options]
     options include:
-      -d              Dump the boot event records to the console.
-      -h              Show this help.
-      -l              Log all metrics to logstorage.
-      -r              Record the relative time of a named boot event.
+      -h, --help            Show this help
+      -l, --log             Log all metrics to logstorage
+      -p, --print           Dump the boot event records to the console
+      -r, --record          Record the timestamp of a named boot event
+      --record_boot_reason  Record the reason why the device booted
 
 ## Relative time ##
 
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 1bdcf2b..22a67bb 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -56,19 +56,31 @@
     LOG(ERROR) << "Failed to read /proc/uptime";
   }
 
+  // Cast intentionally rounds down.
+  int32_t uptime = static_cast<int32_t>(strtod(uptime_str.c_str(), NULL));
+  AddBootEventWithValue(name, uptime);
+}
+
+// The implementation of AddBootEventValue makes use of the mtime file
+// attribute to store the value associated with a boot event in order to
+// optimize on-disk size requirements and small-file thrashing.
+void BootEventRecordStore::AddBootEventWithValue(
+    const std::string& name, int32_t value) {
   std::string record_path = GetBootEventPath(name);
   if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
     PLOG(ERROR) << "Failed to create " << record_path;
   }
 
+  // Fill out the stat structure for |record_path| in order to get the atime to
+  // set in the utime() call.
   struct stat file_stat;
   if (stat(record_path.c_str(), &file_stat) == -1) {
     PLOG(ERROR) << "Failed to read " << record_path;
   }
 
-  // Cast intentionally rounds down.
-  time_t uptime = static_cast<time_t>(strtod(uptime_str.c_str(), NULL));
-  struct utimbuf times = {file_stat.st_atime, uptime};
+  // Set the |modtime| of the file to store the value of the boot event while
+  // preserving the |actime| (as read by stat).
+  struct utimbuf times = {/* actime */ file_stat.st_atime, /* modtime */ value};
   if (utime(record_path.c_str(), &times) == -1) {
     PLOG(ERROR) << "Failed to set mtime for " << record_path;
   }
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h
index 77978ef..d1b7835 100644
--- a/bootstat/boot_event_record_store.h
+++ b/bootstat/boot_event_record_store.h
@@ -37,6 +37,10 @@
   // Persists the boot event named |name| in the record store.
   void AddBootEvent(const std::string& name);
 
+  // Persists the boot event named |name| with the associated |value| in the
+  // record store.
+  void AddBootEventWithValue(const std::string& name, int32_t value);
+
   // Returns a list of all of the boot events persisted in the record store.
   std::vector<BootEventRecord> GetAllBootEvents() const;
 
@@ -45,6 +49,7 @@
   // more test-friendly path.
   FRIEND_TEST(BootEventRecordStoreTest, AddSingleBootEvent);
   FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
+  FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
 
   // Sets the filesystem path of the record store.
   void SetStorePath(const std::string& path);
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 384f84d..3e6d706 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -154,3 +154,15 @@
     EXPECT_TRUE(FuzzUptimeEquals(uptime, *i));
   }
 }
+
+TEST_F(BootEventRecordStoreTest, AddBootEventWithValue) {
+  BootEventRecordStore store;
+  store.SetStorePath(GetStorePathForTesting());
+
+  store.AddBootEventWithValue("permian", 42);
+
+  auto events = store.GetAllBootEvents();
+  ASSERT_EQ(1U, events.size());
+  EXPECT_EQ("permian", events[0].first);
+  EXPECT_EQ(42, events[0].second);
+}
\ No newline at end of file
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a83f8ad..1d16f69 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,67 @@
   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);
+}
+
+constexpr int32_t kUnknownBootReason = 1;
+
+// 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, int32_t> kBootReasonMap = {
+  {"unknown", kUnknownBootReason},
+  {"normal", 2},
+  {"recovery", 3},
+  {"reboot", 4},
+  {"PowerKey", 5},
+  {"hard_reset", 6},
+  {"kernel_panic", 7},
+  {"rpm_err", 8},
+  {"hw_reset", 9},
+  {"tz_err", 10},
+  {"adsp_err", 11},
+  {"modem_err", 12},
+  {"mba_err", 13},
+  {"Watchdog", 14},
+  {"Panic", 15},
+  {"power_key", 16},
+  {"power_on", 17},
+  {"Reboot", 18},
+  {"rtc", 19},
+  {"edl", 20},
+};
+
+// 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) {
+  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 +163,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;
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 2c37dd2..218b9f8 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -10,5 +10,8 @@
     # Record boot_complete timing event.
     exec - root root -- /system/bin/bootstat -r boot_complete
 
+    # Record the boot reason.
+    exec - root root -- /system/bin/bootstat --record_boot_reason
+
     # Log all boot events.
     exec - root root -- /system/bin/bootstat -l
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 75d2a2d..aaff64c 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -62,7 +62,9 @@
 
 class LibraryNamespaces {
  public:
-  LibraryNamespaces() : initialized_(false) { }
+  LibraryNamespaces() : initialized_(false) {
+    PreloadPublicLibraries();
+  }
 
   android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader,
                                    bool is_shared,
@@ -108,15 +110,16 @@
   }
 
  private:
-  bool InitPublicNamespace(const char* library_path) {
-    // Make sure all the public libraries are loaded
+  void PreloadPublicLibraries() {
+    // android_init_namespaces() expects all the public libraries
+    // to be loaded so that they can be found by soname alone.
     std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":");
     for (const auto& soname : sonames) {
-      if (dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr) {
-        return false;
-      }
+      dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
     }
+  }
 
+  bool InitPublicNamespace(const char* library_path) {
     // Some apps call dlopen from generated code unknown to linker in which
     // case linker uses anonymous namespace. See b/25844435 for details.
     initialized_ = android_init_namespaces(kPublicNativeLibraries, library_path);