Merge "healthd: init members of BatteryMonitor."
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 22a67bb..8282b40 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -50,7 +50,7 @@
   SetStorePath(BOOTSTAT_DATA_DIR);
 }
 
-void BootEventRecordStore::AddBootEvent(const std::string& name) {
+void BootEventRecordStore::AddBootEvent(const std::string& event) {
   std::string uptime_str;
   if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
     LOG(ERROR) << "Failed to read /proc/uptime";
@@ -58,15 +58,15 @@
 
   // Cast intentionally rounds down.
   int32_t uptime = static_cast<int32_t>(strtod(uptime_str.c_str(), NULL));
-  AddBootEventWithValue(name, uptime);
+  AddBootEventWithValue(event, 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);
+    const std::string& event, int32_t value) {
+  std::string record_path = GetBootEventPath(event);
   if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
     PLOG(ERROR) << "Failed to create " << record_path;
   }
@@ -86,6 +86,22 @@
   }
 }
 
+bool BootEventRecordStore::GetBootEvent(
+    const std::string& event, BootEventRecord* record) const {
+  CHECK_NE(static_cast<BootEventRecord*>(nullptr), record);
+  CHECK(!event.empty());
+
+  const std::string record_path = GetBootEventPath(event);
+  int32_t uptime;
+  if (!ParseRecordEventTime(record_path, &uptime)) {
+    LOG(ERROR) << "Failed to parse boot time record: " << record_path;
+    return false;
+  }
+
+  *record = std::make_pair(event, uptime);
+  return true;
+}
+
 std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::
     GetAllBootEvents() const {
   std::vector<BootEventRecord> events;
@@ -104,14 +120,13 @@
     }
 
     const std::string event = entry->d_name;
-    const std::string record_path = GetBootEventPath(event);
-    int32_t uptime;
-    if (!ParseRecordEventTime(record_path, &uptime)) {
-      LOG(ERROR) << "Failed to parse boot time record: " << record_path;
+    BootEventRecord record;
+    if (!GetBootEvent(event, &record)) {
+      LOG(ERROR) << "Failed to parse boot time event: " << event;
       continue;
     }
 
-    events.push_back(std::make_pair(event, uptime));
+    events.push_back(record);
   }
 
   return events;
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h
index d1b7835..4d5deee 100644
--- a/bootstat/boot_event_record_store.h
+++ b/bootstat/boot_event_record_store.h
@@ -34,12 +34,16 @@
 
   BootEventRecordStore();
 
-  // Persists the boot event named |name| in the record store.
-  void AddBootEvent(const std::string& name);
+  // Persists the boot |event| in the record store.
+  void AddBootEvent(const std::string& event);
 
-  // Persists the boot event named |name| with the associated |value| in the
-  // record store.
-  void AddBootEventWithValue(const std::string& name, int32_t value);
+  // Persists the boot |event| with the associated |value| in the record store.
+  void AddBootEventWithValue(const std::string& event, int32_t value);
+
+  // Queries the named boot |event|. |record| must be non-null. |record|
+  // contains the boot event data on success. Returns true iff the query is
+  // successful.
+  bool GetBootEvent(const std::string& event, BootEventRecord* record) const;
 
   // Returns a list of all of the boot events persisted in the record store.
   std::vector<BootEventRecord> GetAllBootEvents() const;
@@ -50,6 +54,7 @@
   FRIEND_TEST(BootEventRecordStoreTest, AddSingleBootEvent);
   FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
   FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
+  FRIEND_TEST(BootEventRecordStoreTest, GetBootEvent);
 
   // 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 3e6d706..0d7bbb0 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -165,4 +165,27 @@
   ASSERT_EQ(1U, events.size());
   EXPECT_EQ("permian", events[0].first);
   EXPECT_EQ(42, events[0].second);
+}
+
+TEST_F(BootEventRecordStoreTest, GetBootEvent) {
+  BootEventRecordStore store;
+  store.SetStorePath(GetStorePathForTesting());
+
+  // Event does not exist.
+  BootEventRecordStore::BootEventRecord record;
+  bool result = store.GetBootEvent("nonexistent", &record);
+  EXPECT_EQ(false, result);
+
+  // Empty path.
+  EXPECT_DEATH(store.GetBootEvent(std::string(), &record), std::string());
+
+  // Success case.
+  store.AddBootEventWithValue("carboniferous", 314);
+  result = store.GetBootEvent("carboniferous", &record);
+  EXPECT_EQ(true, result);
+  EXPECT_EQ("carboniferous", record.first);
+  EXPECT_EQ(314, record.second);
+
+  // Null |record|.
+  EXPECT_DEATH(store.GetBootEvent("carboniferous", nullptr), std::string());
 }
\ No newline at end of file
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 1d16f69..0c49f82 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -22,6 +22,7 @@
 #include <unistd.h>
 #include <cstddef>
 #include <cstdio>
+#include <ctime>
 #include <map>
 #include <memory>
 #include <string>
@@ -155,6 +156,32 @@
   boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
 }
 
+// Records two metrics related to the user resetting a device: the time at
+// which the device is reset, and the time since the user last reset the
+// device.  The former is only set once per-factory reset.
+void RecordFactoryReset() {
+  BootEventRecordStore boot_event_store;
+  BootEventRecordStore::BootEventRecord record;
+
+  time_t current_time_utc = time(nullptr);
+
+  // The factory_reset boot event does not exist after the device is reset, so
+  // use this signal to mark the time of the factory reset.
+  if (!boot_event_store.GetBootEvent("factory_reset", &record)) {
+    boot_event_store.AddBootEventWithValue("factory_reset", current_time_utc);
+    boot_event_store.AddBootEventWithValue("time_since_factory_reset", 0);
+    return;
+  }
+
+  // Calculate and record the difference in time between now and the
+  // factory_reset time.
+  time_t factory_reset_utc = record.second;
+  time_t time_since_factory_reset = difftime(current_time_utc,
+                                             factory_reset_utc);
+  boot_event_store.AddBootEventWithValue("time_since_factory_reset",
+                                         time_since_factory_reset);
+}
+
 }  // namespace
 
 int main(int argc, char **argv) {
@@ -165,12 +192,14 @@
 
   int option_index = 0;
   static const char boot_reason_str[] = "record_boot_reason";
+  static const char factory_reset_str[] = "record_factory_reset";
   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 },
+    { factory_reset_str, no_argument,       NULL,   0 },
     { NULL,              0,                 NULL,   0 }
   };
 
@@ -182,6 +211,8 @@
         const std::string option_name = long_options[option_index].name;
         if (option_name == boot_reason_str) {
           RecordBootReason();
+        } else if (option_name == factory_reset_str) {
+          RecordFactoryReset();
         } else {
           LOG(ERROR) << "Invalid option: " << option_name;
         }
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index da2880a..e42c4e1 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -28,6 +28,7 @@
 
 #include "tcp.h"
 
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 
 namespace tcp {
@@ -98,7 +99,8 @@
         return false;
     }
 
-    char buffer[kHandshakeLength];
+    char buffer[kHandshakeLength + 1];
+    buffer[kHandshakeLength] = '\0';
     if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) != kHandshakeLength) {
         *error = android::base::StringPrintf(
                 "No initialization message received (%s). Target may not support TCP fastboot",
@@ -111,9 +113,10 @@
         return false;
     }
 
-    if (memcmp(buffer + 2, "01", 2) != 0) {
+    int version = 0;
+    if (!android::base::ParseInt(buffer + 2, &version) || version < kProtocolVersion) {
         *error = android::base::StringPrintf("Unknown TCP protocol version %s (host version %02d)",
-                                             std::string(buffer + 2, 2).c_str(), kProtocolVersion);
+                                             buffer + 2, kProtocolVersion);
         return false;
     }
 
diff --git a/fastboot/tcp_test.cpp b/fastboot/tcp_test.cpp
index 7d80d76..6e867ae 100644
--- a/fastboot/tcp_test.cpp
+++ b/fastboot/tcp_test.cpp
@@ -42,6 +42,16 @@
     EXPECT_EQ("", error);
 }
 
+TEST(TcpConnectTest, TestNewerVersionSuccess) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSend("FB01");
+    mock->AddReceive("FB99");
+
+    std::string error;
+    EXPECT_NE(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_EQ("", error);
+}
+
 TEST(TcpConnectTest, TestSendFailure) {
     std::unique_ptr<SocketMock> mock(new SocketMock);
     mock->ExpectSendFailure("FB01");
@@ -74,11 +84,11 @@
 TEST(TcpConnectTest, TestUnknownVersionFailure) {
     std::unique_ptr<SocketMock> mock(new SocketMock);
     mock->ExpectSend("FB01");
-    mock->AddReceive("FB02");
+    mock->AddReceive("FB00");
 
     std::string error;
     EXPECT_EQ(nullptr, tcp::internal::Connect(std::move(mock), &error));
-    EXPECT_EQ("Unknown TCP protocol version 02 (host version 01)", error);
+    EXPECT_EQ("Unknown TCP protocol version 00 (host version 01)", error);
 }
 
 // Fixture to configure a SocketMock for a successful TCP connection.
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 9a67c7a..50ac6d0 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -62,9 +62,9 @@
     explicit                    String16(const char* o, size_t len);
 
                                 ~String16();
-    
+
     inline  const char16_t*     string() const;
-    
+
             size_t              size() const;
             void                setTo(const String16& other);
             status_t            setTo(const char16_t* other);
@@ -72,12 +72,12 @@
             status_t            setTo(const String16& other,
                                       size_t len,
                                       size_t begin=0);
-    
+
             status_t            append(const String16& other);
             status_t            append(const char16_t* other, size_t len);
-            
+
     inline  String16&           operator=(const String16& other);
-    
+
     inline  String16&           operator+=(const String16& other);
     inline  String16            operator+(const String16& other) const;
 
@@ -90,7 +90,7 @@
 
             bool                startsWith(const String16& prefix) const;
             bool                startsWith(const char16_t* prefix) const;
-            
+
             status_t            makeLower();
 
             status_t            replaceAll(char16_t replaceThis,
@@ -106,16 +106,16 @@
     inline  bool                operator!=(const String16& other) const;
     inline  bool                operator>=(const String16& other) const;
     inline  bool                operator>(const String16& other) const;
-    
+
     inline  bool                operator<(const char16_t* other) const;
     inline  bool                operator<=(const char16_t* other) const;
     inline  bool                operator==(const char16_t* other) const;
     inline  bool                operator!=(const char16_t* other) const;
     inline  bool                operator>=(const char16_t* other) const;
     inline  bool                operator>(const char16_t* other) const;
-    
+
     inline                      operator const char16_t*() const;
-    
+
 private:
             const char16_t*     mString;
 };
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 6a5273f..449fb20 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -77,7 +77,7 @@
         //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
         //printHexData(1, str, buf->size(), 16, 1);
         //printf("\n");
-        
+
         return u16str;
     }
 
@@ -127,7 +127,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -142,7 +142,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -228,7 +228,7 @@
     } else if (otherLen == 0) {
         return NO_ERROR;
     }
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
@@ -249,7 +249,7 @@
     } else if (otherLen == 0) {
         return NO_ERROR;
     }
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {