bootstat: Handle v1 record files which do not contain file contents.

Bug: 27836969
Change-Id: I18fcdab7ca32d00af3f8827f42d47868492ed719
This commit is contained in:
James Hawkins 2016-03-24 16:26:20 -07:00
parent abdb758ef6
commit 84fda19c83
3 changed files with 56 additions and 3 deletions

View File

@ -55,8 +55,11 @@ bool ParseRecordEventTime(const std::string& path, int32_t* uptime) {
return false;
}
int32_t value = std::stoi(content);
bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
// Ignore existing bootstat records (which do not contain file content).
if (!content.empty()) {
int32_t value = std::stoi(content);
bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
}
return true;
}

View File

@ -55,6 +55,7 @@ class BootEventRecordStore {
FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
FRIEND_TEST(BootEventRecordStoreTest, GetBootEvent);
FRIEND_TEST(BootEventRecordStoreTest, GetBootEventNoFileContent);
// Sets the filesystem path of the record store.
void SetStorePath(const std::string& path);

View File

@ -17,12 +17,16 @@
#include "boot_event_record_store.h"
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "uptime_parser.h"
@ -31,6 +35,36 @@ using testing::UnorderedElementsAreArray;
namespace {
// Creates a fake boot event record file at |record_path| containing the boot
// record |value|. This method is necessary as truncating a
// BootEventRecordStore-created file would modify the mtime, which would alter
// the value of the record.
bool CreateEmptyBootEventRecord(const std::string& record_path, int32_t value) {
android::base::unique_fd record_fd(creat(record_path.c_str(), S_IRUSR | S_IWUSR));
if (record_fd.get() == -1) {
return false;
}
// Writing the value as content in the record file is a debug measure to
// ensure the validity of the file mtime value, i.e., to check that the record
// file mtime values are not changed once set.
// TODO(jhawkins): Remove this block.
if (!android::base::WriteStringToFd(std::to_string(value), record_fd.get())) {
return false;
}
// Set the |mtime| of the file to store the value of the boot event while
// preserving the |atime|.
struct timespec atime = {/* tv_sec */ 0, /* tv_usec */ UTIME_OMIT};
struct timespec mtime = {/* tv_sec */ value, /* tv_usec */ 0};
const struct timespec times[] = {atime, mtime};
if (futimens(record_fd.get(), times) != 0) {
return false;
}
return true;
}
// Returns true if the time difference between |a| and |b| is no larger
// than 10 seconds. This allow for a relatively large fuzz when comparing
// two timestamps taken back-to-back.
@ -178,4 +212,19 @@ TEST_F(BootEventRecordStoreTest, GetBootEvent) {
// Null |record|.
EXPECT_DEATH(store.GetBootEvent("carboniferous", nullptr), std::string());
}
}
// Tests that the BootEventRecordStore is capable of handling an older record
// protocol which does not contain file contents.
TEST_F(BootEventRecordStoreTest, GetBootEventNoFileContent) {
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
EXPECT_TRUE(CreateEmptyBootEventRecord(store.GetBootEventPath("devonian"), 2718));
BootEventRecordStore::BootEventRecord record;
bool result = store.GetBootEvent("devonian", &record);
EXPECT_EQ(true, result);
EXPECT_EQ("devonian", record.first);
EXPECT_EQ(2718, record.second);
}