Merge "system/core: Add initial implementation of the bootstat command."

This commit is contained in:
James Hawkins 2016-01-19 23:23:48 +00:00 committed by Gerrit Code Review
commit d0009911de
10 changed files with 974 additions and 0 deletions

137
bootstat/Android.mk Normal file
View file

@ -0,0 +1,137 @@
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
bootstat_c_includes := external/gtest/include
bootstat_lib_src_files := \
boot_event_record_store.cpp \
event_log_list_builder.cpp
bootstat_src_files := \
bootstat.cpp
bootstat_test_src_files := \
boot_event_record_store_test.cpp \
event_log_list_builder_test.cpp \
testrunner.cpp
bootstat_shared_libs := \
libbase \
liblog
bootstat_cflags := \
-Wall \
-Wextra \
-Werror
bootstat_cppflags := \
-Wno-non-virtual-dtor
bootstat_debug_cflags := \
$(bootstat_cflags) \
-UNDEBUG
# 524291 corresponds to sysui_histogram, from
# frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
bootstat_cflags += -DHISTOGRAM_LOG_TAG=524291
# bootstat static library
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := libbootstat
LOCAL_CFLAGS := $(bootstat_cflags)
LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
include $(BUILD_STATIC_LIBRARY)
# bootstat static library, debug
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := libbootstat_debug
LOCAL_CFLAGS := $(bootstat_cflags)
LOCAL_CPPFLAGS := $(bootstat_debug_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
include $(BUILD_STATIC_LIBRARY)
# bootstat host static library, debug
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := libbootstat_host_debug
LOCAL_CFLAGS := $(bootstat_debug_cflags)
LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
include $(BUILD_HOST_STATIC_LIBRARY)
# bootstat binary
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := bootstat
LOCAL_CFLAGS := $(bootstat_cflags)
LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat
LOCAL_SRC_FILES := $(bootstat_src_files)
include $(BUILD_EXECUTABLE)
# Native tests
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := bootstat_tests
LOCAL_CFLAGS := $(bootstat_tests_cflags)
LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat_debug libgmock
LOCAL_SRC_FILES := $(bootstat_test_src_files)
include $(BUILD_NATIVE_TEST)
# Host native tests
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := bootstat_tests
LOCAL_CFLAGS := $(bootstat_tests_cflags)
LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat_host_debug libgmock_host
LOCAL_SRC_FILES := $(bootstat_test_src_files)
include $(BUILD_HOST_NATIVE_TEST)

47
bootstat/README.md Normal file
View file

@ -0,0 +1,47 @@
# bootstat #
The bootstat command records boot events (e.g., `firmware_loaded`,
`boot_complete`) and the relative time at which these events occurred. The
command also aggregates boot event metrics locally and logs the metrics for
analysis.
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.
## Relative time ##
The timestamp recorded by bootstat is the uptime of the system, i.e., the
number of seconds since the system booted.
## Recording boot events ##
To record the relative time of an event during the boot phase, call `bootstat`
with the `-r` option and the name of the boot event.
$ bootstat -r boot_complete
The relative time at which the command runs is recorded along with the name of
the boot event to be persisted.
## Logging boot events ##
To log the persisted boot events, call `bootstat` with the `-l` option.
$ bootstat -l
bootstat logs all boot events recorded using the `-r` option to the EventLog
using the Tron histogram. On GMS devices these logs are uploaded via Clearcut
for aggregation and analysis.
## Printing boot events ##
To print the set of persisted boot events, call `bootstat` with the `-p` option.
$ bootstat -p
Boot events:
------------
boot_complete 71

View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "boot_event_record_store.h"
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <utime.h>
#include <cstdlib>
#include <base/file.h>
#include <base/logging.h>
namespace {
const char BOOTSTAT_DATA_DIR[] = "/data/misc/bootstat/";
// Given a boot even record file at |path|, extracts the event's relative time
// from the record into |uptime|.
bool ParseRecordEventTime(const std::string& path, int32_t* uptime) {
DCHECK_NE(static_cast<int32_t*>(nullptr), uptime);
struct stat file_stat;
if (stat(path.c_str(), &file_stat) == -1) {
PLOG(ERROR) << "Failed to read " << path;
return false;
}
*uptime = file_stat.st_mtime;
return true;
}
} // namespace
BootEventRecordStore::BootEventRecordStore() {
SetStorePath(BOOTSTAT_DATA_DIR);
}
void BootEventRecordStore::AddBootEvent(const std::string& name) {
std::string uptime_str;
if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
LOG(ERROR) << "Failed to read /proc/uptime";
}
std::string record_path = GetBootEventPath(name);
if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
PLOG(ERROR) << "Failed to create " << record_path;
}
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};
if (utime(record_path.c_str(), &times) == -1) {
PLOG(ERROR) << "Failed to set mtime for " << record_path;
}
}
std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::
GetAllBootEvents() const {
std::vector<BootEventRecord> events;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(store_path_.c_str()), closedir);
// This case could happen due to external manipulation of the filesystem,
// so crash out if the record store doesn't exist.
CHECK_NE(static_cast<DIR*>(nullptr), dir.get());
struct dirent* entry;
while ((entry = readdir(dir.get())) != NULL) {
// Only parse regular files.
if (entry->d_type != DT_REG) {
continue;
}
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;
continue;
}
events.push_back(std::make_pair(event, uptime));
}
return events;
}
void BootEventRecordStore::SetStorePath(const std::string& path) {
DCHECK_EQ('/', path.back());
store_path_ = path;
}
std::string BootEventRecordStore::GetBootEventPath(
const std::string& event) const {
DCHECK_EQ('/', store_path_.back());
return store_path_ + event;
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BOOT_EVENT_RECORD_STORE_H_
#define BOOT_EVENT_RECORD_STORE_H_
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include <base/macros.h>
#include <gtest/gtest_prod.h>
// BootEventRecordStore manages the persistence of boot events to the record
// store and the retrieval of all boot event records from the store.
class BootEventRecordStore {
public:
// A BootEventRecord consists of the event name and the timestamp the event
// occurred.
typedef std::pair<std::string, int32_t> BootEventRecord;
BootEventRecordStore();
// Persists the boot event named |name| in the record store.
void AddBootEvent(const std::string& name);
// Returns a list of all of the boot events persisted in the record store.
std::vector<BootEventRecord> GetAllBootEvents() const;
private:
// The tests call SetStorePath to override the default store location with a
// more test-friendly path.
FRIEND_TEST(BootEventRecordStoreTest, AddSingleBootEvent);
FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
// Sets the filesystem path of the record store.
void SetStorePath(const std::string& path);
// Constructs the full path of the given boot |event|.
std::string GetBootEventPath(const std::string& event) const;
// The filesystem path of the record store.
std::string store_path_;
DISALLOW_COPY_AND_ASSIGN(BootEventRecordStore);
};
#endif // BOOT_EVENT_RECORD_STORE_H_

View file

@ -0,0 +1,156 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "boot_event_record_store.h"
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdint>
#include <cstdlib>
#include <base/file.h>
#include <base/test_utils.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using testing::UnorderedElementsAreArray;
namespace {
// 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.
bool FuzzUptimeEquals(int32_t a, int32_t b) {
const int32_t FUZZ_SECONDS = 10;
return (abs(a - b) <= FUZZ_SECONDS);
}
// Returns the uptime as read from /proc/uptime, rounded down to an integer.
int32_t ReadUptime() {
std::string uptime_str;
if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
return -1;
}
// Cast to int to round down.
return static_cast<int32_t>(strtod(uptime_str.c_str(), NULL));
}
// Recursively deletes the directory at |path|.
void DeleteDirectory(const std::string& path) {
typedef std::unique_ptr<DIR, decltype(&closedir)> ScopedDIR;
ScopedDIR dir(opendir(path.c_str()), closedir);
ASSERT_NE(nullptr, dir.get());
struct dirent* entry;
while ((entry = readdir(dir.get())) != NULL) {
const std::string entry_name(entry->d_name);
if (entry_name == "." || entry_name == "..") {
continue;
}
const std::string entry_path = path + "/" + entry_name;
if (entry->d_type == DT_DIR) {
DeleteDirectory(entry_path);
} else {
unlink(entry_path.c_str());
}
}
rmdir(path.c_str());
}
class BootEventRecordStoreTest : public ::testing::Test {
public:
BootEventRecordStoreTest() {
store_path_ = std::string(store_dir_.path) + "/";
}
const std::string& GetStorePathForTesting() const {
return store_path_;
}
private:
void TearDown() {
// This removes the record store temporary directory even though
// TemporaryDir should already take care of it, but this method cleans up
// the test files added to the directory which prevent TemporaryDir from
// being able to remove the directory.
DeleteDirectory(store_path_);
}
// A scoped temporary directory. Using this abstraction provides creation of
// the directory and the path to the directory, which is stored in
// |store_path_|.
TemporaryDir store_dir_;
// The path to the temporary directory used by the BootEventRecordStore to
// persist records. The directory is created and destroyed for each test.
std::string store_path_;
DISALLOW_COPY_AND_ASSIGN(BootEventRecordStoreTest);
};
} // namespace
TEST_F(BootEventRecordStoreTest, AddSingleBootEvent) {
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
int32_t uptime = ReadUptime();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cenozoic");
auto events = store.GetAllBootEvents();
ASSERT_EQ(1U, events.size());
EXPECT_EQ("cenozoic", events[0].first);
EXPECT_TRUE(FuzzUptimeEquals(uptime, events[0].second));
}
TEST_F(BootEventRecordStoreTest, AddMultipleBootEvents) {
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
int32_t uptime = ReadUptime();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cretaceous");
store.AddBootEvent("jurassic");
store.AddBootEvent("triassic");
const std::string EXPECTED_NAMES[] = {
"cretaceous",
"jurassic",
"triassic",
};
auto events = store.GetAllBootEvents();
ASSERT_EQ(3U, events.size());
std::vector<std::string> names;
std::vector<int32_t> timestamps;
for (auto i = events.begin(); i != events.end(); ++i) {
names.push_back(i->first);
timestamps.push_back(i->second);
}
EXPECT_THAT(names, UnorderedElementsAreArray(EXPECTED_NAMES));
for (auto i = timestamps.cbegin(); i != timestamps.cend(); ++i) {
EXPECT_TRUE(FuzzUptimeEquals(uptime, *i));
}
}

