Loading bootstat/boot_event_record_store.cpp +24 −9 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ BootEventRecordStore::BootEventRecordStore() { 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"; Loading @@ -58,15 +58,15 @@ void BootEventRecordStore::AddBootEvent(const std::string& name) { // 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; } Loading @@ -86,6 +86,22 @@ void BootEventRecordStore::AddBootEventWithValue( } } 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; Loading @@ -104,14 +120,13 @@ std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore:: } 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; Loading bootstat/boot_event_record_store.h +10 −5 Original line number Diff line number Diff line Loading @@ -34,12 +34,16 @@ class BootEventRecordStore { 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; Loading @@ -50,6 +54,7 @@ class BootEventRecordStore { 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); Loading bootstat/boot_event_record_store_test.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -166,3 +166,26 @@ TEST_F(BootEventRecordStoreTest, AddBootEventWithValue) { 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 bootstat/bootstat.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <unistd.h> #include <cstddef> #include <cstdio> #include <ctime> #include <map> #include <memory> #include <string> Loading Loading @@ -155,6 +156,32 @@ void RecordBootReason() { 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) { Loading @@ -165,12 +192,14 @@ int main(int argc, char **argv) { 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 } }; Loading @@ -182,6 +211,8 @@ int main(int argc, char **argv) { 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; } Loading Loading
bootstat/boot_event_record_store.cpp +24 −9 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ BootEventRecordStore::BootEventRecordStore() { 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"; Loading @@ -58,15 +58,15 @@ void BootEventRecordStore::AddBootEvent(const std::string& name) { // 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; } Loading @@ -86,6 +86,22 @@ void BootEventRecordStore::AddBootEventWithValue( } } 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; Loading @@ -104,14 +120,13 @@ std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore:: } 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; Loading
bootstat/boot_event_record_store.h +10 −5 Original line number Diff line number Diff line Loading @@ -34,12 +34,16 @@ class BootEventRecordStore { 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; Loading @@ -50,6 +54,7 @@ class BootEventRecordStore { 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); Loading
bootstat/boot_event_record_store_test.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -166,3 +166,26 @@ TEST_F(BootEventRecordStoreTest, AddBootEventWithValue) { 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
bootstat/bootstat.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <unistd.h> #include <cstddef> #include <cstdio> #include <ctime> #include <map> #include <memory> #include <string> Loading Loading @@ -155,6 +156,32 @@ void RecordBootReason() { 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) { Loading @@ -165,12 +192,14 @@ int main(int argc, char **argv) { 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 } }; Loading @@ -182,6 +211,8 @@ int main(int argc, char **argv) { 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; } Loading