bootstat: Refactor init/utils/boot_clock into base/chrono_utils.

Use this for bootstat and init. This replaces the custom uptime parser in
bootstat.

This is a reland of aosp/332854 with a fix for Darwin.

Bug: 34352037
Test: chrono_utils_test
Change-Id: Ib2567d8df0e460ab59753ac1c053dd7f9f1008a7
This commit is contained in:
James Hawkins 2017-02-13 15:47:21 -08:00
parent a3e4977325
commit 7c92e48450
15 changed files with 185 additions and 93 deletions

View File

@ -42,21 +42,32 @@ cc_library {
srcs: [
"errors_unix.cpp",
"properties.cpp",
"chrono_utils.cpp",
],
cppflags: ["-Wexit-time-destructors"],
},
darwin: {
srcs: ["errors_unix.cpp"],
srcs: [
"chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
},
linux_bionic: {
srcs: ["errors_unix.cpp"],
srcs: [
"chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
enabled: true,
},
linux: {
srcs: ["errors_unix.cpp"],
srcs: [
"chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
host_ldlibs: ["-lrt"],
},
windows: {
srcs: [
@ -88,7 +99,14 @@ cc_test {
],
target: {
android: {
srcs: ["properties_test.cpp"],
srcs: [
"chrono_utils_test.cpp",
"properties_test.cpp"
],
},
linux: {
srcs: ["chrono_utils_test.cpp"],
host_ldlibs: ["-lrt"],
},
windows: {
srcs: ["utf8_test.cpp"],

43
base/chrono_utils.cpp Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 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 "android-base/chrono_utils.h"
#include <time.h>
namespace android {
namespace base {
boot_clock::time_point boot_clock::now() {
timespec ts;
clockid_t clk_id;
#ifdef __ANDROID__
clk_id = CLOCK_BOOTTIME;
#else
// Darwin does not support CLOCK_BOOTTIME. CLOCK_MONOTONIC is a sufficient
// fallback; the only loss of precision is the time duration when the system
// is suspended.
clk_id = CLOCK_MONOTONIC;
#endif // __ANDROID__
clock_gettime(clk_id, &ts);
return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
std::chrono::nanoseconds(ts.tv_nsec));
}
} // namespace base
} // namespace android

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2017 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 "android-base/chrono_utils.h"
#include <time.h>
#include <chrono>
#include <gtest/gtest.h>
namespace android {
namespace base {
std::chrono::seconds GetBootTimeSeconds() {
struct timespec now;
clock_gettime(CLOCK_BOOTTIME, &now);
auto now_tp = boot_clock::time_point(
std::chrono::seconds(now.tv_sec) + std::chrono::nanoseconds(now.tv_nsec));
return std::chrono::duration_cast<std::chrono::seconds>(
now_tp.time_since_epoch());
}
// Tests (at least) the seconds accuracy of the boot_clock::now() method.
TEST(ChronoUtilsTest, BootClockNowSeconds) {
auto now = GetBootTimeSeconds();
auto boot_seconds = std::chrono::duration_cast<std::chrono::seconds>(
boot_clock::now().time_since_epoch());
EXPECT_EQ(now, boot_seconds);
}
} // namespace base
} // namespace android

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2017 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.
@ -14,16 +14,24 @@
* limitations under the License.
*/
#ifndef UPTIME_PARSER_H_
#define UPTIME_PARSER_H_
#ifndef ANDROID_BASE_CHRONO_UTILS_H
#define ANDROID_BASE_CHRONO_UTILS_H
#include <time.h>
#include <chrono>
namespace bootstat {
namespace android {
namespace base {
// Returns the number of seconds the system has been on since reboot.
time_t ParseUptime();
// A std::chrono clock based on CLOCK_BOOTTIME.
class boot_clock {
public:
typedef std::chrono::nanoseconds duration;
typedef std::chrono::time_point<boot_clock, duration> time_point;
} // namespace bootstat
static time_point now();
};
#endif // UPTIME_PARSER_H_
} // namespace base
} // namespace android
#endif // ANDROID_BASE_CHRONO_UTILS_H

View File

@ -16,7 +16,6 @@
bootstat_lib_src_files = [
"boot_event_record_store.cpp",
"uptime_parser.cpp",
]
cc_defaults {

View File

@ -20,13 +20,16 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <utime.h>
#include <chrono>
#include <cstdlib>
#include <string>
#include <utility>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include "uptime_parser.h"
namespace {
@ -55,7 +58,9 @@ BootEventRecordStore::BootEventRecordStore() {
}
void BootEventRecordStore::AddBootEvent(const std::string& event) {
AddBootEventWithValue(event, bootstat::ParseUptime());
auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
android::base::boot_clock::now().time_since_epoch());
AddBootEventWithValue(event, uptime.count());
}
// The implementation of AddBootEventValue makes use of the mtime file

View File

@ -21,15 +21,18 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <android-base/chrono_utils.h>
#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"
using testing::UnorderedElementsAreArray;
@ -89,6 +92,12 @@ void DeleteDirectory(const std::string& path) {
rmdir(path.c_str());
}
// Returns the time in seconds since boot.
time_t GetUptimeSeconds() {
return std::chrono::duration_cast<std::chrono::seconds>(
android::base::boot_clock::now().time_since_epoch()).count();
}
class BootEventRecordStoreTest : public ::testing::Test {
public:
BootEventRecordStoreTest() {
@ -126,7 +135,7 @@ TEST_F(BootEventRecordStoreTest, AddSingleBootEvent) {
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
time_t uptime = bootstat::ParseUptime();
time_t uptime = GetUptimeSeconds();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cenozoic");
@ -141,7 +150,7 @@ TEST_F(BootEventRecordStoreTest, AddMultipleBootEvents) {
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
time_t uptime = bootstat::ParseUptime();
time_t uptime = GetUptimeSeconds();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cretaceous");

View File

@ -21,6 +21,7 @@
#include <getopt.h>
#include <unistd.h>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdio>
@ -31,6 +32,7 @@
#include <vector>
#include <android/log.h>
#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@ -38,7 +40,6 @@
#include <metricslogger/metrics_logger.h>
#include "boot_event_record_store.h"
#include "uptime_parser.h"
namespace {
@ -247,7 +248,8 @@ void RecordBootComplete() {
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
time_t uptime = bootstat::ParseUptime();
auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
android::base::boot_clock::now().time_since_epoch());
time_t current_time_utc = time(nullptr);
if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
@ -274,22 +276,22 @@ void RecordBootComplete() {
// Log the amount of time elapsed until the device is decrypted, which
// includes the variable amount of time the user takes to enter the
// decryption password.
boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime);
boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
// Subtract the decryption time to normalize the boot cycle timing.
time_t boot_complete = uptime - record.second;
std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
boot_complete);
boot_complete.count());
} else {
boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
uptime);
uptime.count());
}
// Record the total time from device startup to boot complete, regardless of
// encryption state.
boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");

View File

@ -1,38 +0,0 @@
/*
* 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 "uptime_parser.h"
#include <time.h>
#include <cstdlib>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
namespace bootstat {
time_t ParseUptime() {
std::string uptime_str;
if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
PLOG(ERROR) << "Failed to read /proc/uptime";
return -1;
}
// Cast intentionally rounds down.
return static_cast<time_t>(strtod(uptime_str.c_str(), NULL));
}
} // namespace bootstat

View File

@ -36,7 +36,7 @@ LOCAL_MODULE := init_parser_tests
LOCAL_SRC_FILES := \
parser/tokenizer_test.cpp \
LOCAL_STATIC_LIBRARIES := libinit_parser
LOCAL_STATIC_LIBRARIES := libbase libinit_parser
LOCAL_CLANG := true
include $(BUILD_HOST_NATIVE_TEST)
endif

View File

@ -40,6 +40,7 @@
#include <selinux/label.h>
#include <selinux/android.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@ -68,6 +69,7 @@
#include "util.h"
#include "watchdogd.h"
using android::base::boot_clock;
using android::base::StringPrintf;
struct selabel_handle *sehandle;
@ -750,7 +752,7 @@ int main(int argc, char** argv) {
return watchdogd_main(argc, argv);
}
boot_clock::time_point start_time = boot_clock::now();
boot_clock::time_point start_time = android::base::boot_clock::now();
// Clear the umask.
umask(0);

View File

@ -32,6 +32,7 @@
#include <selinux/selinux.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
@ -47,6 +48,7 @@
#include "property_service.h"
#include "util.h"
using android::base::boot_clock;
using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::WriteStringToFile;

View File

@ -25,6 +25,8 @@
#include <string>
#include <vector>
#include <android-base/chrono_utils.h>
#include "action.h"
#include "capabilities.h"
#include "descriptors.h"
@ -135,8 +137,8 @@ private:
unsigned flags_;
pid_t pid_;
boot_clock::time_point time_started_; // time of last start
boot_clock::time_point time_crashed_; // first crash within inspection window
android::base::boot_clock::time_point time_started_; // time of last start
android::base::boot_clock::time_point time_crashed_; // first crash within inspection window
int crash_count_; // number of times crashed within window
uid_t uid_;

View File

@ -51,6 +51,8 @@
#include "property_service.h"
#include "util.h"
using android::base::boot_clock;
static unsigned int do_decode_uid(const char *s)
{
unsigned int v;
@ -199,11 +201,16 @@ bool write_file(const char* path, const char* content) {
return success;
}
boot_clock::time_point boot_clock::now() {
timespec ts;
clock_gettime(CLOCK_BOOTTIME, &ts);
return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
std::chrono::nanoseconds(ts.tv_nsec));
Timer::Timer() : start_(boot_clock::now()) {
}
double Timer::duration_s() const {
typedef std::chrono::duration<double> double_duration;
return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
}
int64_t Timer::duration_ms() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
}
int mkdir_recursive(const char *pathname, mode_t mode)

View File

@ -25,6 +25,8 @@
#include <ostream>
#include <string>
#include <android-base/chrono_utils.h>
#define COLDBOOT_DONE "/dev/.coldboot_done"
using namespace std::chrono_literals;
@ -35,32 +37,16 @@ int create_socket(const char *name, int type, mode_t perm,
bool read_file(const char* path, std::string* content);
bool write_file(const char* path, const char* content);
// A std::chrono clock based on CLOCK_BOOTTIME.
class boot_clock {
public:
typedef std::chrono::nanoseconds duration;
typedef std::chrono::time_point<boot_clock, duration> time_point;
static constexpr bool is_steady = true;
static time_point now();
};
class Timer {
public:
Timer() : start_(boot_clock::now()) {
}
Timer();
double duration_s() const {
typedef std::chrono::duration<double> double_duration;
return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
}
double duration_s() const;
int64_t duration_ms() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
}
int64_t duration_ms() const;
private:
boot_clock::time_point start_;
android::base::boot_clock::time_point start_;
};
std::ostream& operator<<(std::ostream& os, const Timer& t);