Merge remote-tracking branch 'cros/upstream' into cros/master
BUG=chromium:815356
TEST=unittest
TEST=precq
TEST=cros flash
Change-Id: I8d9c37411708d0cae61613b285123a090ce6deb1
diff --git a/.clang-format b/.clang-format
deleted file mode 120000
index f412743..0000000
--- a/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../../build/tools/brillo-clang-format
\ No newline at end of file
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..c1244fe
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+#
+# This is the .clang-format file used by all Brillo projects, conforming to the
+# style guide defined by Brillo. To use this file create a *relative* symlink in
+# your project pointing to this file, as this repository is expected to be
+# present in all manifests.
+#
+# See go/brillo-c++-style for details about the style guide.
+#
+
+# WARN: We do not symlink this file to the original file because their location
+# are different in AOSP and CrOS. Keep in sync with the original file if
+# possible.
+
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+BinPackArguments: false
+BinPackParameters: false
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+PointerAlignment: Left
+TabWidth: 2
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
index 3b8b271..f2c7831 100644
--- a/PRESUBMIT.cfg
+++ b/PRESUBMIT.cfg
@@ -3,5 +3,6 @@
hook1=../../../platform2/common-mk/gyplint.py ${PRESUBMIT_FILES}
[Hook Overrides]
+clang_format_check: true
cros_license_check: false
aosp_license_check: true
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 58cca09..192e6ab 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -53,6 +53,9 @@
send_member="SetUpdateOverCellularPermission"/>
<allow send_destination="org.chromium.UpdateEngine"
send_interface="org.chromium.UpdateEngineInterface"
+ send_member="SetUpdateOverCellularTarget"/>
+ <allow send_destination="org.chromium.UpdateEngine"
+ send_interface="org.chromium.UpdateEngineInterface"
send_member="GetUpdateOverCellularPermission"/>
<allow send_destination="org.chromium.UpdateEngine"
send_interface="org.chromium.UpdateEngineInterface"
diff --git a/WATCHLISTS b/WATCHLISTS
deleted file mode 100644
index bcce0de..0000000
--- a/WATCHLISTS
+++ /dev/null
@@ -1,14 +0,0 @@
-# See http://dev.chromium.org/developers/contributing-code/watchlists for
-# a description of this file's format.
-# Please keep these keys in alphabetical order.
-
-{
- 'WATCHLIST_DEFINITIONS': {
- 'all': {
- 'filepath': '.',
- },
- },
- 'WATCHLISTS': {
- 'all': ['adlr@chromium.org', 'petkov@chromium.org']
- },
-}
diff --git a/binder_bindings/android/brillo/IUpdateEngine.aidl b/binder_bindings/android/brillo/IUpdateEngine.aidl
index e549a4d..56e1524 100644
--- a/binder_bindings/android/brillo/IUpdateEngine.aidl
+++ b/binder_bindings/android/brillo/IUpdateEngine.aidl
@@ -34,6 +34,8 @@
void SetP2PUpdatePermission(in boolean enabled);
boolean GetP2PUpdatePermission();
void SetUpdateOverCellularPermission(in boolean enabled);
+ void SetUpdateOverCellularTarget(in String target_version,
+ in long target_size);
boolean GetUpdateOverCellularPermission();
long GetDurationSinceUpdate();
String GetPrevVersion();
diff --git a/binder_service_brillo.cc b/binder_service_brillo.cc
index 3f01e42..d082add 100644
--- a/binder_service_brillo.cc
+++ b/binder_service_brillo.cc
@@ -153,6 +153,13 @@
&UpdateEngineService::SetUpdateOverCellularPermission, enabled);
}
+Status BinderUpdateEngineBrilloService::SetUpdateOverCellularTarget(
+ const String16& target_version, int64_t target_size) {
+ return CallCommonHandler(&UpdateEngineService::SetUpdateOverCellularTarget,
+ NormalString(target_version),
+ target_size);
+}
+
Status BinderUpdateEngineBrilloService::GetUpdateOverCellularPermission(
bool* out_cellular_permission) {
return CallCommonHandler(
diff --git a/binder_service_brillo.h b/binder_service_brillo.h
index c802fca..d0d0dc9 100644
--- a/binder_service_brillo.h
+++ b/binder_service_brillo.h
@@ -75,6 +75,8 @@
bool* out_p2p_permission) override;
android::binder::Status SetUpdateOverCellularPermission(
bool enabled) override;
+ android::binder::Status SetUpdateOverCellularTarget(
+ const android::String16& target_version, int64_t target_size) override;
android::binder::Status GetUpdateOverCellularPermission(
bool* out_cellular_permission) override;
android::binder::Status GetDurationSinceUpdate(
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h
index 41fab48..5a3dccf 100644
--- a/client_library/include/update_engine/update_status.h
+++ b/client_library/include/update_engine/update_status.h
@@ -23,17 +23,24 @@
namespace update_engine {
+// ATTENTION: When adding a new enum value here, always append at the end and
+// make sure to make proper adjustments in UpdateAttempter:ActionCompleted(). If
+// any enum memeber is deprecated, the assigned value of other members should
+// not change. See b/62842358.
enum class UpdateStatus {
IDLE = 0,
- CHECKING_FOR_UPDATE,
- UPDATE_AVAILABLE,
- DOWNLOADING,
- VERIFYING,
- FINALIZING,
- UPDATED_NEED_REBOOT,
- REPORTING_ERROR_EVENT,
- ATTEMPTING_ROLLBACK,
- DISABLED,
+ CHECKING_FOR_UPDATE = 1,
+ UPDATE_AVAILABLE = 2,
+ DOWNLOADING = 3,
+ VERIFYING = 4,
+ FINALIZING = 5,
+ UPDATED_NEED_REBOOT = 6,
+ REPORTING_ERROR_EVENT = 7,
+ ATTEMPTING_ROLLBACK = 8,
+ DISABLED = 9,
+ // Broadcast this state when an update aborts because user preferences do not
+ // allow updates, e.g. over cellular network.
+ NEED_PERMISSION_TO_UPDATE = 10,
};
// Enum of bit-wise flags for controlling how updates are attempted.
diff --git a/common/constants.cc b/common/constants.cc
index 5941c93..215ca31 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -47,6 +47,7 @@
"metrics-attempt-last-reporting-time";
const char kPrefsMetricsCheckLastReportingTime[] =
"metrics-check-last-reporting-time";
+const char kPrefsNoIgnoreBackoff[] = "no-ignore-backoff";
const char kPrefsNumReboots[] = "num-reboots";
const char kPrefsNumResponsesSeen[] = "num-responses-seen";
const char kPrefsOmahaCohort[] = "omaha-cohort";
@@ -60,6 +61,7 @@
const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
const char kPrefsPreviousVersion[] = "previous-version";
const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
+const char kPrefsRollbackHappened[] = "rollback-happened";
const char kPrefsRollbackVersion[] = "rollback-version";
const char kPrefsChannelOnSlotPrefix[] = "channel-on-slot-";
const char kPrefsSystemUpdatedMarker[] = "system-updated-marker";
@@ -75,6 +77,10 @@
const char kPrefsUpdateFirstSeenAt[] = "update-first-seen-at";
const char kPrefsUpdateOverCellularPermission[] =
"update-over-cellular-permission";
+const char kPrefsUpdateOverCellularTargetVersion[] =
+ "update-over-cellular-target-version";
+const char kPrefsUpdateOverCellularTargetSize[] =
+ "update-over-cellular-target-size";
const char kPrefsUpdateServerCertificate[] = "update-server-cert";
const char kPrefsUpdateStateNextDataLength[] = "update-state-next-data-length";
const char kPrefsUpdateStateNextDataOffset[] = "update-state-next-data-offset";
diff --git a/common/constants.h b/common/constants.h
index fc15fce..78353d8 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -49,6 +49,7 @@
extern const char kPrefsManifestSignatureSize[];
extern const char kPrefsMetricsAttemptLastReportingTime[];
extern const char kPrefsMetricsCheckLastReportingTime[];
+extern const char kPrefsNoIgnoreBackoff[];
extern const char kPrefsNumReboots[];
extern const char kPrefsNumResponsesSeen[];
extern const char kPrefsOmahaCohort[];
@@ -62,6 +63,7 @@
extern const char kPrefsPostInstallSucceeded[];
extern const char kPrefsPreviousVersion[];
extern const char kPrefsResumedUpdateFailures[];
+extern const char kPrefsRollbackHappened[];
extern const char kPrefsRollbackVersion[];
extern const char kPrefsChannelOnSlotPrefix[];
extern const char kPrefsSystemUpdatedMarker[];
@@ -76,6 +78,8 @@
extern const char kPrefsUpdateDurationUptime[];
extern const char kPrefsUpdateFirstSeenAt[];
extern const char kPrefsUpdateOverCellularPermission[];
+extern const char kPrefsUpdateOverCellularTargetVersion[];
+extern const char kPrefsUpdateOverCellularTargetSize[];
extern const char kPrefsUpdateServerCertificate[];
extern const char kPrefsUpdateStateNextDataLength[];
extern const char kPrefsUpdateStateNextDataOffset[];
diff --git a/common/error_code.h b/common/error_code.h
index c7e4967..0d86a7b 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -73,14 +73,16 @@
kFilesystemVerifierError = 47,
kUserCanceled = 48,
kNonCriticalUpdateInOOBE = 49,
- // kOmahaUpdateIgnoredOverCellular = 50,
+ kOmahaUpdateIgnoredOverCellular = 50,
// kPayloadTimestampError = 51,
kUpdatedButNotActive = 52,
kNoUpdate = 53,
+ kRollbackNotPossible = 54,
+ kFirstActiveOmahaPingSentPersistenceError = 55,
// VERY IMPORTANT! When adding new error codes:
//
- // 1) Update tools/metrics/histograms/histograms.xml in Chrome.
+ // 1) Update tools/metrics/histograms/enums.xml in Chrome.
//
// 2) Update the assorted switch statements in update_engine which won't
// build until this case is added.
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index 5efc120..2a2a0a3 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -144,10 +144,16 @@
return "ErrorCode::kUserCanceled";
case ErrorCode::kNonCriticalUpdateInOOBE:
return "ErrorCode::kNonCriticalUpdateInOOBE";
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
+ return "ErrorCode::kOmahaUpdateIgnoredOverCellular";
case ErrorCode::kUpdatedButNotActive:
return "ErrorCode::kUpdatedButNotActive";
case ErrorCode::kNoUpdate:
return "ErrorCode::kNoUpdate";
+ case ErrorCode::kRollbackNotPossible:
+ return "ErrorCode::kRollbackNotPossible";
+ case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
+ return "ErrorCode::kFirstActiveOmahaPingSentPersistenceError";
// Don't add a default case to let the compiler warn about newly added
// error codes which should be added here.
}
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 01d23d0..d68b0f8 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -34,6 +34,18 @@
// false.
static const int kPowerwashCountNotSet = -1;
+ // Default value for crossystem tpm_kernver.
+ static const int kMinKernelKeyVersion = 3;
+
+ // Default value for crossystem tpm_fwver.
+ static const int kMinFirmwareKeyVersion = 13;
+
+ // Default value for crossystem kernel_max_rollforward. This value is the
+ // default for consumer devices and effectively means "unlimited rollforward
+ // is allowed", which is the same as the behavior prior to implementing
+ // roll forward prevention.
+ static const int kMaxKernelRollforward = 0xfffffffe;
+
FakeHardware() = default;
// HardwareInterface methods.
@@ -59,6 +71,19 @@
std::string GetECVersion() const override { return ec_version_; }
+ int GetMinKernelKeyVersion() const override {
+ return min_kernel_key_version_;
+ }
+
+ int GetMinFirmwareKeyVersion() const override {
+ return min_firmware_key_version_;
+ }
+
+ bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override {
+ kernel_max_rollforward_ = kernel_max_rollforward;
+ return true;
+ }
+
int GetPowerwashCount() const override { return powerwash_count_; }
bool SchedulePowerwash() override {
@@ -85,8 +110,9 @@
return first_active_omaha_ping_sent_;
}
- void SetFirstActiveOmahaPingSent() override {
+ bool SetFirstActiveOmahaPingSent() override {
first_active_omaha_ping_sent_ = true;
+ return true;
}
// Setters
@@ -129,20 +155,35 @@
ec_version_ = ec_version;
}
+ void SetMinKernelKeyVersion(int min_kernel_key_version) {
+ min_kernel_key_version_ = min_kernel_key_version;
+ }
+
+ void SetMinFirmwareKeyVersion(int min_firmware_key_version) {
+ min_firmware_key_version_ = min_firmware_key_version;
+ }
+
void SetPowerwashCount(int powerwash_count) {
powerwash_count_ = powerwash_count;
}
+ // Getters to verify state.
+ int GetMaxKernelKeyRollforward() const { return kernel_max_rollforward_; }
+
private:
bool is_official_build_{true};
bool is_normal_boot_mode_{true};
bool are_dev_features_enabled_{false};
bool is_oobe_enabled_{true};
bool is_oobe_complete_{true};
- base::Time oobe_timestamp_{base::Time::FromTimeT(1169280000)}; // Jan 20, 2007
+ // Jan 20, 2007
+ base::Time oobe_timestamp_{base::Time::FromTimeT(1169280000)};
std::string hardware_class_{"Fake HWID BLAH-1234"};
std::string firmware_version_{"Fake Firmware v1.0.1"};
std::string ec_version_{"Fake EC v1.0a"};
+ int min_kernel_key_version_{kMinKernelKeyVersion};
+ int min_firmware_key_version_{kMinFirmwareKeyVersion};
+ int kernel_max_rollforward_{kMaxKernelRollforward};
int powerwash_count_{kPowerwashCountNotSet};
bool powerwash_scheduled_{false};
bool first_active_omaha_ping_sent_{false};
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 541a68a..239e7c8 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -68,6 +68,21 @@
// running a custom chrome os ec.
virtual std::string GetECVersion() const = 0;
+ // Returns the minimum kernel key version that verified boot on Chrome OS
+ // will allow to boot. This is the value of crossystem tpm_kernver. Returns
+ // -1 on error, or if not running on Chrome OS.
+ virtual int GetMinKernelKeyVersion() const = 0;
+
+ // Returns the minimum firmware key version that verified boot on Chrome OS
+ // will allow to boot. This is the value of crossystem tpm_fwver. Returns
+ // -1 on error, or if not running on Chrome OS.
+ virtual int GetMinFirmwareKeyVersion() const = 0;
+
+ // Sets the maximum kernel key version that verified boot should roll
+ // forward to. This is the value of crossystem kernel_max_rollforward.
+ // Returns false if the value cannot be set, or if not running on Chrome OS.
+ virtual bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) = 0;
+
// Returns the powerwash_count from the stateful. If the file is not found
// or is invalid, returns -1. Brand new machines out of the factory or after
// recovery don't have this value set.
@@ -95,9 +110,9 @@
// |SetFirstActiveOmahaPingSent()|.
virtual bool GetFirstActiveOmahaPingSent() const = 0;
- // Persist the fact that first active ping was sent to omaha. It bails out if
- // it fails.
- virtual void SetFirstActiveOmahaPingSent() = 0;
+ // Persist the fact that first active ping was sent to omaha and returns false
+ // if failed to persist it.
+ virtual bool SetFirstActiveOmahaPingSent() = 0;
};
} // namespace chromeos_update_engine
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 867216e..73110e9 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -32,6 +32,7 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
diff --git a/common/mock_hardware.h b/common/mock_hardware.h
index 42fa7ba..662ccd9 100644
--- a/common/mock_hardware.h
+++ b/common/mock_hardware.h
@@ -54,6 +54,15 @@
ON_CALL(*this, GetECVersion())
.WillByDefault(testing::Invoke(&fake_,
&FakeHardware::GetECVersion));
+ ON_CALL(*this, GetMinKernelKeyVersion())
+ .WillByDefault(
+ testing::Invoke(&fake_, &FakeHardware::GetMinKernelKeyVersion));
+ ON_CALL(*this, GetMinFirmwareKeyVersion())
+ .WillByDefault(
+ testing::Invoke(&fake_, &FakeHardware::GetMinFirmwareKeyVersion));
+ ON_CALL(*this, SetMaxKernelKeyRollforward())
+ .WillByDefault(
+ testing::Invoke(&fake_, &FakeHardware::SetMaxKernelKeyRollforward));
ON_CALL(*this, GetPowerwashCount())
.WillByDefault(testing::Invoke(&fake_,
&FakeHardware::GetPowerwashCount));
@@ -81,6 +90,10 @@
MOCK_CONST_METHOD0(GetHardwareClass, std::string());
MOCK_CONST_METHOD0(GetFirmwareVersion, std::string());
MOCK_CONST_METHOD0(GetECVersion, std::string());
+ MOCK_CONST_METHOD0(GetMinKernelKeyVersion, int());
+ MOCK_CONST_METHOD0(GetMinFirmwareKeyVersion, int());
+ MOCK_CONST_METHOD1(SetMaxKernelKeyRollforward,
+ bool(int kernel_max_rollforward));
MOCK_CONST_METHOD0(GetPowerwashCount, int());
MOCK_CONST_METHOD1(GetNonVolatileDirectory, bool(base::FilePath*));
MOCK_CONST_METHOD1(GetPowerwashSafeDirectory, bool(base::FilePath*));
diff --git a/common/subprocess.cc b/common/subprocess.cc
index 4e6d352..1715cb0 100644
--- a/common/subprocess.cc
+++ b/common/subprocess.cc
@@ -23,6 +23,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <base/bind.h>
@@ -281,14 +282,22 @@
return proc_return_code != brillo::Process::kErrorExitStatus;
}
-bool Subprocess::SubprocessInFlight() {
- for (const auto& pid_record : subprocess_records_) {
- if (!pid_record.second->callback.is_null())
- return true;
+void Subprocess::FlushBufferedLogsAtExit() {
+ if (!subprocess_records_.empty()) {
+ LOG(INFO) << "We are exiting, but there are still in flight subprocesses!";
+ for (auto& pid_record : subprocess_records_) {
+ SubprocessRecord* record = pid_record.second.get();
+ // Make sure we read any remaining process output.
+ OnStdoutReady(record);
+ if (!record->stdout.empty()) {
+ LOG(INFO) << "Subprocess(" << pid_record.first << ") output:\n"
+ << record->stdout;
+ }
+ }
}
- return false;
}
+
Subprocess* Subprocess::subprocess_singleton_ = nullptr;
} // namespace chromeos_update_engine
diff --git a/common/subprocess.h b/common/subprocess.h
index b655fb7..209158b 100644
--- a/common/subprocess.h
+++ b/common/subprocess.h
@@ -101,8 +101,10 @@
return *subprocess_singleton_;
}
- // Returns true iff there is at least one subprocess we're waiting on.
- bool SubprocessInFlight();
+ // Tries to log all in flight processes's output. It is used right before
+ // exiting the update_engine, probably when the subprocess caused a system
+ // shutdown.
+ void FlushBufferedLogsAtExit();
private:
FRIEND_TEST(SubprocessTest, CancelTest);
diff --git a/common/subprocess_unittest.cc b/common/subprocess_unittest.cc
index c8996db..10710e8 100644
--- a/common/subprocess_unittest.cc
+++ b/common/subprocess_unittest.cc
@@ -32,6 +32,7 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
diff --git a/common/utils.cc b/common/utils.cc
index d935535..b06954b 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -1070,6 +1070,18 @@
return true;
}
+int VersionPrefix(const std::string& version) {
+ if (version.empty()) {
+ return 0;
+ }
+ vector<string> tokens = base::SplitString(
+ version, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+ int value;
+ if (tokens.empty() || !base::StringToInt(tokens[0], &value))
+ return -1; // Target version is invalid.
+ return value;
+}
+
} // namespace utils
} // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index 5c44083..cbc5eb9 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -317,6 +317,11 @@
// reboot. Returns whether it succeeded getting the boot_id.
bool GetBootId(std::string* boot_id);
+// Returns the integer value of the first section of |version|. E.g. for
+// "10575.39." returns 10575. Returns 0 if |version| is empty, returns -1 if
+// first section of |version| is invalid (e.g. not a number).
+int VersionPrefix(const std::string& version);
+
} // namespace utils
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 62f9f6c..16fa481 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -303,9 +303,8 @@
base::Time::Exploded exploded = (base::Time::Exploded) {
.year = 2001, .month = 9, .day_of_week = 0, .day_of_month = 9,
.hour = 1, .minute = 46, .second = 40, .millisecond = 42};
- base::Time time;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time));
- EXPECT_EQ(time, utils::TimeFromStructTimespec(&ts));
+ EXPECT_EQ(base::Time::FromUTCExploded(exploded),
+ utils::TimeFromStructTimespec(&ts));
}
TEST(UtilsTest, DecodeAndStoreBase64String) {
@@ -512,4 +511,16 @@
EXPECT_FALSE(utils::IsMountpoint(file.value()));
}
+TEST(UtilsTest, VersionPrefix) {
+ EXPECT_EQ(10575, utils::VersionPrefix("10575.39."));
+ EXPECT_EQ(10575, utils::VersionPrefix("10575.39"));
+ EXPECT_EQ(10575, utils::VersionPrefix("10575.x"));
+ EXPECT_EQ(10575, utils::VersionPrefix("10575."));
+ EXPECT_EQ(10575, utils::VersionPrefix("10575"));
+ EXPECT_EQ(0, utils::VersionPrefix(""));
+ EXPECT_EQ(-1, utils::VersionPrefix("x"));
+ EXPECT_EQ(-1, utils::VersionPrefix("1x"));
+ EXPECT_EQ(-1, utils::VersionPrefix("x.1"));
+}
+
} // namespace chromeos_update_engine
diff --git a/common_service.cc b/common_service.cc
index 2c8f80d..2fdd700 100644
--- a/common_service.cc
+++ b/common_service.cc
@@ -16,7 +16,6 @@
#include "update_engine/common_service.h"
-#include <set>
#include <string>
#include <base/bind.h>
@@ -41,7 +40,6 @@
using base::StringPrintf;
using brillo::ErrorPtr;
using brillo::string_utils::ToString;
-using std::set;
using std::string;
using update_engine::UpdateAttemptFlags;
using update_engine::UpdateEngineStatus;
@@ -258,22 +256,11 @@
bool UpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error,
bool in_allowed) {
- set<string> allowed_types;
- const policy::DevicePolicy* device_policy = system_state_->device_policy();
-
- // The device_policy is loaded in a lazy way before an update check. Load it
- // now from the libbrillo cache if it wasn't already loaded.
- if (!device_policy) {
- UpdateAttempter* update_attempter = system_state_->update_attempter();
- if (update_attempter) {
- update_attempter->RefreshDevicePolicy();
- device_policy = system_state_->device_policy();
- }
- }
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
// Check if this setting is allowed by the device policy.
- if (device_policy &&
- device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
LogAndSetError(error,
FROM_HERE,
"Ignoring the update over cellular setting since there's "
@@ -286,7 +273,8 @@
PrefsInterface* prefs = system_state_->prefs();
- if (!prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) {
+ if (!prefs ||
+ !prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) {
LogAndSetError(error,
FROM_HERE,
string("Error setting the update over cellular to ") +
@@ -296,24 +284,66 @@
return true;
}
-bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* /* error */,
- bool* out_allowed) {
- ConnectionManagerInterface* cm = system_state_->connection_manager();
+bool UpdateEngineService::SetUpdateOverCellularTarget(
+ brillo::ErrorPtr* error,
+ const std::string& target_version,
+ int64_t target_size) {
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
- // The device_policy is loaded in a lazy way before an update check and is
- // used to determine if an update is allowed over cellular. Load the device
- // policy now from the libbrillo cache if it wasn't already loaded.
- if (!system_state_->device_policy()) {
- UpdateAttempter* update_attempter = system_state_->update_attempter();
- if (update_attempter)
- update_attempter->RefreshDevicePolicy();
+ // Check if this setting is allowed by the device policy.
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
+ LogAndSetError(error,
+ FROM_HERE,
+ "Ignoring the update over cellular setting since there's "
+ "a device policy enforcing this setting.");
+ return false;
}
- // Return the current setting based on the same logic used while checking for
- // updates. A log message could be printed as the result of this test.
- LOG(INFO) << "Checking if updates over cellular networks are allowed:";
- *out_allowed = cm->IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown);
+ // If the policy wasn't loaded yet, then it is still OK to change the local
+ // setting because the policy will be checked again during the update check.
+
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs ||
+ !prefs->SetString(kPrefsUpdateOverCellularTargetVersion,
+ target_version) ||
+ !prefs->SetInt64(kPrefsUpdateOverCellularTargetSize, target_size)) {
+ LogAndSetError(
+ error, FROM_HERE, "Error setting the target for update over cellular.");
+ return false;
+ }
+ return true;
+}
+
+bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* error,
+ bool* out_allowed) {
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
+
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
+ // We have device policy, so ignore the user preferences.
+ *out_allowed = connection_manager->IsUpdateAllowedOver(
+ ConnectionType::kCellular, ConnectionTethering::kUnknown);
+ } else {
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
+ // Update is not allowed as user preference is not set or not available.
+ *out_allowed = false;
+ return true;
+ }
+
+ bool is_allowed;
+
+ if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed)) {
+ LogAndSetError(error,
+ FROM_HERE,
+ "Error getting the update over cellular preference.");
+ return false;
+ }
+ *out_allowed = is_allowed;
+ }
return true;
}
diff --git a/common_service.h b/common_service.h
index 544dd93..824ef97 100644
--- a/common_service.h
+++ b/common_service.h
@@ -114,6 +114,12 @@
bool SetUpdateOverCellularPermission(brillo::ErrorPtr* error,
bool in_allowed);
+ // If there's no device policy installed, sets the update over cellular
+ // target. Otherwise, this method returns with an error.
+ bool SetUpdateOverCellularTarget(brillo::ErrorPtr* error,
+ const std::string& target_version,
+ int64_t target_size);
+
// Returns the current value of the update over cellular network setting,
// either forced by the device policy if the device is enrolled or the current
// user preference otherwise.
diff --git a/connection_manager.cc b/connection_manager.cc
index be707bc..4063f24 100644
--- a/connection_manager.cc
+++ b/connection_manager.cc
@@ -31,6 +31,7 @@
#include "update_engine/connection_utils.h"
#include "update_engine/shill_proxy.h"
#include "update_engine/system_state.h"
+#include "update_engine/update_attempter.h"
using org::chromium::flimflam::ManagerProxyInterface;
using org::chromium::flimflam::ServiceProxyInterface;
@@ -59,16 +60,27 @@
case ConnectionType::kCellular: {
set<string> allowed_types;
+
const policy::DevicePolicy* device_policy =
system_state_->device_policy();
- // A device_policy is loaded in a lazy way right before an update check,
- // so the device_policy should be already loaded at this point. If it's
- // not, return a safe value for this setting.
+ // The device_policy is loaded in a lazy way before an update check. Load
+ // it now from the libbrillo cache if it wasn't already loaded.
if (!device_policy) {
- LOG(INFO) << "Disabling updates over cellular networks as there's no "
- "device policy loaded yet.";
- return false;
+ UpdateAttempter* update_attempter = system_state_->update_attempter();
+ if (update_attempter) {
+ update_attempter->RefreshDevicePolicy();
+ device_policy = system_state_->device_policy();
+ }
+ }
+
+ if (!device_policy) {
+ // Device policy fails to be loaded (possibly due to guest account). We
+ // do not check the local user setting here, which should be checked by
+ // |OmahaRequestAction| during checking for update.
+ LOG(INFO) << "Allowing updates over cellular as device policy "
+ "fails to be loaded.";
+ return true;
}
if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
@@ -82,31 +94,14 @@
LOG(INFO) << "Allowing updates over cellular per device policy.";
return true;
- } else {
- // There's no update setting in the device policy, using the local user
- // setting.
- PrefsInterface* prefs = system_state_->prefs();
-
- if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
- LOG(INFO) << "Disabling updates over cellular connection as there's "
- "no device policy setting nor user preference present.";
- return false;
- }
-
- bool stored_value;
- if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission,
- &stored_value)) {
- return false;
- }
-
- if (!stored_value) {
- LOG(INFO) << "Disabling updates over cellular connection per user "
- "setting.";
- return false;
- }
- LOG(INFO) << "Allowing updates over cellular per user setting.";
- return true;
}
+
+ // If there's no update setting in the device policy, we do not check
+ // the local user setting here, which should be checked by
+ // |OmahaRequestAction| during checking for update.
+ LOG(INFO) << "Allowing updates over cellular as device policy does "
+ "not include update setting.";
+ return true;
}
default:
@@ -121,6 +116,21 @@
}
}
+bool ConnectionManager::IsAllowedConnectionTypesForUpdateSet() const {
+ const policy::DevicePolicy* device_policy = system_state_->device_policy();
+ if (!device_policy) {
+ LOG(INFO) << "There's no device policy loaded yet.";
+ return false;
+ }
+
+ set<string> allowed_types;
+ if (!device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
+ return false;
+ }
+
+ return true;
+}
+
bool ConnectionManager::GetConnectionProperties(
ConnectionType* out_type, ConnectionTethering* out_tethering) {
dbus::ObjectPath default_service_path;
diff --git a/connection_manager.h b/connection_manager.h
index e5a9d49..dc563ef 100644
--- a/connection_manager.h
+++ b/connection_manager.h
@@ -17,6 +17,7 @@
#ifndef UPDATE_ENGINE_CONNECTION_MANAGER_H_
#define UPDATE_ENGINE_CONNECTION_MANAGER_H_
+#include <memory>
#include <string>
#include <base/macros.h>
@@ -43,6 +44,7 @@
ConnectionTethering* out_tethering) override;
bool IsUpdateAllowedOver(ConnectionType type,
ConnectionTethering tethering) const override;
+ bool IsAllowedConnectionTypesForUpdateSet() const override;
private:
// Returns (via out_path) the default network path, or empty string if
diff --git a/connection_manager_android.cc b/connection_manager_android.cc
index 2dd824a..6da4cee 100644
--- a/connection_manager_android.cc
+++ b/connection_manager_android.cc
@@ -16,6 +16,8 @@
#include "update_engine/connection_manager_android.h"
+#include <memory>
+
namespace chromeos_update_engine {
namespace connection_manager {
@@ -34,5 +36,8 @@
ConnectionType type, ConnectionTethering tethering) const {
return true;
}
+bool ConnectionManagerAndroid::IsAllowedConnectionTypesForUpdateSet() const {
+ return false;
+}
} // namespace chromeos_update_engine
diff --git a/connection_manager_android.h b/connection_manager_android.h
index 0cd5e73..006f4ea 100644
--- a/connection_manager_android.h
+++ b/connection_manager_android.h
@@ -34,6 +34,7 @@
ConnectionTethering* out_tethering) override;
bool IsUpdateAllowedOver(ConnectionType type,
ConnectionTethering tethering) const override;
+ bool IsAllowedConnectionTypesForUpdateSet() const override;
DISALLOW_COPY_AND_ASSIGN(ConnectionManagerAndroid);
};
diff --git a/connection_manager_interface.h b/connection_manager_interface.h
index df8eb4b..2faeb80 100644
--- a/connection_manager_interface.h
+++ b/connection_manager_interface.h
@@ -46,6 +46,10 @@
virtual bool IsUpdateAllowedOver(ConnectionType type,
ConnectionTethering tethering) const = 0;
+ // Returns true if the allowed connection types for update is set in the
+ // device policy. Otherwise, returns false.
+ virtual bool IsAllowedConnectionTypesForUpdateSet() const = 0;
+
protected:
ConnectionManagerInterface() = default;
diff --git a/connection_manager_unittest.cc b/connection_manager_unittest.cc
index e26a686..85b8c57 100644
--- a/connection_manager_unittest.cc
+++ b/connection_manager_unittest.cc
@@ -16,8 +16,10 @@
#include "update_engine/connection_manager.h"
+#include <memory>
#include <set>
#include <string>
+#include <utility>
#include <base/logging.h>
#include <brillo/any.h>
@@ -276,16 +278,24 @@
ConnectionTethering::kConfirmed));
}
-TEST_F(ConnectionManagerTest, BlockUpdatesOverCellularByDefaultTest) {
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
+TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularByDefaultTest) {
+ policy::MockDevicePolicy device_policy;
+ // Set an empty device policy.
+ fake_system_state_.set_device_policy(&device_policy);
+
+ EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
+ ConnectionTethering::kUnknown));
}
-TEST_F(ConnectionManagerTest, BlockUpdatesOverTetheredNetworkByDefaultTest) {
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kConfirmed));
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kConfirmed));
+TEST_F(ConnectionManagerTest, AllowUpdatesOverTetheredNetworkByDefaultTest) {
+ policy::MockDevicePolicy device_policy;
+ // Set an empty device policy.
+ fake_system_state_.set_device_policy(&device_policy);
+
+ EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
+ ConnectionTethering::kConfirmed));
+ EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
+ ConnectionTethering::kConfirmed));
EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
ConnectionTethering::kSuspected));
}
@@ -310,62 +320,27 @@
ConnectionTethering::kUnknown));
}
-TEST_F(ConnectionManagerTest, BlockUpdatesOver3GIfErrorInPolicyFetchTest) {
- policy::MockDevicePolicy allow_3g_policy;
+TEST_F(ConnectionManagerTest, AllowUpdatesOver3GIfPolicyIsNotSet) {
+ policy::MockDevicePolicy device_policy;
- fake_system_state_.set_device_policy(&allow_3g_policy);
-
- set<string> allowed_set;
- allowed_set.insert(StringForConnectionType(ConnectionType::kCellular));
+ fake_system_state_.set_device_policy(&device_policy);
// Return false for GetAllowedConnectionTypesForUpdate and see
- // that updates are still blocked for 3G despite the value being in
- // the string set above.
- EXPECT_CALL(allow_3g_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(1)
- .WillOnce(DoAll(SetArgPointee<0>(allowed_set), Return(false)));
-
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, UseUserPrefForUpdatesOverCellularIfNoPolicyTest) {
- policy::MockDevicePolicy no_policy;
- testing::NiceMock<MockPrefs>* prefs = fake_system_state_.mock_prefs();
-
- fake_system_state_.set_device_policy(&no_policy);
-
- // No setting enforced by the device policy, user prefs should be used.
- EXPECT_CALL(no_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(3)
- .WillRepeatedly(Return(false));
-
- // No user pref: block.
- EXPECT_CALL(*prefs, Exists(kPrefsUpdateOverCellularPermission))
+ // that updates are allowed as device policy is not set. Further
+ // check is left to |OmahaRequestAction|.
+ EXPECT_CALL(device_policy, GetAllowedConnectionTypesForUpdate(_))
.Times(1)
.WillOnce(Return(false));
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
- // Allow per user pref.
- EXPECT_CALL(*prefs, Exists(kPrefsUpdateOverCellularPermission))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(*prefs, GetBoolean(kPrefsUpdateOverCellularPermission, _))
- .Times(1)
- .WillOnce(DoAll(SetArgPointee<1>(true), Return(true)));
EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
ConnectionTethering::kUnknown));
+}
- // Block per user pref.
- EXPECT_CALL(*prefs, Exists(kPrefsUpdateOverCellularPermission))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(*prefs, GetBoolean(kPrefsUpdateOverCellularPermission, _))
- .Times(1)
- .WillOnce(DoAll(SetArgPointee<1>(false), Return(true)));
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
+TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularIfPolicyFailsToBeLoaded) {
+ fake_system_state_.set_device_policy(nullptr);
+
+ EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
+ ConnectionTethering::kUnknown));
}
TEST_F(ConnectionManagerTest, StringForConnectionTypeTest) {
diff --git a/dbus_bindings/org.chromium.KioskAppService.dbus-xml b/dbus_bindings/org.chromium.KioskAppService.dbus-xml
new file mode 100644
index 0000000..11b888b
--- /dev/null
+++ b/dbus_bindings/org.chromium.KioskAppService.dbus-xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/chromium/KioskAppService"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <interface name="org.chromium.KioskAppServiceInterface">
+ <method name="GetRequiredPlatformVersion">
+ <arg name="required_platform_version" type="s" direction="out" />
+ </method>
+ </interface>
+</node>
diff --git a/dbus_bindings/org.chromium.LibCrosService.dbus-xml b/dbus_bindings/org.chromium.LibCrosService.dbus-xml
deleted file mode 100644
index 3111c63..0000000
--- a/dbus_bindings/org.chromium.LibCrosService.dbus-xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/org/chromium/LibCrosService"
- xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
- <interface name="org.chromium.LibCrosServiceInterface">
- <method name="GetKioskAppRequiredPlatformVersion">
- <arg name="required_platform_version" type="s" direction="out" />
- </method>
- </interface>
-</node>
diff --git a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml b/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
index 848f775..a20f33f 100644
--- a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
+++ b/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
@@ -67,6 +67,10 @@
<method name="SetUpdateOverCellularPermission">
<arg type="b" name="allowed" direction="in" />
</method>
+ <method name="SetUpdateOverCellularTarget">
+ <arg type="s" name="target_version" direction="in" />
+ <arg type="x" name="target_size" direction="in" />
+ </method>
<method name="GetUpdateOverCellularPermission">
<arg type="b" name="allowed" direction="out" />
</method>
diff --git a/dbus_service.cc b/dbus_service.cc
index 47aeec7..bb4ff33 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -133,6 +133,14 @@
return common_->SetUpdateOverCellularPermission(error, in_allowed);
}
+bool DBusUpdateEngineService::SetUpdateOverCellularTarget(
+ brillo::ErrorPtr* error,
+ const std::string& target_version,
+ int64_t target_size) {
+ return common_->SetUpdateOverCellularTarget(
+ error, target_version, target_size);
+}
+
bool DBusUpdateEngineService::GetUpdateOverCellularPermission(
ErrorPtr* error, bool* out_allowed) {
return common_->GetUpdateOverCellularPermission(error, out_allowed);
diff --git a/dbus_service.h b/dbus_service.h
index b754661..e461fa6 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -114,6 +114,12 @@
bool SetUpdateOverCellularPermission(brillo::ErrorPtr* error,
bool in_allowed) override;
+ // If there's no device policy installed, sets the update over cellular
+ // target. Otherwise, this method returns with an error.
+ bool SetUpdateOverCellularTarget(brillo::ErrorPtr* error,
+ const std::string& target_version,
+ int64_t target_size) override;
+
// Returns the current value of the update over cellular network setting,
// either forced by the device policy if the device is enrolled or the current
// user preference otherwise.
@@ -154,7 +160,7 @@
class UpdateEngineAdaptor : public org::chromium::UpdateEngineInterfaceAdaptor,
public ServiceObserverInterface {
public:
- UpdateEngineAdaptor(SystemState* system_state);
+ explicit UpdateEngineAdaptor(SystemState* system_state);
~UpdateEngineAdaptor() = default;
// Register the DBus object with the update engine service asynchronously.
diff --git a/hardware_android.cc b/hardware_android.cc
index c0b87ce..3f0fb59 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -164,6 +164,21 @@
return GetProperty(kPropBootBaseband, "");
}
+int HardwareAndroid::GetMinKernelKeyVersion() const {
+ LOG(WARNING) << "STUB: No Kernel key version is available.";
+ return -1;
+}
+
+int HardwareAndroid::GetMinFirmwareKeyVersion() const {
+ LOG(WARNING) << "STUB: No Firmware key version is available.";
+ return -1;
+}
+
+bool HardwareAndroid::SetMaxKernelKeyRollforward(int kernel_max_rollforward) {
+ LOG(WARNING) << "STUB: Setting kernel_max_rollforward is not supported.";
+ return false;
+}
+
int HardwareAndroid::GetPowerwashCount() const {
LOG(WARNING) << "STUB: Assuming no factory reset was performed.";
return 0;
@@ -198,9 +213,10 @@
return false;
}
-void HardwareAndroid::SetFirstActiveOmahaPingSent() {
- LOG(WARNING) << "STUB: Assuming first active omaha is never set.";
- return;
+bool HardwareAndroid::SetFirstActiveOmahaPingSent() {
+ LOG(WARNING) << "STUB: Assuming first active omaha is set.";
+ // We will set it true, so its failure doesn't cause escalation.
+ return true;
}
} // namespace chromeos_update_engine
diff --git a/hardware_android.h b/hardware_android.h
index 37393ce..981f033 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -42,13 +42,16 @@
std::string GetHardwareClass() const override;
std::string GetFirmwareVersion() const override;
std::string GetECVersion() const override;
+ int GetMinKernelKeyVersion() const override;
+ int GetMinFirmwareKeyVersion() const override;
+ bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
int GetPowerwashCount() const override;
bool SchedulePowerwash() override;
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
bool GetFirstActiveOmahaPingSent() const override;
- void SetFirstActiveOmahaPingSent() override;
+ bool SetFirstActiveOmahaPingSent() override;
private:
DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 8c19aa7..08303d0 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -16,6 +16,8 @@
#include "update_engine/hardware_chromeos.h"
+#include <utility>
+
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
@@ -180,6 +182,19 @@
return utils::ParseECVersion(input_line);
}
+int HardwareChromeOS::GetMinKernelKeyVersion() const {
+ return VbGetSystemPropertyInt("tpm_kernver");
+}
+
+int HardwareChromeOS::GetMinFirmwareKeyVersion() const {
+ return VbGetSystemPropertyInt("tpm_fwver");
+}
+
+bool HardwareChromeOS::SetMaxKernelKeyRollforward(int kernel_max_rollforward) {
+ return VbSetSystemPropertyInt("kernel_max_rollforward",
+ kernel_max_rollforward) == 0;
+}
+
int HardwareChromeOS::GetPowerwashCount() const {
int powerwash_count;
base::FilePath marker_path = base::FilePath(kPowerwashSafeDirectory).Append(
@@ -272,7 +287,7 @@
return static_cast<bool>(active_ping);
}
-void HardwareChromeOS::SetFirstActiveOmahaPingSent() {
+bool HardwareChromeOS::SetFirstActiveOmahaPingSent() {
int exit_code = 0;
string output;
vector<string> vpd_set_cmd = {
@@ -282,7 +297,7 @@
LOG(ERROR) << "Failed to set vpd key for " << kActivePingKey
<< " with exit code: " << exit_code
<< " with error: " << output;
- return;
+ return false;
}
vector<string> vpd_dump_cmd = { "dump_vpd_log", "--force" };
@@ -291,7 +306,9 @@
LOG(ERROR) << "Failed to cache " << kActivePingKey<< " using dump_vpd_log"
<< " with exit code: " << exit_code
<< " with error: " << output;
+ return false;
}
+ return true;
}
} // namespace chromeos_update_engine
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 3a0bba2..6bdd37a 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -17,6 +17,7 @@
#ifndef UPDATE_ENGINE_HARDWARE_CHROMEOS_H_
#define UPDATE_ENGINE_HARDWARE_CHROMEOS_H_
+#include <memory>
#include <string>
#include <vector>
@@ -46,13 +47,16 @@
std::string GetHardwareClass() const override;
std::string GetFirmwareVersion() const override;
std::string GetECVersion() const override;
+ int GetMinKernelKeyVersion() const override;
+ int GetMinFirmwareKeyVersion() const override;
+ bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
int GetPowerwashCount() const override;
bool SchedulePowerwash() override;
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
bool GetFirstActiveOmahaPingSent() const override;
- void SetFirstActiveOmahaPingSent() override;
+ bool SetFirstActiveOmahaPingSent() override;
private:
friend class HardwareChromeOSTest;
diff --git a/init/update-engine.conf b/init/update-engine.conf
index 4c05cf4..d3681db 100644
--- a/init/update-engine.conf
+++ b/init/update-engine.conf
@@ -22,7 +22,10 @@
# also updating that reference.
start on starting system-services
stop on stopping system-services
-respawn
+# The default is 10 failures every 5 seconds, but even if we crash early, it is
+# hard to catch that. So here we set the crash rate as 10 failures every 20
+# seconds which will include the default and more.
+respawn limit 10 20
expect fork
diff --git a/main.cc b/main.cc
index 5cf53ce..67a150e 100644
--- a/main.cc
+++ b/main.cc
@@ -194,6 +194,8 @@
chromeos_update_engine::UpdateEngineDaemon update_engine_daemon;
int exit_code = update_engine_daemon.Run();
+ chromeos_update_engine::Subprocess::Get().FlushBufferedLogsAtExit();
+
LOG(INFO) << "A/B Update Engine terminating with exit code " << exit_code;
return exit_code;
}
diff --git a/metrics_reporter_android.h b/metrics_reporter_android.h
index a33e6f9..8a27ef6 100644
--- a/metrics_reporter_android.h
+++ b/metrics_reporter_android.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_METRICS_REPORTER_ANDROID_H_
#define UPDATE_ENGINE_METRICS_REPORTER_ANDROID_H_
+#include <string>
+
#include "update_engine/common/error_code.h"
#include "update_engine/metrics_constants.h"
#include "update_engine/metrics_reporter_interface.h"
@@ -33,6 +35,9 @@
void ReportRollbackMetrics(metrics::RollbackResult result) override {}
+ void ReportEnterpriseRollbackMetrics(
+ bool success, const std::string& rollback_version) override {}
+
void ReportDailyMetrics(base::TimeDelta os_age) override {}
void ReportUpdateCheckMetrics(
@@ -80,6 +85,12 @@
void ReportInstallDateProvisioningSource(int source, int max) override {}
+ void ReportInternalErrorCode(ErrorCode error_code) override {}
+
+ void ReportKeyVersionMetrics(int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success) override {}
+
private:
DISALLOW_COPY_AND_ASSIGN(MetricsReporterAndroid);
};
diff --git a/metrics_reporter_interface.h b/metrics_reporter_interface.h
index e96ac1e..b677aaa 100644
--- a/metrics_reporter_interface.h
+++ b/metrics_reporter_interface.h
@@ -18,6 +18,7 @@
#define UPDATE_ENGINE_METRICS_REPORTER_INTERFACE_H_
#include <memory>
+#include <string>
#include <base/time/time.h>
@@ -43,12 +44,20 @@
virtual void Initialize() = 0;
- // Helper function to report metrics related to rollback. The
+ // Helper function to report metrics related to user-initiated rollback. The
// following metrics are reported:
//
// |kMetricRollbackResult|
virtual void ReportRollbackMetrics(metrics::RollbackResult result) = 0;
+ // Helper function to report metrics related to enterprise (admin-initiated)
+ // rollback:
+ //
+ // |kMetricEnterpriseRollbackSuccess|
+ // |kMetricEnterpriseRollbackFailure|
+ virtual void ReportEnterpriseRollbackMetrics(
+ bool success, const std::string& rollback_version) = 0;
+
// Helper function to report metrics reported once a day. The
// following metrics are reported:
//
@@ -64,6 +73,8 @@
// |kMetricCheckDownloadErrorCode|
// |kMetricCheckTimeSinceLastCheckMinutes|
// |kMetricCheckTimeSinceLastCheckUptimeMinutes|
+ // |kMetricCheckTargetVersion|
+ // |kMetricCheckRollbackTargetVersion|
//
// The |kMetricCheckResult| metric will only be reported if |result|
// is not |kUnset|.
@@ -78,6 +89,10 @@
// |kMetricCheckTimeSinceLastCheckUptimeMinutes| metrics are
// automatically reported and calculated by maintaining persistent
// and process-local state variables.
+ //
+ // |kMetricCheckTargetVersion| reports the first section of the target version
+ // if it's set, |kMetricCheckRollbackTargetVersion| reports the same, but only
+ // if rollback is also allowed using enterprise policy.
virtual void ReportUpdateCheckMetrics(
SystemState* system_state,
metrics::CheckResult result,
@@ -195,6 +210,22 @@
//
// |kMetricInstallDateProvisioningSource|
virtual void ReportInstallDateProvisioningSource(int source, int max) = 0;
+
+ // Helper function to report an internal error code. The following metrics are
+ // reported:
+ //
+ // |kMetricAttemptInternalErrorCode|
+ virtual void ReportInternalErrorCode(ErrorCode error_code) = 0;
+
+ // Helper function to report metrics related to the verified boot key
+ // versions:
+ //
+ // |kMetricKernelMinVersion|
+ // |kMetricKernelMaxRollforwardVersion|
+ // |kMetricKernelMaxRollforwardSetSuccess|
+ virtual void ReportKeyVersionMetrics(int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success) = 0;
};
} // namespace chromeos_update_engine
diff --git a/metrics_reporter_omaha.cc b/metrics_reporter_omaha.cc
index df3e4d4..f0c6643 100644
--- a/metrics_reporter_omaha.cc
+++ b/metrics_reporter_omaha.cc
@@ -17,9 +17,9 @@
#include "update_engine/metrics_reporter_omaha.h"
#include <memory>
-#include <string>
#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
#include <metrics/metrics_library.h>
#include "update_engine/common/clock_interface.h"
@@ -27,6 +27,7 @@
#include "update_engine/common/prefs_interface.h"
#include "update_engine/common/utils.h"
#include "update_engine/metrics_utils.h"
+#include "update_engine/omaha_request_params.h"
#include "update_engine/system_state.h"
using std::string;
@@ -43,6 +44,9 @@
"UpdateEngine.Check.DownloadErrorCode";
const char kMetricCheckReaction[] = "UpdateEngine.Check.Reaction";
const char kMetricCheckResult[] = "UpdateEngine.Check.Result";
+const char kMetricCheckTargetVersion[] = "UpdateEngine.Check.TargetVersion";
+const char kMetricCheckRollbackTargetVersion[] =
+ "UpdateEngine.Check.RollbackTargetVersion";
const char kMetricCheckTimeSinceLastCheckMinutes[] =
"UpdateEngine.Check.TimeSinceLastCheckMinutes";
const char kMetricCheckTimeSinceLastCheckUptimeMinutes[] =
@@ -102,12 +106,25 @@
// UpdateEngine.Rollback.* metric.
const char kMetricRollbackResult[] = "UpdateEngine.Rollback.Result";
+// UpdateEngine.EnterpriseRollback.* metrics.
+const char kMetricEnterpriseRollbackFailure[] =
+ "UpdateEngine.EnterpriseRollback.Failure";
+const char kMetricEnterpriseRollbackSuccess[] =
+ "UpdateEngine.EnterpriseRollback.Success";
+
// UpdateEngine.CertificateCheck.* metrics.
const char kMetricCertificateCheckUpdateCheck[] =
"UpdateEngine.CertificateCheck.UpdateCheck";
const char kMetricCertificateCheckDownload[] =
"UpdateEngine.CertificateCheck.Download";
+// UpdateEngine.KernelKey.* metrics.
+const char kMetricKernelMinVersion[] = "UpdateEngine.KernelKey.MinVersion";
+const char kMetricKernelMaxRollforwardVersion[] =
+ "UpdateEngine.KernelKey.MaxRollforwardVersion";
+const char kMetricKernelMaxRollforwardSetSuccess[] =
+ "UpdateEngine.KernelKey.MaxRollforwardSetSuccess";
+
// UpdateEngine.* metrics.
const char kMetricFailedUpdateCount[] = "UpdateEngine.FailedUpdateCount";
const char kMetricInstallDateProvisioningSource[] =
@@ -196,6 +213,25 @@
30 * 24 * 60, // max: 30 days
50); // num_buckets
}
+
+ // First section of target version specified for the update.
+ if (system_state && system_state->request_params()) {
+ string target_version =
+ system_state->request_params()->target_version_prefix();
+ value = utils::VersionPrefix(target_version);
+ if (value != 0) {
+ metric = metrics::kMetricCheckTargetVersion;
+ LOG(INFO) << "Sending " << value << " for metric " << metric
+ << " (sparse)";
+ metrics_lib_->SendSparseToUMA(metric, value);
+ if (system_state->request_params()->rollback_allowed()) {
+ metric = metrics::kMetricCheckRollbackTargetVersion;
+ LOG(INFO) << "Sending " << value << " for metric " << metric
+ << " (sparse)";
+ metrics_lib_->SendSparseToUMA(metric, value);
+ }
+ }
+ }
}
void MetricsReporterOmaha::ReportAbnormallyTerminatedUpdateAttemptMetrics() {
@@ -271,12 +307,7 @@
static_cast<int>(metrics::AttemptResult::kNumConstants));
if (internal_error_code != ErrorCode::kSuccess) {
- metric = metrics::kMetricAttemptInternalErrorCode;
- LOG(INFO) << "Uploading " << internal_error_code << " for metric "
- << metric;
- metrics_lib_->SendEnumToUMA(metric,
- static_cast<int>(internal_error_code),
- static_cast<int>(ErrorCode::kUmaReportedMax));
+ ReportInternalErrorCode(internal_error_code);
}
base::TimeDelta time_since_last;
@@ -495,6 +526,16 @@
metric, value, static_cast<int>(metrics::RollbackResult::kNumConstants));
}
+void MetricsReporterOmaha::ReportEnterpriseRollbackMetrics(
+ bool success, const string& rollback_version) {
+ int value = utils::VersionPrefix(rollback_version);
+ string metric = metrics::kMetricEnterpriseRollbackSuccess;
+ if (!success)
+ metric = metrics::kMetricEnterpriseRollbackFailure;
+ LOG(INFO) << "Sending " << value << " for metric " << metric;
+ metrics_lib_->SendSparseToUMA(metric, value);
+}
+
void MetricsReporterOmaha::ReportCertificateCheckMetrics(
ServerToCheck server_to_check, CertificateCheckResult result) {
string metric;
@@ -547,4 +588,33 @@
max);
}
+void MetricsReporterOmaha::ReportInternalErrorCode(ErrorCode error_code) {
+ auto metric = metrics::kMetricAttemptInternalErrorCode;
+ LOG(INFO) << "Uploading " << error_code << " for metric " << metric;
+ metrics_lib_->SendEnumToUMA(metric,
+ static_cast<int>(error_code),
+ static_cast<int>(ErrorCode::kUmaReportedMax));
+}
+
+void MetricsReporterOmaha::ReportKeyVersionMetrics(
+ int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success) {
+ int value = kernel_min_version;
+ string metric = metrics::kMetricKernelMinVersion;
+ LOG(INFO) << "Sending " << value << " for metric " << metric;
+ metrics_lib_->SendSparseToUMA(metric, value);
+
+ value = kernel_max_rollforward_version;
+ metric = metrics::kMetricKernelMaxRollforwardVersion;
+ LOG(INFO) << "Sending " << value << " for metric " << metric;
+ metrics_lib_->SendSparseToUMA(metric, value);
+
+ bool bool_value = kernel_max_rollforward_success;
+ metric = metrics::kMetricKernelMaxRollforwardSetSuccess;
+ LOG(INFO) << "Sending " << bool_value << " for metric " << metric
+ << " (bool)";
+ metrics_lib_->SendBoolToUMA(metric, bool_value);
+}
+
} // namespace chromeos_update_engine
diff --git a/metrics_reporter_omaha.h b/metrics_reporter_omaha.h
index 5e88923..10aef86 100644
--- a/metrics_reporter_omaha.h
+++ b/metrics_reporter_omaha.h
@@ -18,6 +18,7 @@
#define UPDATE_ENGINE_METRICS_REPORTER_OMAHA_H_
#include <memory>
+#include <string>
#include <base/time/time.h>
#include <metrics/metrics_library.h>
@@ -42,6 +43,8 @@
extern const char kMetricCheckDownloadErrorCode[];
extern const char kMetricCheckReaction[];
extern const char kMetricCheckResult[];
+extern const char kMetricCheckTargetVersion[];
+extern const char kMetricCheckRollbackTargetVersion[];
extern const char kMetricCheckTimeSinceLastCheckMinutes[];
extern const char kMetricCheckTimeSinceLastCheckUptimeMinutes[];
@@ -77,10 +80,19 @@
// UpdateEngine.Rollback.* metric.
extern const char kMetricRollbackResult[];
+// UpdateEngine.EnterpriseRollback.* metrics.
+extern const char kMetricEnterpriseRollbackFailure[];
+extern const char kMetricEnterpriseRollbackSuccess[];
+
// UpdateEngine.CertificateCheck.* metrics.
extern const char kMetricCertificateCheckUpdateCheck[];
extern const char kMetricCertificateCheckDownload[];
+// UpdateEngine.KernelKey.* metrics.
+extern const char kMetricKernelMinVersion[];
+extern const char kMetricKernelMaxRollforwardVersion[];
+extern const char kMetricKernelMaxRollforwardSetSuccess[];
+
// UpdateEngine.* metrics.
extern const char kMetricFailedUpdateCount[];
extern const char kMetricInstallDateProvisioningSource[];
@@ -98,6 +110,9 @@
void ReportRollbackMetrics(metrics::RollbackResult result) override;
+ void ReportEnterpriseRollbackMetrics(
+ bool success, const std::string& rollback_version) override;
+
void ReportDailyMetrics(base::TimeDelta os_age) override;
void ReportUpdateCheckMetrics(
@@ -145,6 +160,12 @@
void ReportInstallDateProvisioningSource(int source, int max) override;
+ void ReportInternalErrorCode(ErrorCode error_code) override;
+
+ void ReportKeyVersionMetrics(int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success) override;
+
private:
friend class MetricsReporterOmahaTest;
diff --git a/metrics_reporter_omaha_unittest.cc b/metrics_reporter_omaha_unittest.cc
index 2fe5d66..878a323 100644
--- a/metrics_reporter_omaha_unittest.cc
+++ b/metrics_reporter_omaha_unittest.cc
@@ -29,8 +29,9 @@
#include "update_engine/fake_system_state.h"
using base::TimeDelta;
-using testing::AnyNumber;
using testing::_;
+using testing::AnyNumber;
+using testing::Return;
namespace chromeos_update_engine {
class MetricsReporterOmahaTest : public ::testing::Test {
@@ -85,6 +86,14 @@
static_cast<int>(error_code)))
.Times(2);
+ // Not pinned nor rollback
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckTargetVersion, _))
+ .Times(0);
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
+ .Times(0);
+
EXPECT_CALL(
*mock_metrics_lib_,
SendToUMA(metrics::kMetricCheckTimeSinceLastCheckMinutes, 1, _, _, _))
@@ -101,6 +110,62 @@
// Advance the clock by 1 minute and report the same metrics again.
fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000));
fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000));
+ // Allow rollback
+ reporter_.ReportUpdateCheckMetrics(
+ &fake_system_state, result, reaction, error_code);
+}
+
+TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsPinned) {
+ FakeSystemState fake_system_state;
+
+ OmahaRequestParams params(&fake_system_state);
+ params.set_target_version_prefix("10575.");
+ params.set_rollback_allowed(false);
+ fake_system_state.set_request_params(¶ms);
+
+ metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
+ metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
+ metrics::DownloadErrorCode error_code =
+ metrics::DownloadErrorCode::kHttpStatus200;
+
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
+ // Target version set, but not a rollback.
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
+ .Times(1);
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
+ .Times(0);
+
+ reporter_.ReportUpdateCheckMetrics(
+ &fake_system_state, result, reaction, error_code);
+}
+
+TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsRollback) {
+ FakeSystemState fake_system_state;
+
+ OmahaRequestParams params(&fake_system_state);
+ params.set_target_version_prefix("10575.");
+ params.set_rollback_allowed(true);
+ fake_system_state.set_request_params(¶ms);
+
+ metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
+ metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
+ metrics::DownloadErrorCode error_code =
+ metrics::DownloadErrorCode::kHttpStatus200;
+
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
+ // Rollback.
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
+ .Times(1);
+ EXPECT_CALL(
+ *mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, 10575))
+ .Times(1);
+
reporter_.ReportUpdateCheckMetrics(
&fake_system_state, result, reaction, error_code);
}
@@ -357,6 +422,18 @@
reporter_.ReportRollbackMetrics(result);
}
+TEST_F(MetricsReporterOmahaTest, ReportEnterpriseRollbackMetrics) {
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricEnterpriseRollbackSuccess, 10575))
+ .Times(1);
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricEnterpriseRollbackFailure, 10323))
+ .Times(1);
+
+ reporter_.ReportEnterpriseRollbackMetrics(/*success=*/true, "10575.39.2");
+ reporter_.ReportEnterpriseRollbackMetrics(/*success=*/false, "10323.67.7");
+}
+
TEST_F(MetricsReporterOmahaTest, ReportCertificateCheckMetrics) {
ServerToCheck server_to_check = ServerToCheck::kUpdate;
CertificateCheckResult result = CertificateCheckResult::kValid;
@@ -401,4 +478,26 @@
reporter_.ReportInstallDateProvisioningSource(source, max);
}
+TEST_F(MetricsReporterOmahaTest, ReportKeyVersionMetrics) {
+ int kernel_min_version = 0x00040002;
+ int kernel_max_rollforward_version = 0xfffffffe;
+ bool kernel_max_rollforward_success = true;
+ EXPECT_CALL(
+ *mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricKernelMinVersion, kernel_min_version))
+ .Times(1);
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendSparseToUMA(metrics::kMetricKernelMaxRollforwardVersion,
+ kernel_max_rollforward_version))
+ .Times(1);
+ EXPECT_CALL(*mock_metrics_lib_,
+ SendBoolToUMA(metrics::kMetricKernelMaxRollforwardSetSuccess,
+ kernel_max_rollforward_success))
+ .Times(1);
+
+ reporter_.ReportKeyVersionMetrics(kernel_min_version,
+ kernel_max_rollforward_version,
+ kernel_max_rollforward_success);
+}
+
} // namespace chromeos_update_engine
diff --git a/metrics_reporter_stub.h b/metrics_reporter_stub.h
index 6ffd05c..486dc2f 100644
--- a/metrics_reporter_stub.h
+++ b/metrics_reporter_stub.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
#define UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
+#include <string>
+
#include "update_engine/common/error_code.h"
#include "update_engine/metrics_constants.h"
#include "update_engine/metrics_reporter_interface.h"
@@ -33,6 +35,9 @@
void ReportRollbackMetrics(metrics::RollbackResult result) override {}
+ void ReportEnterpriseRollbackMetrics(
+ bool success, const std::string& rollback_version) override {}
+
void ReportDailyMetrics(base::TimeDelta os_age) override {}
void ReportUpdateCheckMetrics(
@@ -80,6 +85,10 @@
void ReportInstallDateProvisioningSource(int source, int max) override {}
+ void ReportKeyVersionMetrics(int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success) override {}
+
private:
DISALLOW_COPY_AND_ASSIGN(MetricsReporterStub);
};
diff --git a/metrics_utils.cc b/metrics_utils.cc
index f87828f..b85f257 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -82,6 +82,7 @@
case ErrorCode::kNewRootfsVerificationError:
case ErrorCode::kNewKernelVerificationError:
+ case ErrorCode::kRollbackNotPossible:
return metrics::AttemptResult::kVerificationFailed;
case ErrorCode::kPostinstallRunnerError:
@@ -113,7 +114,9 @@
case ErrorCode::kPostinstallPowerwashError:
case ErrorCode::kUpdateCanceledByChannelChange:
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
case ErrorCode::kNoUpdate:
+ case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
return metrics::AttemptResult::kInternalError;
// Special flags. These can't happen (we mask them out above) but
@@ -214,8 +217,11 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
case ErrorCode::kUpdatedButNotActive:
case ErrorCode::kNoUpdate:
+ case ErrorCode::kRollbackNotPossible:
+ case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
break;
// Special flags. These can't happen (we mask them out above) but
diff --git a/mock_connection_manager.h b/mock_connection_manager.h
index e37460b..2fff68c 100644
--- a/mock_connection_manager.h
+++ b/mock_connection_manager.h
@@ -36,6 +36,7 @@
MOCK_CONST_METHOD2(IsUpdateAllowedOver,
bool(ConnectionType type, ConnectionTethering tethering));
+ MOCK_CONST_METHOD0(IsAllowedConnectionTypesForUpdateSet, bool());
};
} // namespace chromeos_update_engine
diff --git a/mock_metrics_reporter.h b/mock_metrics_reporter.h
index 3d39049..c678a80 100644
--- a/mock_metrics_reporter.h
+++ b/mock_metrics_reporter.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_MOCK_METRICS_REPORTER_H_
#define UPDATE_ENGINE_MOCK_METRICS_REPORTER_H_
+#include <string>
+
#include <gmock/gmock.h>
#include "update_engine/metrics_reporter_interface.h"
@@ -29,6 +31,9 @@
MOCK_METHOD1(ReportRollbackMetrics, void(metrics::RollbackResult result));
+ MOCK_METHOD2(ReportEnterpriseRollbackMetrics,
+ void(bool success, const std::string& rollback_version));
+
MOCK_METHOD1(ReportDailyMetrics, void(base::TimeDelta os_age));
MOCK_METHOD4(ReportUpdateCheckMetrics,
@@ -77,6 +82,13 @@
MOCK_METHOD1(ReportTimeToReboot, void(int time_to_reboot_minutes));
MOCK_METHOD2(ReportInstallDateProvisioningSource, void(int source, int max));
+
+ MOCK_METHOD1(ReportInternalErrorCode, void(ErrorCode error_code));
+
+ MOCK_METHOD3(ReportKeyVersionMetrics,
+ void(int kernel_min_version,
+ int kernel_max_rollforward_version,
+ bool kernel_max_rollforward_success));
};
} // namespace chromeos_update_engine
diff --git a/mock_omaha_request_params.h b/mock_omaha_request_params.h
index 6d8d3d8..2fe5e01 100644
--- a/mock_omaha_request_params.h
+++ b/mock_omaha_request_params.h
@@ -50,6 +50,7 @@
MOCK_METHOD3(SetTargetChannel, bool(const std::string& channel,
bool is_powerwash_allowed,
std::string* error));
+ MOCK_CONST_METHOD0(target_version_prefix, std::string(void));
MOCK_METHOD0(UpdateDownloadChannel, void(void));
MOCK_CONST_METHOD0(IsUpdateUrlOfficial, bool(void));
MOCK_CONST_METHOD0(ShouldPowerwash, bool(void));
diff --git a/mock_payload_state.h b/mock_payload_state.h
index 259dcaf..f543842 100644
--- a/mock_payload_state.h
+++ b/mock_payload_state.h
@@ -68,6 +68,8 @@
MOCK_METHOD1(GetCurrentBytesDownloaded, uint64_t(DownloadSource source));
MOCK_METHOD1(GetTotalBytesDownloaded, uint64_t(DownloadSource source));
MOCK_METHOD0(GetNumReboots, uint32_t());
+ MOCK_METHOD0(GetRollbackHappened, bool());
+ MOCK_METHOD1(SetRollbackHappened, void(bool));
MOCK_METHOD0(GetRollbackVersion, std::string());
MOCK_METHOD0(GetP2PNumAttempts, int());
MOCK_METHOD0(GetP2PFirstAttemptTimestamp, base::Time());
diff --git a/mock_update_attempter.h b/mock_update_attempter.h
index d88b840..405fdd6 100644
--- a/mock_update_attempter.h
+++ b/mock_update_attempter.h
@@ -29,12 +29,14 @@
public:
using UpdateAttempter::UpdateAttempter;
- MOCK_METHOD6(Update, void(const std::string& app_version,
- const std::string& omaha_url,
- const std::string& target_channel,
- const std::string& target_version_prefix,
- bool obey_proxies,
- bool interactive));
+ MOCK_METHOD7(Update,
+ void(const std::string& app_version,
+ const std::string& omaha_url,
+ const std::string& target_channel,
+ const std::string& target_version_prefix,
+ bool rollback_allowed,
+ bool obey_proxies,
+ bool interactive));
MOCK_METHOD1(GetStatus, bool(update_engine::UpdateEngineStatus* out_status));
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 78d8d50..ca6e348 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -35,6 +35,7 @@
#include <brillo/key_value_store.h>
#include <expat.h>
#include <metrics/metrics_library.h>
+#include <policy/libpolicy.h>
#include "update_engine/common/action_pipe.h"
#include "update_engine/common/constants.h"
@@ -52,6 +53,7 @@
using base::Time;
using base::TimeDelta;
+using chromeos_update_manager::kRollforwardInfinity;
using std::map;
using std::string;
using std::vector;
@@ -87,6 +89,9 @@
// updatecheck attributes (without the underscore prefix).
static const char* kEolAttr = "eol";
+static const char* kRollback = "rollback";
+static const char* kFirmwareVersion = "firmware_version";
+static const char* kKernelVersion = "kernel_version";
namespace {
@@ -126,10 +131,17 @@
if (include_ping)
app_body = GetPingXml(ping_active_days, ping_roll_call_days);
if (!ping_only) {
- app_body += base::StringPrintf(
- " <updatecheck targetversionprefix=\"%s\""
- "></updatecheck>\n",
- XmlEncodeWithDefault(params->target_version_prefix(), "").c_str());
+ app_body += " <updatecheck";
+ if (!params->target_version_prefix().empty()) {
+ app_body += base::StringPrintf(
+ " targetversionprefix=\"%s\"",
+ XmlEncodeWithDefault(params->target_version_prefix(), "").c_str());
+ // Rollback requires target_version_prefix set.
+ if (params->rollback_allowed()) {
+ app_body += " rollback_allowed=\"true\"";
+ }
+ }
+ app_body += "></updatecheck>\n";
// If this is the first update check after a reboot following a previous
// update, generate an event containing the previous version number. If
@@ -620,12 +632,14 @@
std::unique_ptr<HttpFetcher> http_fetcher,
bool ping_only)
: system_state_(system_state),
+ params_(system_state->request_params()),
event_(event),
http_fetcher_(std::move(http_fetcher)),
+ policy_provider_(std::make_unique<policy::PolicyProvider>()),
ping_only_(ping_only),
ping_active_days_(0),
ping_roll_call_days_(0) {
- params_ = system_state->request_params();
+ policy_provider_->Reload();
}
OmahaRequestAction::~OmahaRequestAction() {}
@@ -986,6 +1000,18 @@
// Parse the updatecheck attributes.
PersistEolStatus(parser_data->updatecheck_attrs);
+ // Rollback-related updatecheck attributes.
+ // Defaults to false if attribute is not present.
+ output_object->is_rollback =
+ ParseBool(parser_data->updatecheck_attrs[kRollback]);
+ // Defaults to 0 if attribute is not present. This is fine for these values,
+ // because it's the lowest possible value, and the rollback image won't be
+ // installed, if the values in the TPM are larger than these, and in case the
+ // values in the TPM are 0, all images will be able to boot up.
+ output_object->firmware_version = static_cast<uint32_t>(
+ ParseInt(parser_data->updatecheck_attrs[kFirmwareVersion]));
+ output_object->kernel_version = static_cast<uint32_t>(
+ ParseInt(parser_data->updatecheck_attrs[kKernelVersion]));
if (!ParseStatus(parser_data, output_object, completer))
return false;
@@ -1102,6 +1128,9 @@
PayloadStateInterface* const payload_state = system_state_->payload_state();
+ // Set the max kernel key version based on whether rollback is allowed.
+ SetMaxKernelKeyVersionForRollback();
+
// Events are best effort transactions -- assume they always succeed.
if (IsEvent()) {
CHECK(!HasOutputPipe()) << "No output pipe allowed for event requests.";
@@ -1161,7 +1190,10 @@
// their a=-1 in the past and we have to set first_active_omaha_ping_sent for
// future checks.
if (!system_state_->hardware()->GetFirstActiveOmahaPingSent()) {
- system_state_->hardware()->SetFirstActiveOmahaPingSent();
+ if (!system_state_->hardware()->SetFirstActiveOmahaPingSent()) {
+ system_state_->metrics_reporter()->ReportInternalErrorCode(
+ ErrorCode::kFirstActiveOmahaPingSentPersistenceError);
+ }
}
if (!HasOutputPipe()) {
@@ -1177,9 +1209,11 @@
output_object.update_exists = true;
SetOutputObject(output_object);
- if (ShouldIgnoreUpdate(output_object)) {
- output_object.update_exists = false;
- completer.set_code(ErrorCode::kOmahaUpdateIgnoredPerPolicy);
+ ErrorCode error = ErrorCode::kSuccess;
+ if (ShouldIgnoreUpdate(&error, output_object)) {
+ // No need to change output_object.update_exists here, since the value
+ // has been output to the pipe.
+ completer.set_code(error);
return;
}
@@ -1237,7 +1271,8 @@
if (system_state_->hardware()->IsOOBEEnabled() &&
!system_state_->hardware()->IsOOBEComplete(nullptr) &&
- output_object.deadline.empty() &&
+ (output_object.deadline.empty() ||
+ payload_state->GetRollbackHappened()) &&
params_->app_version() != "ForcedUpdate") {
output_object.update_exists = false;
LOG(INFO) << "Ignoring non-critical Omaha updates until OOBE is done.";
@@ -1639,6 +1674,7 @@
break;
case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
result = metrics::CheckResult::kUpdateAvailable;
reaction = metrics::CheckReaction::kIgnored;
break;
@@ -1673,7 +1709,7 @@
}
bool OmahaRequestAction::ShouldIgnoreUpdate(
- const OmahaResponse& response) const {
+ ErrorCode* error, const OmahaResponse& response) const {
// Note: policy decision to not update to a version we rolled back from.
string rollback_version =
system_state_->payload_state()->GetRollbackVersion();
@@ -1681,11 +1717,12 @@
LOG(INFO) << "Detected previous rollback from version " << rollback_version;
if (rollback_version == response.version) {
LOG(INFO) << "Received version that we rolled back from. Ignoring.";
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
return true;
}
}
- if (!IsUpdateAllowedOverCurrentConnection()) {
+ if (!IsUpdateAllowedOverCurrentConnection(error, response)) {
LOG(INFO) << "Update is not allowed over current connection.";
return true;
}
@@ -1700,7 +1737,62 @@
return false;
}
-bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection() const {
+bool OmahaRequestAction::IsUpdateAllowedOverCellularByPrefs(
+ const OmahaResponse& response) const {
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs) {
+ LOG(INFO) << "Disabling updates over cellular as the preferences are "
+ "not available.";
+ return false;
+ }
+
+ bool is_allowed;
+
+ if (prefs->Exists(kPrefsUpdateOverCellularPermission) &&
+ prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed) &&
+ is_allowed) {
+ LOG(INFO) << "Allowing updates over cellular as permission preference is "
+ "set to true.";
+ return true;
+ }
+
+ if (!prefs->Exists(kPrefsUpdateOverCellularTargetVersion) ||
+ !prefs->Exists(kPrefsUpdateOverCellularTargetSize)) {
+ LOG(INFO) << "Disabling updates over cellular as permission preference is "
+ "set to false or does not exist while target does not exist.";
+ return false;
+ }
+
+ std::string target_version;
+ int64_t target_size;
+
+ if (!prefs->GetString(kPrefsUpdateOverCellularTargetVersion,
+ &target_version) ||
+ !prefs->GetInt64(kPrefsUpdateOverCellularTargetSize, &target_size)) {
+ LOG(INFO) << "Disabling updates over cellular as the target version or "
+ "size is not accessible.";
+ return false;
+ }
+
+ uint64_t total_packages_size = 0;
+ for (const auto& package : response.packages) {
+ total_packages_size += package.size;
+ }
+ if (target_version == response.version &&
+ static_cast<uint64_t>(target_size) == total_packages_size) {
+ LOG(INFO) << "Allowing updates over cellular as the target matches the"
+ "omaha response.";
+ return true;
+ } else {
+ LOG(INFO) << "Disabling updates over cellular as the target does not"
+ "match the omaha response.";
+ return false;
+ }
+}
+
+bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection(
+ ErrorCode* error, const OmahaResponse& response) const {
ConnectionType type;
ConnectionTethering tethering;
ConnectionManagerInterface* connection_manager =
@@ -1710,11 +1802,97 @@
<< "Defaulting to allow updates.";
return true;
}
+
bool is_allowed = connection_manager->IsUpdateAllowedOver(type, tethering);
+ bool is_device_policy_set =
+ connection_manager->IsAllowedConnectionTypesForUpdateSet();
+ // Treats tethered connection as if it is cellular connection.
+ bool is_over_cellular = type == ConnectionType::kCellular ||
+ tethering == ConnectionTethering::kConfirmed;
+
+ if (!is_over_cellular) {
+ // There's no need to further check user preferences as we are not over
+ // cellular connection.
+ if (!is_allowed)
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
+ } else if (is_device_policy_set) {
+ // There's no need to further check user preferences as the device policy
+ // is set regarding updates over cellular.
+ if (!is_allowed)
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
+ } else {
+ // Deivce policy is not set, so user preferences overwrite whether to
+ // allow updates over cellular.
+ is_allowed = IsUpdateAllowedOverCellularByPrefs(response);
+ if (!is_allowed)
+ *error = ErrorCode::kOmahaUpdateIgnoredOverCellular;
+ }
+
LOG(INFO) << "We are connected via "
<< connection_utils::StringForConnectionType(type)
<< ", Updates allowed: " << (is_allowed ? "Yes" : "No");
return is_allowed;
}
+bool OmahaRequestAction::IsRollbackEnabled() const {
+ if (policy_provider_->IsConsumerDevice()) {
+ LOG(INFO) << "Rollback is not enabled for consumer devices.";
+ return false;
+ }
+
+ if (!policy_provider_->device_policy_is_loaded()) {
+ LOG(INFO) << "No device policy is loaded. Assuming rollback enabled.";
+ return true;
+ }
+
+ int allowed_milestones;
+ if (!policy_provider_->GetDevicePolicy().GetRollbackAllowedMilestones(
+ &allowed_milestones)) {
+ LOG(INFO) << "RollbackAllowedMilestones policy can't be read. "
+ "Defaulting to rollback enabled.";
+ return true;
+ }
+
+ LOG(INFO) << "Rollback allows " << allowed_milestones << " milestones.";
+ return allowed_milestones > 0;
+}
+
+void OmahaRequestAction::SetMaxKernelKeyVersionForRollback() const {
+ int max_kernel_rollforward;
+ int min_kernel_version = system_state_->hardware()->GetMinKernelKeyVersion();
+ if (IsRollbackEnabled()) {
+ // If rollback is enabled, set the max kernel key version to the current
+ // kernel key version. This has the effect of freezing kernel key roll
+ // forwards.
+ //
+ // TODO(zentaro): This behavior is temporary, and ensures that no kernel
+ // key roll forward happens until the server side components of rollback
+ // are implemented. Future changes will allow the Omaha server to return
+ // the kernel key version from max_rollback_versions in the past. At that
+ // point the max kernel key version will be set to that value, creating a
+ // sliding window of versions that can be rolled back to.
+ LOG(INFO) << "Rollback is enabled. Setting kernel_max_rollforward to "
+ << min_kernel_version;
+ max_kernel_rollforward = min_kernel_version;
+ } else {
+ // For devices that are not rollback enabled (ie. consumer devices), the
+ // max kernel key version is set to 0xfffffffe, which is logically
+ // infinity. This maintains the previous behavior that that kernel key
+ // versions roll forward each time they are incremented.
+ LOG(INFO) << "Rollback is disabled. Setting kernel_max_rollforward to "
+ << kRollforwardInfinity;
+ max_kernel_rollforward = kRollforwardInfinity;
+ }
+
+ bool max_rollforward_set =
+ system_state_->hardware()->SetMaxKernelKeyRollforward(
+ max_kernel_rollforward);
+ if (!max_rollforward_set) {
+ LOG(ERROR) << "Failed to set kernel_max_rollforward";
+ }
+ // Report metrics
+ system_state_->metrics_reporter()->ReportKeyVersionMetrics(
+ min_kernel_version, max_kernel_rollforward, max_rollforward_set);
+}
+
} // namespace chromeos_update_engine
diff --git a/omaha_request_action.h b/omaha_request_action.h
index 924da40..7f526ec 100644
--- a/omaha_request_action.h
+++ b/omaha_request_action.h
@@ -39,6 +39,10 @@
// The Omaha Request action makes a request to Omaha and can output
// the response on the output ActionPipe.
+namespace policy {
+class PolicyProvider;
+}
+
namespace chromeos_update_engine {
// Encodes XML entities in a given string. Input must be ASCII-7 valid. If
@@ -172,6 +176,7 @@
bool IsEvent() const { return event_.get() != nullptr; }
private:
+ friend class OmahaRequestActionTest;
FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE);
FRIEND_TEST(OmahaRequestActionTest,
GetInstallDateWhenOOBECompletedWithInvalidDate);
@@ -292,11 +297,24 @@
void OnLookupPayloadViaP2PCompleted(const std::string& url);
// Returns true if the current update should be ignored.
- bool ShouldIgnoreUpdate(const OmahaResponse& response) const;
+ bool ShouldIgnoreUpdate(ErrorCode* error,
+ const OmahaResponse& response) const;
+
+ // Return true if updates are allowed by user preferences.
+ bool IsUpdateAllowedOverCellularByPrefs(const OmahaResponse& response) const;
// Returns true if updates are allowed over the current type of connection.
// False otherwise.
- bool IsUpdateAllowedOverCurrentConnection() const;
+ bool IsUpdateAllowedOverCurrentConnection(
+ ErrorCode* error, const OmahaResponse& response) const;
+
+ // Returns true if rollback is enabled. Always returns false for consumer
+ // devices.
+ bool IsRollbackEnabled() const;
+
+ // Sets the appropriate max kernel key version based on whether rollback is
+ // enabled.
+ void SetMaxKernelKeyVersionForRollback() const;
// Global system context.
SystemState* system_state_;
@@ -310,6 +328,9 @@
// pointer to the HttpFetcher that does the http work
std::unique_ptr<HttpFetcher> http_fetcher_;
+ // Used for fetching information about the device policy.
+ std::unique_ptr<policy::PolicyProvider> policy_provider_;
+
// If true, only include the <ping> element in the request.
bool ping_only_;
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 9a01a13..7c9fe41 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -20,6 +20,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <base/bind.h>
@@ -35,6 +36,8 @@
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gtest/gtest.h>
+#include <policy/libpolicy.h>
+#include <policy/mock_libpolicy.h>
#include "update_engine/common/action_pipe.h"
#include "update_engine/common/constants.h"
@@ -49,9 +52,11 @@
#include "update_engine/mock_connection_manager.h"
#include "update_engine/mock_payload_state.h"
#include "update_engine/omaha_request_params.h"
+#include "update_engine/update_manager/rollback_prefs.h"
using base::Time;
using base::TimeDelta;
+using chromeos_update_manager::kRollforwardInfinity;
using std::string;
using std::vector;
using testing::AllOf;
@@ -61,6 +66,7 @@
using testing::Le;
using testing::NiceMock;
using testing::Return;
+using testing::ReturnRef;
using testing::ReturnPointee;
using testing::SaveArg;
using testing::SetArgPointee;
@@ -68,6 +74,10 @@
namespace {
+static_assert(kRollforwardInfinity == 0xfffffffe,
+ "Don't change the value of kRollforward infinity unless its "
+ "size has been changed in firmware.");
+
const char kTestAppId[] = "test-app-id";
const char kTestAppId2[] = "test-app2-id";
@@ -219,6 +229,23 @@
class OmahaRequestActionTest : public ::testing::Test {
protected:
void SetUp() override {
+ request_params_.set_os_sp("service_pack");
+ request_params_.set_os_board("x86-generic");
+ request_params_.set_app_id(kTestAppId);
+ request_params_.set_app_version("0.1.0.0");
+ request_params_.set_app_lang("en-US");
+ request_params_.set_current_channel("unittest");
+ request_params_.set_target_channel("unittest");
+ request_params_.set_hwid("OEM MODEL 09235 7471");
+ request_params_.set_fw_version("ChromeOSFirmware.1.0");
+ request_params_.set_ec_version("0X0A1");
+ request_params_.set_delta_okay(true);
+ request_params_.set_interactive(false);
+ request_params_.set_update_url("http://url");
+ request_params_.set_target_version_prefix("");
+ request_params_.set_rollback_allowed(false);
+ request_params_.set_is_powerwash_allowed(false);
+
fake_system_state_.set_request_params(&request_params_);
fake_system_state_.set_prefs(&fake_prefs_);
}
@@ -238,8 +265,22 @@
// about reporting UpdateEngine.Check.{Result,Reaction,DownloadError}
// UMA statistics. Use the appropriate ::kUnset value to specify that
// the given metric should not be reported.
- bool TestUpdateCheck(OmahaRequestParams* request_params,
- const string& http_response,
+ bool TestUpdateCheck(const string& http_response,
+ int fail_http_response_code,
+ bool ping_only,
+ bool is_consumer_device,
+ int rollback_allowed_milestones,
+ bool is_policy_loaded,
+ ErrorCode expected_code,
+ metrics::CheckResult expected_check_result,
+ metrics::CheckReaction expected_check_reaction,
+ metrics::DownloadErrorCode expected_download_error_code,
+ OmahaResponse* out_response,
+ brillo::Blob* out_post_data);
+
+ // Overload of TestUpdateCheck that does not supply |is_consumer_device| or
+ // |rollback_allowed_milestones| which are only required for rollback tests.
+ bool TestUpdateCheck(const string& http_response,
int fail_http_response_code,
bool ping_only,
ErrorCode expected_code,
@@ -249,6 +290,10 @@
OmahaResponse* out_response,
brillo::Blob* out_post_data);
+ void TestRollbackCheck(bool is_consumer_device,
+ int rollback_allowed_milestones,
+ bool is_policy_loaded);
+
// Runs and checks a ping test. |ping_only| indicates whether it should send
// only a ping or also an updatecheck.
void PingTest(bool ping_only);
@@ -272,26 +317,8 @@
FakeSystemState fake_system_state_;
FakeUpdateResponse fake_update_response_;
-
- // By default, all tests use these objects unless they replace them in the
- // fake_system_state_.
- OmahaRequestParams request_params_ = OmahaRequestParams{
- &fake_system_state_,
- constants::kOmahaPlatformName,
- OmahaRequestParams::kOsVersion,
- "service_pack",
- "x86-generic",
- kTestAppId,
- "0.1.0.0",
- "en-US",
- "unittest",
- "OEM MODEL 09235 7471",
- "ChromeOSFirmware.1.0",
- "0X0A1",
- false, // delta okay
- false, // interactive
- "http://url",
- ""}; // target_version_prefix
+ // Used by all tests.
+ OmahaRequestParams request_params_{&fake_system_state_};
FakePrefs fake_prefs_;
};
@@ -360,10 +387,12 @@
};
bool OmahaRequestActionTest::TestUpdateCheck(
- OmahaRequestParams* request_params,
const string& http_response,
int fail_http_response_code,
bool ping_only,
+ bool is_consumer_device,
+ int rollback_allowed_milestones,
+ bool is_policy_loaded,
ErrorCode expected_code,
metrics::CheckResult expected_check_result,
metrics::CheckReaction expected_check_reaction,
@@ -378,12 +407,32 @@
if (fail_http_response_code >= 0) {
fetcher->FailTransfer(fail_http_response_code);
}
- if (request_params)
- fake_system_state_.set_request_params(request_params);
+ // This ensures the tests didn't forget to update fake_system_state_ if they
+ // are not using the default request_params_.
+ EXPECT_EQ(&request_params_, fake_system_state_.request_params());
+
OmahaRequestAction action(&fake_system_state_,
nullptr,
base::WrapUnique(fetcher),
ping_only);
+ auto mock_policy_provider =
+ std::make_unique<NiceMock<policy::MockPolicyProvider>>();
+ EXPECT_CALL(*mock_policy_provider, IsConsumerDevice())
+ .WillRepeatedly(Return(is_consumer_device));
+
+ EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded())
+ .WillRepeatedly(Return(is_policy_loaded));
+
+ const policy::MockDevicePolicy device_policy;
+ const bool get_allowed_milestone_succeeds = rollback_allowed_milestones >= 0;
+ EXPECT_CALL(device_policy, GetRollbackAllowedMilestones(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(rollback_allowed_milestones),
+ Return(get_allowed_milestone_succeeds)));
+
+ EXPECT_CALL(*mock_policy_provider, GetDevicePolicy())
+ .WillRepeatedly(ReturnRef(device_policy));
+
+ action.policy_provider_ = std::move(mock_policy_provider);
OmahaRequestActionTestProcessorDelegate delegate;
delegate.expected_code_ = expected_code;
@@ -418,11 +467,54 @@
return collector_action.has_input_object_;
}
+bool OmahaRequestActionTest::TestUpdateCheck(
+ const string& http_response,
+ int fail_http_response_code,
+ bool ping_only,
+ ErrorCode expected_code,
+ metrics::CheckResult expected_check_result,
+ metrics::CheckReaction expected_check_reaction,
+ metrics::DownloadErrorCode expected_download_error_code,
+ OmahaResponse* out_response,
+ brillo::Blob* out_post_data) {
+ return TestUpdateCheck(http_response,
+ fail_http_response_code,
+ ping_only,
+ true, // is_consumer_device
+ 0, // rollback_allowed_milestones
+ false, // is_policy_loaded
+ expected_code,
+ expected_check_result,
+ expected_check_reaction,
+ expected_download_error_code,
+ out_response,
+ out_post_data);
+}
+
+void OmahaRequestActionTest::TestRollbackCheck(bool is_consumer_device,
+ int rollback_allowed_milestones,
+ bool is_policy_loaded) {
+ OmahaResponse response;
+ fake_update_response_.deadline = "20101020";
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ is_consumer_device,
+ rollback_allowed_milestones,
+ is_policy_loaded,
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ ASSERT_TRUE(response.update_exists);
+}
+
// Tests Event requests -- they should always succeed. |out_post_data|
// may be null; if non-null, the post-data received by the mock
// HttpFetcher is returned.
-void TestEvent(OmahaRequestParams params,
- OmahaEvent* event,
+void TestEvent(OmahaEvent* event,
const string& http_response,
brillo::Blob* out_post_data) {
brillo::FakeMessageLoop loop(nullptr);
@@ -431,7 +523,6 @@
http_response.size(),
nullptr);
FakeSystemState fake_system_state;
- fake_system_state.set_request_params(¶ms);
OmahaRequestAction action(&fake_system_state,
event,
base::WrapUnique(fetcher),
@@ -454,41 +545,36 @@
TEST_F(OmahaRequestActionTest, RejectEntities) {
OmahaResponse response;
fake_update_response_.include_entity = true;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kOmahaRequestXMLHasEntityDecl,
- metrics::CheckResult::kParsingError,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestXMLHasEntityDecl,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, NoUpdateTest) {
OmahaResponse response;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, MultiAppNoUpdateTest) {
OmahaResponse response;
fake_update_response_.multi_app_no_update = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -503,8 +589,7 @@
TEST_F(OmahaRequestActionTest, MultiAppNoPartialUpdateTest) {
OmahaResponse response;
fake_update_response_.multi_app_no_update = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -519,7 +604,6 @@
TEST_F(OmahaRequestActionTest, NoSelfUpdateTest) {
OmahaResponse response;
ASSERT_TRUE(TestUpdateCheck(
- nullptr, // request_params
"<response><app><updatecheck status=\"ok\"><manifest><actions><action "
"event=\"postinstall\" noupdate=\"true\"/></actions>"
"</manifest></updatecheck></app></response>",
@@ -539,17 +623,15 @@
TEST_F(OmahaRequestActionTest, ValidUpdateTest) {
OmahaResponse response;
fake_update_response_.deadline = "20101020";
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
EXPECT_EQ(fake_update_response_.version, response.version);
EXPECT_EQ("", response.system_version);
@@ -572,8 +654,7 @@
TEST_F(OmahaRequestActionTest, MultiPackageUpdateTest) {
OmahaResponse response;
fake_update_response_.multi_package = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -602,8 +683,7 @@
TEST_F(OmahaRequestActionTest, MultiAppUpdateTest) {
OmahaResponse response;
fake_update_response_.multi_app = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -635,8 +715,7 @@
// trigger the lining up of the app and system versions
request_params_.set_system_app_id(fake_update_response_.app_id2);
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -667,8 +746,7 @@
OmahaResponse response;
fake_update_response_.multi_app = true;
fake_update_response_.multi_app_self_update = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -696,8 +774,7 @@
OmahaResponse response;
fake_update_response_.multi_app = true;
fake_update_response_.multi_package = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -733,8 +810,7 @@
TEST_F(OmahaRequestActionTest, PowerwashTest) {
OmahaResponse response;
fake_update_response_.powerwash = true;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -789,20 +865,182 @@
EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kEthernet, _))
.WillRepeatedly(Return(false));
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kOmahaUpdateIgnoredPerPolicy,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kIgnored,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaUpdateIgnoredPerPolicy,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kIgnored,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
+TEST_F(OmahaRequestActionTest, ValidUpdateOverCellularAllowedByDevicePolicy) {
+ // This test tests that update over cellular is allowed as device policy
+ // says yes.
+ OmahaResponse response;
+ MockConnectionManager mock_cm;
+
+ fake_system_state_.set_connection_manager(&mock_cm);
+
+ EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
+ SetArgPointee<1>(ConnectionTethering::kUnknown),
+ Return(true)));
+ EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
+ .WillRepeatedly(Return(true));
+
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_TRUE(response.update_exists);
+}
+
+TEST_F(OmahaRequestActionTest, ValidUpdateOverCellularBlockedByDevicePolicy) {
+ // This test tests that update over cellular is blocked as device policy
+ // says no.
+ OmahaResponse response;
+ MockConnectionManager mock_cm;
+
+ fake_system_state_.set_connection_manager(&mock_cm);
+
+ EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
+ SetArgPointee<1>(ConnectionTethering::kUnknown),
+ Return(true)));
+ EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
+ .WillRepeatedly(Return(false));
+
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaUpdateIgnoredPerPolicy,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kIgnored,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_FALSE(response.update_exists);
+}
+
+TEST_F(OmahaRequestActionTest,
+ ValidUpdateOverCellularAllowedByUserPermissionTrue) {
+ // This test tests that, when device policy is not set, update over cellular
+ // is allowed as permission for update over cellular is set to true.
+ OmahaResponse response;
+ MockConnectionManager mock_cm;
+
+ fake_prefs_.SetBoolean(kPrefsUpdateOverCellularPermission, true);
+ fake_system_state_.set_connection_manager(&mock_cm);
+
+ EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
+ SetArgPointee<1>(ConnectionTethering::kUnknown),
+ Return(true)));
+ EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
+ .WillRepeatedly(Return(true));
+
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_TRUE(response.update_exists);
+}
+
+TEST_F(OmahaRequestActionTest,
+ ValidUpdateOverCellularBlockedByUpdateTargetNotMatch) {
+ // This test tests that, when device policy is not set and permission for
+ // update over cellular is set to false or does not exist, update over
+ // cellular is blocked as update target does not match the omaha response.
+ OmahaResponse response;
+ MockConnectionManager mock_cm;
+ // A version different from the version in omaha response.
+ string diff_version = "99.99.99";
+ // A size different from the size in omaha response.
+ int64_t diff_size = 999;
+
+ fake_prefs_.SetString(kPrefsUpdateOverCellularTargetVersion, diff_version);
+ fake_prefs_.SetInt64(kPrefsUpdateOverCellularTargetSize, diff_size);
+ // This test tests cellular (3G) being the only connection type being allowed.
+ fake_system_state_.set_connection_manager(&mock_cm);
+
+ EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
+ SetArgPointee<1>(ConnectionTethering::kUnknown),
+ Return(true)));
+ EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
+ .WillRepeatedly(Return(true));
+
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaUpdateIgnoredOverCellular,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kIgnored,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_FALSE(response.update_exists);
+}
+
+TEST_F(OmahaRequestActionTest,
+ ValidUpdateOverCellularAllowedByUpdateTargetMatch) {
+ // This test tests that, when device policy is not set and permission for
+ // update over cellular is set to false or does not exist, update over
+ // cellular is allowed as update target matches the omaha response.
+ OmahaResponse response;
+ MockConnectionManager mock_cm;
+ // A version same as the version in omaha response.
+ string new_version = fake_update_response_.version;
+ // A size same as the size in omaha response.
+ int64_t new_size = fake_update_response_.size;
+
+ fake_prefs_.SetString(kPrefsUpdateOverCellularTargetVersion, new_version);
+ fake_prefs_.SetInt64(kPrefsUpdateOverCellularTargetSize, new_size);
+ fake_system_state_.set_connection_manager(&mock_cm);
+
+ EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
+ SetArgPointee<1>(ConnectionTethering::kUnknown),
+ Return(true)));
+ EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
+ .WillRepeatedly(Return(true));
+
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_TRUE(response.update_exists);
+}
+
TEST_F(OmahaRequestActionTest, ValidUpdateBlockedByRollback) {
string rollback_version = "1234.0.0";
OmahaResponse response;
@@ -814,30 +1052,27 @@
.WillRepeatedly(Return(rollback_version));
fake_update_response_.version = rollback_version;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kOmahaUpdateIgnoredPerPolicy,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kIgnored,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaUpdateIgnoredPerPolicy,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kIgnored,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
-// Verify that update checks called during OOBE will only try to download
-// an update if the response includes a non-empty deadline field.
+// Verify that update checks called during OOBE will not try to download an
+// update if the response doesn't include the deadline field.
TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBE) {
OmahaResponse response;
+ fake_system_state_.fake_hardware()->UnsetIsOOBEComplete();
// TODO(senj): set better default value for metrics::checkresult in
// OmahaRequestAction::ActionCompleted.
- fake_system_state_.fake_hardware()->UnsetIsOOBEComplete();
- ASSERT_FALSE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kNonCriticalUpdateInOOBE,
@@ -847,11 +1082,16 @@
&response,
nullptr));
EXPECT_FALSE(response.update_exists);
+}
- // The IsOOBEComplete() value is ignored when the OOBE flow is not enabled.
+// Verify that the IsOOBEComplete() value is ignored when the OOBE flow is not
+// enabled.
+TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBEDisabled) {
+ OmahaResponse response;
+ fake_system_state_.fake_hardware()->UnsetIsOOBEComplete();
fake_system_state_.fake_hardware()->SetIsOOBEEnabled(false);
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
+
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -861,122 +1101,131 @@
&response,
nullptr));
EXPECT_TRUE(response.update_exists);
- fake_system_state_.fake_hardware()->SetIsOOBEEnabled(true);
+}
- // The payload is applied when a deadline was set in the response.
+// Verify that update checks called during OOBE will still try to download an
+// update if the response includes the deadline field.
+TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBEDeadlineSet) {
+ OmahaResponse response;
+ fake_system_state_.fake_hardware()->UnsetIsOOBEComplete();
fake_update_response_.deadline = "20101020";
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
+// Verify that update checks called during OOBE will not try to download an
+// update if a rollback happened, even when the response includes the deadline
+// field.
+TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBERollback) {
+ OmahaResponse response;
+ fake_system_state_.fake_hardware()->UnsetIsOOBEComplete();
+ fake_update_response_.deadline = "20101020";
+ EXPECT_CALL(*(fake_system_state_.mock_payload_state()), GetRollbackHappened())
+ .WillOnce(Return(true));
+
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kNonCriticalUpdateInOOBE,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
+ EXPECT_FALSE(response.update_exists);
+}
+
TEST_F(OmahaRequestActionTest, WallClockBasedWaitAloneCausesScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_update_check_count_wait_enabled(false);
- params.set_waiting_period(TimeDelta::FromDays(2));
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_update_check_count_wait_enabled(false);
+ request_params_.set_waiting_period(TimeDelta::FromDays(2));
- ASSERT_FALSE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kOmahaUpdateDeferredPerPolicy,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kDeferring,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaUpdateDeferredPerPolicy,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kDeferring,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
// Verify if we are interactive check we don't defer.
- params.set_interactive(true);
- ASSERT_TRUE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ request_params_.set_interactive(true);
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, NoWallClockBasedWaitCausesNoScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(false);
- params.set_waiting_period(TimeDelta::FromDays(2));
+ request_params_.set_wall_clock_based_wait_enabled(false);
+ request_params_.set_waiting_period(TimeDelta::FromDays(2));
+ request_params_.set_update_check_count_wait_enabled(true);
+ request_params_.set_min_update_checks_needed(1);
+ request_params_.set_max_update_checks_allowed(8);
- params.set_update_check_count_wait_enabled(true);
- params.set_min_update_checks_needed(1);
- params.set_max_update_checks_allowed(8);
-
- ASSERT_TRUE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, ZeroMaxDaysToScatterCausesNoScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta::FromDays(2));
-
- params.set_update_check_count_wait_enabled(true);
- params.set_min_update_checks_needed(1);
- params.set_max_update_checks_allowed(8);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta::FromDays(2));
+ request_params_.set_update_check_count_wait_enabled(true);
+ request_params_.set_min_update_checks_needed(1);
+ request_params_.set_max_update_checks_allowed(8);
fake_update_response_.max_days_to_scatter = "0";
- ASSERT_TRUE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, ZeroUpdateCheckCountCausesNoScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta());
-
- params.set_update_check_count_wait_enabled(true);
- params.set_min_update_checks_needed(0);
- params.set_max_update_checks_allowed(0);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta());
+ request_params_.set_update_check_count_wait_enabled(true);
+ request_params_.set_min_update_checks_needed(0);
+ request_params_.set_max_update_checks_allowed(0);
ASSERT_TRUE(TestUpdateCheck(
- ¶ms,
fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
@@ -995,16 +1244,13 @@
TEST_F(OmahaRequestActionTest, NonZeroUpdateCheckCountCausesScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta());
-
- params.set_update_check_count_wait_enabled(true);
- params.set_min_update_checks_needed(1);
- params.set_max_update_checks_allowed(8);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta());
+ request_params_.set_update_check_count_wait_enabled(true);
+ request_params_.set_min_update_checks_needed(1);
+ request_params_.set_max_update_checks_allowed(8);
ASSERT_FALSE(TestUpdateCheck(
- ¶ms,
fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
@@ -1021,35 +1267,30 @@
EXPECT_FALSE(response.update_exists);
// Verify if we are interactive check we don't defer.
- params.set_interactive(true);
- ASSERT_TRUE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ request_params_.set_interactive(true);
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, ExistingUpdateCheckCountCausesScattering) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta());
-
- params.set_update_check_count_wait_enabled(true);
- params.set_min_update_checks_needed(1);
- params.set_max_update_checks_allowed(8);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta());
+ request_params_.set_update_check_count_wait_enabled(true);
+ request_params_.set_min_update_checks_needed(1);
+ request_params_.set_max_update_checks_allowed(8);
ASSERT_TRUE(fake_prefs_.SetInt64(kPrefsUpdateCheckCount, 5));
ASSERT_FALSE(TestUpdateCheck(
- ¶ms,
fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
@@ -1068,31 +1309,27 @@
EXPECT_FALSE(response.update_exists);
// Verify if we are interactive check we don't defer.
- params.set_interactive(true);
- ASSERT_TRUE(
- TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ request_params_.set_interactive(true);
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, CohortsArePersisted) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
fake_update_response_.include_cohorts = true;
fake_update_response_.cohort = "s/154454/8479665";
fake_update_response_.cohorthint = "please-put-me-on-beta";
fake_update_response_.cohortname = "stable";
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1115,7 +1352,6 @@
TEST_F(OmahaRequestActionTest, CohortsAreUpdated) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohort, "old_value"));
EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohortHint, "old_hint"));
EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohortName, "old_name"));
@@ -1124,8 +1360,7 @@
fake_update_response_.cohorthint = "please-put-me-on-beta";
fake_update_response_.cohortname = "";
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1147,11 +1382,9 @@
TEST_F(OmahaRequestActionTest, CohortsAreNotModifiedWhenMissing) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
EXPECT_TRUE(fake_prefs_.SetString(kPrefsOmahaCohort, "old_value"));
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1171,14 +1404,12 @@
TEST_F(OmahaRequestActionTest, CohortsArePersistedWhenNoUpdate) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
fake_update_response_.include_cohorts = true;
fake_update_response_.cohort = "s/154454/8479665";
fake_update_response_.cohorthint = "please-put-me-on-beta";
fake_update_response_.cohortname = "stable";
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetNoUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1201,15 +1432,13 @@
TEST_F(OmahaRequestActionTest, MultiAppCohortTest) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
fake_update_response_.multi_app = true;
fake_update_response_.include_cohorts = true;
fake_update_response_.cohort = "s/154454/8479665";
fake_update_response_.cohorthint = "please-put-me-on-beta";
fake_update_response_.cohortname = "stable";
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1236,8 +1465,6 @@
brillo::FakeMessageLoop loop(nullptr);
loop.SetAsCurrent();
- OmahaRequestParams params = request_params_;
- fake_system_state_.set_request_params(¶ms);
OmahaRequestAction action(
&fake_system_state_,
nullptr,
@@ -1260,40 +1487,35 @@
TEST_F(OmahaRequestActionTest, InvalidXmlTest) {
OmahaResponse response;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- "invalid xml>",
- -1,
- false, // ping_only
- ErrorCode::kOmahaRequestXMLParseError,
- metrics::CheckResult::kParsingError,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestXMLParseError,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, EmptyResponseTest) {
OmahaResponse response;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- "",
- -1,
- false, // ping_only
- ErrorCode::kOmahaRequestEmptyResponseError,
- metrics::CheckResult::kParsingError,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck("",
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestEmptyResponseError,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, MissingStatusTest) {
OmahaResponse response;
ASSERT_FALSE(TestUpdateCheck(
- nullptr, // request_params
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
"<daystart elapsed_seconds=\"100\"/>"
"<app appid=\"foo\" status=\"ok\">"
@@ -1313,7 +1535,6 @@
TEST_F(OmahaRequestActionTest, InvalidStatusTest) {
OmahaResponse response;
ASSERT_FALSE(TestUpdateCheck(
- nullptr, // request_params
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
"<daystart elapsed_seconds=\"100\"/>"
"<app appid=\"foo\" status=\"ok\">"
@@ -1333,7 +1554,6 @@
TEST_F(OmahaRequestActionTest, MissingNodesetTest) {
OmahaResponse response;
ASSERT_FALSE(TestUpdateCheck(
- nullptr, // request_params
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
"<daystart elapsed_seconds=\"100\"/>"
"<app appid=\"foo\" status=\"ok\">"
@@ -1374,8 +1594,7 @@
LOG(INFO) << "Input Response = " << input_response;
OmahaResponse response;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- input_response,
+ ASSERT_TRUE(TestUpdateCheck(input_response,
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -1457,39 +1676,26 @@
brillo::Blob post_data;
// Make sure XML Encode is being called on the params
- OmahaRequestParams params(&fake_system_state_,
- constants::kOmahaPlatformName,
- OmahaRequestParams::kOsVersion,
- "testtheservice_pack>",
- "x86 generic<id",
- kTestAppId,
- "0.1.0.0",
- "en-US",
- "unittest_track<",
- "<OEM MODEL>",
- "ChromeOSFirmware.1.0",
- "EC100",
- false, // delta okay
- false, // interactive
- "http://url",
- ""); // target_version_prefix
+ request_params_.set_os_sp("testtheservice_pack>");
+ request_params_.set_os_board("x86 generic<id");
+ request_params_.set_current_channel("unittest_track<");
+ request_params_.set_target_channel("unittest_track<");
+ request_params_.set_hwid("<OEM MODEL>");
fake_prefs_.SetString(kPrefsOmahaCohort, "evil\nstring");
fake_prefs_.SetString(kPrefsOmahaCohortHint, "evil&string\\");
fake_prefs_.SetString(kPrefsOmahaCohortName,
base::JoinString(
vector<string>(100, "My spoon is too big."), " "));
OmahaResponse response;
- ASSERT_FALSE(
- TestUpdateCheck(¶ms,
- "invalid xml>",
- -1,
- false, // ping_only
- ErrorCode::kOmahaRequestXMLParseError,
- metrics::CheckResult::kParsingError,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- &response,
- &post_data));
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestXMLParseError,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ &post_data));
// convert post_data to string
string post_str(post_data.begin(), post_data.end());
EXPECT_NE(string::npos, post_str.find("testtheservice_pack>"));
@@ -1513,17 +1719,15 @@
fake_update_response_.deadline = "<20110101";
fake_update_response_.more_info_url = "testthe<url";
fake_update_response_.codebase = "testthe&codebase/";
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_EQ("testthe<url", response.more_info_url);
EXPECT_EQ("testthe&codebase/file.signed",
@@ -1535,17 +1739,15 @@
OmahaResponse response;
// overflows int32_t:
fake_update_response_.size = 123123123123123ull;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_EQ(fake_update_response_.size, response.packages[0].size);
}
@@ -1560,8 +1762,7 @@
// An existing but empty previous version means that we didn't reboot to a new
// update, therefore, no need to update the previous version.
EXPECT_CALL(prefs, SetString(kPrefsPreviousVersion, _)).Times(0);
- ASSERT_FALSE(TestUpdateCheck(nullptr, // request_params
- "invalid xml>",
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -1572,9 +1773,9 @@
&post_data));
// convert post_data to string
string post_str(post_data.begin(), post_data.end());
- EXPECT_NE(post_str.find(
- " <ping active=\"1\" a=\"-1\" r=\"-1\"></ping>\n"
- " <updatecheck targetversionprefix=\"\"></updatecheck>\n"),
+ EXPECT_NE(
+ post_str.find(" <ping active=\"1\" a=\"-1\" r=\"-1\"></ping>\n"
+ " <updatecheck></updatecheck>\n"),
string::npos);
EXPECT_NE(post_str.find("hardware_class=\"OEM MODEL 09235 7471\""),
string::npos);
@@ -1589,8 +1790,7 @@
TEST_F(OmahaRequestActionTest, FormatSuccessEventOutputTest) {
brillo::Blob post_data;
- TestEvent(request_params_,
- new OmahaEvent(OmahaEvent::kTypeUpdateDownloadStarted),
+ TestEvent(new OmahaEvent(OmahaEvent::kTypeUpdateDownloadStarted),
"invalid xml>",
&post_data);
// convert post_data to string
@@ -1606,8 +1806,7 @@
TEST_F(OmahaRequestActionTest, FormatErrorEventOutputTest) {
brillo::Blob post_data;
- TestEvent(request_params_,
- new OmahaEvent(OmahaEvent::kTypeDownloadComplete,
+ TestEvent(new OmahaEvent(OmahaEvent::kTypeDownloadComplete,
OmahaEvent::kResultError,
ErrorCode::kError),
"invalid xml>",
@@ -1626,9 +1825,6 @@
TEST_F(OmahaRequestActionTest, IsEventTest) {
string http_response("doesn't matter");
- // Create a copy of the OmahaRequestParams to reuse it later.
- OmahaRequestParams params = request_params_;
- fake_system_state_.set_request_params(¶ms);
OmahaRequestAction update_check_action(
&fake_system_state_,
nullptr,
@@ -1638,8 +1834,6 @@
false);
EXPECT_FALSE(update_check_action.IsEvent());
- params = request_params_;
- fake_system_state_.set_request_params(¶ms);
OmahaRequestAction event_action(
&fake_system_state_,
new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
@@ -1655,24 +1849,10 @@
bool delta_okay = i == 1;
const char* delta_okay_str = delta_okay ? "true" : "false";
brillo::Blob post_data;
- OmahaRequestParams params(&fake_system_state_,
- constants::kOmahaPlatformName,
- OmahaRequestParams::kOsVersion,
- "service_pack",
- "x86-generic",
- kTestAppId,
- "0.1.0.0",
- "en-US",
- "unittest_track",
- "OEM MODEL REV 1234",
- "ChromeOSFirmware.1.0",
- "EC100",
- delta_okay,
- false, // interactive
- "http://url",
- ""); // target_version_prefix
- ASSERT_FALSE(TestUpdateCheck(¶ms,
- "invalid xml>",
+
+ request_params_.set_delta_okay(delta_okay);
+
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -1696,24 +1876,10 @@
const char* interactive_str = interactive ? "ondemandupdate" : "scheduler";
brillo::Blob post_data;
FakeSystemState fake_system_state;
- OmahaRequestParams params(&fake_system_state_,
- constants::kOmahaPlatformName,
- OmahaRequestParams::kOsVersion,
- "service_pack",
- "x86-generic",
- kTestAppId,
- "0.1.0.0",
- "en-US",
- "unittest_track",
- "OEM MODEL REV 1234",
- "ChromeOSFirmware.1.0",
- "EC100",
- true, // delta_okay
- interactive,
- "http://url",
- ""); // target_version_prefix
- ASSERT_FALSE(TestUpdateCheck(¶ms,
- "invalid xml>",
+
+ request_params_.set_interactive(interactive);
+
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -1724,13 +1890,75 @@
&post_data));
// convert post_data to string
string post_str(post_data.begin(), post_data.end());
- EXPECT_NE(post_str.find(base::StringPrintf("installsource=\"%s\"",
- interactive_str)),
+ EXPECT_NE(post_str.find(
+ base::StringPrintf("installsource=\"%s\"", interactive_str)),
string::npos)
<< "i = " << i;
}
}
+TEST_F(OmahaRequestActionTest, FormatTargetVersionPrefixOutputTest) {
+ for (int i = 0; i < 2; i++) {
+ bool target_version_set = i == 1;
+ const char* target_version_prefix = target_version_set ? "10032." : "";
+ brillo::Blob post_data;
+ FakeSystemState fake_system_state;
+
+ request_params_.set_target_version_prefix(target_version_prefix);
+
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestXMLParseError,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
+ // convert post_data to string
+ string post_str(post_data.begin(), post_data.end());
+ if (target_version_set) {
+ EXPECT_NE(post_str.find("<updatecheck targetversionprefix=\"10032.\">"),
+ string::npos)
+ << "i = " << i;
+ } else {
+ EXPECT_EQ(post_str.find("targetversionprefix"), string::npos)
+ << "i = " << i;
+ }
+ }
+}
+
+TEST_F(OmahaRequestActionTest, FormatRollbackAllowedOutputTest) {
+ for (int i = 0; i < 4; i++) {
+ bool rollback_allowed = i / 2 == 0;
+ bool target_version_set = i % 2 == 0;
+ brillo::Blob post_data;
+ FakeSystemState fake_system_state;
+
+ request_params_.set_target_version_prefix(target_version_set ? "10032."
+ : "");
+ request_params_.set_rollback_allowed(rollback_allowed);
+
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
+ -1,
+ false, // ping_only
+ ErrorCode::kOmahaRequestXMLParseError,
+ metrics::CheckResult::kParsingError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
+ // convert post_data to string
+ string post_str(post_data.begin(), post_data.end());
+ if (rollback_allowed && target_version_set) {
+ EXPECT_NE(post_str.find("rollback_allowed=\"true\""), string::npos)
+ << "i = " << i;
+ } else {
+ EXPECT_EQ(post_str.find("rollback_allowed"), string::npos) << "i = " << i;
+ }
+ }
+}
+
TEST_F(OmahaRequestActionTest, OmahaEventTest) {
OmahaEvent default_event;
EXPECT_EQ(OmahaEvent::kTypeUnknown, default_event.type);
@@ -1768,8 +1996,7 @@
EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
.WillOnce(DoAll(SetArgPointee<1>(five_days_ago), Return(true)));
brillo::Blob post_data;
- ASSERT_TRUE(TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
-1,
ping_only,
ErrorCode::kSuccess,
@@ -1814,17 +2041,15 @@
EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
.WillOnce(DoAll(SetArgPointee<1>(now), Return(true)));
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
string post_str(post_data.begin(), post_data.end());
EXPECT_NE(post_str.find("<ping active=\"1\" a=\"3\"></ping>"),
string::npos);
@@ -1846,17 +2071,15 @@
EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
.WillOnce(DoAll(SetArgPointee<1>(four_days_ago), Return(true)));
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
string post_str(post_data.begin(), post_data.end());
EXPECT_NE(post_str.find("<ping active=\"1\" r=\"4\"></ping>\n"),
string::npos);
@@ -1883,17 +2106,15 @@
EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _))
.WillOnce(Return(true));
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
string post_str(post_data.begin(), post_data.end());
EXPECT_EQ(post_str.find("ping"), string::npos);
}
@@ -1910,17 +2131,15 @@
EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
brillo::Blob post_data;
- EXPECT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- true, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUnset,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ EXPECT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ true, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUnset,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
EXPECT_EQ(0U, post_data.size());
}
@@ -1944,8 +2163,7 @@
.WillOnce(Return(true));
brillo::Blob post_data;
ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ TestUpdateCheck("<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
"protocol=\"3.0\"><daystart elapsed_seconds=\"100\"/>"
"<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
"<updatecheck status=\"noupdate\"/></app></response>",
@@ -1981,8 +2199,7 @@
AllOf(Ge(midnight), Le(midnight_slack))))
.WillOnce(Return(true));
ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ TestUpdateCheck("<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
"protocol=\"3.0\"><daystart elapsed_seconds=\"200\"/>"
"<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
"<updatecheck status=\"noupdate\"/></app></response>",
@@ -2004,8 +2221,7 @@
EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ TestUpdateCheck("<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
"protocol=\"3.0\"><daystart blah=\"200\"/>"
"<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
"<updatecheck status=\"noupdate\"/></app></response>",
@@ -2027,8 +2243,7 @@
EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ TestUpdateCheck("<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
"protocol=\"3.0\"><daystart elapsed_seconds=\"x\"/>"
"<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
"<updatecheck status=\"noupdate\"/></app></response>",
@@ -2046,8 +2261,7 @@
// Test that the "eol" flags is only parsed from the "_eol" attribute and not
// the "eol" attribute.
ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ TestUpdateCheck("<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
"protocol=\"3.0\"><app appid=\"foo\" status=\"ok\">"
"<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
"_eol=\"security-only\" eol=\"eol\" _foo=\"bar\"/>"
@@ -2070,8 +2284,7 @@
TEST_F(OmahaRequestActionTest, NoUniqueIDTest) {
brillo::Blob post_data;
- ASSERT_FALSE(TestUpdateCheck(nullptr, // request_params
- "invalid xml>",
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -2090,17 +2303,15 @@
OmahaResponse response;
const int http_error_code =
static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + 501;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- "",
- 501,
- false, // ping_only
- static_cast<ErrorCode>(http_error_code),
- metrics::CheckResult::kDownloadError,
- metrics::CheckReaction::kUnset,
- static_cast<metrics::DownloadErrorCode>(501),
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck("",
+ 501,
+ false, // ping_only
+ static_cast<ErrorCode>(http_error_code),
+ metrics::CheckResult::kDownloadError,
+ metrics::CheckReaction::kUnset,
+ static_cast<metrics::DownloadErrorCode>(501),
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
@@ -2108,32 +2319,28 @@
OmahaResponse response;
const int http_error_code =
static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + 999;
- ASSERT_FALSE(
- TestUpdateCheck(nullptr, // request_params
- "",
- 1500,
- false, // ping_only
- static_cast<ErrorCode>(http_error_code),
- metrics::CheckResult::kDownloadError,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kHttpStatusOther,
- &response,
- nullptr));
+ ASSERT_FALSE(TestUpdateCheck("",
+ 1500,
+ false, // ping_only
+ static_cast<ErrorCode>(http_error_code),
+ metrics::CheckResult::kDownloadError,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kHttpStatusOther,
+ &response,
+ nullptr));
EXPECT_FALSE(response.update_exists);
}
TEST_F(OmahaRequestActionTest, TestUpdateFirstSeenAtGetsPersistedFirstTime) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta().FromDays(1));
- params.set_update_check_count_wait_enabled(false);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta().FromDays(1));
+ request_params_.set_update_check_count_wait_enabled(false);
Time arbitrary_date;
ASSERT_TRUE(Time::FromString("6/4/1989", &arbitrary_date));
fake_system_state_.fake_clock()->SetWallclockTime(arbitrary_date);
- ASSERT_FALSE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_FALSE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kOmahaUpdateDeferredPerPolicy,
@@ -2149,9 +2356,8 @@
EXPECT_FALSE(response.update_exists);
// Verify if we are interactive check we don't defer.
- params.set_interactive(true);
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ request_params_.set_interactive(true);
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -2165,10 +2371,9 @@
TEST_F(OmahaRequestActionTest, TestUpdateFirstSeenAtGetsUsedIfAlreadyPresent) {
OmahaResponse response;
- OmahaRequestParams params = request_params_;
- params.set_wall_clock_based_wait_enabled(true);
- params.set_waiting_period(TimeDelta().FromDays(1));
- params.set_update_check_count_wait_enabled(false);
+ request_params_.set_wall_clock_based_wait_enabled(true);
+ request_params_.set_waiting_period(TimeDelta().FromDays(1));
+ request_params_.set_update_check_count_wait_enabled(false);
Time t1, t2;
ASSERT_TRUE(Time::FromString("1/1/2012", &t1));
@@ -2176,8 +2381,7 @@
ASSERT_TRUE(
fake_prefs_.SetInt64(kPrefsUpdateFirstSeenAt, t1.ToInternalValue()));
fake_system_state_.fake_clock()->SetWallclockTime(t2);
- ASSERT_TRUE(TestUpdateCheck(¶ms,
- fake_update_response_.GetUpdateResponse(),
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
-1,
false, // ping_only
ErrorCode::kSuccess,
@@ -2201,17 +2405,16 @@
ASSERT_TRUE(tempdir.CreateUniqueTempDir());
brillo::Blob post_data;
- OmahaRequestParams params(&fake_system_state_);
- params.set_root(tempdir.GetPath().value());
- params.set_app_id("{22222222-2222-2222-2222-222222222222}");
- params.set_app_version("1.2.3.4");
- params.set_product_components("o.bundle=1");
- params.set_current_channel("canary-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- EXPECT_TRUE(params.ShouldPowerwash());
- ASSERT_FALSE(TestUpdateCheck(¶ms,
- "invalid xml>",
+ request_params_.set_root(tempdir.GetPath().value());
+ request_params_.set_app_id("{22222222-2222-2222-2222-222222222222}");
+ request_params_.set_app_version("1.2.3.4");
+ request_params_.set_product_components("o.bundle=1");
+ request_params_.set_current_channel("canary-channel");
+ EXPECT_TRUE(
+ request_params_.SetTargetChannel("stable-channel", true, nullptr));
+ request_params_.UpdateDownloadChannel();
+ EXPECT_TRUE(request_params_.ShouldPowerwash());
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -2235,17 +2438,16 @@
ASSERT_TRUE(tempdir.CreateUniqueTempDir());
brillo::Blob post_data;
- OmahaRequestParams params(&fake_system_state_);
- params.set_root(tempdir.GetPath().value());
- params.set_app_id("{11111111-1111-1111-1111-111111111111}");
- params.set_app_version("5.6.7.8");
- params.set_product_components("o.bundle=1");
- params.set_current_channel("stable-channel");
- EXPECT_TRUE(params.SetTargetChannel("canary-channel", false, nullptr));
- params.UpdateDownloadChannel();
- EXPECT_FALSE(params.ShouldPowerwash());
- ASSERT_FALSE(TestUpdateCheck(¶ms,
- "invalid xml>",
+ request_params_.set_root(tempdir.GetPath().value());
+ request_params_.set_app_id("{11111111-1111-1111-1111-111111111111}");
+ request_params_.set_app_version("5.6.7.8");
+ request_params_.set_product_components("o.bundle=1");
+ request_params_.set_current_channel("stable-channel");
+ EXPECT_TRUE(
+ request_params_.SetTargetChannel("canary-channel", false, nullptr));
+ request_params_.UpdateDownloadChannel();
+ EXPECT_FALSE(request_params_.ShouldPowerwash());
+ ASSERT_FALSE(TestUpdateCheck("invalid xml>",
-1,
false, // ping_only
ErrorCode::kOmahaRequestXMLParseError,
@@ -2273,17 +2475,15 @@
fake_system_state_.fake_hardware()->SetPowerwashCount(1);
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
// We shouldn't send a ping in this case since powerwash > 0.
string post_str(post_data.begin(), post_data.end());
EXPECT_EQ(string::npos, post_str.find("<ping"));
@@ -2301,17 +2501,15 @@
fake_system_state_.fake_hardware()->SetFirstActiveOmahaPingSent();
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
// We shouldn't send a ping in this case since
// first_active_omaha_ping_sent=true
string post_str(post_data.begin(), post_data.end());
@@ -2324,17 +2522,15 @@
fake_prefs_.SetString(kPrefsPreviousVersion, "1.2.3.4");
brillo::Blob post_data;
- ASSERT_TRUE(
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetNoUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kNoUpdateAvailable,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset,
- nullptr,
- &post_data));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetNoUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kNoUpdateAvailable,
+ metrics::CheckReaction::kUnset,
+ metrics::DownloadErrorCode::kUnset,
+ nullptr,
+ &post_data));
string post_str(post_data.begin(), post_data.end());
// An event 54 is included and has the right version.
@@ -2364,7 +2560,6 @@
bool expected_allow_p2p_for_sharing,
const string& expected_p2p_url) {
OmahaResponse response;
- OmahaRequestParams request_params = request_params_;
bool actual_allow_p2p_for_downloading = initial_allow_p2p_for_downloading;
bool actual_allow_p2p_for_sharing = initial_allow_p2p_for_sharing;
string actual_p2p_url;
@@ -2395,17 +2590,15 @@
fake_update_response_.disable_p2p_for_downloading =
omaha_disable_p2p_for_downloading;
fake_update_response_.disable_p2p_for_sharing = omaha_disable_p2p_for_sharing;
- ASSERT_TRUE(
- TestUpdateCheck(&request_params,
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- &response,
- nullptr));
+ ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ &response,
+ nullptr));
EXPECT_TRUE(response.update_exists);
EXPECT_EQ(omaha_disable_p2p_for_downloading,
@@ -2500,17 +2693,15 @@
bool OmahaRequestActionTest::InstallDateParseHelper(const string &elapsed_days,
OmahaResponse *response) {
fake_update_response_.elapsed_days = elapsed_days;
- return
- TestUpdateCheck(nullptr, // request_params
- fake_update_response_.GetUpdateResponse(),
- -1,
- false, // ping_only
- ErrorCode::kSuccess,
- metrics::CheckResult::kUpdateAvailable,
- metrics::CheckReaction::kUpdating,
- metrics::DownloadErrorCode::kUnset,
- response,
- nullptr);
+ return TestUpdateCheck(fake_update_response_.GetUpdateResponse(),
+ -1,
+ false, // ping_only
+ ErrorCode::kSuccess,
+ metrics::CheckResult::kUpdateAvailable,
+ metrics::CheckReaction::kUpdating,
+ metrics::DownloadErrorCode::kUnset,
+ response,
+ nullptr);
}
TEST_F(OmahaRequestActionTest, ParseInstallDateFromResponse) {
@@ -2612,4 +2803,128 @@
EXPECT_EQ(prefs_days, 28);
}
+// Verifies that a device with no device policy, and is not a consumer
+// device sets the max kernel key version to the current version.
+// ie. the same behavior as if rollback is enabled.
+TEST_F(OmahaRequestActionTest, NoPolicyEnterpriseDevicesSetMaxRollback) {
+ FakeHardware* fake_hw = fake_system_state_.fake_hardware();
+
+ // Setup and verify some initial default values for the kernel TPM
+ // values that control verified boot and rollback.
+ const int min_kernel_version = 4;
+ fake_hw->SetMinKernelKeyVersion(min_kernel_version);
+ fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+
+ EXPECT_CALL(
+ *fake_system_state_.mock_metrics_reporter(),
+ ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
+ .Times(1);
+
+ TestRollbackCheck(false /* is_consumer_device */,
+ 3 /* rollback_allowed_milestones */,
+ false /* is_policy_loaded */);
+
+ // Verify kernel_max_rollforward was set to the current minimum
+ // kernel key version. This has the effect of freezing roll
+ // forwards indefinitely. This will hold the rollback window
+ // open until a future change will be able to move this forward
+ // relative the configured window.
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward());
+}
+
+// Verifies that a conmsumer device with no device policy sets the
+// max kernel key version to the current version. ie. the same
+// behavior as if rollback is enabled.
+TEST_F(OmahaRequestActionTest, NoPolicyConsumerDevicesSetMaxRollback) {
+ FakeHardware* fake_hw = fake_system_state_.fake_hardware();
+
+ // Setup and verify some initial default values for the kernel TPM
+ // values that control verified boot and rollback.
+ const int min_kernel_version = 3;
+ fake_hw->SetMinKernelKeyVersion(min_kernel_version);
+ fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+
+ EXPECT_CALL(
+ *fake_system_state_.mock_metrics_reporter(),
+ ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
+ .Times(1);
+
+ TestRollbackCheck(true /* is_consumer_device */,
+ 3 /* rollback_allowed_milestones */,
+ false /* is_policy_loaded */);
+
+ // Verify that with rollback disabled that kernel_max_rollforward
+ // was set to logical infinity. This is the expected behavior for
+ // consumer devices and matches the existing behavior prior to the
+ // rollback features.
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+}
+
+// Verifies that a device with rollback enabled sets kernel_max_rollforward
+// in the TPM to prevent roll forward.
+TEST_F(OmahaRequestActionTest, RollbackEnabledDevicesSetMaxRollback) {
+ FakeHardware* fake_hw = fake_system_state_.fake_hardware();
+
+ // Setup and verify some initial default values for the kernel TPM
+ // values that control verified boot and rollback.
+ const int allowed_milestones = 4;
+ const int min_kernel_version = 3;
+ fake_hw->SetMinKernelKeyVersion(min_kernel_version);
+ fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+
+ EXPECT_CALL(
+ *fake_system_state_.mock_metrics_reporter(),
+ ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
+ .Times(1);
+
+ TestRollbackCheck(false /* is_consumer_device */,
+ allowed_milestones,
+ true /* is_policy_loaded */);
+
+ // Verify that with rollback enabled that kernel_max_rollforward
+ // was set to the current minimum kernel key version. This has
+ // the effect of freezing roll forwards indefinitely. This will
+ // hold the rollback window open until a future change will
+ // be able to move this forward relative the configured window.
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward());
+}
+
+// Verifies that a device with rollback disabled sets kernel_max_rollforward
+// in the TPM to logical infinity, to allow roll forward.
+TEST_F(OmahaRequestActionTest, RollbackDisabledDevicesSetMaxRollback) {
+ FakeHardware* fake_hw = fake_system_state_.fake_hardware();
+
+ // Setup and verify some initial default values for the kernel TPM
+ // values that control verified boot and rollback.
+ const int allowed_milestones = 0;
+ const int min_kernel_version = 3;
+ fake_hw->SetMinKernelKeyVersion(min_kernel_version);
+ fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+
+ EXPECT_CALL(
+ *fake_system_state_.mock_metrics_reporter(),
+ ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
+ .Times(1);
+
+ TestRollbackCheck(false /* is_consumer_device */,
+ allowed_milestones,
+ true /* is_policy_loaded */);
+
+ // Verify that with rollback disabled that kernel_max_rollforward
+ // was set to logical infinity.
+ EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
+ EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
+}
+
} // namespace chromeos_update_engine
diff --git a/omaha_request_params.h b/omaha_request_params.h
index 60619f9..62cbdab 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -49,52 +49,12 @@
os_version_(kOsVersion),
delta_okay_(true),
interactive_(false),
+ rollback_allowed_(false),
wall_clock_based_wait_enabled_(false),
update_check_count_wait_enabled_(false),
min_update_checks_needed_(kDefaultMinUpdateChecks),
max_update_checks_allowed_(kDefaultMaxUpdateChecks) {}
- OmahaRequestParams(SystemState* system_state,
- const std::string& in_os_platform,
- const std::string& in_os_version,
- const std::string& in_os_sp,
- const std::string& in_os_board,
- const std::string& in_app_id,
- const std::string& in_app_version,
- const std::string& in_app_lang,
- const std::string& in_target_channel,
- const std::string& in_hwid,
- const std::string& in_fw_version,
- const std::string& in_ec_version,
- bool in_delta_okay,
- bool in_interactive,
- const std::string& in_update_url,
- const std::string& in_target_version_prefix)
- : system_state_(system_state),
- os_platform_(in_os_platform),
- os_version_(in_os_version),
- os_sp_(in_os_sp),
- app_lang_(in_app_lang),
- hwid_(in_hwid),
- fw_version_(in_fw_version),
- ec_version_(in_ec_version),
- delta_okay_(in_delta_okay),
- interactive_(in_interactive),
- update_url_(in_update_url),
- target_version_prefix_(in_target_version_prefix),
- wall_clock_based_wait_enabled_(false),
- update_check_count_wait_enabled_(false),
- min_update_checks_needed_(kDefaultMinUpdateChecks),
- max_update_checks_allowed_(kDefaultMaxUpdateChecks) {
- image_props_.board = in_os_board;
- image_props_.product_id = in_app_id;
- image_props_.canary_product_id = in_app_id;
- image_props_.version = in_app_version;
- image_props_.current_channel = in_target_channel;
- mutable_image_props_.target_channel = in_target_channel;
- mutable_image_props_.is_powerwash_allowed = false;
- }
-
virtual ~OmahaRequestParams();
// Setters and getters for the various properties.
@@ -164,6 +124,12 @@
return target_version_prefix_;
}
+ inline void set_rollback_allowed(bool rollback_allowed) {
+ rollback_allowed_ = rollback_allowed;
+ }
+
+ inline bool rollback_allowed() const { return rollback_allowed_; }
+
inline void set_wall_clock_based_wait_enabled(bool enabled) {
wall_clock_based_wait_enabled_ = enabled;
}
@@ -204,7 +170,6 @@
// Suggested defaults
static const char kOsVersion[];
- static const char kIsPowerwashAllowedKey[];
static const int64_t kDefaultMinUpdateChecks = 0;
static const int64_t kDefaultMaxUpdateChecks = 8;
@@ -249,6 +214,21 @@
void set_target_channel(const std::string& channel) {
mutable_image_props_.target_channel = channel;
}
+ void set_os_sp(const std::string& os_sp) { os_sp_ = os_sp; }
+ void set_os_board(const std::string& os_board) {
+ image_props_.board = os_board;
+ }
+ void set_app_lang(const std::string& app_lang) { app_lang_ = app_lang; }
+ void set_hwid(const std::string& hwid) { hwid_ = hwid; }
+ void set_fw_version(const std::string& fw_version) {
+ fw_version_ = fw_version;
+ }
+ void set_ec_version(const std::string& ec_version) {
+ ec_version_ = ec_version;
+ }
+ void set_is_powerwash_allowed(bool powerwash_allowed) {
+ mutable_image_props_.is_powerwash_allowed = powerwash_allowed;
+ }
private:
FRIEND_TEST(OmahaRequestParamsTest, ChannelIndexTest);
@@ -279,15 +259,6 @@
// Compares hwid to a set of whitelisted prefixes.
bool CollectECFWVersions() const;
- // These are individual helper methods to initialize the said properties from
- // the LSB value.
- void SetTargetChannelFromLsbValue();
- void SetCurrentChannelFromLsbValue();
- void SetIsPowerwashAllowedFromLsbValue();
-
- // Initializes the required properties from the LSB value.
- void InitFromLsbValue();
-
// Gets the machine type (e.g. "i686").
std::string GetMachineType() const;
@@ -337,6 +308,9 @@
// to be pinned to. It's empty otherwise.
std::string target_version_prefix_;
+ // Whether the client is accepting rollback images too.
+ bool rollback_allowed_;
+
// True if scattering is enabled, in which case waiting_period_ specifies the
// amount of absolute time that we've to wait for before sending a request to
// Omaha.
@@ -354,9 +328,7 @@
// When reading files, prepend root_ to the paths. Useful for testing.
std::string root_;
- // TODO(jaysri): Uncomment this after fixing unit tests, as part of
- // chromium-os:39752
- // DISALLOW_COPY_AND_ASSIGN(OmahaRequestParams);
+ DISALLOW_COPY_AND_ASSIGN(OmahaRequestParams);
};
} // namespace chromeos_update_engine
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index ce77f31..ae9db47 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -44,9 +44,6 @@
void SetUp() override {
// Create a uniquely named test directory.
ASSERT_TRUE(tempdir_.CreateUniqueTempDir());
- // Create a fresh copy of the params for each test, so there's no
- // unintended reuse of state across tests.
- params_ = OmahaRequestParams(&fake_system_state_);
params_.set_root(tempdir_.GetPath().value());
SetLockDown(false);
fake_system_state_.set_prefs(&fake_prefs_);
@@ -57,8 +54,8 @@
fake_system_state_.fake_hardware()->SetIsNormalBootMode(locked_down);
}
- OmahaRequestParams params_;
FakeSystemState fake_system_state_;
+ OmahaRequestParams params_{&fake_system_state_};
FakePrefs fake_prefs_;
base::ScopedTempDir tempdir_;
diff --git a/omaha_response.h b/omaha_response.h
index 3fb2f6d..ef69de2 100644
--- a/omaha_response.h
+++ b/omaha_response.h
@@ -83,6 +83,15 @@
// PST, according to the Omaha Server's clock and timezone (PST8PDT,
// aka "Pacific Time".)
int install_date_days = -1;
+
+ // True if the returned image is a rollback for the device.
+ bool is_rollback = false;
+ // Kernel version of the returned rollback image. 0 if the image is not a
+ // rollback.
+ uint32_t kernel_version = 0;
+ // Firmware version of the returned rollback image. 0 if the image is not a
+ // rollback.
+ uint32_t firmware_version = 0;
};
static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index 5a1d7b1..775c0a8 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -138,6 +138,26 @@
system_state_->prefs()->SetString(current_channel_key,
params->download_channel());
+ // Checking whether device is able to boot up the returned rollback image.
+ if (response.is_rollback) {
+ if (!params->rollback_allowed()) {
+ LOG(ERROR) << "Received rollback image but rollback is not allowed.";
+ completer.set_code(ErrorCode::kOmahaResponseInvalid);
+ return;
+ }
+ auto min_kernel_key_version = static_cast<uint32_t>(
+ system_state_->hardware()->GetMinKernelKeyVersion());
+ auto min_firmware_key_version = static_cast<uint32_t>(
+ system_state_->hardware()->GetMinFirmwareKeyVersion());
+ if (response.kernel_version < min_kernel_key_version ||
+ response.firmware_version < min_firmware_key_version) {
+ LOG(ERROR) << "Device won't be able to boot up the rollback image.";
+ completer.set_code(ErrorCode::kRollbackNotPossible);
+ return;
+ }
+ install_plan_.is_rollback = true;
+ }
+
if (response.powerwash_required || params->ShouldPowerwash())
install_plan_.powerwash_required = true;
@@ -155,9 +175,16 @@
// method and UpdateStatus signal. A potential issue is that update_engine may
// be unresponsive during an update download.
if (!deadline_file_.empty()) {
- utils::WriteFile(deadline_file_.c_str(),
- response.deadline.data(),
- response.deadline.size());
+ if (payload_state->GetRollbackHappened()) {
+ // Don't do forced update if rollback has happened since the last update
+ // check where policy was present.
+ LOG(INFO) << "Not forcing update because a rollback happened.";
+ utils::WriteFile(deadline_file_.c_str(), nullptr, 0);
+ } else {
+ utils::WriteFile(deadline_file_.c_str(),
+ response.deadline.data(),
+ response.deadline.size());
+ }
chmod(deadline_file_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
diff --git a/omaha_response_handler_action.h b/omaha_response_handler_action.h
index 63c7b2d..0a001b8 100644
--- a/omaha_response_handler_action.h
+++ b/omaha_response_handler_action.h
@@ -85,6 +85,12 @@
friend class OmahaResponseHandlerActionTest;
FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
+ FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
+ FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedRollback);
FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
DISALLOW_COPY_AND_ASSIGN(OmahaResponseHandlerAction);
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 9e2cdd1..55c642b 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -223,6 +223,34 @@
in.deadline = "some-deadline";
InstallPlan install_plan;
fake_system_state_.fake_boot_control()->SetCurrentSlot(0);
+ // Because rollback happened, the deadline shouldn't be written into the
+ // file.
+ EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
+ GetRollbackHappened())
+ .WillOnce(Return(true));
+ EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
+ EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
+ EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
+ EXPECT_EQ(1U, install_plan.target_slot);
+ string deadline;
+ EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
+ EXPECT_TRUE(deadline.empty());
+ EXPECT_EQ(in.version, install_plan.version);
+ }
+ {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.version = "a.b.c.d";
+ in.packages.push_back(
+ {.payload_urls = {kLongName}, .size = 12, .hash = kPayloadHashHex});
+ in.more_info_url = "http://more/info";
+ in.prompt = true;
+ in.deadline = "some-deadline";
+ InstallPlan install_plan;
+ fake_system_state_.fake_boot_control()->SetCurrentSlot(0);
+ EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
+ GetRollbackHappened())
+ .WillOnce(Return(false));
EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
@@ -467,6 +495,103 @@
EXPECT_TRUE(install_plan.hash_checks_mandatory);
}
+TEST_F(OmahaResponseHandlerActionTest, RollbackTest) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.packages.push_back({.payload_urls = {"https://RollbackTest"},
+ .size = 1,
+ .hash = kPayloadHashHex});
+ in.is_rollback = true;
+ in.kernel_version = 0x00010002;
+ in.firmware_version = 0x00030004;
+
+ fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
+ fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
+
+ OmahaRequestParams params(&fake_system_state_);
+ params.set_rollback_allowed(true);
+
+ fake_system_state_.set_request_params(¶ms);
+ InstallPlan install_plan;
+ EXPECT_TRUE(DoTest(in, "", &install_plan));
+ EXPECT_TRUE(install_plan.is_rollback);
+}
+
+TEST_F(OmahaResponseHandlerActionTest, RollbackKernelVersionErrorTest) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.packages.push_back({.payload_urls = {"https://RollbackTest"},
+ .size = 1,
+ .hash = kPayloadHashHex});
+ in.is_rollback = true;
+ in.kernel_version = 0x00010001; // This is lower than the minimum.
+ in.firmware_version = 0x00030004;
+
+ fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
+ fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
+
+ OmahaRequestParams params(&fake_system_state_);
+ params.set_rollback_allowed(true);
+
+ fake_system_state_.set_request_params(¶ms);
+ InstallPlan install_plan;
+ EXPECT_FALSE(DoTest(in, "", &install_plan));
+}
+
+TEST_F(OmahaResponseHandlerActionTest, RollbackFirmwareVersionErrorTest) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.packages.push_back({.payload_urls = {"https://RollbackTest"},
+ .size = 1,
+ .hash = kPayloadHashHex});
+ in.is_rollback = true;
+ in.kernel_version = 0x00010002;
+ in.firmware_version = 0x00030003; // This is lower than the minimum.
+
+ fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
+ fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
+
+ OmahaRequestParams params(&fake_system_state_);
+ params.set_rollback_allowed(true);
+
+ fake_system_state_.set_request_params(¶ms);
+ InstallPlan install_plan;
+ EXPECT_FALSE(DoTest(in, "", &install_plan));
+}
+
+TEST_F(OmahaResponseHandlerActionTest, RollbackNotRollbackTest) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.packages.push_back({.payload_urls = {"https://RollbackTest"},
+ .size = 1,
+ .hash = kPayloadHashHex});
+ in.is_rollback = false;
+
+ OmahaRequestParams params(&fake_system_state_);
+ params.set_rollback_allowed(true);
+
+ fake_system_state_.set_request_params(¶ms);
+ InstallPlan install_plan;
+ EXPECT_TRUE(DoTest(in, "", &install_plan));
+ EXPECT_FALSE(install_plan.is_rollback);
+}
+
+TEST_F(OmahaResponseHandlerActionTest, RollbackNotAllowedTest) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.packages.push_back({.payload_urls = {"https://RollbackTest"},
+ .size = 1,
+ .hash = kPayloadHashHex});
+ in.is_rollback = true;
+
+ OmahaRequestParams params(&fake_system_state_);
+ params.set_rollback_allowed(false);
+
+ fake_system_state_.set_request_params(¶ms);
+ InstallPlan install_plan;
+ EXPECT_FALSE(DoTest(in, "", &install_plan));
+}
+
TEST_F(OmahaResponseHandlerActionTest, SystemVersionTest) {
OmahaResponse in;
in.update_exists = true;
diff --git a/payload_consumer/download_action_unittest.cc b/payload_consumer/download_action_unittest.cc
index 5dac550..a3ad5b9 100644
--- a/payload_consumer/download_action_unittest.cc
+++ b/payload_consumer/download_action_unittest.cc
@@ -29,6 +29,7 @@
#include <base/files/file_util.h>
#include <base/location.h>
#include <base/strings/stringprintf.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
#include <brillo/message_loops/message_loop.h>
diff --git a/payload_consumer/filesystem_verifier_action_unittest.cc b/payload_consumer/filesystem_verifier_action_unittest.cc
index b4f7f7f..2e1d95d 100644
--- a/payload_consumer/filesystem_verifier_action_unittest.cc
+++ b/payload_consumer/filesystem_verifier_action_unittest.cc
@@ -26,6 +26,7 @@
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gmock/gmock.h>
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index 5cdfbc1..929cad3 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -127,6 +127,9 @@
// False otherwise.
bool run_post_install{true};
+ // True if this update is a rollback.
+ bool is_rollback{false};
+
// If not blank, a base-64 encoded representation of the PEM-encoded
// public key in the response.
std::string public_key_rsa;
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index b6af131..83d910f 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -57,7 +57,8 @@
CHECK(HasInputObject());
install_plan_ = GetInputObject();
- if (install_plan_.powerwash_required) {
+ // Currently we're always powerwashing when rolling back.
+ if (install_plan_.powerwash_required || install_plan_.is_rollback) {
if (hardware_->SchedulePowerwash()) {
powerwash_scheduled_ = true;
} else {
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index f15171b..b7f0fdc 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -28,6 +28,7 @@
#include <base/message_loop/message_loop.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gmock/gmock.h>
@@ -38,6 +39,7 @@
#include "update_engine/common/fake_hardware.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
+#include "update_engine/mock_payload_state.h"
using brillo::MessageLoop;
using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
@@ -94,9 +96,10 @@
// Setup an action processor and run the PostinstallRunnerAction with a single
// partition |device_path|, running the |postinstall_program| command from
// there.
- void RunPosinstallAction(const string& device_path,
- const string& postinstall_program,
- bool powerwash_required);
+ void RunPostinstallAction(const string& device_path,
+ const string& postinstall_program,
+ bool powerwash_required,
+ bool is_rollback);
public:
void ResumeRunningAction() {
@@ -162,10 +165,11 @@
ActionProcessor* processor_{nullptr};
};
-void PostinstallRunnerActionTest::RunPosinstallAction(
+void PostinstallRunnerActionTest::RunPostinstallAction(
const string& device_path,
const string& postinstall_program,
- bool powerwash_required) {
+ bool powerwash_required,
+ bool is_rollback) {
ActionProcessor processor;
processor_ = &processor;
ObjectFeederAction<InstallPlan> feeder_action;
@@ -178,6 +182,7 @@
install_plan.partitions = {part};
install_plan.download_url = "http://127.0.0.1:8080/update";
install_plan.powerwash_required = powerwash_required;
+ install_plan.is_rollback = is_rollback;
feeder_action.set_obj(install_plan);
PostinstallRunnerAction runner_action(&fake_boot_control_, &fake_hardware_);
postinstall_action_ = &runner_action;
@@ -240,7 +245,8 @@
// /postinst command which only exits 0.
TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), kPostinstallDefaultScript, false);
+
+ RunPostinstallAction(loop.dev(), kPostinstallDefaultScript, false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
EXPECT_TRUE(processor_delegate_.processing_done_called_);
@@ -250,14 +256,31 @@
TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "bin/postinst_link", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_link", false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
}
TEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
// Run a simple postinstall program but requiring a powerwash.
- RunPosinstallAction(loop.dev(), "bin/postinst_example", true);
+ RunPostinstallAction(loop.dev(),
+ "bin/postinst_example",
+ /*powerwash_required=*/true,
+ false);
+ EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
+
+ // Check that powerwash was scheduled.
+ EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
+}
+
+TEST_F(PostinstallRunnerActionTest, RunAsRootRollbackTest) {
+ ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
+
+ // Run a simple postinstall program, rollback happened.
+ RunPostinstallAction(loop.dev(),
+ "bin/postinst_example",
+ false,
+ /*is_rollback=*/true);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
// Check that powerwash was scheduled.
@@ -267,7 +290,7 @@
// Runs postinstall from a partition file that doesn't mount, so it should
// fail.
TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
- RunPosinstallAction("/dev/null", kPostinstallDefaultScript, false);
+ RunPostinstallAction("/dev/null", kPostinstallDefaultScript, false, false);
EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
// In case of failure, Postinstall should not signal a powerwash even if it
@@ -279,7 +302,7 @@
// fail.
TEST_F(PostinstallRunnerActionTest, RunAsRootErrScriptTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "bin/postinst_fail1", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_fail1", false, false);
EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
}
@@ -287,7 +310,7 @@
// UMA with a different error code. Test those cases are properly detected.
TEST_F(PostinstallRunnerActionTest, RunAsRootFirmwareBErrScriptTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "bin/postinst_fail3", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_fail3", false, false);
EXPECT_EQ(ErrorCode::kPostinstallBootedFromFirmwareB,
processor_delegate_.code_);
}
@@ -295,7 +318,7 @@
// Check that you can't specify an absolute path.
TEST_F(PostinstallRunnerActionTest, RunAsRootAbsolutePathNotAllowedTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "/etc/../bin/sh", false);
+ RunPostinstallAction(loop.dev(), "/etc/../bin/sh", false, false);
EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
}
@@ -304,7 +327,7 @@
// SElinux labels are only set on Android.
TEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "bin/self_check_context", false);
+ RunPosinstallAction(loop.dev(), "bin/self_check_context", false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
}
#endif // __ANDROID__
@@ -317,7 +340,7 @@
loop_.PostTask(FROM_HERE,
base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
base::Unretained(this)));
- RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_suspend", false, false);
// postinst_suspend returns 0 only if it was suspended at some point.
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
EXPECT_TRUE(processor_delegate_.processing_done_called_);
@@ -329,7 +352,7 @@
// Wait for the action to start and then cancel it.
CancelWhenStarted();
- RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_suspend", false, false);
// When canceling the action, the action never finished and therefore we had
// a ProcessingStopped call instead.
EXPECT_FALSE(processor_delegate_.code_set_);
@@ -352,7 +375,7 @@
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
setup_action_delegate_ = &mock_delegate_;
- RunPosinstallAction(loop.dev(), "bin/postinst_progress", false);
+ RunPostinstallAction(loop.dev(), "bin/postinst_progress", false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
}
diff --git a/payload_generator/deflate_utils.cc b/payload_generator/deflate_utils.cc
index e331142..2719048 100644
--- a/payload_generator/deflate_utils.cc
+++ b/payload_generator/deflate_utils.cc
@@ -287,12 +287,16 @@
}
// Search for deflates if the file is in zip format.
+ // .zvoice files may eventually move out of rootfs. If that happens, remove
+ // ".zvoice" (crbug.com/782918).
+ const string zip_file_extensions[] = {".apk", ".zip", ".jar", ".zvoice"};
bool is_zip =
- base::EndsWith(
- file.name, ".apk", base::CompareCase::INSENSITIVE_ASCII) ||
- base::EndsWith(
- file.name, ".zip", base::CompareCase::INSENSITIVE_ASCII) ||
- base::EndsWith(file.name, ".jar", base::CompareCase::INSENSITIVE_ASCII);
+ any_of(zip_file_extensions,
+ std::end(zip_file_extensions),
+ [&file](const string& ext) {
+ return base::EndsWith(
+ file.name, ext, base::CompareCase::INSENSITIVE_ASCII);
+ });
if (is_zip && extract_deflates) {
brillo::Blob data;
diff --git a/payload_state.cc b/payload_state.cc
index b0e949b..d891da0 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -64,6 +64,7 @@
url_index_(0),
url_failure_count_(0),
url_switch_count_(0),
+ rollback_happened_(false),
attempt_num_bytes_downloaded_(0),
attempt_connection_type_(metrics::ConnectionType::kUnknown),
attempt_type_(AttemptType::kUpdate) {
@@ -93,6 +94,7 @@
}
LoadNumReboots();
LoadNumResponsesSeen();
+ LoadRollbackHappened();
LoadRollbackVersion();
LoadP2PFirstAttemptTimestamp();
LoadP2PNumAttempts();
@@ -354,8 +356,11 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
case ErrorCode::kUpdatedButNotActive:
case ErrorCode::kNoUpdate:
+ case ErrorCode::kRollbackNotPossible:
+ case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
LOG(INFO) << "Not incrementing URL index or failure count for this error";
break;
@@ -405,9 +410,11 @@
}
}
- if (!system_state_->hardware()->IsOfficialBuild()) {
+ if (!system_state_->hardware()->IsOfficialBuild() &&
+ !prefs_->Exists(kPrefsNoIgnoreBackoff)) {
// Backoffs are needed only for official builds. We do not want any delays
- // or update failures due to backoffs during testing or development.
+ // or update failures due to backoffs during testing or development. Unless
+ // the |kPrefsNoIgnoreBackoff| is manually set.
LOG(INFO) << "No backoffs for test/dev images. "
<< "Can proceed with the download";
return false;
@@ -1069,6 +1076,25 @@
SetNumReboots(GetPersistedValue(kPrefsNumReboots, prefs_));
}
+void PayloadState::LoadRollbackHappened() {
+ CHECK(powerwash_safe_prefs_);
+ bool rollback_happened = false;
+ powerwash_safe_prefs_->GetBoolean(kPrefsRollbackHappened, &rollback_happened);
+ SetRollbackHappened(rollback_happened);
+}
+
+void PayloadState::SetRollbackHappened(bool rollback_happened) {
+ CHECK(powerwash_safe_prefs_);
+ LOG(INFO) << "Setting rollback-happened to " << rollback_happened << ".";
+ rollback_happened_ = rollback_happened;
+ if (rollback_happened) {
+ powerwash_safe_prefs_->SetBoolean(kPrefsRollbackHappened,
+ rollback_happened);
+ } else {
+ powerwash_safe_prefs_->Delete(kPrefsRollbackHappened);
+ }
+}
+
void PayloadState::LoadRollbackVersion() {
CHECK(powerwash_safe_prefs_);
string rollback_version;
diff --git a/payload_state.h b/payload_state.h
index 17c1ce0..e8b0db0 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -80,7 +80,8 @@
}
inline std::string GetCurrentUrl() override {
- return candidate_urls_.size() && candidate_urls_[payload_index_].size()
+ return (payload_index_ < candidate_urls_.size() &&
+ url_index_ < candidate_urls_[payload_index_].size())
? candidate_urls_[payload_index_][url_index_]
: "";
}
@@ -119,6 +120,10 @@
void UpdateEngineStarted() override;
+ inline bool GetRollbackHappened() override { return rollback_happened_; }
+
+ void SetRollbackHappened(bool rollback_happened) override;
+
inline std::string GetRollbackVersion() override {
return rollback_version_;
}
@@ -162,6 +167,7 @@
FRIEND_TEST(PayloadStateTest, RebootAfterUpdateFailedMetric);
FRIEND_TEST(PayloadStateTest, RebootAfterUpdateSucceed);
FRIEND_TEST(PayloadStateTest, RebootAfterCanceledUpdate);
+ FRIEND_TEST(PayloadStateTest, RollbackHappened);
FRIEND_TEST(PayloadStateTest, RollbackVersion);
FRIEND_TEST(PayloadStateTest, UpdateSuccessWithWipedPrefs);
@@ -359,6 +365,10 @@
uint64_t total_bytes_downloaded,
bool log);
+ // Loads whether rollback has happened on this device since the last update
+ // check where policy was available. This info is preserved over powerwash.
+ void LoadRollbackHappened();
+
// Loads the blacklisted version from our prefs file.
void LoadRollbackVersion();
@@ -370,9 +380,10 @@
void ResetRollbackVersion();
inline uint32_t GetUrlIndex() {
- return url_index_ ? std::min(candidate_urls_[payload_index_].size() - 1,
- url_index_)
- : 0;
+ return (url_index_ != 0 && payload_index_ < candidate_urls_.size())
+ ? std::min(candidate_urls_[payload_index_].size() - 1,
+ url_index_)
+ : 0;
}
// Computes the list of candidate URLs from the total list of payload URLs in
@@ -546,6 +557,11 @@
// allowed as per device policy.
std::vector<std::vector<std::string>> candidate_urls_;
+ // This stores whether rollback has happened since the last time device policy
+ // was available during update check. When this is set, we're preventing
+ // forced updates to avoid update-rollback loops.
+ bool rollback_happened_;
+
// This stores a blacklisted version set as part of rollback. When we rollback
// we store the version of the os from which we are rolling back from in order
// to guarantee that we do not re-update to it on the next au attempt after
diff --git a/payload_state_interface.h b/payload_state_interface.h
index f553909..3adc148 100644
--- a/payload_state_interface.h
+++ b/payload_state_interface.h
@@ -155,6 +155,16 @@
// Called at update_engine startup to do various house-keeping.
virtual void UpdateEngineStarted() = 0;
+ // Returns whether a rollback happened since the last update check with policy
+ // present.
+ virtual bool GetRollbackHappened() = 0;
+
+ // Sets whether rollback has happened on this device since the last update
+ // check where policy was available. This info is preserved over powerwash.
+ // This prevents forced updates happening on a rolled back device before
+ // device policy is available.
+ virtual void SetRollbackHappened(bool rollback_happened) = 0;
+
// Returns the version from before a rollback if our last update was a
// rollback.
virtual std::string GetRollbackVersion() = 0;
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index 52c28d0..637891b 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -985,6 +985,37 @@
EXPECT_EQ(0U, payload_state.GetNumReboots());
}
+TEST(PayloadStateTest, RollbackHappened) {
+ FakeSystemState fake_system_state;
+ PayloadState payload_state;
+
+ NiceMock<MockPrefs>* mock_powerwash_safe_prefs =
+ fake_system_state.mock_powerwash_safe_prefs();
+ EXPECT_TRUE(payload_state.Initialize(&fake_system_state));
+
+ // Verify pre-conditions are good.
+ EXPECT_FALSE(payload_state.GetRollbackHappened());
+
+ // Set to true.
+ EXPECT_CALL(*mock_powerwash_safe_prefs,
+ SetBoolean(kPrefsRollbackHappened, true));
+ payload_state.SetRollbackHappened(true);
+ EXPECT_TRUE(payload_state.GetRollbackHappened());
+
+ // Set to false.
+ EXPECT_CALL(*mock_powerwash_safe_prefs, Delete(kPrefsRollbackHappened));
+ payload_state.SetRollbackHappened(false);
+ EXPECT_FALSE(payload_state.GetRollbackHappened());
+
+ // Let's verify we can reload it correctly.
+ EXPECT_CALL(*mock_powerwash_safe_prefs, GetBoolean(kPrefsRollbackHappened, _))
+ .WillOnce(DoAll(SetArgPointee<1>(true), Return(true)));
+ EXPECT_CALL(*mock_powerwash_safe_prefs,
+ SetBoolean(kPrefsRollbackHappened, true));
+ payload_state.LoadRollbackHappened();
+ EXPECT_TRUE(payload_state.GetRollbackHappened());
+}
+
TEST(PayloadStateTest, RollbackVersion) {
FakeSystemState fake_system_state;
PayloadState payload_state;
diff --git a/proxy_resolver_unittest.cc b/proxy_resolver_unittest.cc
index 484aae1..070b361 100644
--- a/proxy_resolver_unittest.cc
+++ b/proxy_resolver_unittest.cc
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#include <base/bind.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
using std::deque;
diff --git a/real_system_state.cc b/real_system_state.cc
index 0ce326b..8f4c731 100644
--- a/real_system_state.cc
+++ b/real_system_state.cc
@@ -67,8 +67,8 @@
}
#if USE_CHROME_KIOSK_APP
- libcros_proxy_.reset(new org::chromium::LibCrosServiceInterfaceProxy(
- DBusConnection::Get()->GetDBus(), chromeos::kLibCrosServiceName));
+ kiosk_app_proxy_.reset(new org::chromium::KioskAppServiceInterfaceProxy(
+ DBusConnection::Get()->GetDBus(), chromeos::kKioskAppServiceName));
#endif // USE_CHROME_KIOSK_APP
LOG_IF(INFO, !hardware_->IsNormalBootMode()) << "Booted in dev mode.";
@@ -150,7 +150,7 @@
chromeos_update_manager::State* um_state =
chromeos_update_manager::DefaultStateFactory(&policy_provider_,
#if USE_CHROME_KIOSK_APP
- libcros_proxy_.get(),
+ kiosk_app_proxy_.get(),
#else
nullptr,
#endif // USE_CHROME_KIOSK_APP
diff --git a/real_system_state.h b/real_system_state.h
index 49f7c31..f1cd38f 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -25,7 +25,7 @@
#include <policy/device_policy.h>
#if USE_CHROME_KIOSK_APP
-#include <libcros/dbus-proxies.h>
+#include <kiosk-app/dbus-proxies.h>
#endif // USE_CHROME_KIOSK_APP
#include "update_engine/certificate_checker.h"
@@ -129,7 +129,8 @@
private:
// Real DBus proxies using the DBus connection.
#if USE_CHROME_KIOSK_APP
- std::unique_ptr<org::chromium::LibCrosServiceInterfaceProxy> libcros_proxy_;
+ std::unique_ptr<org::chromium::KioskAppServiceInterfaceProxy>
+ kiosk_app_proxy_;
#endif // USE_CHROME_KIOSK_APP
// Interface for the power manager.
diff --git a/scripts/paycheck.py b/scripts/paycheck.py
index 96b1032..0050f5b 100755
--- a/scripts/paycheck.py
+++ b/scripts/paycheck.py
@@ -89,6 +89,9 @@
'validation'))
check_args.add_argument('-m', '--meta-sig', metavar='FILE',
help='verify metadata against its signature')
+ check_args.add_argument('-s', '--metadata-size', metavar='NUM', default=0,
+ help='the metadata size to verify with the one in'
+ ' payload')
check_args.add_argument('-p', '--root-part-size', metavar='NUM',
default=0, type=int,
help='override rootfs partition size auto-inference')
@@ -128,7 +131,8 @@
args.check = (args.check or args.report or args.assert_type or
args.block_size or args.allow_unhashed or
args.disabled_tests or args.meta_sig or args.key or
- args.root_part_size or args.kern_part_size)
+ args.root_part_size or args.kern_part_size or
+ args.metadata_size)
# Check the arguments, enforce payload type accordingly.
if (args.src_kern is None) != (args.src_root is None):
@@ -202,6 +206,7 @@
payload.Check(
pubkey_file_name=args.key,
metadata_sig_file=metadata_sig_file,
+ metadata_size=int(args.metadata_size),
report_out_file=report_file,
assert_type=args.assert_type,
block_size=int(args.block_size),
diff --git a/scripts/update_payload/checker.py b/scripts/update_payload/checker.py
index e9e9958..68c70d4 100644
--- a/scripts/update_payload/checker.py
+++ b/scripts/update_payload/checker.py
@@ -1231,13 +1231,14 @@
raise error.PayloadError('Unknown signature version (%d).' %
sig.version)
- def Run(self, pubkey_file_name=None, metadata_sig_file=None,
+ def Run(self, pubkey_file_name=None, metadata_sig_file=None, metadata_size=0,
rootfs_part_size=0, kernel_part_size=0, report_out_file=None):
"""Checker entry point, invoking all checks.
Args:
pubkey_file_name: Public key used for signature verification.
metadata_sig_file: Metadata signature, if verification is desired.
+ metadata_size: metadata size, if verification is desired
rootfs_part_size: The size of rootfs partitions in bytes (default: infer
based on payload type and version).
kernel_part_size: The size of kernel partitions in bytes (default: use
@@ -1258,6 +1259,12 @@
self.payload.ResetFile()
try:
+ # Check metadata_size (if provided).
+ if metadata_size and self.payload.data_offset != metadata_size:
+ raise error.PayloadError('Invalid payload metadata size in payload(%d) '
+ 'vs given(%d)' % (self.payload.data_offset,
+ metadata_size))
+
# Check metadata signature (if provided).
if metadata_sig_file:
metadata_sig = base64.b64decode(metadata_sig_file.read())
diff --git a/scripts/update_payload/checker_unittest.py b/scripts/update_payload/checker_unittest.py
index f718234..68f1807 100755
--- a/scripts/update_payload/checker_unittest.py
+++ b/scripts/update_payload/checker_unittest.py
@@ -1127,8 +1127,8 @@
def DoRunTest(self, rootfs_part_size_provided, kernel_part_size_provided,
fail_wrong_payload_type, fail_invalid_block_size,
- fail_mismatched_block_size, fail_excess_data,
- fail_rootfs_part_size_exceeded,
+ fail_mismatched_metadata_size, fail_mismatched_block_size,
+ fail_excess_data, fail_rootfs_part_size_exceeded,
fail_kernel_part_size_exceeded):
"""Tests Run()."""
# Generate a test payload. For this test, we generate a full update that
@@ -1178,6 +1178,11 @@
else:
use_block_size = block_size
+ # For the unittests 246 is the value that generated for the payload.
+ metadata_size = 246
+ if fail_mismatched_metadata_size:
+ metadata_size += 1
+
kwargs = {
'payload_gen_dargs': {
'privkey_file_name': test_utils._PRIVKEY_FILE_NAME,
@@ -1196,9 +1201,10 @@
kwargs = {'pubkey_file_name': test_utils._PUBKEY_FILE_NAME,
'rootfs_part_size': rootfs_part_size,
+ 'metadata_size': metadata_size,
'kernel_part_size': kernel_part_size}
should_fail = (fail_wrong_payload_type or fail_mismatched_block_size or
- fail_excess_data or
+ fail_mismatched_metadata_size or fail_excess_data or
fail_rootfs_part_size_exceeded or
fail_kernel_part_size_exceeded)
if should_fail:
@@ -1353,6 +1359,7 @@
'kernel_part_size_provided': (True, False),
'fail_wrong_payload_type': (True, False),
'fail_invalid_block_size': (True, False),
+ 'fail_mismatched_metadata_size': (True, False),
'fail_mismatched_block_size': (True, False),
'fail_excess_data': (True, False),
'fail_rootfs_part_size_exceeded': (True, False),
diff --git a/scripts/update_payload/payload.py b/scripts/update_payload/payload.py
index 380d6d0..15f66d0 100644
--- a/scripts/update_payload/payload.py
+++ b/scripts/update_payload/payload.py
@@ -273,14 +273,15 @@
return not self.IsDelta()
def Check(self, pubkey_file_name=None, metadata_sig_file=None,
- report_out_file=None, assert_type=None, block_size=0,
- rootfs_part_size=0, kernel_part_size=0, allow_unhashed=False,
- disabled_tests=()):
+ metadata_size=0, report_out_file=None, assert_type=None,
+ block_size=0, rootfs_part_size=0, kernel_part_size=0,
+ allow_unhashed=False, disabled_tests=()):
"""Checks the payload integrity.
Args:
pubkey_file_name: public key used for signature verification
metadata_sig_file: metadata signature, if verification is desired
+ metadata_size: metadata size, if verification is desired
report_out_file: file object to dump the report to
assert_type: assert that payload is either 'full' or 'delta'
block_size: expected filesystem / payload block size
@@ -300,6 +301,7 @@
allow_unhashed=allow_unhashed, disabled_tests=disabled_tests)
helper.Run(pubkey_file_name=pubkey_file_name,
metadata_sig_file=metadata_sig_file,
+ metadata_size=metadata_size,
rootfs_part_size=rootfs_part_size,
kernel_part_size=kernel_part_size,
report_out_file=report_out_file)
diff --git a/tar_bunzip2.gypi b/tar_bunzip2.gypi
index 8c6614a..4d1be28 100644
--- a/tar_bunzip2.gypi
+++ b/tar_bunzip2.gypi
@@ -21,9 +21,6 @@
{
'rule_name': 'tar-bunzip2',
'extension': 'bz2',
- 'inputs': [
- '<(RULE_INPUT_PATH)',
- ],
'outputs': [
# The .flag file is used to mark the timestamp of the file extraction
# and re-run this action if a new .bz2 file is generated.
diff --git a/test_http_server.cc b/test_http_server.cc
index cf15672..39a12ed 100644
--- a/test_http_server.cc
+++ b/test_http_server.cc
@@ -98,11 +98,9 @@
request->raw_headers = headers;
// Break header into lines.
- vector<string> lines = base::SplitStringUsingSubstr(
- headers.substr(0, headers.length() - strlen(EOL EOL)),
- EOL,
- base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL);
+ vector<string> lines;
+ base::SplitStringUsingSubstr(
+ headers.substr(0, headers.length() - strlen(EOL EOL)), EOL, &lines);
// Decode URL line.
vector<string> terms = base::SplitString(lines[0], base::kWhitespaceASCII,
diff --git a/update_attempter.cc b/update_attempter.cc
index fa172df..67b7471 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -31,6 +31,7 @@
#include <base/rand_util.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <brillo/bind_lambda.h>
#include <brillo/data_encoding.h>
#include <brillo/errors/error_codes.h>
#include <brillo/message_loops/message_loop.h>
@@ -47,6 +48,7 @@
#include "update_engine/common/prefs_interface.h"
#include "update_engine/common/subprocess.h"
#include "update_engine/common/utils.h"
+#include "update_engine/connection_manager_interface.h"
#include "update_engine/libcurl_http_fetcher.h"
#include "update_engine/metrics_reporter_interface.h"
#include "update_engine/omaha_request_action.h"
@@ -60,6 +62,7 @@
#include "update_engine/power_manager_interface.h"
#include "update_engine/system_state.h"
#include "update_engine/update_manager/policy.h"
+#include "update_engine/update_manager/policy_utils.h"
#include "update_engine/update_manager/update_manager.h"
#include "update_engine/update_status_utils.h"
@@ -238,6 +241,7 @@
const string& omaha_url,
const string& target_channel,
const string& target_version_prefix,
+ bool rollback_allowed,
bool obey_proxies,
bool interactive) {
// This is normally called frequently enough so it's appropriate to use as a
@@ -276,6 +280,7 @@
omaha_url,
target_channel,
target_version_prefix,
+ rollback_allowed,
obey_proxies,
interactive)) {
return;
@@ -351,6 +356,7 @@
const string& omaha_url,
const string& target_channel,
const string& target_version_prefix,
+ bool rollback_allowed,
bool obey_proxies,
bool interactive) {
http_response_code_ = 0;
@@ -359,9 +365,16 @@
// Refresh the policy before computing all the update parameters.
RefreshDevicePolicy();
+ // Check whether we need to clear the rollback-happened preference after
+ // policy is available again.
+ UpdateRollbackHappened();
+
// Update the target version prefix.
omaha_request_params_->set_target_version_prefix(target_version_prefix);
+ // Set whether rollback is allowed.
+ omaha_request_params_->set_rollback_allowed(rollback_allowed);
+
CalculateScatteringParams(interactive);
CalculateP2PParams(interactive);
@@ -407,6 +420,8 @@
LOG(INFO) << "target_version_prefix = "
<< omaha_request_params_->target_version_prefix()
+ << ", rollback_allowed = "
+ << omaha_request_params_->rollback_allowed()
<< ", scatter_factor_in_seconds = "
<< utils::FormatSecs(scatter_factor_.InSeconds());
@@ -813,11 +828,13 @@
}
bool UpdateAttempter::RebootIfNeeded() {
+#ifdef __ANDROID__
if (status_ != UpdateStatus::UPDATED_NEED_REBOOT) {
LOG(INFO) << "Reboot requested, but status is "
<< UpdateStatusToString(status_) << ", so not rebooting.";
return false;
}
+#endif // __ANDROID__
if (system_state_->power_manager()->RequestReboot())
return true;
@@ -879,7 +896,8 @@
forced_omaha_url_,
params.target_channel,
params.target_version_prefix,
- false,
+ params.rollback_allowed,
+ /*obey_proxies=*/false,
params.interactive);
// Always clear the forced app_version and omaha_url after an update attempt
// so the next update uses the defaults.
@@ -903,6 +921,19 @@
last_checked_time_ = system_state_->clock()->GetWallclockTime().ToTimeT();
}
+void UpdateAttempter::UpdateRollbackHappened() {
+ DCHECK(system_state_);
+ DCHECK(system_state_->payload_state());
+ DCHECK(policy_provider_);
+ if (system_state_->payload_state()->GetRollbackHappened() &&
+ (policy_provider_->device_policy_is_loaded() ||
+ policy_provider_->IsConsumerDevice())) {
+ // Rollback happened, but we already went through OOBE and policy is
+ // present or it's a consumer device.
+ system_state_->payload_state()->SetRollbackHappened(false);
+ }
+}
+
// Delegate methods:
void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
ErrorCode code) {
@@ -971,6 +1002,14 @@
payload.metadata_signature + ":";
}
+ // If we just downloaded a rollback image, we should preserve this fact
+ // over the following powerwash.
+ if (install_plan.is_rollback) {
+ system_state_->payload_state()->SetRollbackHappened(true);
+ system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
+ /*success=*/true, install_plan.version);
+ }
+
// Expect to reboot into the new version to send the proper metric during
// next boot.
system_state_->payload_state()->ExpectRebootInNewVersion(
@@ -1033,9 +1072,23 @@
consecutive_failed_update_checks_ = 0;
}
+ const OmahaResponse& omaha_response =
+ omaha_request_action->GetOutputObject();
// Store the server-dictated poll interval, if any.
server_dictated_poll_interval_ =
- std::max(0, omaha_request_action->GetOutputObject().poll_interval);
+ std::max(0, omaha_response.poll_interval);
+
+ // This update is ignored by omaha request action because update over
+ // cellular connection is not allowed. Needs to ask for user's permissions
+ // to update.
+ if (code == ErrorCode::kOmahaUpdateIgnoredOverCellular) {
+ new_version_ = omaha_response.version;
+ new_payload_size_ = 0;
+ for (const auto& package : omaha_response.packages) {
+ new_payload_size_ += package.size;
+ }
+ SetStatusAndNotify(UpdateStatus::NEED_PERMISSION_TO_UPDATE);
+ }
}
} else if (type == OmahaResponseHandlerAction::StaticType()) {
// Depending on the returned error code, note that an update is available.
@@ -1063,9 +1116,23 @@
// If the current state is at or past the download phase, count the failure
// in case a switch to full update becomes necessary. Ignore network
// transfer timeouts and failures.
- if (status_ >= UpdateStatus::DOWNLOADING &&
- code != ErrorCode::kDownloadTransferError) {
- MarkDeltaUpdateFailure();
+ if (code != ErrorCode::kDownloadTransferError) {
+ switch (status_) {
+ case UpdateStatus::IDLE:
+ case UpdateStatus::CHECKING_FOR_UPDATE:
+ case UpdateStatus::UPDATE_AVAILABLE:
+ case UpdateStatus::NEED_PERMISSION_TO_UPDATE:
+ break;
+ case UpdateStatus::DOWNLOADING:
+ case UpdateStatus::VERIFYING:
+ case UpdateStatus::FINALIZING:
+ case UpdateStatus::UPDATED_NEED_REBOOT:
+ case UpdateStatus::REPORTING_ERROR_EVENT:
+ case UpdateStatus::ATTEMPTING_ROLLBACK:
+ case UpdateStatus::DISABLED:
+ MarkDeltaUpdateFailure();
+ break;
+ }
}
if (code != ErrorCode::kNoUpdate) {
// On failure, schedule an error event to be sent to Omaha.
@@ -1311,6 +1378,15 @@
LOG(ERROR) << "Update failed.";
system_state_->payload_state()->UpdateFailed(error_event_->error_code);
+ // Send metrics if it was a rollback.
+ if (response_handler_action_) {
+ const InstallPlan& install_plan = response_handler_action_->install_plan();
+ if (install_plan.is_rollback) {
+ system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
+ /*success=*/false, install_plan.version);
+ }
+ }
+
// Send it to Omaha.
LOG(INFO) << "Reporting the error event";
shared_ptr<OmahaRequestAction> error_event_action(
diff --git a/update_attempter.h b/update_attempter.h
index 82fe4c0..44255b0 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -83,6 +83,7 @@
const std::string& omaha_url,
const std::string& target_channel,
const std::string& target_version_prefix,
+ bool rollback_allowed,
bool obey_proxies,
bool interactive);
@@ -266,8 +267,17 @@
FRIEND_TEST(UpdateAttempterTest, MarkDeltaUpdateFailureTest);
FRIEND_TEST(UpdateAttempterTest, PingOmahaTest);
FRIEND_TEST(UpdateAttempterTest, ReportDailyMetrics);
+ FRIEND_TEST(UpdateAttempterTest, RollbackNotAllowed);
+ FRIEND_TEST(UpdateAttempterTest, RollbackAllowed);
+ FRIEND_TEST(UpdateAttempterTest, RollbackAllowedSetAndReset);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
+ FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest);
FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionTest);
+ FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
+ FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedRollback);
FRIEND_TEST(UpdateAttempterTest, TargetVersionPrefixSetAndReset);
FRIEND_TEST(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart);
FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
@@ -337,6 +347,7 @@
const std::string& omaha_url,
const std::string& target_channel,
const std::string& target_version_prefix,
+ bool rollback_allowed,
bool obey_proxies,
bool interactive);
@@ -398,6 +409,10 @@
// Updates the time an update was last attempted to the current time.
void UpdateLastCheckedTime();
+ // Checks whether we need to clear the rollback-happened preference after
+ // policy is available again.
+ void UpdateRollbackHappened();
+
// Returns whether an update is currently running or scheduled.
bool IsUpdateRunningOrScheduled();
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 4677d31..80c9638 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -22,12 +22,14 @@
#include <base/files/file_util.h>
#include <base/message_loop/message_loop.h>
+#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gtest/gtest.h>
#include <policy/libpolicy.h>
#include <policy/mock_device_policy.h>
+#include <policy/mock_libpolicy.h>
#include "update_engine/common/fake_clock.h"
#include "update_engine/common/fake_prefs.h"
@@ -63,6 +65,7 @@
using testing::Property;
using testing::Return;
using testing::ReturnPointee;
+using testing::ReturnRef;
using testing::SaveArg;
using testing::SetArgPointee;
using update_engine::UpdateAttemptFlags;
@@ -71,6 +74,8 @@
namespace chromeos_update_engine {
+const char kRollbackVersion[] = "10575.39.2";
+
// Test a subclass rather than the main class directly so that we can mock out
// methods within the class. There're explicit unit tests for the mocked out
// methods.
@@ -165,6 +170,9 @@
void P2PEnabledInteractiveStart();
void P2PEnabledStartingFailsStart();
void P2PEnabledHousekeepingFailsStart();
+ void ResetRollbackHappenedStart(bool is_consumer,
+ bool is_policy_available,
+ bool expected_reset);
bool actual_using_p2p_for_downloading() {
return actual_using_p2p_for_downloading_;
@@ -472,7 +480,7 @@
EXPECT_CALL(*processor_, StartProcessing());
}
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
loop_.PostTask(FROM_HERE,
base::Bind(&UpdateAttempterTest::UpdateTestVerify,
base::Unretained(this)));
@@ -694,7 +702,7 @@
fake_system_state_.set_p2p_manager(&mock_p2p_manager);
mock_p2p_manager.fake().SetP2PEnabled(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading_);
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -716,7 +724,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(false);
mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading());
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -739,7 +747,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading());
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -761,7 +769,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
mock_p2p_manager.fake().SetPerformHousekeepingResult(true);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_TRUE(actual_using_p2p_for_downloading());
EXPECT_TRUE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -784,7 +792,13 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
mock_p2p_manager.fake().SetPerformHousekeepingResult(true);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update("", "", "", "", false, true /* interactive */);
+ attempter_.Update("",
+ "",
+ "",
+ "",
+ false,
+ false,
+ /*interactive=*/true);
EXPECT_FALSE(actual_using_p2p_for_downloading());
EXPECT_TRUE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -815,7 +829,7 @@
attempter_.policy_provider_.reset(
new policy::PolicyProvider(std::move(device_policy)));
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
ScheduleQuitMainLoop();
@@ -854,7 +868,7 @@
attempter_.policy_provider_.reset(
new policy::PolicyProvider(std::move(device_policy)));
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
// Make sure the file still exists.
@@ -870,7 +884,7 @@
// However, if the count is already 0, it's not decremented. Test that.
initial_value = 0;
EXPECT_TRUE(fake_prefs.SetInt64(kPrefsUpdateCheckCount, initial_value));
- attempter_.Update("", "", "", "", false, false);
+ attempter_.Update("", "", "", "", false, false, false);
EXPECT_TRUE(fake_prefs.Exists(kPrefsUpdateCheckCount));
EXPECT_TRUE(fake_prefs.GetInt64(kPrefsUpdateCheckCount, &new_value));
EXPECT_EQ(initial_value, new_value);
@@ -915,7 +929,13 @@
new policy::PolicyProvider(std::move(device_policy)));
// Trigger an interactive check so we can test that scattering is disabled.
- attempter_.Update("", "", "", "", false, true);
+ attempter_.Update("",
+ "",
+ "",
+ "",
+ false,
+ false,
+ /*interactive=*/true);
EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
// Make sure scattering is disabled for manual (i.e. user initiated) update
@@ -1044,15 +1064,35 @@
}
TEST_F(UpdateAttempterTest, TargetVersionPrefixSetAndReset) {
- attempter_.CalculateUpdateParams("", "", "", "1234", false, false);
+ attempter_.CalculateUpdateParams("", "", "", "1234", false, false, false);
EXPECT_EQ("1234",
fake_system_state_.request_params()->target_version_prefix());
- attempter_.CalculateUpdateParams("", "", "", "", false, false);
+ attempter_.CalculateUpdateParams("", "", "", "", false, false, false);
EXPECT_TRUE(
fake_system_state_.request_params()->target_version_prefix().empty());
}
+TEST_F(UpdateAttempterTest, RollbackAllowedSetAndReset) {
+ attempter_.CalculateUpdateParams("",
+ "",
+ "",
+ "1234",
+ /*rollback_allowed=*/true,
+ false,
+ false);
+ EXPECT_TRUE(fake_system_state_.request_params()->rollback_allowed());
+
+ attempter_.CalculateUpdateParams("",
+ "",
+ "",
+ "1234",
+ /*rollback_allowed=*/false,
+ false,
+ false);
+ EXPECT_FALSE(fake_system_state_.request_params()->rollback_allowed());
+}
+
TEST_F(UpdateAttempterTest, UpdateDeferredByPolicyTest) {
// Construct an OmahaResponseHandlerAction that has processed an InstallPlan,
// but the update is being deferred by the Policy.
@@ -1118,6 +1158,20 @@
attempter_.GetCurrentUpdateAttemptFlags());
}
+TEST_F(UpdateAttempterTest, RollbackNotAllowed) {
+ UpdateCheckParams params = {.updates_enabled = true,
+ .rollback_allowed = false};
+ attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
+ EXPECT_FALSE(fake_system_state_.request_params()->rollback_allowed());
+}
+
+TEST_F(UpdateAttempterTest, RollbackAllowed) {
+ UpdateCheckParams params = {.updates_enabled = true,
+ .rollback_allowed = true};
+ attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
+ EXPECT_TRUE(fake_system_state_.request_params()->rollback_allowed());
+}
+
TEST_F(UpdateAttempterTest, InteractiveUpdateUsesPassedRestrictions) {
attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
@@ -1139,4 +1193,136 @@
attempter_.GetCurrentUpdateAttemptFlags());
}
+void UpdateAttempterTest::ResetRollbackHappenedStart(bool is_consumer,
+ bool is_policy_loaded,
+ bool expected_reset) {
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(), GetRollbackHappened())
+ .WillRepeatedly(Return(true));
+ auto mock_policy_provider =
+ std::make_unique<NiceMock<policy::MockPolicyProvider>>();
+ EXPECT_CALL(*mock_policy_provider, IsConsumerDevice())
+ .WillRepeatedly(Return(is_consumer));
+ EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded())
+ .WillRepeatedly(Return(is_policy_loaded));
+ const policy::MockDevicePolicy device_policy;
+ EXPECT_CALL(*mock_policy_provider, GetDevicePolicy())
+ .WillRepeatedly(ReturnRef(device_policy));
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(),
+ SetRollbackHappened(false))
+ .Times(expected_reset ? 1 : 0);
+ attempter_.policy_provider_ = std::move(mock_policy_provider);
+ attempter_.Update("", "", "", "", false, false, false);
+ ScheduleQuitMainLoop();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedOobe) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/false,
+ /*is_policy_loaded=*/false,
+ /*expected_reset=*/false));
+ loop_.Run();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedConsumer) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/true,
+ /*is_policy_loaded=*/false,
+ /*expected_reset=*/true));
+ loop_.Run();
+}
+
+TEST_F(UpdateAttempterTest, ResetRollbackHappenedEnterprise) {
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
+ base::Unretained(this),
+ /*is_consumer=*/false,
+ /*is_policy_loaded=*/true,
+ /*expected_reset=*/true));
+ loop_.Run();
+}
+
+TEST_F(UpdateAttempterTest, SetRollbackHappenedRollback) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = true;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(),
+ SetRollbackHappened(true))
+ .Times(1);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, SetRollbackHappenedNotRollback) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = false;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_payload_state(),
+ SetRollbackHappened(true))
+ .Times(0);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsRollbackSuccess) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = true;
+ response_action->install_plan_.version = kRollbackVersion;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+ ReportEnterpriseRollbackMetrics(true, kRollbackVersion))
+ .Times(1);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = false;
+ response_action->install_plan_.version = kRollbackVersion;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+ ReportEnterpriseRollbackMetrics(_, _))
+ .Times(0);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsRollbackFailure) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = true;
+ response_action->install_plan_.version = kRollbackVersion;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+ ReportEnterpriseRollbackMetrics(false, kRollbackVersion))
+ .Times(1);
+ MockAction action;
+ attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackFailure) {
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.is_rollback = false;
+ response_action->install_plan_.version = kRollbackVersion;
+ attempter_.response_handler_action_.reset(response_action);
+
+ EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+ ReportEnterpriseRollbackMetrics(_, _))
+ .Times(0);
+ MockAction action;
+ attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
+ attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
+}
+
} // namespace chromeos_update_engine
diff --git a/update_engine.gyp b/update_engine.gyp
index 7cb2a7d..30daf2a 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -104,16 +104,16 @@
'includes': ['../../../platform2/common-mk/generate-dbus-adaptors.gypi'],
},
{
- 'target_name': 'update_engine-dbus-libcros-client',
+ 'target_name': 'update_engine-dbus-kiosk-app-client',
'type': 'none',
'actions': [{
- 'action_name': 'update_engine-dbus-libcros-client-action',
+ 'action_name': 'update_engine-dbus-kiosk-app-client-action',
'variables': {
- 'mock_output_file': 'include/libcros/dbus-proxy-mocks.h',
- 'proxy_output_file': 'include/libcros/dbus-proxies.h',
+ 'mock_output_file': 'include/kiosk-app/dbus-proxy-mocks.h',
+ 'proxy_output_file': 'include/kiosk-app/dbus-proxies.h',
},
'sources': [
- 'dbus_bindings/org.chromium.LibCrosService.dbus-xml',
+ 'dbus_bindings/org.chromium.KioskAppService.dbus-xml',
],
'includes': ['../../../platform2/common-mk/generate-dbus-proxies.gypi'],
}],
@@ -304,7 +304,7 @@
}],
['USE_chrome_kiosk_app == 1', {
'dependencies': [
- 'update_engine-dbus-libcros-client',
+ 'update_engine-dbus-kiosk-app-client',
],
}],
],
diff --git a/update_engine_client.cc b/update_engine_client.cc
index 55206b2..b7096c5 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -458,8 +458,8 @@
LOG(INFO) << "Target Channel (pending update): " << target_channel;
}
- bool do_update_request = FLAGS_check_for_update | FLAGS_update |
- !FLAGS_app_version.empty() |
+ bool do_update_request = FLAGS_check_for_update || FLAGS_update ||
+ !FLAGS_app_version.empty() ||
!FLAGS_omaha_url.empty();
if (FLAGS_update) FLAGS_follow = true;
diff --git a/update_manager/android_things_policy.cc b/update_manager/android_things_policy.cc
index 20d10d8..4afcf12 100644
--- a/update_manager/android_things_policy.cc
+++ b/update_manager/android_things_policy.cc
@@ -53,6 +53,8 @@
result->updates_enabled = true;
result->target_channel.clear();
result->target_version_prefix.clear();
+ result->rollback_allowed = false;
+ result->rollback_allowed_milestones = -1;
result->interactive = false;
// Build a list of policies to consult. Note that each policy may modify the
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
index a437c02..b2505ee 100644
--- a/update_manager/boxed_value.cc
+++ b/update_manager/boxed_value.cc
@@ -26,6 +26,7 @@
#include "update_engine/common/utils.h"
#include "update_engine/connection_utils.h"
+#include "update_engine/update_manager/rollback_prefs.h"
#include "update_engine/update_manager/shill_provider.h"
#include "update_engine/update_manager/updater_provider.h"
@@ -133,6 +134,25 @@
return "Unknown";
}
+template <>
+string BoxedValue::ValuePrinter<RollbackToTargetVersion>(const void* value) {
+ const RollbackToTargetVersion* val =
+ reinterpret_cast<const RollbackToTargetVersion*>(value);
+ switch (*val) {
+ case RollbackToTargetVersion::kUnspecified:
+ return "Unspecified";
+ case RollbackToTargetVersion::kDisabled:
+ return "Disabled";
+ case RollbackToTargetVersion::kRollbackWithFullPowerwash:
+ return "Rollback with full powerwash";
+ case RollbackToTargetVersion::kMaxValue:
+ NOTREACHED();
+ return "Max value";
+ }
+ NOTREACHED();
+ return "Unknown";
+}
+
template<>
string BoxedValue::ValuePrinter<Stage>(const void* value) {
const Stage* val = reinterpret_cast<const Stage*>(value);
diff --git a/update_manager/boxed_value_unittest.cc b/update_manager/boxed_value_unittest.cc
index 4aeaec8..04de3d4 100644
--- a/update_manager/boxed_value_unittest.cc
+++ b/update_manager/boxed_value_unittest.cc
@@ -26,6 +26,7 @@
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
+#include "update_engine/update_manager/rollback_prefs.h"
#include "update_engine/update_manager/shill_provider.h"
#include "update_engine/update_manager/umtest_utils.h"
#include "update_engine/update_manager/updater_provider.h"
@@ -192,6 +193,21 @@
.ToString());
}
+TEST(UmBoxedValueTest, RollbackToTargetVersionToString) {
+ EXPECT_EQ("Unspecified",
+ BoxedValue(new RollbackToTargetVersion(
+ RollbackToTargetVersion::kUnspecified))
+ .ToString());
+ EXPECT_EQ("Disabled",
+ BoxedValue(
+ new RollbackToTargetVersion(RollbackToTargetVersion::kDisabled))
+ .ToString());
+ EXPECT_EQ("Rollback with full powerwash",
+ BoxedValue(new RollbackToTargetVersion(
+ RollbackToTargetVersion::kRollbackWithFullPowerwash))
+ .ToString());
+}
+
TEST(UmBoxedValueTest, SetConnectionTypeToString) {
set<ConnectionType>* set1 = new set<ConnectionType>;
set1->insert(ConnectionType::kWimax);
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index ae2ec9d..95c47aa 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -141,8 +141,11 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
case ErrorCode::kUpdatedButNotActive:
case ErrorCode::kNoUpdate:
+ case ErrorCode::kRollbackNotPossible:
+ case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
LOG(INFO) << "Not changing URL index or failure count due to error "
<< chromeos_update_engine::utils::ErrorCodeToString(err_code)
<< " (" << static_cast<int>(err_code) << ")";
@@ -199,6 +202,8 @@
result->updates_enabled = true;
result->target_channel.clear();
result->target_version_prefix.clear();
+ result->rollback_allowed = false;
+ result->rollback_allowed_milestones = -1;
result->interactive = false;
EnoughSlotsAbUpdatesPolicyImpl enough_slots_ab_updates_policy;
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 095f516..bed4d53 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -189,8 +189,11 @@
// Override specific device policy attributes.
fake_state_.device_policy_provider()->var_target_version_prefix()->
reset(new string("1.2"));
- fake_state_.device_policy_provider()->var_release_channel_delegated()->
- reset(new bool(false));
+ fake_state_.device_policy_provider()
+ ->var_rollback_allowed_milestones()
+ ->reset(new int(5));
+ fake_state_.device_policy_provider()->var_release_channel_delegated()->reset(
+ new bool(false));
fake_state_.device_policy_provider()->var_release_channel()->
reset(new string("foo-channel"));
@@ -199,10 +202,70 @@
&Policy::UpdateCheckAllowed, &result);
EXPECT_TRUE(result.updates_enabled);
EXPECT_EQ("1.2", result.target_version_prefix);
+ EXPECT_EQ(5, result.rollback_allowed_milestones);
EXPECT_EQ("foo-channel", result.target_channel);
EXPECT_FALSE(result.interactive);
}
+TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackAllowed) {
+ // Update check is allowed, response includes attributes for use in the
+ // request.
+ SetUpdateCheckAllowed(true);
+
+ // Override RollbackToTargetVersion device policy attribute.
+ fake_state_.device_policy_provider()->var_rollback_to_target_version()->reset(
+ new RollbackToTargetVersion(
+ RollbackToTargetVersion::kRollbackWithFullPowerwash));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_TRUE(result.rollback_allowed);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackDisabled) {
+ // Update check is allowed, response includes attributes for use in the
+ // request.
+ SetUpdateCheckAllowed(true);
+
+ // Override RollbackToTargetVersion device policy attribute.
+ fake_state_.device_policy_provider()->var_rollback_to_target_version()->reset(
+ new RollbackToTargetVersion(RollbackToTargetVersion::kDisabled));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_FALSE(result.rollback_allowed);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackUnspecified) {
+ // Update check is allowed, response includes attributes for use in the
+ // request.
+ SetUpdateCheckAllowed(true);
+
+ // Override RollbackToTargetVersion device policy attribute.
+ fake_state_.device_policy_provider()->var_rollback_to_target_version()->reset(
+ new RollbackToTargetVersion(RollbackToTargetVersion::kUnspecified));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_FALSE(result.rollback_allowed);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackNotSet) {
+ // Update check is allowed, response includes attributes for use in the
+ // request.
+ SetUpdateCheckAllowed(true);
+
+ // Don't set RollbackToTargetVersion device policy attribute.
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_FALSE(result.rollback_allowed);
+}
+
TEST_F(UmChromeOSPolicyTest,
UpdateCheckAllowedUpdatesDisabledForUnofficialBuilds) {
// UpdateCheckAllowed should return kAskMeAgainLater if this is an unofficial
diff --git a/update_manager/default_policy.cc b/update_manager/default_policy.cc
index bc4f98e..5509abc 100644
--- a/update_manager/default_policy.cc
+++ b/update_manager/default_policy.cc
@@ -40,6 +40,8 @@
result->updates_enabled = true;
result->target_channel.clear();
result->target_version_prefix.clear();
+ result->rollback_allowed = false;
+ result->rollback_allowed_milestones = -1; // No version rolls should happen.
result->interactive = false;
// Ensure that the minimum interval is set. If there's no clock, this defaults
diff --git a/update_manager/device_policy_provider.h b/update_manager/device_policy_provider.h
index 3537d13..22613a1 100644
--- a/update_manager/device_policy_provider.h
+++ b/update_manager/device_policy_provider.h
@@ -24,6 +24,7 @@
#include <policy/libpolicy.h>
#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/rollback_prefs.h"
#include "update_engine/update_manager/shill_provider.h"
#include "update_engine/update_manager/variable.h"
@@ -46,6 +47,15 @@
virtual Variable<std::string>* var_target_version_prefix() = 0;
+ // Variable returning what should happen if the target_version_prefix is
+ // earlier than the current Chrome OS version.
+ virtual Variable<RollbackToTargetVersion>*
+ var_rollback_to_target_version() = 0;
+
+ // Variable returning the number of Chrome milestones rollback should be
+ // possible. Rollback protection will be postponed by this many versions.
+ virtual Variable<int>* var_rollback_allowed_milestones() = 0;
+
// Returns a non-negative scatter interval used for updates.
virtual Variable<base::TimeDelta>* var_scatter_factor() = 0;
diff --git a/update_manager/enterprise_device_policy_impl.cc b/update_manager/enterprise_device_policy_impl.cc
index 4e0def5..e2a0c87 100644
--- a/update_manager/enterprise_device_policy_impl.cc
+++ b/update_manager/enterprise_device_policy_impl.cc
@@ -68,14 +68,39 @@
result->target_version_prefix = *kiosk_required_platform_version_p;
LOG(INFO) << "Allow kiosk app to control Chrome version policy is set, "
<< "target version is " << result->target_version_prefix;
+ // TODO(hunyadym): Add support of rollback for kiosk apps.
} else {
// Determine whether a target version prefix is dictated by policy.
const string* target_version_prefix_p =
ec->GetValue(dp_provider->var_target_version_prefix());
if (target_version_prefix_p)
result->target_version_prefix = *target_version_prefix_p;
+
+ const RollbackToTargetVersion* rollback_to_target_version_p =
+ ec->GetValue(dp_provider->var_rollback_to_target_version());
+ if (rollback_to_target_version_p) {
+ switch (*rollback_to_target_version_p) {
+ case RollbackToTargetVersion::kUnspecified:
+ case RollbackToTargetVersion::kDisabled:
+ result->rollback_allowed = false;
+ break;
+ case RollbackToTargetVersion::kRollbackWithFullPowerwash:
+ result->rollback_allowed = true;
+ break;
+ case RollbackToTargetVersion::kMaxValue:
+ NOTREACHED();
+ // Don't add a default case to let the compiler warn about newly
+ // added enum values which should be added here.
+ }
+ }
}
+ // Determine allowed milestones for rollback
+ const int* rollback_allowed_milestones_p =
+ ec->GetValue(dp_provider->var_rollback_allowed_milestones());
+ if (rollback_allowed_milestones_p)
+ result->rollback_allowed_milestones = *rollback_allowed_milestones_p;
+
// Determine whether a target channel is dictated by policy.
const bool* release_channel_delegated_p =
ec->GetValue(dp_provider->var_release_channel_delegated());
diff --git a/update_manager/fake_device_policy_provider.h b/update_manager/fake_device_policy_provider.h
index 9e4f5b7..957341c 100644
--- a/update_manager/fake_device_policy_provider.h
+++ b/update_manager/fake_device_policy_provider.h
@@ -50,6 +50,15 @@
return &var_target_version_prefix_;
}
+ FakeVariable<RollbackToTargetVersion>* var_rollback_to_target_version()
+ override {
+ return &var_rollback_to_target_version_;
+ }
+
+ FakeVariable<int>* var_rollback_allowed_milestones() override {
+ return &var_rollback_allowed_milestones_;
+ }
+
FakeVariable<base::TimeDelta>* var_scatter_factor() override {
return &var_scatter_factor_;
}
@@ -86,6 +95,10 @@
"update_disabled", kVariableModePoll};
FakeVariable<std::string> var_target_version_prefix_{
"target_version_prefix", kVariableModePoll};
+ FakeVariable<RollbackToTargetVersion> var_rollback_to_target_version_{
+ "rollback_to_target_version", kVariableModePoll};
+ FakeVariable<int> var_rollback_allowed_milestones_{
+ "rollback_allowed_milestones", kVariableModePoll};
FakeVariable<base::TimeDelta> var_scatter_factor_{
"scatter_factor", kVariableModePoll};
FakeVariable<std::set<chromeos_update_engine::ConnectionType>>
diff --git a/update_manager/policy.h b/update_manager/policy.h
index f7a72d8..ee163b3 100644
--- a/update_manager/policy.h
+++ b/update_manager/policy.h
@@ -24,6 +24,7 @@
#include "update_engine/common/error_code.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/rollback_prefs.h"
#include "update_engine/update_manager/state.h"
namespace chromeos_update_manager {
@@ -47,6 +48,13 @@
//
// A target version prefix, if imposed by policy; otherwise, an empty string.
std::string target_version_prefix;
+ // Specifies whether rollback images are allowed by device policy.
+ bool rollback_allowed;
+ // Specifies the number of Chrome milestones rollback should be allowed,
+ // starting from the stable version at any time. Value is -1 if unspecified
+ // (e.g. no device policy is available yet), in this case no version
+ // roll-forward should happen.
+ int rollback_allowed_milestones;
// A target channel, if so imposed by policy; otherwise, an empty string.
std::string target_channel;
diff --git a/update_manager/real_device_policy_provider.cc b/update_manager/real_device_policy_provider.cc
index d9880c3..3675624 100644
--- a/update_manager/real_device_policy_provider.cc
+++ b/update_manager/real_device_policy_provider.cc
@@ -126,6 +126,23 @@
}
}
+bool RealDevicePolicyProvider::ConvertRollbackToTargetVersion(
+ RollbackToTargetVersion* rollback_to_target_version) const {
+ int rollback_to_target_version_int;
+ if (!policy_provider_->GetDevicePolicy().GetRollbackToTargetVersion(
+ &rollback_to_target_version_int)) {
+ return false;
+ }
+ if (rollback_to_target_version_int < 0 ||
+ rollback_to_target_version_int >=
+ static_cast<int>(RollbackToTargetVersion::kMaxValue)) {
+ return false;
+ }
+ *rollback_to_target_version =
+ static_cast<RollbackToTargetVersion>(rollback_to_target_version_int);
+ return true;
+}
+
bool RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate(
set<ConnectionType>* allowed_types) const {
set<string> allowed_types_str;
@@ -176,6 +193,14 @@
UpdateVariable(&var_update_disabled_, &DevicePolicy::GetUpdateDisabled);
UpdateVariable(&var_target_version_prefix_,
&DevicePolicy::GetTargetVersionPrefix);
+ UpdateVariable(&var_rollback_to_target_version_,
+ &RealDevicePolicyProvider::ConvertRollbackToTargetVersion);
+ UpdateVariable(&var_rollback_allowed_milestones_,
+ &DevicePolicy::GetRollbackAllowedMilestones);
+ if (policy_provider_->IsConsumerDevice()) {
+ // For consumer devices (which won't ever have policy), set value to 0.
+ var_rollback_allowed_milestones_.SetValue(0);
+ }
UpdateVariable(&var_scatter_factor_,
&RealDevicePolicyProvider::ConvertScatterFactor);
UpdateVariable(
diff --git a/update_manager/real_device_policy_provider.h b/update_manager/real_device_policy_provider.h
index 5b5ee58..54216f1 100644
--- a/update_manager/real_device_policy_provider.h
+++ b/update_manager/real_device_policy_provider.h
@@ -20,6 +20,7 @@
#include <memory>
#include <set>
#include <string>
+#include <utility>
#include <brillo/message_loops/message_loop.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
@@ -71,6 +72,14 @@
return &var_target_version_prefix_;
}
+ Variable<RollbackToTargetVersion>* var_rollback_to_target_version() override {
+ return &var_rollback_to_target_version_;
+ }
+
+ Variable<int>* var_rollback_allowed_milestones() override {
+ return &var_rollback_allowed_milestones_;
+ }
+
Variable<base::TimeDelta>* var_scatter_factor() override {
return &var_scatter_factor_;
}
@@ -130,6 +139,11 @@
AsyncCopyVariable<T>* var,
bool (RealDevicePolicyProvider::*getter_method)(T*) const);
+ // Wrapper for DevicePolicy::GetRollbackToTargetVersion() that converts the
+ // result to RollbackToTargetVersion.
+ bool ConvertRollbackToTargetVersion(
+ RollbackToTargetVersion* rollback_to_target_version) const;
+
// Wrapper for DevicePolicy::GetScatterFactorInSeconds() that converts the
// result to a base::TimeDelta. It returns the same value as
// GetScatterFactorInSeconds().
@@ -164,6 +178,10 @@
AsyncCopyVariable<bool> var_update_disabled_{"update_disabled"};
AsyncCopyVariable<std::string> var_target_version_prefix_{
"target_version_prefix"};
+ AsyncCopyVariable<RollbackToTargetVersion> var_rollback_to_target_version_{
+ "rollback_to_target_version"};
+ AsyncCopyVariable<int> var_rollback_allowed_milestones_{
+ "rollback_allowed_milestones"};
AsyncCopyVariable<base::TimeDelta> var_scatter_factor_{"scatter_factor"};
AsyncCopyVariable<std::set<chromeos_update_engine::ConnectionType>>
var_allowed_connection_types_for_update_{
diff --git a/update_manager/real_device_policy_provider_unittest.cc b/update_manager/real_device_policy_provider_unittest.cc
index 167cbd9..f5d0e23 100644
--- a/update_manager/real_device_policy_provider_unittest.cc
+++ b/update_manager/real_device_policy_provider_unittest.cc
@@ -178,6 +178,10 @@
UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel_delegated());
UmTestUtils::ExpectVariableNotSet(provider_->var_update_disabled());
UmTestUtils::ExpectVariableNotSet(provider_->var_target_version_prefix());
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_rollback_to_target_version());
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_rollback_allowed_milestones());
UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor());
UmTestUtils::ExpectVariableNotSet(
provider_->var_allowed_connection_types_for_update());
@@ -218,6 +222,61 @@
true, provider_->var_allow_kiosk_app_control_chrome_version());
}
+TEST_F(UmRealDevicePolicyProviderTest, RollbackToTargetVersionConverted) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetRollbackToTargetVersion(_))
+#if USE_DBUS
+ .Times(2)
+#else
+ .Times(1)
+#endif // USE_DBUS
+ .WillRepeatedly(DoAll(SetArgPointee<0>(2), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableHasValue(
+ RollbackToTargetVersion::kRollbackWithFullPowerwash,
+ provider_->var_rollback_to_target_version());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesOobe) {
+ SetUpNonExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0);
+ ON_CALL(mock_policy_provider_, IsConsumerDevice())
+ .WillByDefault(Return(false));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_rollback_allowed_milestones());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesConsumer) {
+ SetUpNonExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0);
+ ON_CALL(mock_policy_provider_, IsConsumerDevice())
+ .WillByDefault(Return(true));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableHasValue(
+ 0, provider_->var_rollback_allowed_milestones());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest,
+ RollbackAllowedMilestonesEnterprisePolicySet) {
+ SetUpExistentDevicePolicy();
+ ON_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(2), Return(true)));
+ ON_CALL(mock_policy_provider_, IsConsumerDevice())
+ .WillByDefault(Return(false));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableHasValue(
+ 2, provider_->var_rollback_allowed_milestones());
+}
+
TEST_F(UmRealDevicePolicyProviderTest, ScatterFactorConverted) {
SetUpExistentDevicePolicy();
EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
diff --git a/update_manager/real_shill_provider_unittest.cc b/update_manager/real_shill_provider_unittest.cc
index 6506923..af674d0 100644
--- a/update_manager/real_shill_provider_unittest.cc
+++ b/update_manager/real_shill_provider_unittest.cc
@@ -94,9 +94,7 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
+ return Time::FromLocalExploded(now_exp);
}
Time ConnChangedTime() {
diff --git a/update_manager/real_system_provider.cc b/update_manager/real_system_provider.cc
index fdf7e86..53e9ab3 100644
--- a/update_manager/real_system_provider.cc
+++ b/update_manager/real_system_provider.cc
@@ -21,7 +21,7 @@
#include <base/logging.h>
#include <base/time/time.h>
#if USE_CHROME_KIOSK_APP
-#include <libcros/dbus-proxies.h>
+#include <kiosk-app/dbus-proxies.h>
#endif // USE_CHROME_KIOSK_APP
#include "update_engine/common/utils.h"
@@ -126,8 +126,8 @@
string* required_platform_version) {
#if USE_CHROME_KIOSK_APP
brillo::ErrorPtr error;
- if (!libcros_proxy_->GetKioskAppRequiredPlatformVersion(
- required_platform_version, &error)) {
+ if (!kiosk_app_proxy_->GetRequiredPlatformVersion(required_platform_version,
+ &error)) {
LOG(WARNING) << "Failed to get kiosk required platform version";
required_platform_version->clear();
return false;
diff --git a/update_manager/real_system_provider.h b/update_manager/real_system_provider.h
index 80a8615..9d71d0d 100644
--- a/update_manager/real_system_provider.h
+++ b/update_manager/real_system_provider.h
@@ -26,7 +26,7 @@
namespace org {
namespace chromium {
-class LibCrosServiceInterfaceProxyInterface;
+class KioskAppServiceInterfaceProxyInterface;
} // namespace chromium
} // namespace org
@@ -38,11 +38,12 @@
RealSystemProvider(
chromeos_update_engine::HardwareInterface* hardware,
chromeos_update_engine::BootControlInterface* boot_control,
- org::chromium::LibCrosServiceInterfaceProxyInterface* libcros_proxy)
+ org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy)
: hardware_(hardware),
#if USE_CHROME_KIOSK_APP
boot_control_(boot_control),
- libcros_proxy_(libcros_proxy) {}
+ kiosk_app_proxy_(kiosk_app_proxy) {
+ }
#else
boot_control_(boot_control) {}
#endif // USE_CHROME_KIOSK_APP
@@ -83,7 +84,7 @@
chromeos_update_engine::HardwareInterface* const hardware_;
chromeos_update_engine::BootControlInterface* const boot_control_;
#if USE_CHROME_KIOSK_APP
- org::chromium::LibCrosServiceInterfaceProxyInterface* const libcros_proxy_;
+ org::chromium::KioskAppServiceInterfaceProxyInterface* const kiosk_app_proxy_;
#endif // USE_CHROME_KIOSK_APP
DISALLOW_COPY_AND_ASSIGN(RealSystemProvider);
diff --git a/update_manager/real_system_provider_unittest.cc b/update_manager/real_system_provider_unittest.cc
index 103a35f..4e4da67 100644
--- a/update_manager/real_system_provider_unittest.cc
+++ b/update_manager/real_system_provider_unittest.cc
@@ -26,10 +26,10 @@
#include "update_engine/common/fake_hardware.h"
#include "update_engine/update_manager/umtest_utils.h"
#if USE_CHROME_KIOSK_APP
-#include "libcros/dbus-proxies.h"
-#include "libcros/dbus-proxy-mocks.h"
+#include "kiosk-app/dbus-proxies.h"
+#include "kiosk-app/dbus-proxy-mocks.h"
-using org::chromium::LibCrosServiceInterfaceProxyMock;
+using org::chromium::KioskAppServiceInterfaceProxyMock;
#endif // USE_CHROME_KIOSK_APP
using std::unique_ptr;
using testing::_;
@@ -49,14 +49,13 @@
protected:
void SetUp() override {
#if USE_CHROME_KIOSK_APP
- libcros_proxy_mock_.reset(new LibCrosServiceInterfaceProxyMock());
- ON_CALL(*libcros_proxy_mock_,
- GetKioskAppRequiredPlatformVersion(_, _, _))
+ kiosk_app_proxy_mock_.reset(new KioskAppServiceInterfaceProxyMock());
+ ON_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
.WillByDefault(
DoAll(SetArgPointee<0>(kRequiredPlatformVersion), Return(true)));
provider_.reset(new RealSystemProvider(
- &fake_hardware_, &fake_boot_control_, libcros_proxy_mock_.get()));
+ &fake_hardware_, &fake_boot_control_, kiosk_app_proxy_mock_.get()));
#else
provider_.reset(
new RealSystemProvider(&fake_hardware_, &fake_boot_control_, nullptr));
@@ -69,7 +68,7 @@
unique_ptr<RealSystemProvider> provider_;
#if USE_CHROME_KIOSK_APP
- unique_ptr<LibCrosServiceInterfaceProxyMock> libcros_proxy_mock_;
+ unique_ptr<KioskAppServiceInterfaceProxyMock> kiosk_app_proxy_mock_;
#endif // USE_CHROME_KIOSK_APP
};
@@ -98,8 +97,7 @@
}
TEST_F(UmRealSystemProviderTest, KioskRequiredPlatformVersionFailure) {
- EXPECT_CALL(*libcros_proxy_mock_,
- GetKioskAppRequiredPlatformVersion(_, _, _))
+ EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
.WillOnce(Return(false));
UmTestUtils::ExpectVariableNotSet(
@@ -108,15 +106,13 @@
TEST_F(UmRealSystemProviderTest,
KioskRequiredPlatformVersionRecoveryFromFailure) {
- EXPECT_CALL(*libcros_proxy_mock_,
- GetKioskAppRequiredPlatformVersion(_, _, _))
+ EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
.WillOnce(Return(false));
UmTestUtils::ExpectVariableNotSet(
provider_->var_kiosk_required_platform_version());
- testing::Mock::VerifyAndClearExpectations(libcros_proxy_mock_.get());
+ testing::Mock::VerifyAndClearExpectations(kiosk_app_proxy_mock_.get());
- EXPECT_CALL(*libcros_proxy_mock_,
- GetKioskAppRequiredPlatformVersion(_, _, _))
+ EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
.WillOnce(
DoAll(SetArgPointee<0>(kRequiredPlatformVersion), Return(true)));
UmTestUtils::ExpectVariableHasValue(
diff --git a/update_manager/real_time_provider.cc b/update_manager/real_time_provider.cc
index db26816..ca3acad 100644
--- a/update_manager/real_time_provider.cc
+++ b/update_manager/real_time_provider.cc
@@ -43,10 +43,7 @@
Time::Exploded now_exp;
clock_->GetWallclockTime().LocalExplode(&now_exp);
now_exp.hour = now_exp.minute = now_exp.second = now_exp.millisecond = 0;
- Time* now = new Time();
- bool success = Time::FromLocalExploded(now_exp, now);
- DCHECK(success);
- return now;
+ return new Time(Time::FromLocalExploded(now_exp));
}
private:
diff --git a/update_manager/real_time_provider_unittest.cc b/update_manager/real_time_provider_unittest.cc
index f8db30b..0e1ef34 100644
--- a/update_manager/real_time_provider_unittest.cc
+++ b/update_manager/real_time_provider_unittest.cc
@@ -51,9 +51,7 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
+ return Time::FromLocalExploded(now_exp);
}
FakeClock fake_clock_;
@@ -68,8 +66,7 @@
exploded.minute = 0;
exploded.second = 0;
exploded.millisecond = 0;
- Time expected;
- ignore_result(Time::FromLocalExploded(exploded, &expected));
+ const Time expected = Time::FromLocalExploded(exploded);
fake_clock_.SetWallclockTime(now);
UmTestUtils::ExpectVariableHasValue(expected, provider_->var_curr_date());
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
index b653885..efe042c 100644
--- a/update_manager/real_updater_provider_unittest.cc
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -57,9 +57,7 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
+ return Time::FromLocalExploded(now_exp);
}
// Rounds down a timestamp to the nearest second. This is useful when faking
@@ -68,9 +66,7 @@
Time::Exploded exp;
time.LocalExplode(&exp);
exp.millisecond = 0;
- Time rounded_time;
- ignore_result(Time::FromLocalExploded(exp, &rounded_time));
- return rounded_time;
+ return Time::FromLocalExploded(exp);
}
ACTION_P(ActionSetUpdateEngineStatusLastCheckedTime, time) {
diff --git a/update_manager/rollback_prefs.h b/update_manager/rollback_prefs.h
new file mode 100644
index 0000000..1783eb0
--- /dev/null
+++ b/update_manager/rollback_prefs.h
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 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 UPDATE_ENGINE_UPDATE_MANAGER_ROLLBACK_PREFS_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ROLLBACK_PREFS_H_
+
+namespace chromeos_update_manager {
+
+// Value used to represent that kernel key versions can always roll-forward.
+// This is the maximum value of a kernel key version.
+constexpr int kRollforwardInfinity = 0xfffffffe;
+
+// Whether the device should roll back to the target version, and if yes, which
+// type of rollback should it do. Matches chrome_device_policy.proto's
+// AutoUpdateSettingsProto::RollbackToTargetVersion.
+enum class RollbackToTargetVersion {
+ kUnspecified = 0,
+ kDisabled = 1,
+ kRollbackWithFullPowerwash = 2,
+ // This value must be the last entry.
+ kMaxValue = 3
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_ROLLBACK_PREFS_H_
diff --git a/update_manager/state_factory.cc b/update_manager/state_factory.cc
index 208ed51..7293692 100644
--- a/update_manager/state_factory.cc
+++ b/update_manager/state_factory.cc
@@ -46,7 +46,7 @@
State* DefaultStateFactory(
policy::PolicyProvider* policy_provider,
- org::chromium::LibCrosServiceInterfaceProxyInterface* libcros_proxy,
+ org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy,
chromeos_update_engine::SystemState* system_state) {
chromeos_update_engine::ClockInterface* const clock = system_state->clock();
unique_ptr<RealConfigProvider> config_provider(
@@ -70,7 +70,7 @@
#endif // USE_SHILL
unique_ptr<RealRandomProvider> random_provider(new RealRandomProvider());
unique_ptr<RealSystemProvider> system_provider(new RealSystemProvider(
- system_state->hardware(), system_state->boot_control(), libcros_proxy));
+ system_state->hardware(), system_state->boot_control(), kiosk_app_proxy));
unique_ptr<RealTimeProvider> time_provider(new RealTimeProvider(clock));
unique_ptr<RealUpdaterProvider> updater_provider(
diff --git a/update_manager/state_factory.h b/update_manager/state_factory.h
index 689684a..1c1c1d9 100644
--- a/update_manager/state_factory.h
+++ b/update_manager/state_factory.h
@@ -22,7 +22,7 @@
namespace org {
namespace chromium {
-class LibCrosServiceInterfaceProxyInterface;
+class KioskAppServiceInterfaceProxyInterface;
} // namespace chromium
} // namespace org
@@ -35,7 +35,7 @@
// to initialize.
State* DefaultStateFactory(
policy::PolicyProvider* policy_provider,
- org::chromium::LibCrosServiceInterfaceProxyInterface* libcros_proxy,
+ org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy,
chromeos_update_engine::SystemState* system_state);
} // namespace chromeos_update_manager
diff --git a/update_manager/update_manager_unittest.cc b/update_manager/update_manager_unittest.cc
index 125a60c..9625b53 100644
--- a/update_manager/update_manager_unittest.cc
+++ b/update_manager/update_manager_unittest.cc
@@ -67,9 +67,7 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
+ return Time::FromLocalExploded(now_exp);
}
} // namespace
diff --git a/update_status_utils.cc b/update_status_utils.cc
index ff039b8..5de3381 100644
--- a/update_status_utils.cc
+++ b/update_status_utils.cc
@@ -30,6 +30,8 @@
return update_engine::kUpdateStatusCheckingForUpdate;
case UpdateStatus::UPDATE_AVAILABLE:
return update_engine::kUpdateStatusUpdateAvailable;
+ case UpdateStatus::NEED_PERMISSION_TO_UPDATE:
+ return update_engine::kUpdateStatusNeedPermissionToUpdate;
case UpdateStatus::DOWNLOADING:
return update_engine::kUpdateStatusDownloading;
case UpdateStatus::VERIFYING:
@@ -61,6 +63,9 @@
} else if (s == update_engine::kUpdateStatusUpdateAvailable) {
*status = UpdateStatus::UPDATE_AVAILABLE;
return true;
+ } else if (s == update_engine::kUpdateStatusNeedPermissionToUpdate) {
+ *status = UpdateStatus::NEED_PERMISSION_TO_UPDATE;
+ return true;
} else if (s == update_engine::kUpdateStatusDownloading) {
*status = UpdateStatus::DOWNLOADING;
return true;