144
bootstat/bootstat.cpp Normal file
View file

@ -0,0 +1,144 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// The bootstat command provides options to persist boot events with the current
// 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 <unistd.h>
#include <cstddef>
#include <cstdio>
#include <memory>
#include <string>
#include <base/logging.h>
#include <log/log.h>
#include "boot_event_record_store.h"
#include "event_log_list_builder.h"
namespace {
// 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;
EventLogListBuilder log_builder;
log_builder.Append(event);
log_builder.Append(data);
std::unique_ptr<uint8_t[]> log;
size_t size;
log_builder.Release(&log, &size);
android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
}
// Scans the boot event record store for record files and logs each boot event
// via EventLog.
void LogBootEvents() {
BootEventRecordStore boot_event_store;
auto events = boot_event_store.GetAllBootEvents();
for (auto i = events.cbegin(); i != events.cend(); ++i) {
LogBootEvent(i->first, i->second);
}
}
void PrintBootEvents() {
printf("Boot events:\n");
printf("------------\n");
BootEventRecordStore boot_event_store;
auto events = boot_event_store.GetAllBootEvents();
for (auto i = events.cbegin(); i != events.cend(); ++i) {
printf("%s\t%d\n", i->first.c_str(), i->second);
}
}
void ShowHelp(const char *cmd) {
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");
}
// Constructs a readable, printable string from the givencommand line
// arguments.
std::string GetCommandLine(int argc, char **argv) {
std::string cmd;
for (int i = 0; i < argc; ++i) {
cmd += argv[i];
cmd += " ";
}
return cmd;
}
} // namespace
int main(int argc, char **argv) {
android::base::InitLogging(argv);
const std::string cmd_line = GetCommandLine(argc, argv);
LOG(INFO) << "Service started: " << cmd_line;
int opt = 0;
while ((opt = getopt(argc, argv, "hlpr:")) != -1) {
switch (opt) {
case 'h': {
ShowHelp(argv[0]);
break;
}
case 'l': {
LogBootEvents();
break;
}
case 'p': {
PrintBootEvents();
break;
}
case 'r': {
// |optarg| is an external variable set by getopt representing
// the option argument.
const char* event = optarg;
BootEventRecordStore boot_event_store;
boot_event_store.AddBootEvent(event);
break;
}
default: {
DCHECK_EQ(opt, '?');
// |optopt| is an external variable set by getopt representing
// the value of the invalid option.
LOG(ERROR) << "Invalid option: " << optopt;
ShowHelp(argv[0]);
return EXIT_FAILURE;
}
}
}
return 0;
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "event_log_list_builder.h"
#include <cinttypes>
#include <string>
#include <base/logging.h>
#include <log/log.h>
namespace {
const size_t MAX_EVENT_PAYLOAD_SIZE = 512 - 1; // Leave room for final '\n'.
const size_t EVENT_TYPE_SIZE = 1; // Size in bytes of the event type marker.
} // namespace
EventLogListBuilder::EventLogListBuilder()
: payload_count_(0),
payload_size_(0),
payload_(std::make_unique<uint8_t[]>(MAX_EVENT_PAYLOAD_SIZE)) {
memset(payload_.get(), 0, MAX_EVENT_PAYLOAD_SIZE);
// Set up the top-level EventLog data type.
AppendByte(EVENT_TYPE_LIST);
// Skip over the byte prepresenting the number of items in the list. This
// value is set in Release().
payload_size_++;
}
bool EventLogListBuilder::Append(int value) {
DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
if (!IsSpaceAvailable(sizeof(value) + EVENT_TYPE_SIZE)) {
return false;
}
AppendByte(EVENT_TYPE_INT);
AppendData(&value, sizeof(value));
payload_count_++;
return true;
}
bool EventLogListBuilder::Append(const std::string& value) {
DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
int len = value.length();
if (!IsSpaceAvailable(sizeof(len) + len)) {
return false;
}
AppendByte(EVENT_TYPE_STRING);
AppendData(&len, sizeof(len));
AppendData(value.c_str(), len);
payload_count_++;
return true;
}
void EventLogListBuilder::Release(std::unique_ptr<uint8_t[]>* log,
size_t* size) {
// Finalize the log payload.
payload_[1] = payload_count_;
// Return the log payload.
*size = payload_size_;
*log = std::move(payload_);
}
void EventLogListBuilder::AppendData(const void* data, size_t size) {
DCHECK_LT(payload_size_ + size, MAX_EVENT_PAYLOAD_SIZE);
memcpy(&payload_[payload_size_], data, size);
payload_size_ += size;
}
void EventLogListBuilder::AppendByte(uint8_t byte) {
DCHECK_LT(payload_size_ + sizeof(byte), MAX_EVENT_PAYLOAD_SIZE);
payload_[payload_size_++] = byte;
}
bool EventLogListBuilder::IsSpaceAvailable(size_t value_size) {
size_t space_needed = value_size + EVENT_TYPE_SIZE;
if (payload_size_ + space_needed > MAX_EVENT_PAYLOAD_SIZE) {
size_t remaining = MAX_EVENT_PAYLOAD_SIZE - payload_size_;
LOG(WARNING) << "Not enough space for value. remain=" <<
remaining << "; needed=" << space_needed;
return false;
}
return true;
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EVENT_LOG_LIST_BUILDER_H_
#define EVENT_LOG_LIST_BUILDER_H_
#include <cstdint>
#include <memory>
#include <base/macros.h>
// EventLogListBuilder provides a mechanism to build an EventLog list
// consisting of int and string EventLog values.
//
// NOTE: This class does not provide the ability to append an embedded list,
// i.e., a list containing a list.
class EventLogListBuilder {
public:
EventLogListBuilder();
// Append a single value of a specified type.
bool Append(int value);
bool Append(const std::string& value);
// Finalizes construction of the EventLog list and releases the data
// to the caller. Caller takes ownership of the payload. No further calls
// to append* may be made once the payload is acquired by the caller.
void Release(std::unique_ptr<uint8_t[]>* log, size_t* size);
private:
// Appends |data| of the given |size| to the payload.
void AppendData(const void* data, size_t size);
// Appends a single byte to the payload.
void AppendByte(uint8_t byte);
// Returns true iff the remaining capacity in |payload_| is large enough to
// accommodate |value_size| bytes. The space required to log the event type
// is included in the internal calculation so must not be passed in to
// |value_size|.
bool IsSpaceAvailable(size_t value_size);
// The number of items in the EventLog list.
size_t payload_count_;
// The size of the data stored in |payload_|. Used to track where to insert
// new data.
size_t payload_size_;
// The payload constructed by calls to log*. The payload may only contain
// MAX_EVENT_PAYLOAD (512) bytes.
std::unique_ptr<uint8_t[]> payload_;
DISALLOW_COPY_AND_ASSIGN(EventLogListBuilder);
};
#endif // EVENT_LOG_LIST_BUILDER_H_

View file

@ -0,0 +1,113 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "event_log_list_builder.h"
#include <inttypes.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <log/log.h>
using testing::ElementsAreArray;
TEST(EventLogListBuilder, Empty) {
EventLogListBuilder builder;
const uint8_t EXPECTED_LOG[] = {
EVENT_TYPE_LIST,
0, // Number of items in the list.
};
std::unique_ptr<uint8_t[]> log;
size_t size;
builder.Release(&log, &size);
EXPECT_EQ(2U, size);
uint8_t* log_data = log.get();
EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
ElementsAreArray(EXPECTED_LOG));
}
TEST(EventLogListBuilder, SingleInt) {
EventLogListBuilder builder;
const uint8_t EXPECTED_LOG[] = {
EVENT_TYPE_LIST,
1, // Number of items in the list.
EVENT_TYPE_INT,
42, 0, 0, 0, // 4 byte integer value.
};
builder.Append(42);
std::unique_ptr<uint8_t[]> log;
size_t size;
builder.Release(&log, &size);
EXPECT_EQ(7U, size);
uint8_t* log_data = log.get();
EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
ElementsAreArray(EXPECTED_LOG));
}
TEST(EventLogListBuilder, SingleString) {
EventLogListBuilder builder;
const uint8_t EXPECTED_LOG[] = {
EVENT_TYPE_LIST,
1, // Number of items in the list.
EVENT_TYPE_STRING,
5, 0, 0, 0, // 4 byte length of the string.
'D', 'r', 'o', 'i', 'd',
};
builder.Append("Droid");
std::unique_ptr<uint8_t[]> log;
size_t size;
builder.Release(&log, &size);
EXPECT_EQ(12U, size);
uint8_t* log_data = log.get();
EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
ElementsAreArray(EXPECTED_LOG));
}
TEST(EventLogListBuilder, IntThenString) {
EventLogListBuilder builder;
const uint8_t EXPECTED_LOG[] = {
EVENT_TYPE_LIST,
2, // Number of items in the list.
EVENT_TYPE_INT,
42, 0, 0, 0, // 4 byte integer value.
EVENT_TYPE_STRING,
5, 0, 0, 0, // 4 byte length of the string.
'D', 'r', 'o', 'i', 'd',
};
builder.Append(42);
builder.Append("Droid");
std::unique_ptr<uint8_t[]> log;
size_t size;
builder.Release(&log, &size);
EXPECT_EQ(17U, size);
uint8_t* log_data = log.get();
EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
ElementsAreArray(EXPECTED_LOG));
}

24
bootstat/testrunner.cpp Normal file
View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <base/logging.h>
#include <gtest/gtest.h>
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger);
return RUN_ALL_TESTS();
}