Merge "bootstat: Record metrics for factory_reset and time_since_factory_reset."
This commit is contained in:
commit
8a97f88a6d
4 changed files with 88 additions and 14 deletions
|
|
@ -50,7 +50,7 @@ BootEventRecordStore::BootEventRecordStore() {
|
||||||
SetStorePath(BOOTSTAT_DATA_DIR);
|
SetStorePath(BOOTSTAT_DATA_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BootEventRecordStore::AddBootEvent(const std::string& name) {
|
void BootEventRecordStore::AddBootEvent(const std::string& event) {
|
||||||
std::string uptime_str;
|
std::string uptime_str;
|
||||||
if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
|
if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
|
||||||
LOG(ERROR) << "Failed to read /proc/uptime";
|
LOG(ERROR) << "Failed to read /proc/uptime";
|
||||||
|
|
@ -58,15 +58,15 @@ void BootEventRecordStore::AddBootEvent(const std::string& name) {
|
||||||
|
|
||||||
// Cast intentionally rounds down.
|
// Cast intentionally rounds down.
|
||||||
int32_t uptime = static_cast<int32_t>(strtod(uptime_str.c_str(), NULL));
|
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
|
// The implementation of AddBootEventValue makes use of the mtime file
|
||||||
// attribute to store the value associated with a boot event in order to
|
// attribute to store the value associated with a boot event in order to
|
||||||
// optimize on-disk size requirements and small-file thrashing.
|
// optimize on-disk size requirements and small-file thrashing.
|
||||||
void BootEventRecordStore::AddBootEventWithValue(
|
void BootEventRecordStore::AddBootEventWithValue(
|
||||||
const std::string& name, int32_t value) {
|
const std::string& event, int32_t value) {
|
||||||
std::string record_path = GetBootEventPath(name);
|
std::string record_path = GetBootEventPath(event);
|
||||||
if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
|
if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
|
||||||
PLOG(ERROR) << "Failed to create " << record_path;
|
PLOG(ERROR) << "Failed to create " << record_path;
|
||||||
}
|
}
|
||||||
|
|
@ -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::
|
std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::
|
||||||
GetAllBootEvents() const {
|
GetAllBootEvents() const {
|
||||||
std::vector<BootEventRecord> events;
|
std::vector<BootEventRecord> events;
|
||||||
|
|
@ -104,14 +120,13 @@ std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string event = entry->d_name;
|
const std::string event = entry->d_name;
|
||||||
const std::string record_path = GetBootEventPath(event);
|
BootEventRecord record;
|
||||||
int32_t uptime;
|
if (!GetBootEvent(event, &record)) {
|
||||||
if (!ParseRecordEventTime(record_path, &uptime)) {
|
LOG(ERROR) << "Failed to parse boot time event: " << event;
|
||||||
LOG(ERROR) << "Failed to parse boot time record: " << record_path;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.push_back(std::make_pair(event, uptime));
|
events.push_back(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
return events;
|
return events;
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,16 @@ class BootEventRecordStore {
|
||||||
|
|
||||||
BootEventRecordStore();
|
BootEventRecordStore();
|
||||||
|
|
||||||
// Persists the boot event named |name| in the record store.
|
// Persists the boot |event| in the record store.
|
||||||
void AddBootEvent(const std::string& name);
|
void AddBootEvent(const std::string& event);
|
||||||
|
|
||||||
// Persists the boot event named |name| with the associated |value| in the
|
// Persists the boot |event| with the associated |value| in the record store.
|
||||||
// record store.
|
void AddBootEventWithValue(const std::string& event, int32_t value);
|
||||||
void AddBootEventWithValue(const std::string& name, 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.
|
// Returns a list of all of the boot events persisted in the record store.
|
||||||
std::vector<BootEventRecord> GetAllBootEvents() const;
|
std::vector<BootEventRecord> GetAllBootEvents() const;
|
||||||
|
|
@ -50,6 +54,7 @@ class BootEventRecordStore {
|
||||||
FRIEND_TEST(BootEventRecordStoreTest, AddSingleBootEvent);
|
FRIEND_TEST(BootEventRecordStoreTest, AddSingleBootEvent);
|
||||||
FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
|
FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
|
||||||
FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
|
FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
|
||||||
|
FRIEND_TEST(BootEventRecordStoreTest, GetBootEvent);
|
||||||
|
|
||||||
// Sets the filesystem path of the record store.
|
// Sets the filesystem path of the record store.
|
||||||
void SetStorePath(const std::string& path);
|
void SetStorePath(const std::string& path);
|
||||||
|
|
|
||||||
|
|
@ -165,4 +165,27 @@ TEST_F(BootEventRecordStoreTest, AddBootEventWithValue) {
|
||||||
ASSERT_EQ(1U, events.size());
|
ASSERT_EQ(1U, events.size());
|
||||||
EXPECT_EQ("permian", events[0].first);
|
EXPECT_EQ("permian", events[0].first);
|
||||||
EXPECT_EQ(42, events[0].second);
|
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());
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -155,6 +156,32 @@ void RecordBootReason() {
|
||||||
boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
|
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
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
@ -165,12 +192,14 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static const char boot_reason_str[] = "record_boot_reason";
|
static const char boot_reason_str[] = "record_boot_reason";
|
||||||
|
static const char factory_reset_str[] = "record_factory_reset";
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "log", no_argument, NULL, 'l' },
|
{ "log", no_argument, NULL, 'l' },
|
||||||
{ "print", no_argument, NULL, 'p' },
|
{ "print", no_argument, NULL, 'p' },
|
||||||
{ "record", required_argument, NULL, 'r' },
|
{ "record", required_argument, NULL, 'r' },
|
||||||
{ boot_reason_str, no_argument, NULL, 0 },
|
{ boot_reason_str, no_argument, NULL, 0 },
|
||||||
|
{ factory_reset_str, no_argument, NULL, 0 },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -182,6 +211,8 @@ int main(int argc, char **argv) {
|
||||||
const std::string option_name = long_options[option_index].name;
|
const std::string option_name = long_options[option_index].name;
|
||||||
if (option_name == boot_reason_str) {
|
if (option_name == boot_reason_str) {
|
||||||
RecordBootReason();
|
RecordBootReason();
|
||||||
|
} else if (option_name == factory_reset_str) {
|
||||||
|
RecordFactoryReset();
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << "Invalid option: " << option_name;
|
LOG(ERROR) << "Invalid option: " << option_name;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue