Add update reboot metric to the update engine.
This change add the Installer.UpdateNumReboots metric.
This records the number of reboots that occurred while an update was being
attempted. It uses a marker file stored in tmp to discover whether or not
it's already recorded the reboot.
BUG=chromium:226766
TEST=Unittests | ran an update on a test machine and rebooted/resumed and
checked about:histograms to confirm numbers. Also restart update-engine to
verify it didn't double count that.
Change-Id: I5d2af9d5b62a9d974c7c6243a89cb3359051b650
Reviewed-on: https://gerrit.chromium.org/gerrit/47710
Tested-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Chris Sosa <sosa@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
diff --git a/constants.cc b/constants.cc
index 0bc95f7..3609a02 100644
--- a/constants.cc
+++ b/constants.cc
@@ -9,8 +9,12 @@
const char kPowerwashMarkerFile[] =
"/mnt/stateful_partition/factory_install_reset";
+const char kSystemRebootedMarkerFile[] = "/tmp/update_engine_update_recorded";
+
const char kPowerwashCommand[] = "safe fast\n";
+const char kStatefulPartition[] = "/mnt/stateful_partition";
+
// Constants defining keys for the persisted state of update engine.
const char kPrefsBackoffExpiryTime[] = "backoff-expiry-time";
const char kPrefsCertificateReportToSendDownload[] =
@@ -25,6 +29,7 @@
const char kPrefsLastActivePingDay[] = "last-active-ping-day";
const char kPrefsLastRollCallPingDay[] = "last-roll-call-ping-day";
const char kPrefsManifestMetadataSize[] = "manifest-metadata-size";
+const char kPrefsNumReboots[] = "num-reboots";
const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number";
const char kPrefsPreviousVersion[] = "previous-version";
const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
diff --git a/constants.h b/constants.h
index 3b8a918..e97ec90 100644
--- a/constants.h
+++ b/constants.h
@@ -11,9 +11,15 @@
// completes successfully so that the device is powerwashed on next reboot.
extern const char kPowerwashMarkerFile[];
+// Path to the marker file we use to indicate we've recorded a system reboot.
+extern const char kSystemRebootedMarkerFile[];
+
// The contents of the powerwash marker file.
extern const char kPowerwashCommand[];
+// Path to the stateful partition on the root filesystem.
+extern const char kStatefulPartition[];
+
// Constants related to preferences.
extern const char kPrefsBackoffExpiryTime[];
extern const char kPrefsCertificateReportToSendDownload[];
@@ -26,6 +32,7 @@
extern const char kPrefsLastActivePingDay[];
extern const char kPrefsLastRollCallPingDay[];
extern const char kPrefsManifestMetadataSize[];
+extern const char kPrefsNumReboots[];
extern const char kPrefsPayloadAttemptNumber[];
extern const char kPrefsPreviousVersion[];
extern const char kPrefsResumedUpdateFailures[];
diff --git a/integration_unittest.cc b/integration_unittest.cc
index f42b89e..e54c0e2 100644
--- a/integration_unittest.cc
+++ b/integration_unittest.cc
@@ -7,6 +7,7 @@
#include <glib.h>
#include <pthread.h>
#include <gtest/gtest.h>
+#include "update_engine/constants.h"
#include "update_engine/download_action.h"
#include "update_engine/install_action.h"
#include "update_engine/libcurl_http_fetcher.h"
@@ -134,7 +135,7 @@
ASSERT_EQ(0, system("rm -f /tmp/update_engine_test_postinst_out.txt"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, system((string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition +
+ kStatefulPartition +
"/etc").c_str()));
ASSERT_TRUE(WriteFileString(string(kTestDir) + "/etc/lsb-release",
"GOOGLE_RELEASE=0.2.0.0\n"
diff --git a/mock_payload_state.h b/mock_payload_state.h
index fe744de..88578b5 100644
--- a/mock_payload_state.h
+++ b/mock_payload_state.h
@@ -21,6 +21,7 @@
MOCK_METHOD1(SetResponse, void(const OmahaResponse& response));
MOCK_METHOD0(DownloadComplete, void());
MOCK_METHOD1(DownloadProgress, void(size_t count));
+ MOCK_METHOD0(UpdateResumed, void());
MOCK_METHOD0(UpdateRestarted, void());
MOCK_METHOD0(UpdateSucceeded, void());
MOCK_METHOD1(UpdateFailed, void(ActionExitCode error));
@@ -37,6 +38,7 @@
MOCK_METHOD0(GetUpdateDurationUptime, base::TimeDelta());
MOCK_METHOD1(GetCurrentBytesDownloaded, uint64_t(DownloadSource source));
MOCK_METHOD1(GetTotalBytesDownloaded, uint64_t(DownloadSource source));
+ MOCK_METHOD0(GetNumReboots, uint32_t());
};
} // namespace chromeos_update_engine
diff --git a/mock_system_state.h b/mock_system_state.h
index b7f9211..ac93d16 100644
--- a/mock_system_state.h
+++ b/mock_system_state.h
@@ -32,6 +32,7 @@
MOCK_METHOD1(set_device_policy, void(const policy::DevicePolicy*));
MOCK_CONST_METHOD0(device_policy, const policy::DevicePolicy*());
+ MOCK_METHOD0(system_rebooted, bool());
inline virtual ConnectionManager* connection_manager() {
return connection_manager_;
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index e550070..c3a3f1b 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -1479,7 +1479,7 @@
const string kTestDir = "omaha_request_action-test";
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition + "/etc"));
+ kStatefulPartition + "/etc"));
vector<char> post_data;
NiceMock<PrefsMock> prefs;
ASSERT_TRUE(WriteFileString(
@@ -1488,7 +1488,7 @@
"CHROMEOS_BOARD_APPID={22222222-2222-2222-2222-222222222222}\n"
"CHROMEOS_RELEASE_TRACK=canary-channel\n"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_IS_POWERWASH_ALLOWED=true\n"
"CHROMEOS_RELEASE_TRACK=stable-channel\n"));
OmahaRequestParams params = kDefaultTestParams;
@@ -1519,7 +1519,7 @@
const string kTestDir = "omaha_request_action-test";
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition + "/etc"));
+ kStatefulPartition + "/etc"));
vector<char> post_data;
NiceMock<PrefsMock> prefs;
ASSERT_TRUE(WriteFileString(
@@ -1528,7 +1528,7 @@
"CHROMEOS_BOARD_APPID={22222222-2222-2222-2222-222222222222}\n"
"CHROMEOS_RELEASE_TRACK=stable-channel\n"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_TRACK=canary-channel\n"));
OmahaRequestParams params = kDefaultTestParams;
params.set_root(string("./") + kTestDir);
diff --git a/omaha_request_params.cc b/omaha_request_params.cc
index 591a6f6..f30e771 100644
--- a/omaha_request_params.cc
+++ b/omaha_request_params.cc
@@ -15,6 +15,7 @@
#include <base/file_util.h>
#include <policy/device_policy.h>
+#include "update_engine/constants.h"
#include "update_engine/simple_key_value_store.h"
#include "update_engine/system_state.h"
#include "update_engine/utils.h"
@@ -132,7 +133,7 @@
}
TEST_AND_RETURN_FALSE(IsValidChannel(new_target_channel));
- FilePath kFile(root_ + utils::kStatefulPartition + "/etc/lsb-release");
+ FilePath kFile(root_ + kStatefulPartition + "/etc/lsb-release");
string file_data;
map<string, string> data;
if (file_util::ReadFileToString(kFile, &file_data)) {
@@ -213,7 +214,7 @@
bool stateful_override) const {
vector<string> files;
if (stateful_override) {
- files.push_back(string(utils::kStatefulPartition) + "/etc/lsb-release");
+ files.push_back(string(kStatefulPartition) + "/etc/lsb-release");
}
files.push_back("/etc/lsb-release");
for (vector<string>::const_iterator it = files.begin();
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index 31ccd66..c12abcb 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -8,6 +8,7 @@
#include "base/file_util.h"
#include "gtest/gtest.h"
+#include "update_engine/constants.h"
#include "update_engine/install_plan.h"
#include "update_engine/mock_system_state.h"
#include "update_engine/omaha_request_params.h"
@@ -31,7 +32,7 @@
virtual void SetUp() {
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition + "/etc"));
+ kStatefulPartition + "/etc"));
// Create a fresh copy of the params for each test, so there's no
// unintended reuse of state across tests.
MockSystemState mock_system_state;
@@ -258,7 +259,7 @@
"CHROMEOS_RELEASE_TRACK=dev-channel\n"
"CHROMEOS_AUSERVER=http://www.google.com"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_BOARD=x86-generic\n"
"CHROMEOS_RELEASE_TRACK=beta-channel\n"
"CHROMEOS_AUSERVER=https://www.google.com"));
@@ -286,7 +287,7 @@
"CHROMEOS_RELEASE_TRACK=dev-channel\n"
"CHROMEOS_AUSERVER=https://www.google.com"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_BOARD=x86-generic\n"
"CHROMEOS_RELEASE_TRACK=stable-channel\n"
"CHROMEOS_AUSERVER=http://www.google.com"));
@@ -312,7 +313,7 @@
"CHROMEOS_RELEASE_TRACK=dev-channel\n"
"CHROMEOS_AUSERVER=http://www.google.com"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_BOARD=x86-generic\n"
"CHROMEOS_RELEASE_TRACK=dev-channel"));
MockSystemState mock_system_state;
@@ -474,7 +475,7 @@
// Set a different channel in stateful LSB release.
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_TRACK=stable-channel\n"
"CHROMEOS_IS_POWERWASH_ALLOWED=true\n"));
@@ -518,7 +519,7 @@
"CHROMEOS_RELEASE_TRACK=canary-channel\n"
"CHROMEOS_AUSERVER=http://www.google.com"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_BOARD=x86-generic\n"
"CHROMEOS_RELEASE_TRACK=stable-channel\n"
"CHROMEOS_AUSERVER=https://www.google.com"));
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index af47289..f494aa0 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -53,7 +53,9 @@
install_plan_.hash_checks_mandatory = AreHashChecksMandatory(response);
install_plan_.is_resume =
DeltaPerformer::CanResumeUpdate(system_state_->prefs(), response.hash);
- if (!install_plan_.is_resume) {
+ if (install_plan_.is_resume) {
+ system_state_->payload_state()->UpdateResumed();
+ } else {
system_state_->payload_state()->UpdateRestarted();
LOG_IF(WARNING, !DeltaPerformer::ResetUpdateProgress(
system_state_->prefs(), false))
@@ -84,7 +86,7 @@
// hacky solution but should be OK for now.
//
// TODO(petkov): Rearchitect this to avoid communication through a
- // file. Ideallly, we would include this information in D-Bus's GetStatus
+ // file. Ideally, we would include this information in D-Bus's GetStatus
// method and UpdateStatus signal. A potential issue is that update_engine may
// be unresponsive during an update download.
utils::WriteFile(kDeadlineFile,
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 88ac0c4..cb27f82 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -240,12 +240,12 @@
const string kTestDir = "omaha_response_handler_action-test";
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition + "/etc"));
+ kStatefulPartition + "/etc"));
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
"CHROMEOS_RELEASE_TRACK=canary-channel\n"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_IS_POWERWASH_ALLOWED=true\n"
"CHROMEOS_RELEASE_TRACK=stable-channel\n"));
@@ -277,12 +277,12 @@
const string kTestDir = "omaha_response_handler_action-test";
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
- utils::kStatefulPartition + "/etc"));
+ kStatefulPartition + "/etc"));
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
"CHROMEOS_RELEASE_TRACK=stable-channel\n"));
ASSERT_TRUE(WriteFileString(
- kTestDir + utils::kStatefulPartition + "/etc/lsb-release",
+ kTestDir + kStatefulPartition + "/etc/lsb-release",
"CHROMEOS_RELEASE_TRACK=canary-channel\n"));
MockSystemState mock_system_state;
diff --git a/payload_state.cc b/payload_state.cc
index 2a26722..bae21b9 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -58,6 +58,7 @@
LoadCurrentBytesDownloaded(source);
LoadTotalBytesDownloaded(source);
}
+ LoadNumReboots();
return true;
}
@@ -124,9 +125,15 @@
SetUrlFailureCount(0);
}
+void PayloadState::UpdateResumed() {
+ LOG(INFO) << "Resuming an update that was previously started.";
+ UpdateNumReboots();
+}
+
void PayloadState::UpdateRestarted() {
LOG(INFO) << "Starting a new update";
ResetDownloadSourcesOnNewUpdate();
+ SetNumReboots(0);
}
void PayloadState::UpdateSucceeded() {
@@ -135,6 +142,7 @@
SetUpdateTimestampEnd(Time::Now());
ReportBytesDownloadedMetrics();
ReportUpdateUrlSwitchesMetric();
+ ReportRebootMetrics();
}
void PayloadState::UpdateFailed(ActionExitCode error) {
@@ -435,6 +443,39 @@
kNumDefaultUmaBuckets);
}
+void PayloadState::ReportRebootMetrics() {
+ // Report the number of num_reboots.
+ string metric = "Installer.UpdateNumReboots";
+ uint32_t num_reboots = GetNumReboots();
+ LOG(INFO) << "Uploading reboot count of " << num_reboots << " for metric "
+ << metric;
+ system_state_->metrics_lib()->SendToUMA(
+ metric,
+ static_cast<int>(num_reboots), // sample
+ 0, // min = 0.
+ 50, // max
+ 25); // buckets
+ SetNumReboots(0);
+}
+
+void PayloadState::UpdateNumReboots() {
+ // We only update the reboot count when the system has been detected to have
+ // been rebooted.
+ if (!system_state_->system_rebooted()) {
+ return;
+ }
+
+ SetNumReboots(GetNumReboots() + 1);
+}
+
+void PayloadState::SetNumReboots(uint32_t num_reboots) {
+ CHECK(prefs_);
+ num_reboots_ = num_reboots;
+ prefs_->SetInt64(kPrefsNumReboots, num_reboots);
+ LOG(INFO) << "Number of Reboots during current update attempt = "
+ << num_reboots_;
+}
+
void PayloadState::ResetPersistedState() {
SetPayloadAttemptNumber(0);
SetUrlIndex(0);
@@ -686,6 +727,10 @@
SetUpdateDurationUptime(stored_delta);
}
+void PayloadState::LoadNumReboots() {
+ SetNumReboots(GetPersistedValue(kPrefsNumReboots));
+}
+
void PayloadState::SetUpdateDurationUptimeExtended(const TimeDelta& value,
const Time& timestamp,
bool use_logging) {
diff --git a/payload_state.h b/payload_state.h
index 5427c74..43fe5cc 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -35,6 +35,7 @@
virtual void SetResponse(const OmahaResponse& response);
virtual void DownloadComplete();
virtual void DownloadProgress(size_t count);
+ virtual void UpdateResumed();
virtual void UpdateRestarted();
virtual void UpdateSucceeded();
virtual void UpdateFailed(ActionExitCode error);
@@ -76,6 +77,10 @@
return source < kNumDownloadSources ? total_bytes_downloaded_[source] : 0;
}
+ virtual inline uint32_t GetNumReboots() {
+ return num_reboots_;
+ }
+
private:
// Increments the payload attempt number which governs the backoff behavior
// at the time of the next update check.
@@ -112,6 +117,9 @@
// Reports the metric related to number of URL switches.
void ReportUpdateUrlSwitchesMetric();
+ // Reports the various metrics related to rebooting during an update.
+ void ReportRebootMetrics();
+
// Resets all the persisted state values which are maintained relative to the
// current response signature. The response signature itself is not reset.
void ResetPersistedState();
@@ -235,6 +243,18 @@
// The global state of the system.
SystemState* system_state_;
+ // Initializes |num_reboots_| from the persisted state.
+ void LoadNumReboots();
+
+ // Sets |num_reboots| for the update attempt. Also persists the
+ // value being set so that we resume from the same value in case of a process
+ // restart.
+ void SetNumReboots(uint32_t num_reboots);
+
+ // Checks to see if the device rebooted since the last call and if so
+ // increments num_reboots.
+ void UpdateNumReboots();
+
// Interface object with which we read/write persisted state. This must
// be set by calling the Initialize method before calling any other method.
PrefsInterface* prefs_;
@@ -276,6 +296,11 @@
// data we read from the socket.
DownloadSource current_download_source_;
+ // The number of system reboots during an update attempt. Technically since
+ // we don't go out of our way to not update it when not attempting an update,
+ // also records the number of reboots before the next update attempt starts.
+ uint32_t num_reboots_;
+
// The timestamp until which we've to wait before attempting to download the
// payload again, so as to backoff repeated downloads.
base::Time backoff_expiry_time_;
diff --git a/payload_state_interface.h b/payload_state_interface.h
index 76b847a..e092290 100644
--- a/payload_state_interface.h
+++ b/payload_state_interface.h
@@ -40,6 +40,9 @@
// able to make forward progress with the current URL.
virtual void DownloadProgress(size_t count) = 0;
+ // This method should be called every time we resume an update attempt.
+ virtual void UpdateResumed() = 0;
+
// This method should be called every time we begin a new update. This method
// should not be called when we resume an update from the previously
// downloaded point. This is used to reset the metrics for each new update.
@@ -99,6 +102,9 @@
// source since the the last successful update. This is used to compute the
// overhead we incur.
virtual uint64_t GetTotalBytesDownloaded(DownloadSource source) = 0;
+
+ // Returns the reboot count for this update attempt.
+ virtual uint32_t GetNumReboots() = 0;
};
} // namespace chromeos_update_engine
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index a0f5a42..2be5896 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -4,6 +4,8 @@
#include <glib.h>
+#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/stringprintf.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -99,6 +101,7 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
.Times(AtLeast(1));
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0)).Times(AtLeast(1));
PayloadState payload_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
payload_state.SetResponse(response);
@@ -143,6 +146,8 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
.Times(AtLeast(1));
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0))
+ .Times(AtLeast(1));
PayloadState payload_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
payload_state.SetResponse(response);
@@ -185,6 +190,8 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
.Times(AtLeast(1));
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0))
+ .Times(AtLeast(1));
PayloadState payload_state;
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
payload_state.SetResponse(response);
@@ -219,6 +226,9 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, _)).Times(AtLeast(2));
+ // Reboots will be set
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, _)).Times(AtLeast(1));
+
// Url index should go from 0 to 1 twice.
EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 1)).Times(AtLeast(1));
@@ -325,6 +335,8 @@
.Times(AtLeast(1));
EXPECT_CALL(*prefs, SetInt64(kTotalBytesDownloadedFromHttp, progress_bytes))
.Times(AtLeast(1));
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0))
+ .Times(AtLeast(1));
EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
@@ -638,6 +650,9 @@
EXPECT_EQ(https_total,
payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
+ // Don't care about other metrics in this test.
+ EXPECT_CALL(*mock_system_state.mock_metrics_lib(), SendToUMA(
+ _,_,_,_,_)).Times(AtLeast(0));
EXPECT_CALL(*mock_system_state.mock_metrics_lib(), SendToUMA(
"Installer.SuccessfulMBsDownloadedFromHttpServer",
http_chunk / kNumBytesInOneMiB, _, _, _));
@@ -696,6 +711,32 @@
payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
}
+TEST(PayloadStateTest, NumRebootsIncrementsCorrectly) {
+ MockSystemState mock_system_state;
+ PayloadState payload_state;
+ NiceMock<PrefsMock>* prefs = mock_system_state.mock_prefs();
+ EXPECT_CALL(*prefs, SetInt64(_,_)).Times(AtLeast(0));
+ EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 1)).Times(AtLeast(1));
+
+ EXPECT_TRUE(payload_state.Initialize(&mock_system_state));
+
+ payload_state.UpdateRestarted();
+ EXPECT_EQ(0, payload_state.GetNumReboots());
+
+ EXPECT_CALL(mock_system_state, system_rebooted()).WillOnce(Return(true));
+ payload_state.UpdateResumed();
+ // Num reboots should be incremented because system rebooted detected.
+ EXPECT_EQ(1, payload_state.GetNumReboots());
+
+ EXPECT_CALL(mock_system_state, system_rebooted()).WillOnce(Return(false));
+ payload_state.UpdateResumed();
+ // Num reboots should now be 1 as reboot was not detected.
+ EXPECT_EQ(1, payload_state.GetNumReboots());
+
+ // Restart the update again to verify we set the num of reboots back to 0.
+ payload_state.UpdateRestarted();
+ EXPECT_EQ(0, payload_state.GetNumReboots());
+}
}
diff --git a/postinstall_runner_action.cc b/postinstall_runner_action.cc
index 934b461..802a2cd 100644
--- a/postinstall_runner_action.cc
+++ b/postinstall_runner_action.cc
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <vector>
-#include "update_engine/constants.h"
+#include "update_engine/action_processor.h"
#include "update_engine/subprocess.h"
#include "update_engine/utils.h"
diff --git a/postinstall_runner_action_unittest.cc b/postinstall_runner_action_unittest.cc
index 81f4420..85954dd 100644
--- a/postinstall_runner_action_unittest.cc
+++ b/postinstall_runner_action_unittest.cc
@@ -98,7 +98,7 @@
// True if the post-install action is expected to succeed.
bool should_succeed = do_losetup && !err_code;
- const string mountpoint(string(utils::kStatefulPartition) +
+ const string mountpoint(string(kStatefulPartition) +
"/au_destination");
string cwd;
diff --git a/real_system_state.h b/real_system_state.h
index ecb2fc0..72a07ad 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -64,6 +64,10 @@
return &request_params_;
}
+ virtual inline bool system_rebooted(){
+ return system_rebooted_;
+ }
+
// Initializes this concrete object. Other methods should be invoked only
// if the object has been initialized successfully.
bool Initialize(bool enable_gpio);
@@ -101,6 +105,11 @@
// Common parameters for all Omaha requests.
OmahaRequestParams request_params_;
+
+ // If true, this is the first instance of the update engine since the system
+ // rebooted. Important for tracking whether you are running instance of the
+ // update engine on first boot or due to a crash/restart.
+ bool system_rebooted_;
};
} // namespace chromeos_update_engine
diff --git a/system_state.cc b/system_state.cc
index 432b99f..da18500 100644
--- a/system_state.cc
+++ b/system_state.cc
@@ -5,6 +5,7 @@
#include <base/file_util.h>
#include "update_engine/real_system_state.h"
+#include "update_engine/utils.h"
namespace chromeos_update_engine {
@@ -14,7 +15,8 @@
RealSystemState::RealSystemState()
: device_policy_(NULL),
connection_manager_(this),
- request_params_(this) {}
+ request_params_(this),
+ system_rebooted_(false) {}
bool RealSystemState::Initialize(bool enable_gpio) {
metrics_lib_.Init();
@@ -24,6 +26,14 @@
return false;
}
+ if (!utils::FileExists(kSystemRebootedMarkerFile)) {
+ if (!utils::WriteFile(kSystemRebootedMarkerFile, "", 0)) {
+ LOG(ERROR) << "Could not create reboot marker file";
+ return false;
+ }
+ system_rebooted_ = true;
+ }
+
if (!payload_state_.Initialize(this))
return false;
diff --git a/system_state.h b/system_state.h
index 4b30d1a..6f06a34 100644
--- a/system_state.h
+++ b/system_state.h
@@ -64,6 +64,11 @@
// Returns a pointer to the object that stores the parameters that are
// common to all Omaha requests.
virtual OmahaRequestParams* request_params() = 0;
+
+ // If true, this is the first instance of the update engine since the system
+ // restarted. Important for tracking whether you are running instance of the
+ // update engine on first boot or due to a crash/restart.
+ virtual bool system_rebooted() = 0;
};
} // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 1360865..9f01ab9 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -639,6 +639,7 @@
prefs_->Delete(kPrefsUpdateFirstSeenAt);
prefs_->Delete(kPrefsUpdateTimestampStart);
prefs_->Delete(kPrefsUpdateDurationUptime);
+ LOG(INFO) << "Update successfully applied, waiting to reboot.";
SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT,
kUpdateNoticeUnspecified);
diff --git a/utils.cc b/utils.cc
index 3853b94..f0cea0d 100644
--- a/utils.cc
+++ b/utils.cc
@@ -59,7 +59,6 @@
namespace utils {
static const char kDevImageMarker[] = "/root/.dev_mode";
-const char* const kStatefulPartition = "/mnt/stateful_partition";
// Cgroup container is created in update-engine's upstart script located at
// /etc/init/update-engine.conf.
diff --git a/utils.h b/utils.h
index ef42745..72c6ea1 100644
--- a/utils.h
+++ b/utils.h
@@ -197,8 +197,6 @@
HexDumpArray(reinterpret_cast<const unsigned char*>(&vect[0]), vect.size());
}
-extern const char* const kStatefulPartition;
-
bool StringHasSuffix(const std::string& str, const std::string& suffix);
bool StringHasPrefix(const std::string& str, const std::string& prefix);