Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b553896 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I45fbac4a,Ie390459d

* changes:
  bootstat: validate last kmsg and bootreason content more carefully
  bootstat: clang-format rebase
parents 7dcf0767 a16e437e
Loading
Loading
Loading
Loading
+7 −11
Original line number Diff line number Diff line
@@ -66,8 +66,7 @@ void BootEventRecordStore::AddBootEvent(const std::string& event) {
// 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& event, int32_t value) {
void BootEventRecordStore::AddBootEventWithValue(const std::string& event, int32_t value) {
  std::string record_path = GetBootEventPath(event);
  int record_fd = creat(record_path.c_str(), S_IRUSR | S_IWUSR);
  if (record_fd == -1) {
@@ -96,8 +95,7 @@ void BootEventRecordStore::AddBootEventWithValue(
  close(record_fd);
}

bool BootEventRecordStore::GetBootEvent(
    const std::string& event, BootEventRecord* record) const {
bool BootEventRecordStore::GetBootEvent(const std::string& event, BootEventRecord* record) const {
  CHECK_NE(static_cast<BootEventRecord*>(nullptr), record);
  CHECK(!event.empty());

@@ -112,8 +110,7 @@ bool BootEventRecordStore::GetBootEvent(
  return true;
}

std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::
    GetAllBootEvents() const {
std::vector<BootEventRecordStore::BootEventRecord> BootEventRecordStore::GetAllBootEvents() const {
  std::vector<BootEventRecord> events;

  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(store_path_.c_str()), closedir);
@@ -147,8 +144,7 @@ void BootEventRecordStore::SetStorePath(const std::string& path) {
  store_path_ = path;
}

std::string BootEventRecordStore::GetBootEventPath(
    const std::string& event) const {
std::string BootEventRecordStore::GetBootEventPath(const std::string& event) const {
  DCHECK_EQ('/', store_path_.back());
  return store_path_ + event;
}
+2 −2
Original line number Diff line number Diff line
@@ -17,12 +17,12 @@
#ifndef BOOT_EVENT_RECORD_STORE_H_
#define BOOT_EVENT_RECORD_STORE_H_

#include <android-base/macros.h>
#include <gtest/gtest_prod.h>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include <android-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.
+6 −12
Original line number Diff line number Diff line
@@ -101,13 +101,9 @@ time_t GetUptimeSeconds() {

class BootEventRecordStoreTest : public ::testing::Test {
 public:
  BootEventRecordStoreTest() {
    store_path_ = std::string(store_dir_.path) + "/";
  }
  BootEventRecordStoreTest() { store_path_ = std::string(store_dir_.path) + "/"; }

  const std::string& GetStorePathForTesting() const {
    return store_path_;
  }
  const std::string& GetStorePathForTesting() const { return store_path_; }

 private:
  void TearDown() {
@@ -159,9 +155,7 @@ TEST_F(BootEventRecordStoreTest, AddMultipleBootEvents) {
  store.AddBootEvent("triassic");

  const std::string EXPECTED_NAMES[] = {
    "cretaceous",
    "jurassic",
    "triassic",
      "cretaceous", "jurassic", "triassic",
  };

  auto events = store.GetAllBootEvents();
+30 −5
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ test_ota() {
fast and fake (touch build_date on device to make it different)" ]
test_optional_ota() {
  echo "INFO: expected duration of ${TEST} test about 45 seconds" >&2
  echo "WARNING: ${TEST} requires userdebug build" >&2
  adb shell su root touch /data/misc/bootstat/build_date >&2
  adb reboot ota
  wait_for_screen
@@ -425,6 +426,7 @@ Decision to rummage through bootstat data files was made as
a _real_ factory_reset is too destructive to the device." ]
test_factory_reset() {
  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
  echo "WARNING: ${TEST} requires userdebug build" >&2
  adb shell su root rm /data/misc/bootstat/build_date >&2
  adb reboot >&2
  wait_for_screen
@@ -479,7 +481,8 @@ test_hard() {
[ "USAGE: test_battery

battery test (trick):
- echo healthd: battery l=2 | adb shell su root tee /dev/kmsg ; adb reboot cold
- echo healthd: battery l=2<space> | adb shell su root tee /dev/kmsg
- adb reboot cold
- (wait until screen is up, boot has completed)
- adb shell getprop sys.boot.reason
- NB: should report reboot,battery, unless healthd managed to log
@@ -491,7 +494,7 @@ battery test (trick):
    +    setprop logd.kernel false
    +    rm /sys/fs/pstore/console-ramoops
    +    rm /sys/fs/pstore/console-ramoops-0
    +    write /dev/kmsg \"healthd: battery l=2
    +    write /dev/kmsg \"healthd: battery l=2${SPACE}
    +\"
- adb reboot fs
- (wait until screen is up, boot has completed)
@@ -500,9 +503,10 @@ battery test (trick):
- (replace set logd.kernel true to the above, and retry test)" ]
test_battery() {
  echo "INFO: expected duration of ${TEST} test roughly two minutes" >&2
  echo "WARNING: ${TEST} requires userdebug build" >&2
  # Send it _many_ times to combat devices with flakey pstore
  for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
    echo healthd: battery l=2 | adb shell su root tee /dev/kmsg >/dev/null
    echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
  done
  adb reboot cold >&2
  adb wait-for-device
@@ -516,7 +520,7 @@ test_battery() {
      if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then
        # retry
        for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
          echo healthd: battery l=2 | adb shell su root tee /dev/kmsg >/dev/null
          echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
        done
        adb reboot cold >&2
        adb wait-for-device
@@ -550,6 +554,7 @@ kernel_panic test:
- NB: should report kernel_panic,sysrq" ]
test_kernel_panic() {
  echo "INFO: expected duration of ${TEST} test > 2 minutes" >&2
  echo "WARNING: ${TEST} requires userdebug build" >&2
  echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
  wait_for_screen
  EXPECT_PROPERTY sys.boot.reason kernel_panic,sysrq
@@ -640,6 +645,26 @@ test_adb_reboot() {
  report_bootstat_logs reboot,adb
}

[ "USAGE: test_Its_Just_So_Hard_reboot

Its Just So Hard reboot test:
- adb shell reboot 'Its Just So Hard'
- (wait until screen is up, boot has completed)
- adb shell getprop sys.boot.reason
- NB: should report reboot,its_just_so_hard
- NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
test_Its_Just_So_Hard_reboot() {
  echo "INFO: expected duration of ${TEST} test roughly 45 seconds" >&2
  echo "INFO: ${TEST} cleanup requires userdebug build" >&2
  adb shell 'reboot "Its Just So Hard"'
  wait_for_screen
  EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
  EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
  adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
  EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard
  report_bootstat_logs reboot,its_just_so_hard
}

[ "USAGE: ${0##*/} [-s SERIAL] [tests]

Mainline executive to run the above tests" ]
+167 −147
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@
// uploaded to Android log storage via Tron.

#include <getopt.h>
#include <unistd.h>
#include <sys/klog.h>
#include <unistd.h>

#include <chrono>
#include <cmath>
@@ -61,8 +61,7 @@ void LogBootEvents() {
// Records the named boot |event| to the record store. If |value| is non-empty
// and is a proper string representation of an integer value, the converted
// integer value is associated with the boot event.
void RecordBootEventFromCommandLine(
    const std::string& event, const std::string& value_str) {
void RecordBootEventFromCommandLine(const std::string& event, const std::string& value_str) {
  BootEventRecordStore boot_event_store;
  if (!value_str.empty()) {
    int32_t value = 0;
@@ -221,6 +220,7 @@ int32_t BootReasonStrToEnum(const std::string& boot_reason) {

// Canonical list of supported primary reboot reasons.
const std::vector<const std::string> knownReasons = {
    // clang-format off
    // kernel
    "watchdog",
    "kernel_panic",
@@ -233,6 +233,7 @@ const std::vector<const std::string> knownReasons = {
    "warm",
    "shutdown",    // Can not happen from ro.boot.bootreason
    "reboot",      // Default catch-all for anything unknown
    // clang-format on
};

// Returns true if the supplied reason prefix is considered detailed enough.
@@ -320,8 +321,12 @@ bool addKernelPanicSubReason(const std::string& console, std::string& ret) {
// std::transform Helper callback functions:
// Converts a string value representing the reason the system booted to a
// string complying with Android system standard reason.
char tounderline(char c) { return ::isblank(c) ? '_' : c; }
char toprintable(char c) { return ::isprint(c) ? c : '?'; }
char tounderline(char c) {
  return ::isblank(c) ? '_' : c;
}
char toprintable(char c) {
  return ::isprint(c) ? c : '?';
}

const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
@@ -329,6 +334,8 @@ const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";

// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
  static const size_t max_reason_length = 256;

  std::string ret(GetProperty(system_reboot_reason_property));
  std::string reason(boot_reason);
  // If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
@@ -423,9 +430,15 @@ std::string BootReasonStrToReason(const std::string& boot_reason) {
      size_t pos = content.rfind(cmd);
      if (pos != std::string::npos) {
        pos += strlen(cmd);
        std::string subReason(content.substr(pos));
        pos = subReason.find('\'');
        if (pos != std::string::npos) subReason.erase(pos);
        std::string subReason(content.substr(pos, max_reason_length));
        for (pos = 0; pos < subReason.length(); ++pos) {
          char c = tounderline(subReason[pos]);
          if (!::isprint(c) || (c == '\'')) {
            subReason.erase(pos);
            break;
          }
          subReason[pos] = ::tolower(c);
        }
        if (subReason != "") {  // Will not land "reboot" as that is too blunt.
          if (isKernelRebootReason(subReason)) {
            ret = "reboot," + subReason;  // User space can't talk kernel reasons.
@@ -456,13 +469,20 @@ std::string BootReasonStrToReason(const std::string& boot_reason) {
      static const int battery_dead_threshold = 2;  // percent
      static const char battery[] = "healthd: battery l=";
      size_t pos = content.rfind(battery);  // last one
      std::string digits;
      if (pos != std::string::npos) {
        int level = atoi(content.substr(pos + strlen(battery)).c_str());
        digits = content.substr(pos + strlen(battery));
      }
      char* endptr = NULL;
      unsigned long long level = strtoull(digits.c_str(), &endptr, 10);
      if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
        LOG(INFO) << "Battery level at shutdown " << level << "%";
        if (level <= battery_dead_threshold) {
          ret = "shutdown,battery";
        }
      } else {        // Most likely
        digits = "";  // reset digits

        // Content buffer no longer will have console data. Beware if more
        // checks added below, that depend on parsing console content.
        content = "";
@@ -496,8 +516,11 @@ std::string BootReasonStrToReason(const std::string& boot_reason) {

        pos = content.find(match);  // The first one it finds.
        if (pos != std::string::npos) {
          pos += strlen(match);
          int level = atoi(content.substr(pos).c_str());
          digits = content.substr(pos + strlen(match));
        }
        endptr = NULL;
        level = strtoull(digits.c_str(), &endptr, 10);
        if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
          LOG(INFO) << "Battery level at startup " << level << "%";
          if (level <= battery_dead_threshold) {
            ret = "shutdown,battery";
@@ -513,6 +536,10 @@ std::string BootReasonStrToReason(const std::string& boot_reason) {
      // Content buffer no longer will have console data. Beware if more
      // checks added below, that depend on parsing console content.
      content = GetProperty(last_reboot_reason_property);
      // Cleanup last_boot_reason regarding acceptable character set
      std::transform(content.begin(), content.end(), content.begin(), ::tolower);
      std::transform(content.begin(), content.end(), content.begin(), tounderline);
      std::transform(content.begin(), content.end(), content.begin(), toprintable);

      // String is either "reboot,<reason>" or "shutdown,<reason>".
      // We will set if default reasons, only override with detail if thermal.
@@ -580,7 +607,7 @@ std::string CalculateBootCompletePrefix() {
  if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
    boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
    boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
    LOG(INFO) << "Canonical boot reason: " << "reboot,factory_reset";
    LOG(INFO) << "Canonical boot reason: reboot,factory_reset";
    SetProperty(system_reboot_reason_property, "reboot,factory_reset");
    if (GetProperty(bootloader_reboot_reason_property) == "") {
      SetProperty(bootloader_reboot_reason_property, "reboot,factory_reset");
@@ -588,7 +615,7 @@ std::string CalculateBootCompletePrefix() {
  } else if (build_date != record.second) {
    boot_complete_prefix = "ota_" + boot_complete_prefix;
    boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
    LOG(INFO) << "Canonical boot reason: " << "reboot,ota";
    LOG(INFO) << "Canonical boot reason: reboot,ota";
    SetProperty(system_reboot_reason_property, "reboot,ota");
    if (GetProperty(bootloader_reboot_reason_property) == "") {
      SetProperty(bootloader_reboot_reason_property, "reboot,ota");
@@ -599,8 +626,7 @@ std::string CalculateBootCompletePrefix() {
}

// Records the value of a given ro.boottime.init property in milliseconds.
void RecordInitBootTimeProp(
    BootEventRecordStore* boot_event_store, const char* property) {
void RecordInitBootTimeProp(BootEventRecordStore* boot_event_store, const char* property) {
  std::string value = GetProperty(property);

  int32_t time_in_ms;
@@ -685,10 +711,8 @@ void RecordBootComplete() {

  if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
    time_t last_boot_time_utc = record.second;
    time_t time_since_last_boot = difftime(current_time_utc,
                                           last_boot_time_utc);
    boot_event_store.AddBootEventWithValue("time_since_last_boot",
                                           time_since_last_boot);
    time_t time_since_last_boot = difftime(current_time_utc, last_boot_time_utc);
    boot_event_store.AddBootEventWithValue("time_since_last_boot", time_since_last_boot);
  }

  boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc);
@@ -714,8 +738,7 @@ void RecordBootComplete() {
    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
                                           boot_complete.count());
  } else {
      boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
                                             uptime.count());
    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", uptime.count());
  }

  // Record the total time from device startup to boot complete, regardless of
@@ -738,8 +761,7 @@ void RecordBootComplete() {
void RecordBootReason() {
  const std::string reason(GetProperty(bootloader_reboot_reason_property));
  android::metricslogger::LogMultiAction(android::metricslogger::ACTION_BOOT,
                                         android::metricslogger::FIELD_PLATFORM_REASON,
                                         reason);
                                         android::metricslogger::FIELD_PLATFORM_REASON, reason);

  // Log the raw bootloader_boot_reason property value.
  int32_t boot_reason = BootReasonStrToEnum(reason);
@@ -769,21 +791,20 @@ void RecordFactoryReset() {

  if (current_time_utc < 0) {
    // UMA does not display negative values in buckets, so convert to positive.
    android::metricslogger::LogHistogram(
        "factory_reset_current_time_failure", std::abs(current_time_utc));
    android::metricslogger::LogHistogram("factory_reset_current_time_failure",
                                         std::abs(current_time_utc));

    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
    // is losing records somehow.
    boot_event_store.AddBootEventWithValue(
        "factory_reset_current_time_failure", std::abs(current_time_utc));
    boot_event_store.AddBootEventWithValue("factory_reset_current_time_failure",
                                           std::abs(current_time_utc));
    return;
  } else {
    android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);

    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
    // is losing records somehow.
    boot_event_store.AddBootEventWithValue(
        "factory_reset_current_time", current_time_utc);
    boot_event_store.AddBootEventWithValue("factory_reset_current_time", current_time_utc);
  }

  // The factory_reset boot event does not exist after the device is reset, so
@@ -803,13 +824,10 @@ void RecordFactoryReset() {

  // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
  // is losing records somehow.
  boot_event_store.AddBootEventWithValue(
      "factory_reset_record_value", factory_reset_utc);
  boot_event_store.AddBootEventWithValue("factory_reset_record_value", factory_reset_utc);

  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);
  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
@@ -826,6 +844,7 @@ int main(int argc, char **argv) {
  static const char boot_reason_str[] = "record_boot_reason";
  static const char factory_reset_str[] = "record_time_since_factory_reset";
  static const struct option long_options[] = {
      // clang-format off
      { "help",            no_argument,       NULL,   'h' },
      { "log",             no_argument,       NULL,   'l' },
      { "print",           no_argument,       NULL,   'p' },
@@ -835,6 +854,7 @@ int main(int argc, char **argv) {
      { boot_reason_str,   no_argument,       NULL,   0 },
      { factory_reset_str, no_argument,       NULL,   0 },
      { NULL,              0,                 NULL,   0 }
      // clang-format on
  };

  std::string boot_event;