Export AIDL files as a filegroup framework.jar am: 606913a005 am: 52c8a30e37
am: bed28418f9
Change-Id: I5953b78425a9ccbbed265c83e4b90442ff1061d2
diff --git a/Android.mk b/Android.mk
index 6a23168..8f1de53 100644
--- a/Android.mk
+++ b/Android.mk
@@ -305,10 +305,15 @@
proxy_resolver.cc \
real_system_state.cc \
update_attempter.cc \
+ update_manager/android_things_policy.cc \
+ update_manager/api_restricted_downloads_policy_impl.cc \
update_manager/boxed_value.cc \
- update_manager/chromeos_policy.cc \
update_manager/default_policy.cc \
+ update_manager/enough_slots_ab_updates_policy_impl.cc \
update_manager/evaluation_context.cc \
+ update_manager/interactive_update_policy_impl.cc \
+ update_manager/next_update_check_policy_impl.cc \
+ update_manager/official_build_check_policy_impl.cc \
update_manager/policy.cc \
update_manager/real_config_provider.cc \
update_manager/real_device_policy_provider.cc \
@@ -969,10 +974,14 @@
payload_state_unittest.cc \
parcelable_update_engine_status_unittest.cc \
update_attempter_unittest.cc \
+ update_manager/android_things_policy_unittest.cc \
update_manager/boxed_value_unittest.cc \
+ update_manager/chromeos_policy.cc \
update_manager/chromeos_policy_unittest.cc \
update_manager/evaluation_context_unittest.cc \
update_manager/generic_variables_unittest.cc \
+ update_manager/next_update_check_policy_impl_unittest.cc \
+ update_manager/policy_test_utils.cc \
update_manager/prng_unittest.cc \
update_manager/real_device_policy_provider_unittest.cc \
update_manager/real_random_provider_unittest.cc \
diff --git a/binder_bindings/android/brillo/IUpdateEngine.aidl b/binder_bindings/android/brillo/IUpdateEngine.aidl
index b1a1b4f..e549a4d 100644
--- a/binder_bindings/android/brillo/IUpdateEngine.aidl
+++ b/binder_bindings/android/brillo/IUpdateEngine.aidl
@@ -20,7 +20,8 @@
import android.brillo.ParcelableUpdateEngineStatus;
interface IUpdateEngine {
- void AttemptUpdate(in String app_version, in String omaha_url, in int flags);
+ void SetUpdateAttemptFlags(in int flags);
+ boolean AttemptUpdate(in String app_version, in String omaha_url, in int flags);
void AttemptRollback(in boolean powerwash);
boolean CanRollback();
void ResetStatus();
diff --git a/binder_service_brillo.cc b/binder_service_brillo.cc
index 74803c4..3f01e42 100644
--- a/binder_service_brillo.cc
+++ b/binder_service_brillo.cc
@@ -58,12 +58,20 @@
return ToStatus(&error);
}
+Status BinderUpdateEngineBrilloService::SetUpdateAttemptFlags(int flags) {
+ return CallCommonHandler(&UpdateEngineService::SetUpdateAttemptFlags, flags);
+}
+
Status BinderUpdateEngineBrilloService::AttemptUpdate(
- const String16& app_version, const String16& omaha_url, int flags) {
+ const String16& app_version,
+ const String16& omaha_url,
+ int flags,
+ bool* out_result) {
return CallCommonHandler(&UpdateEngineService::AttemptUpdate,
NormalString(app_version),
NormalString(omaha_url),
- flags);
+ flags,
+ out_result);
}
Status BinderUpdateEngineBrilloService::AttemptRollback(bool powerwash) {
diff --git a/binder_service_brillo.h b/binder_service_brillo.h
index 51f0fab..c802fca 100644
--- a/binder_service_brillo.h
+++ b/binder_service_brillo.h
@@ -51,9 +51,11 @@
void SendPayloadApplicationComplete(ErrorCode error_code) override {}
// android::brillo::BnUpdateEngine overrides.
+ android::binder::Status SetUpdateAttemptFlags(int flags) override;
android::binder::Status AttemptUpdate(const android::String16& app_version,
const android::String16& omaha_url,
- int flags) override;
+ int flags,
+ bool* out_result) override;
android::binder::Status AttemptRollback(bool powerwash) override;
android::binder::Status CanRollback(bool* out_can_rollback) override;
android::binder::Status ResetStatus() override;
diff --git a/client_library/client_binder.cc b/client_library/client_binder.cc
index fecd9a3..54b33ed 100644
--- a/client_library/client_binder.cc
+++ b/client_library/client_binder.cc
@@ -25,15 +25,15 @@
#include "update_engine/parcelable_update_engine_status.h"
#include "update_engine/update_status_utils.h"
-using android::OK;
-using android::String16;
-using android::String8;
using android::binder::Status;
using android::brillo::ParcelableUpdateEngineStatus;
using android::getService;
+using android::OK;
+using android::String16;
+using android::String8;
using chromeos_update_engine::StringToUpdateStatus;
-using chromeos_update_engine::UpdateEngineService;
using std::string;
+using update_engine::UpdateAttemptFlags;
namespace update_engine {
namespace internal {
@@ -48,10 +48,14 @@
bool BinderUpdateEngineClient::AttemptUpdate(const string& in_app_version,
const string& in_omaha_url,
bool at_user_request) {
- return service_->AttemptUpdate(String16{in_app_version.c_str()},
- String16{in_omaha_url.c_str()},
- at_user_request ? 0 :
- UpdateEngineService::kAttemptUpdateFlagNonInteractive).isOk();
+ bool started;
+ return service_
+ ->AttemptUpdate(
+ String16{in_app_version.c_str()},
+ String16{in_omaha_url.c_str()},
+ at_user_request ? 0 : UpdateAttemptFlags::kFlagNonInteractive,
+ &started)
+ .isOk();
}
bool BinderUpdateEngineClient::GetStatus(int64_t* out_last_checked_time,
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h
index 76dd865..d93ca91 100644
--- a/client_library/include/update_engine/update_status.h
+++ b/client_library/include/update_engine/update_status.h
@@ -34,6 +34,32 @@
DISABLED,
};
+// Enum of bit-wise flags for controlling how updates are attempted.
+enum UpdateAttemptFlags : int32_t {
+ kNone = 0,
+ // Treat the update like a non-interactive update, even when being triggered
+ // by the interactive APIs.
+ kFlagNonInteractive = (1 << 0),
+ // Restrict (disallow) downloading of updates.
+ kFlagRestrictDownload = (1 << 1),
+};
+
+// These bit-wise operators for the above flags allow for standard bit-wise
+// operations to return values in an expected manner, with the need to
+// continually cast the results back to UpdateAttemptFlags after the implicit
+// conversion to int from enum to perform the bitwise comparison using the
+// underlying type.
+inline UpdateAttemptFlags operator|(const UpdateAttemptFlags& l,
+ const UpdateAttemptFlags& r) {
+ return static_cast<UpdateAttemptFlags>(static_cast<const int32_t&>(l) |
+ static_cast<const int32_t&>(r));
+}
+inline UpdateAttemptFlags operator&(const UpdateAttemptFlags& l,
+ const UpdateAttemptFlags& r) {
+ return static_cast<UpdateAttemptFlags>(static_cast<const int32_t&>(l) &
+ static_cast<const int32_t&>(r));
+}
+
struct UpdateEngineStatus {
// When the update_engine last checked for updates (ms since Epoch)
int64_t last_checked_time_ms;
diff --git a/common_service.cc b/common_service.cc
index 15feca7..370587b 100644
--- a/common_service.cc
+++ b/common_service.cc
@@ -43,6 +43,7 @@
using brillo::string_utils::ToString;
using std::set;
using std::string;
+using update_engine::UpdateAttemptFlags;
using update_engine::UpdateEngineStatus;
namespace chromeos_update_engine {
@@ -72,19 +73,35 @@
// org::chromium::UpdateEngineInterfaceInterface methods implementation.
+bool UpdateEngineService::SetUpdateAttemptFlags(ErrorPtr* /* error */,
+ int32_t in_flags_as_int) {
+ auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
+ LOG(INFO) << "Setting Update Attempt Flags: "
+ << "flags=0x" << std::hex << flags << " "
+ << "RestrictDownload="
+ << ((flags & UpdateAttemptFlags::kFlagRestrictDownload) ? "yes"
+ : "no");
+ system_state_->update_attempter()->SetUpdateAttemptFlags(flags);
+ return true;
+}
+
bool UpdateEngineService::AttemptUpdate(ErrorPtr* /* error */,
const string& in_app_version,
const string& in_omaha_url,
- int32_t in_flags_as_int) {
- AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(in_flags_as_int);
- bool interactive = !(flags & kAttemptUpdateFlagNonInteractive);
+ int32_t in_flags_as_int,
+ bool* out_result) {
+ auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
+ bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
+ bool restrict_downloads = (flags & UpdateAttemptFlags::kFlagRestrictDownload);
LOG(INFO) << "Attempt update: app_version=\"" << in_app_version << "\" "
<< "omaha_url=\"" << in_omaha_url << "\" "
<< "flags=0x" << std::hex << flags << " "
- << "interactive=" << (interactive ? "yes" : "no");
- system_state_->update_attempter()->CheckForUpdate(
- in_app_version, in_omaha_url, interactive);
+ << "interactive=" << (interactive ? "yes " : "no ")
+ << "RestrictDownload=" << (restrict_downloads ? "yes " : "no ");
+
+ *out_result = system_state_->update_attempter()->CheckForUpdate(
+ in_app_version, in_omaha_url, flags);
return true;
}
diff --git a/common_service.h b/common_service.h
index 7e7fea8..544dd93 100644
--- a/common_service.h
+++ b/common_service.h
@@ -31,11 +31,6 @@
class UpdateEngineService {
public:
- // Flags used in the AttemptUpdateWithFlags() D-Bus method.
- typedef enum {
- kAttemptUpdateFlagNonInteractive = (1<<0)
- } AttemptUpdateFlags;
-
// Error domain for all the service errors.
static const char* const kErrorDomain;
@@ -45,10 +40,17 @@
explicit UpdateEngineService(SystemState* system_state);
virtual ~UpdateEngineService() = default;
+ // Set flags that influence how updates and checks are performed. These
+ // influence all future checks and updates until changed or the device
+ // reboots. The |in_flags_as_int| values are a union of values from
+ // |UpdateAttemptFlags|
+ bool SetUpdateAttemptFlags(brillo::ErrorPtr* error, int32_t in_flags_as_int);
+
bool AttemptUpdate(brillo::ErrorPtr* error,
const std::string& in_app_version,
const std::string& in_omaha_url,
- int32_t in_flags_as_int);
+ int32_t in_flags_as_int,
+ bool* out_result);
bool AttemptRollback(brillo::ErrorPtr* error, bool in_powerwash);
diff --git a/common_service_unittest.cc b/common_service_unittest.cc
index 0a7bfc3..c124466 100644
--- a/common_service_unittest.cc
+++ b/common_service_unittest.cc
@@ -28,9 +28,10 @@
#include "update_engine/omaha_utils.h"
using std::string;
+using testing::_;
using testing::Return;
using testing::SetArgumentPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
namespace chromeos_update_engine {
@@ -56,13 +57,32 @@
};
TEST_F(UpdateEngineServiceTest, AttemptUpdate) {
- EXPECT_CALL(*mock_update_attempter_, CheckForUpdate(
- "app_ver", "url", false /* interactive */));
- // The update is non-interactive when we pass the non-interactive flag.
- EXPECT_TRUE(common_service_.AttemptUpdate(
- &error_, "app_ver", "url",
- UpdateEngineService::kAttemptUpdateFlagNonInteractive));
+ EXPECT_CALL(
+ *mock_update_attempter_,
+ CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kFlagNonInteractive))
+ .WillOnce(Return(true));
+
+ // The non-interactive flag needs to be passed through to CheckForUpdate.
+ bool result = false;
+ EXPECT_TRUE(
+ common_service_.AttemptUpdate(&error_,
+ "app_ver",
+ "url",
+ UpdateAttemptFlags::kFlagNonInteractive,
+ &result));
EXPECT_EQ(nullptr, error_);
+ EXPECT_TRUE(result);
+}
+
+TEST_F(UpdateEngineServiceTest, AttemptUpdateReturnsFalse) {
+ EXPECT_CALL(*mock_update_attempter_,
+ CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kNone))
+ .WillOnce(Return(false));
+ bool result = true;
+ EXPECT_TRUE(common_service_.AttemptUpdate(
+ &error_, "app_ver", "url", UpdateAttemptFlags::kNone, &result));
+ EXPECT_EQ(nullptr, error_);
+ EXPECT_FALSE(result);
}
// SetChannel is allowed when there's no device policy (the device is not
diff --git a/mock_update_attempter.h b/mock_update_attempter.h
index 9634bab..d88b840 100644
--- a/mock_update_attempter.h
+++ b/mock_update_attempter.h
@@ -42,9 +42,12 @@
MOCK_METHOD0(ResetStatus, bool(void));
- MOCK_METHOD3(CheckForUpdate, void(const std::string& app_version,
- const std::string& omaha_url,
- bool is_interactive));
+ MOCK_METHOD0(GetCurrentUpdateAttemptFlags, UpdateAttemptFlags(void));
+
+ MOCK_METHOD3(CheckForUpdate,
+ bool(const std::string& app_version,
+ const std::string& omaha_url,
+ UpdateAttemptFlags flags));
MOCK_METHOD0(RefreshDevicePolicy, void(void));
diff --git a/omaha_response_handler_action.cc b/omaha_response_handler_action.cc
index d23c14e..9c5fb4a 100644
--- a/omaha_response_handler_action.cc
+++ b/omaha_response_handler_action.cc
@@ -31,7 +31,11 @@
#include "update_engine/omaha_request_params.h"
#include "update_engine/payload_consumer/delta_performer.h"
#include "update_engine/payload_state_interface.h"
+#include "update_engine/update_manager/policy.h"
+#include "update_engine/update_manager/update_manager.h"
+using chromeos_update_manager::Policy;
+using chromeos_update_manager::UpdateManager;
using std::string;
namespace chromeos_update_engine {
@@ -158,7 +162,14 @@
chmod(deadline_file_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
- completer.set_code(ErrorCode::kSuccess);
+ // Check the generated install-plan with the Policy to confirm that
+ // it can be applied at this time (or at all).
+ UpdateManager* const update_manager = system_state_->update_manager();
+ CHECK(update_manager);
+ auto ec = ErrorCode::kSuccess;
+ update_manager->PolicyRequest(
+ &Policy::UpdateCanBeApplied, &ec, &install_plan_);
+ completer.set_code(ec);
}
bool OmahaResponseHandlerAction::AreHashChecksMandatory(
diff --git a/omaha_response_handler_action.h b/omaha_response_handler_action.h
index 51dfa7a..2974841 100644
--- a/omaha_response_handler_action.h
+++ b/omaha_response_handler_action.h
@@ -89,6 +89,7 @@
friend class OmahaResponseHandlerActionTest;
FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
+ 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 935ae5d..0887e1f 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -20,6 +20,7 @@
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
+#include <brillo/message_loops/fake_message_loop.h>
#include <gtest/gtest.h>
#include "update_engine/common/constants.h"
@@ -29,11 +30,17 @@
#include "update_engine/fake_system_state.h"
#include "update_engine/mock_payload_state.h"
#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/update_manager/mock_policy.h"
using chromeos_update_engine::test_utils::System;
using chromeos_update_engine::test_utils::WriteFileString;
+using chromeos_update_manager::EvalStatus;
+using chromeos_update_manager::FakeUpdateManager;
+using chromeos_update_manager::MockPolicy;
using std::string;
+using testing::DoAll;
using testing::Return;
+using testing::SetArgPointee;
using testing::_;
namespace chromeos_update_engine {
@@ -58,6 +65,13 @@
const string& deadline_file,
InstallPlan* out);
+ // Pointer to the Action, valid after |DoTest|, released when the test is
+ // finished.
+ std::unique_ptr<OmahaResponseHandlerAction> action_;
+ // Captures the action's result code, for tests that need to directly verify
+ // it in non-success cases.
+ ErrorCode action_result_code_;
+
FakeSystemState fake_system_state_;
// "Hash+"
const brillo::Blob expected_hash_ = {0x48, 0x61, 0x73, 0x68, 0x2b};
@@ -99,6 +113,8 @@
const OmahaResponse& in,
const string& test_deadline_file,
InstallPlan* out) {
+ brillo::FakeMessageLoop loop(nullptr);
+ loop.SetAsCurrent();
ActionProcessor processor;
OmahaResponseHandlerActionProcessorDelegate delegate;
processor.set_delegate(&delegate);
@@ -123,15 +139,15 @@
EXPECT_CALL(*(fake_system_state_.mock_payload_state()), GetCurrentUrl())
.WillRepeatedly(Return(current_url));
- OmahaResponseHandlerAction response_handler_action(
+ action_.reset(new OmahaResponseHandlerAction(
&fake_system_state_,
- (test_deadline_file.empty() ?
- constants::kOmahaResponseDeadlineFile : test_deadline_file));
- BondActions(&feeder_action, &response_handler_action);
+ (test_deadline_file.empty() ? constants::kOmahaResponseDeadlineFile
+ : test_deadline_file)));
+ BondActions(&feeder_action, action_.get());
ObjectCollectorAction<InstallPlan> collector_action;
- BondActions(&response_handler_action, &collector_action);
+ BondActions(action_.get(), &collector_action);
processor.EnqueueAction(&feeder_action);
- processor.EnqueueAction(&response_handler_action);
+ processor.EnqueueAction(action_.get());
processor.EnqueueAction(&collector_action);
processor.StartProcessing();
EXPECT_TRUE(!processor.IsRunning())
@@ -139,6 +155,7 @@
if (out)
*out = collector_action.object();
EXPECT_TRUE(delegate.code_set_);
+ action_result_code_ = delegate.code_;
return delegate.code_ == ErrorCode::kSuccess;
}
@@ -480,4 +497,36 @@
EXPECT_EQ(in.system_version, install_plan.system_version);
}
+TEST_F(OmahaResponseHandlerActionTest, TestDeferredByPolicy) {
+ OmahaResponse in;
+ in.update_exists = true;
+ in.version = "a.b.c.d";
+ in.packages.push_back({.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
+ .size = 12,
+ .hash = kPayloadHashHex});
+ // Setup the UpdateManager to disallow the update.
+ FakeClock fake_clock;
+ MockPolicy* mock_policy = new MockPolicy(&fake_clock);
+ FakeUpdateManager* fake_update_manager =
+ fake_system_state_.fake_update_manager();
+ fake_update_manager->set_policy(mock_policy);
+ EXPECT_CALL(*mock_policy, UpdateCanBeApplied(_, _, _, _, _))
+ .WillOnce(
+ DoAll(SetArgPointee<3>(ErrorCode::kOmahaUpdateDeferredPerPolicy),
+ Return(EvalStatus::kSucceeded)));
+ // Perform the Action. It should "fail" with kOmahaUpdateDeferredPerPolicy.
+ InstallPlan install_plan;
+ EXPECT_FALSE(DoTest(in, "", &install_plan));
+ EXPECT_EQ(ErrorCode::kOmahaUpdateDeferredPerPolicy, action_result_code_);
+ // Verify that DoTest() didn't set the output install plan.
+ EXPECT_EQ("", install_plan.version);
+ // Copy the underlying InstallPlan from the Action (like a real Delegate).
+ install_plan = action_->install_plan();
+ // Now verify the InstallPlan that was generated.
+ 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);
+ EXPECT_EQ(in.version, install_plan.version);
+}
+
} // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 9a8900d..a6f9fa5 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -78,6 +78,7 @@
using std::shared_ptr;
using std::string;
using std::vector;
+using update_engine::UpdateAttemptFlags;
using update_engine::UpdateEngineStatus;
namespace chromeos_update_engine {
@@ -772,9 +773,20 @@
return BootControlInterface::kInvalidSlot;
}
-void UpdateAttempter::CheckForUpdate(const string& app_version,
+bool UpdateAttempter::CheckForUpdate(const string& app_version,
const string& omaha_url,
- bool interactive) {
+ UpdateAttemptFlags flags) {
+ bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
+
+ if (interactive && status_ != UpdateStatus::IDLE) {
+ // An update check is either in-progress, or an update has completed and the
+ // system is in UPDATED_NEED_REBOOT. Either way, don't do an interactive
+ // update at this time
+ LOG(INFO) << "Refusing to do an interactive update with an update already "
+ "in progress";
+ return false;
+ }
+
LOG(INFO) << "Forced update check requested.";
forced_app_version_.clear();
forced_omaha_url_.clear();
@@ -796,12 +808,22 @@
forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
}
+ if (interactive) {
+ // Use the passed-in update attempt flags for this update attempt instead
+ // of the previously set ones.
+ current_update_attempt_flags_ = flags;
+ // Note: The caching for non-interactive update checks happens in
+ // OnUpdateScheduled().
+ }
+
if (forced_update_pending_callback_.get()) {
// Make sure that a scheduling request is made prior to calling the forced
// update pending callback.
ScheduleUpdates();
forced_update_pending_callback_->Run(true, interactive);
}
+
+ return true;
}
bool UpdateAttempter::RebootIfNeeded() {
@@ -859,6 +881,15 @@
<< (params.is_interactive ? "interactive" : "periodic")
<< " update.";
+ if (!params.is_interactive) {
+ // Cache the update attempt flags that will be used by this update attempt
+ // so that they can't be changed mid-way through.
+ current_update_attempt_flags_ = update_attempt_flags_;
+ }
+
+ LOG(INFO) << "Update attempt flags in use = 0x" << std::hex
+ << current_update_attempt_flags_;
+
Update(forced_app_version_, forced_omaha_url_, params.target_channel,
params.target_version_prefix, false, params.is_interactive);
// Always clear the forced app_version and omaha_url after an update attempt
@@ -892,6 +923,9 @@
// Reset cpu shares back to normal.
cpu_limiter_.StopLimiter();
+ // reset the state that's only valid for a single update pass
+ current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
+
if (status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
LOG(INFO) << "Error event sent.";
@@ -1012,7 +1046,28 @@
server_dictated_poll_interval_ =
std::max(0, omaha_request_action->GetOutputObject().poll_interval);
}
+ } else if (type == OmahaResponseHandlerAction::StaticType()) {
+ // Depending on the returned error code, note that an update is available.
+ if (code == ErrorCode::kOmahaUpdateDeferredPerPolicy ||
+ code == ErrorCode::kSuccess) {
+ // Note that the status will be updated to DOWNLOADING when some bytes
+ // get actually downloaded from the server and the BytesReceived
+ // callback is invoked. This avoids notifying the user that a download
+ // has started in cases when the server and the client are unable to
+ // initiate the download.
+ CHECK(action == response_handler_action_.get());
+ auto plan = response_handler_action_->install_plan();
+ UpdateLastCheckedTime();
+ new_version_ = plan.version;
+ new_system_version_ = plan.system_version;
+ new_payload_size_ = 0;
+ for (const auto& payload : plan.payloads)
+ new_payload_size_ += payload.size;
+ cpu_limiter_.StartLimiter();
+ SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
+ }
}
+ // General failure cases.
if (code != ErrorCode::kSuccess) {
// 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
@@ -1025,23 +1080,8 @@
CreatePendingErrorEvent(action, code);
return;
}
- // Find out which action completed.
- if (type == OmahaResponseHandlerAction::StaticType()) {
- // Note that the status will be updated to DOWNLOADING when some bytes get
- // actually downloaded from the server and the BytesReceived callback is
- // invoked. This avoids notifying the user that a download has started in
- // cases when the server and the client are unable to initiate the download.
- CHECK(action == response_handler_action_.get());
- const InstallPlan& plan = response_handler_action_->install_plan();
- UpdateLastCheckedTime();
- new_version_ = plan.version;
- new_system_version_ = plan.system_version;
- new_payload_size_ = 0;
- for (const auto& payload : plan.payloads)
- new_payload_size_ += payload.size;
- cpu_limiter_.StartLimiter();
- SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
- } else if (type == DownloadAction::StaticType()) {
+ // Find out which action completed (successfully).
+ if (type == DownloadAction::StaticType()) {
SetStatusAndNotify(UpdateStatus::FINALIZING);
}
}
diff --git a/update_attempter.h b/update_attempter.h
index 4aac60a..d2fe3ec 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -66,6 +66,7 @@
public PostinstallRunnerAction::DelegateInterface {
public:
using UpdateStatus = update_engine::UpdateStatus;
+ using UpdateAttemptFlags = update_engine::UpdateAttemptFlags;
static const int kMaxDeltaUpdateFailures;
UpdateAttempter(SystemState* system_state,
@@ -130,12 +131,28 @@
int http_response_code() const { return http_response_code_; }
void set_http_response_code(int code) { http_response_code_ = code; }
+ // Set flags that influence how updates and checks are performed. These
+ // influence all future checks and updates until changed or the device
+ // reboots.
+ void SetUpdateAttemptFlags(UpdateAttemptFlags flags) {
+ update_attempt_flags_ = flags;
+ }
+
+ // Returns the update attempt flags that are in place for the current update
+ // attempt. These are cached at the start of an update attempt so that they
+ // remain constant throughout the process.
+ virtual UpdateAttemptFlags GetCurrentUpdateAttemptFlags() {
+ return current_update_attempt_flags_;
+ }
+
// This is the internal entry point for going through an
// update. If the current status is idle invokes Update.
// This is called by the DBus implementation.
- virtual void CheckForUpdate(const std::string& app_version,
+ // This returns true if an update check was started, false if a check or an
+ // update was already in progress.
+ virtual bool CheckForUpdate(const std::string& app_version,
const std::string& omaha_url,
- bool is_interactive);
+ UpdateAttemptFlags flags);
// This is the internal entry point for going through a rollback. This will
// attempt to run the postinstall on the non-active partition and set it as
@@ -259,6 +276,9 @@
FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest);
FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionTest);
FRIEND_TEST(UpdateAttempterTest, TargetVersionPrefixSetAndReset);
+ FRIEND_TEST(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart);
+ FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
+ FRIEND_TEST(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable);
FRIEND_TEST(UpdateAttempterTest, UpdateTest);
// CertificateChecker::Observer method.
@@ -437,6 +457,11 @@
std::string new_version_ = "0.0.0.0";
std::string new_system_version_;
uint64_t new_payload_size_ = 0;
+ // Flags influencing all periodic update checks
+ UpdateAttemptFlags update_attempt_flags_ = UpdateAttemptFlags::kNone;
+ // Flags influencing the currently in-progress check (cached at the start of
+ // the update check).
+ UpdateAttemptFlags current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
// Common parameters for all Omaha requests.
OmahaRequestParams* omaha_request_params_ = nullptr;
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index dfeebcf..bdc0196 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -62,10 +62,17 @@
using base::Time;
using base::TimeDelta;
+using chromeos_update_manager::EvalStatus;
+using chromeos_update_manager::UpdateCheckParams;
using org::chromium::NetworkProxyServiceInterfaceProxyInterface;
using org::chromium::NetworkProxyServiceInterfaceProxyMock;
+#if USE_LIBCROS
+using org::chromium::LibCrosServiceInterfaceProxyMock;
+using org::chromium::UpdateEngineLibcrosProxyResolvedInterfaceProxyMock;
+#endif // USE_LIBCROS
using std::string;
using std::unique_ptr;
+using testing::_;
using testing::DoAll;
using testing::Field;
using testing::InSequence;
@@ -76,7 +83,7 @@
using testing::ReturnPointee;
using testing::SaveArg;
using testing::SetArgumentPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
using update_engine::UpdateEngineStatus;
using update_engine::UpdateStatus;
@@ -1042,14 +1049,14 @@
TEST_F(UpdateAttempterTest, CheckForUpdateAUTest) {
fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
- attempter_.CheckForUpdate("", "autest", true);
+ attempter_.CheckForUpdate("", "autest", UpdateAttemptFlags::kNone);
EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
}
TEST_F(UpdateAttempterTest, CheckForUpdateScheduledAUTest) {
fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
- attempter_.CheckForUpdate("", "autest-scheduled", true);
+ attempter_.CheckForUpdate("", "autest-scheduled", UpdateAttemptFlags::kNone);
EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
}
@@ -1063,4 +1070,90 @@
fake_system_state_.request_params()->target_version_prefix().empty());
}
+TEST_F(UpdateAttempterTest, UpdateDeferredByPolicyTest) {
+ // Construct an OmahaResponseHandlerAction that has processed an InstallPlan,
+ // but the update is being deferred by the Policy.
+ OmahaResponseHandlerAction* response_action =
+ new OmahaResponseHandlerAction(&fake_system_state_);
+ response_action->install_plan_.version = "a.b.c.d";
+ response_action->install_plan_.system_version = "b.c.d.e";
+ response_action->install_plan_.payloads.push_back(
+ {.size = 1234ULL, .type = InstallPayloadType::kFull});
+ attempter_.response_handler_action_.reset(response_action);
+ // Inform the UpdateAttempter that the OmahaResponseHandlerAction has
+ // completed, with the deferred-update error code.
+ attempter_.ActionCompleted(
+ nullptr, response_action, ErrorCode::kOmahaUpdateDeferredPerPolicy);
+ {
+ UpdateEngineStatus status;
+ attempter_.GetStatus(&status);
+ EXPECT_EQ(UpdateStatus::UPDATE_AVAILABLE, status.status);
+ EXPECT_EQ(response_action->install_plan_.version, status.new_version);
+ EXPECT_EQ(response_action->install_plan_.system_version,
+ status.new_system_version);
+ EXPECT_EQ(response_action->install_plan_.payloads[0].size,
+ status.new_size_bytes);
+ }
+ // An "error" event should have been created to tell Omaha that the update is
+ // being deferred.
+ EXPECT_TRUE(nullptr != attempter_.error_event_);
+ EXPECT_EQ(OmahaEvent::kTypeUpdateComplete, attempter_.error_event_->type);
+ EXPECT_EQ(OmahaEvent::kResultUpdateDeferred, attempter_.error_event_->result);
+ ErrorCode expected_code = static_cast<ErrorCode>(
+ static_cast<int>(ErrorCode::kOmahaUpdateDeferredPerPolicy) |
+ static_cast<int>(ErrorCode::kTestOmahaUrlFlag));
+ EXPECT_EQ(expected_code, attempter_.error_event_->error_code);
+ // End the processing
+ attempter_.ProcessingDone(nullptr, ErrorCode::kOmahaUpdateDeferredPerPolicy);
+ // Validate the state of the attempter.
+ {
+ UpdateEngineStatus status;
+ attempter_.GetStatus(&status);
+ EXPECT_EQ(UpdateStatus::REPORTING_ERROR_EVENT, status.status);
+ EXPECT_EQ(response_action->install_plan_.version, status.new_version);
+ EXPECT_EQ(response_action->install_plan_.system_version,
+ status.new_system_version);
+ EXPECT_EQ(response_action->install_plan_.payloads[0].size,
+ status.new_size_bytes);
+ }
+}
+
+TEST_F(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable) {
+ EXPECT_FALSE(attempter_.IsUpdateRunningOrScheduled());
+ // Verify in-progress update with UPDATE_AVAILABLE is running
+ attempter_.status_ = UpdateStatus::UPDATE_AVAILABLE;
+ EXPECT_TRUE(attempter_.IsUpdateRunningOrScheduled());
+}
+
+TEST_F(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart) {
+ attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
+
+ UpdateCheckParams params = {.updates_enabled = true};
+ attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
+
+ EXPECT_EQ(UpdateAttemptFlags::kFlagRestrictDownload,
+ attempter_.GetCurrentUpdateAttemptFlags());
+}
+
+TEST_F(UpdateAttempterTest, InteractiveUpdateUsesPassedRestrictions) {
+ attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
+
+ attempter_.CheckForUpdate("", "", UpdateAttemptFlags::kNone);
+ EXPECT_EQ(UpdateAttemptFlags::kNone,
+ attempter_.GetCurrentUpdateAttemptFlags());
+}
+
+TEST_F(UpdateAttempterTest, NonInteractiveUpdateUsesSetRestrictions) {
+ attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kNone);
+
+ // This tests that when CheckForUpdate() is called with the non-interactive
+ // flag set, that it doesn't change the current UpdateAttemptFlags.
+ attempter_.CheckForUpdate("",
+ "",
+ UpdateAttemptFlags::kFlagNonInteractive |
+ UpdateAttemptFlags::kFlagRestrictDownload);
+ EXPECT_EQ(UpdateAttemptFlags::kNone,
+ attempter_.GetCurrentUpdateAttemptFlags());
+}
+
} // namespace chromeos_update_engine
diff --git a/update_manager/android_things_policy.cc b/update_manager/android_things_policy.cc
new file mode 100644
index 0000000..3af93cc
--- /dev/null
+++ b/update_manager/android_things_policy.cc
@@ -0,0 +1,181 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/android_things_policy.h"
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/api_restricted_downloads_policy_impl.h"
+#include "update_engine/update_manager/enough_slots_ab_updates_policy_impl.h"
+#include "update_engine/update_manager/interactive_update_policy_impl.h"
+#include "update_engine/update_manager/official_build_check_policy_impl.h"
+
+using base::Time;
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+const NextUpdateCheckPolicyConstants
+ AndroidThingsPolicy::kNextUpdateCheckPolicyConstants = {
+ .timeout_initial_interval = 7 * 60,
+ .timeout_periodic_interval = 5 * 60 * 60,
+ .timeout_max_backoff_interval = 26 * 60 * 60,
+ .timeout_regular_fuzz = 10 * 60,
+ .attempt_backoff_max_interval_in_days = 16,
+ .attempt_backoff_fuzz_in_hours = 12,
+};
+
+EvalStatus AndroidThingsPolicy::UpdateCheckAllowed(
+ EvaluationContext* ec,
+ State* state,
+ string* error,
+ UpdateCheckParams* result) const {
+ // Set the default return values.
+ result->updates_enabled = true;
+ result->target_channel.clear();
+ result->target_version_prefix.clear();
+ result->is_interactive = false;
+
+ // Build a list of policies to consult. Note that each policy may modify the
+ // result structure, even if it signals kContinue.
+ EnoughSlotsAbUpdatesPolicyImpl enough_slots_ab_updates_policy;
+ OnlyUpdateOfficialBuildsPolicyImpl only_update_official_builds_policy;
+ InteractiveUpdatePolicyImpl interactive_update_policy;
+ NextUpdateCheckTimePolicyImpl next_update_check_time_policy(
+ kNextUpdateCheckPolicyConstants);
+
+ vector<Policy const*> policies_to_consult = {
+ // Do not perform any updates if there are not enough slots to do
+ // A/B updates
+ &enough_slots_ab_updates_policy,
+
+ // Unofficial builds should not perform periodic update checks.
+ &only_update_official_builds_policy,
+
+ // Check to see if an interactive update was requested.
+ &interactive_update_policy,
+
+ // Ensure that periodic update checks are timed properly.
+ &next_update_check_time_policy,
+ };
+
+ // Now that the list of policy implementations, and the order to consult them,
+ // as been setup, do that. If none of the policies make a definitive
+ // decisions about whether or not to check for updates, then allow the update
+ // check to happen.
+ EvalStatus status = ConsultPolicies(policies_to_consult,
+ &Policy::UpdateCheckAllowed,
+ ec,
+ state,
+ error,
+ result);
+ if (status != EvalStatus::kContinue) {
+ return status;
+ } else {
+ // It is time to check for an update.
+ LOG(INFO) << "Allowing update check.";
+ return EvalStatus::kSucceeded;
+ }
+}
+
+// Uses the |UpdateRestrictions| to determine if the download and apply can
+// occur at this time.
+EvalStatus AndroidThingsPolicy::UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ string* error,
+ ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const {
+ // Build a list of policies to consult. Note that each policy may modify the
+ // result structure, even if it signals kContinue.
+ ApiRestrictedDownloadsPolicyImpl api_restricted_downloads_policy;
+
+ vector<Policy const*> policies_to_consult = {
+
+ // Do not apply the update if all updates are restricted by the API.
+ &api_restricted_downloads_policy,
+ };
+
+ // Now that the list of policy implementations, and the order to consult them,
+ // as been setup, do that. If none of the policies make a definitive
+ // decisions about whether or not to check for updates, then allow the update
+ // check to happen.
+ EvalStatus status = ConsultPolicies(policies_to_consult,
+ &Policy::UpdateCanBeApplied,
+ ec,
+ state,
+ error,
+ result,
+ install_plan);
+ if (EvalStatus::kContinue != status) {
+ return status;
+ } else {
+ // The update can proceed.
+ LOG(INFO) << "Allowing update to be applied.";
+ *result = ErrorCode::kSuccess;
+ return EvalStatus::kSucceeded;
+ }
+}
+
+// Always returns |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::UpdateCanStart(EvaluationContext* ec,
+ State* state,
+ string* error,
+ UpdateDownloadParams* result,
+ UpdateState update_state) const {
+ // Update is good to go.
+ result->update_can_start = true;
+ return EvalStatus::kSucceeded;
+}
+
+// Always returns |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::UpdateDownloadAllowed(EvaluationContext* ec,
+ State* state,
+ string* error,
+ bool* result) const {
+ // By default, we allow updates.
+ *result = true;
+ return EvalStatus::kSucceeded;
+}
+
+// P2P is always disabled. Returns |result|==|false| and
+// |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::P2PEnabled(EvaluationContext* ec,
+ State* state,
+ string* error,
+ bool* result) const {
+ *result = false;
+ return EvalStatus::kSucceeded;
+}
+
+// This will return immediately with |EvalStatus::kSucceeded| and set
+// |result|==|false|
+EvalStatus AndroidThingsPolicy::P2PEnabledChanged(EvaluationContext* ec,
+ State* state,
+ string* error,
+ bool* result,
+ bool prev_result) const {
+ *result = false;
+ return EvalStatus::kSucceeded;
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/android_things_policy.h b/update_manager/android_things_policy.h
new file mode 100644
index 0000000..b45e955
--- /dev/null
+++ b/update_manager/android_things_policy.h
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_ANDROID_THINGS_POLICY_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ANDROID_THINGS_POLICY_H_
+
+#include <string>
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// AndroidThingsPolicy implements the policy-related logic used in
+// AndroidThings.
+class AndroidThingsPolicy : public Policy {
+ public:
+ AndroidThingsPolicy() = default;
+ ~AndroidThingsPolicy() override = default;
+
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override;
+
+ // Uses the |UpdateRestrictions| to determine if the download and apply can
+ // occur at this time.
+ EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const override;
+
+ // Always returns |EvalStatus::kSucceeded|
+ EvalStatus UpdateCanStart(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateDownloadParams* result,
+ UpdateState update_state) const override;
+
+ // Always returns |EvalStatus::kSucceeded|
+ EvalStatus UpdateDownloadAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result) const override;
+
+ // P2P is always disabled. Returns |result|==|false| and
+ // |EvalStatus::kSucceeded|
+ virtual EvalStatus P2PEnabled(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result) const override;
+
+ // This will return immediately with |EvalStatus::kSucceeded| and set
+ // |result|==|false|
+ virtual EvalStatus P2PEnabledChanged(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result,
+ bool prev_result) const override;
+
+ protected:
+ // Policy override.
+ std::string PolicyName() const override { return "AndroidThingsPolicy"; }
+
+ private:
+ friend class UmAndroidThingsPolicyTest;
+ FRIEND_TEST(UmAndroidThingsPolicyTest, UpdateCheckAllowedWaitsForTheTimeout);
+
+ static const NextUpdateCheckPolicyConstants kNextUpdateCheckPolicyConstants;
+
+ DISALLOW_COPY_AND_ASSIGN(AndroidThingsPolicy);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_ANDROID_THINGS_POLICY_H_
diff --git a/update_manager/android_things_policy_unittest.cc b/update_manager/android_things_policy_unittest.cc
new file mode 100644
index 0000000..04b0e0e
--- /dev/null
+++ b/update_manager/android_things_policy_unittest.cc
@@ -0,0 +1,184 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/android_things_policy.h"
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+#include "update_engine/update_manager/policy_test_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ErrorCode;
+using chromeos_update_engine::InstallPlan;
+
+namespace chromeos_update_manager {
+
+class UmAndroidThingsPolicyTest : public UmPolicyTestBase {
+ protected:
+ UmAndroidThingsPolicyTest() {
+ policy_ = std::make_unique<AndroidThingsPolicy>();
+ }
+
+ void SetUpDefaultState() override {
+ UmPolicyTestBase::SetUpDefaultState();
+
+ // For the purpose of the tests, this is an official build
+ fake_state_.system_provider()->var_is_official_build()->reset(
+ new bool(true));
+ fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(2));
+ }
+
+ // Configures the policy to return a desired value from UpdateCheckAllowed by
+ // faking the current wall clock time as needed. Restores the default state.
+ // This is used when testing policies that depend on this one.
+ virtual void SetUpdateCheckAllowed(bool allow_check) {
+ Time next_update_check;
+ CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ AndroidThingsPolicy::kNextUpdateCheckPolicyConstants);
+ SetUpDefaultState();
+ Time curr_time = next_update_check;
+ if (allow_check)
+ curr_time += TimeDelta::FromSeconds(1);
+ else
+ curr_time -= TimeDelta::FromSeconds(1);
+ fake_clock_.SetWallclockTime(curr_time);
+ }
+};
+
+TEST_F(UmAndroidThingsPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
+ // We get the next update_check timestamp from the policy's private method
+ // and then we check the public method respects that value on the normal
+ // case.
+ Time next_update_check;
+ Time last_checked_time =
+ fake_clock_.GetWallclockTime() + TimeDelta::FromMinutes(1234);
+
+ LOG(INFO) << "last_checked_time: " << last_checked_time;
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ AndroidThingsPolicy::kNextUpdateCheckPolicyConstants);
+ LOG(INFO) << "Next check allowed at: " << next_update_check;
+
+ // Check that the policy blocks until the next_update_check is reached.
+ SetUpDefaultClock();
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ fake_clock_.SetWallclockTime(next_update_check - TimeDelta::FromSeconds(1));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
+
+ SetUpDefaultClock();
+ SetUpDefaultState();
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(last_checked_time));
+ fake_clock_.SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_TRUE(result.updates_enabled);
+ EXPECT_FALSE(result.is_interactive);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+ UpdateCheckAllowedUpdatesDisabledForUnofficialBuilds) {
+ // UpdateCheckAllowed should return kAskMeAgainLater if this is an unofficial
+ // build; we don't want periodic update checks on developer images.
+
+ fake_state_.system_provider()->var_is_official_build()->reset(
+ new bool(false));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+ UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
+ // UpdateCheckAllowed should return false (kSucceeded) if the image booted
+ // without enough slots to do A/B updates.
+
+ fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(1));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_FALSE(result.updates_enabled);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+ UpdateCheckAllowedForcedUpdateRequestedInteractive) {
+ // UpdateCheckAllowed should return true because a forced update request was
+ // signaled for an interactive update.
+
+ SetUpdateCheckAllowed(true);
+ fake_state_.updater_provider()->var_forced_update_requested()->reset(
+ new UpdateRequestStatus(UpdateRequestStatus::kInteractive));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_TRUE(result.updates_enabled);
+ EXPECT_TRUE(result.is_interactive);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+ UpdateCheckAllowedForcedUpdateRequestedPeriodic) {
+ // UpdateCheckAllowed should return true because a forced update request was
+ // signaled for a periodic check.
+
+ SetUpdateCheckAllowed(true);
+ fake_state_.updater_provider()->var_forced_update_requested()->reset(
+ new UpdateRequestStatus(UpdateRequestStatus::kPeriodic));
+
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+ EXPECT_TRUE(result.updates_enabled);
+ EXPECT_FALSE(result.is_interactive);
+}
+
+TEST_F(UmAndroidThingsPolicyTest, UpdateCanBeAppliedOk) {
+ // UpdateCanBeApplied should return kSucceeded in the base case
+
+ InstallPlan plan;
+ ErrorCode result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCanBeApplied, &result, &plan);
+
+ EXPECT_EQ(ErrorCode::kSuccess, result);
+}
+
+TEST_F(UmAndroidThingsPolicyTest, UpdateCanBeAppliedRestricted) {
+ // UpdateCanBeApplied should return kOmahaUpdateDeferredPerPolicy in
+ // when the restricted flag is set in the Updater.
+
+ fake_state_.updater_provider()->var_update_restrictions()->reset(
+ new UpdateRestrictions(UpdateRestrictions::kRestrictDownloading));
+
+ InstallPlan plan;
+ ErrorCode result;
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCanBeApplied, &result, &plan);
+
+ EXPECT_EQ(ErrorCode::kOmahaUpdateDeferredPerPolicy, result);
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/api_restricted_downloads_policy_impl.cc b/update_manager/api_restricted_downloads_policy_impl.cc
new file mode 100644
index 0000000..d413cca
--- /dev/null
+++ b/update_manager/api_restricted_downloads_policy_impl.cc
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/api_restricted_downloads_policy_impl.h"
+
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+// Allow the API to restrict the downloading of updates.
+EvalStatus ApiRestrictedDownloadsPolicyImpl::UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const {
+ // Next, check to see if updates can be applied (in general).
+ const UpdateRestrictions* update_restrictions_p =
+ ec->GetValue(state->updater_provider()->var_update_restrictions());
+ if (update_restrictions_p) {
+ if (*update_restrictions_p & UpdateRestrictions::kRestrictDownloading) {
+ *result = ErrorCode::kOmahaUpdateDeferredPerPolicy;
+ return EvalStatus::kSucceeded;
+ }
+ }
+
+ // The API isn't restricting downloads, so implicitly allow them to happen
+ // but don't explicitly return success from this policy implementation.
+ return EvalStatus::kContinue;
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/api_restricted_downloads_policy_impl.h b/update_manager/api_restricted_downloads_policy_impl.h
new file mode 100644
index 0000000..69686d6
--- /dev/null
+++ b/update_manager/api_restricted_downloads_policy_impl.h
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Allow the API to restrict the downloading of updates.
+class ApiRestrictedDownloadsPolicyImpl : public PolicyImplBase {
+ public:
+ ApiRestrictedDownloadsPolicyImpl() = default;
+ ~ApiRestrictedDownloadsPolicyImpl() override = default;
+
+ // Policy overrides.
+ EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const override;
+
+ protected:
+ std::string PolicyName() const override {
+ return "ApiRestrictedDownloadsPolicyImpl";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ApiRestrictedDownloadsPolicyImpl);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
index 9758d33..a437c02 100644
--- a/update_manager/boxed_value.cc
+++ b/update_manager/boxed_value.cc
@@ -176,4 +176,19 @@
return "Unknown";
}
+template <>
+string BoxedValue::ValuePrinter<UpdateRestrictions>(const void* value) {
+ const UpdateRestrictions* val =
+ reinterpret_cast<const UpdateRestrictions*>(value);
+
+ if (*val == UpdateRestrictions::kNone) {
+ return "None";
+ }
+ string retval = "Flags:";
+ if (*val & kRestrictDownloading) {
+ retval += " RestrictDownloading";
+ }
+ return retval;
+}
+
} // namespace chromeos_update_manager
diff --git a/update_manager/boxed_value_unittest.cc b/update_manager/boxed_value_unittest.cc
index 2a086a6..83d8de7 100644
--- a/update_manager/boxed_value_unittest.cc
+++ b/update_manager/boxed_value_unittest.cc
@@ -231,4 +231,14 @@
EXPECT_EQ("DeleterMarker:true", value.ToString());
}
+TEST(UmBoxedValueTest, UpdateRestrictionsToString) {
+ EXPECT_EQ(
+ "None",
+ BoxedValue(new UpdateRestrictions(UpdateRestrictions::kNone)).ToString());
+ EXPECT_EQ("Flags: RestrictDownloading",
+ BoxedValue(new UpdateRestrictions(
+ UpdateRestrictions::kRestrictDownloading))
+ .ToString());
+}
+
} // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index da04372..b32b626 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -36,6 +36,7 @@
using chromeos_update_engine::ConnectionTethering;
using chromeos_update_engine::ConnectionType;
using chromeos_update_engine::ErrorCode;
+using chromeos_update_engine::InstallPlan;
using std::get;
using std::max;
using std::min;
@@ -325,6 +326,15 @@
return EvalStatus::kSucceeded;
}
+EvalStatus ChromeOSPolicy::UpdateCanBeApplied(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ ErrorCode* result,
+ InstallPlan* install_plan) const {
+ *result = ErrorCode::kSuccess;
+ return EvalStatus::kSucceeded;
+}
+
EvalStatus ChromeOSPolicy::UpdateCanStart(
EvaluationContext* ec,
State* state,
diff --git a/update_manager/chromeos_policy.h b/update_manager/chromeos_policy.h
index b4370c4..283bedc 100644
--- a/update_manager/chromeos_policy.h
+++ b/update_manager/chromeos_policy.h
@@ -59,6 +59,13 @@
EvaluationContext* ec, State* state, std::string* error,
UpdateCheckParams* result) const override;
+ EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const override;
+
EvalStatus UpdateCanStart(
EvaluationContext* ec,
State* state,
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 0c38700..2cd2aa6 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -418,9 +418,9 @@
}
TEST_F(UmChromeOSPolicyTest,
- UpdateCheckAllowedUpdatesDisabledForRemovableBootDevice) {
+ UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
// UpdateCheckAllowed should return false (kSucceeded) if the image booted
- // from a removable device.
+ // without enough slots to do A/B updates.
fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(1));
diff --git a/update_manager/default_policy.cc b/update_manager/default_policy.cc
index 9a5ce7e..5da1520 100644
--- a/update_manager/default_policy.cc
+++ b/update_manager/default_policy.cc
@@ -16,6 +16,9 @@
#include "update_engine/update_manager/default_policy.h"
+using chromeos_update_engine::ErrorCode;
+using chromeos_update_engine::InstallPlan;
+
namespace {
// A fixed minimum interval between consecutive allowed update checks. This
@@ -53,6 +56,15 @@
return EvalStatus::kAskMeAgainLater;
}
+EvalStatus DefaultPolicy::UpdateCanBeApplied(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ ErrorCode* result,
+ InstallPlan* install_plan) const {
+ *result = ErrorCode::kSuccess;
+ return EvalStatus::kSucceeded;
+}
+
EvalStatus DefaultPolicy::UpdateCanStart(
EvaluationContext* ec,
State* state,
diff --git a/update_manager/default_policy.h b/update_manager/default_policy.h
index 3f41178..136ca35 100644
--- a/update_manager/default_policy.h
+++ b/update_manager/default_policy.h
@@ -69,6 +69,13 @@
EvaluationContext* ec, State* state, std::string* error,
UpdateCheckParams* result) const override;
+ EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const override;
+
EvalStatus UpdateCanStart(
EvaluationContext* ec, State* state, std::string* error,
UpdateDownloadParams* result,
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.cc b/update_manager/enough_slots_ab_updates_policy_impl.cc
new file mode 100644
index 0000000..70f15d4
--- /dev/null
+++ b/update_manager/enough_slots_ab_updates_policy_impl.cc
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/enough_slots_ab_updates_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Do not perform any updates if booted from removable device. This decision
+// is final.
+EvalStatus EnoughSlotsAbUpdatesPolicyImpl::UpdateCheckAllowed(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const {
+ const auto* num_slots_p =
+ ec->GetValue(state->system_provider()->var_num_slots());
+ if (num_slots_p == nullptr || *num_slots_p < 2) {
+ LOG(INFO) << "Not enough slots for A/B updates, disabling update checks.";
+ result->updates_enabled = false;
+ return EvalStatus::kSucceeded;
+ }
+ return EvalStatus::kContinue;
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.h b/update_manager/enough_slots_ab_updates_policy_impl.h
new file mode 100644
index 0000000..c0701f8
--- /dev/null
+++ b/update_manager/enough_slots_ab_updates_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Do not perform any updates if booted from removable device.
+class EnoughSlotsAbUpdatesPolicyImpl : public PolicyImplBase {
+ public:
+ EnoughSlotsAbUpdatesPolicyImpl() = default;
+ ~EnoughSlotsAbUpdatesPolicyImpl() override = default;
+
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override;
+
+ protected:
+ std::string PolicyName() const override {
+ return "EnoughSlotsAbUpdatesPolicyImpl";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EnoughSlotsAbUpdatesPolicyImpl);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/fake_updater_provider.h b/update_manager/fake_updater_provider.h
index a7c15b5..3e03d43 100644
--- a/update_manager/fake_updater_provider.h
+++ b/update_manager/fake_updater_provider.h
@@ -85,6 +85,10 @@
return &var_forced_update_requested_;
}
+ FakeVariable<UpdateRestrictions>* var_update_restrictions() override {
+ return &var_update_restrictions_;
+ }
+
private:
FakeVariable<base::Time>
var_updater_started_time_{ // NOLINT(whitespace/braces)
@@ -121,6 +125,10 @@
FakeVariable<UpdateRequestStatus>
var_forced_update_requested_{ // NOLINT(whitespace/braces)
"forced_update_requested", kVariableModeAsync};
+ FakeVariable<UpdateRestrictions> var_update_restrictions_{
+ // NOLINT(whitespace/braces)
+ "update_restrictions",
+ kVariableModePoll};
DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
};
diff --git a/update_manager/interactive_update_policy_impl.cc b/update_manager/interactive_update_policy_impl.cc
new file mode 100644
index 0000000..df7f17b
--- /dev/null
+++ b/update_manager/interactive_update_policy_impl.cc
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/interactive_update_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Check to see if an interactive update was requested.
+EvalStatus InteractiveUpdatePolicyImpl::UpdateCheckAllowed(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const {
+ UpdaterProvider* const updater_provider = state->updater_provider();
+
+ // First, check to see if an interactive update was requested.
+ const UpdateRequestStatus* forced_update_requested_p =
+ ec->GetValue(updater_provider->var_forced_update_requested());
+ if (forced_update_requested_p != nullptr &&
+ *forced_update_requested_p != UpdateRequestStatus::kNone) {
+ result->is_interactive =
+ (*forced_update_requested_p == UpdateRequestStatus::kInteractive);
+ LOG(INFO) << "Forced update signaled ("
+ << (result->is_interactive ? "interactive" : "periodic")
+ << "), allowing update check.";
+ return EvalStatus::kSucceeded;
+ }
+ return EvalStatus::kContinue;
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/interactive_update_policy_impl.h b/update_manager/interactive_update_policy_impl.h
new file mode 100644
index 0000000..fc68ea3
--- /dev/null
+++ b/update_manager/interactive_update_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Check to see if an interactive update was requested.
+class InteractiveUpdatePolicyImpl : public PolicyImplBase {
+ public:
+ InteractiveUpdatePolicyImpl() = default;
+ ~InteractiveUpdatePolicyImpl() override = default;
+
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override;
+
+ protected:
+ std::string PolicyName() const override {
+ return "InteractiveUpdatePolicyImpl";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InteractiveUpdatePolicyImpl);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/mock_policy.h b/update_manager/mock_policy.h
index 14470e9..8060bf8 100644
--- a/update_manager/mock_policy.h
+++ b/update_manager/mock_policy.h
@@ -36,6 +36,11 @@
testing::_))
.WillByDefault(testing::Invoke(
&default_policy_, &DefaultPolicy::UpdateCheckAllowed));
+ ON_CALL(*this,
+ UpdateCanBeApplied(
+ testing::_, testing::_, testing::_, testing::_, testing::_))
+ .WillByDefault(testing::Invoke(&default_policy_,
+ &DefaultPolicy::UpdateCanBeApplied));
ON_CALL(*this, UpdateCanStart(testing::_, testing::_, testing::_,
testing::_, testing::_))
.WillByDefault(testing::Invoke(
@@ -61,6 +66,13 @@
EvalStatus(EvaluationContext*, State*, std::string*,
UpdateCheckParams*));
+ MOCK_CONST_METHOD5(UpdateCanBeApplied,
+ EvalStatus(EvaluationContext*,
+ State*,
+ std::string*,
+ chromeos_update_engine::ErrorCode*,
+ chromeos_update_engine::InstallPlan*));
+
MOCK_CONST_METHOD5(UpdateCanStart,
EvalStatus(EvaluationContext*, State*, std::string*,
UpdateDownloadParams*, UpdateState));
diff --git a/update_manager/next_update_check_policy_impl.cc b/update_manager/next_update_check_policy_impl.cc
new file mode 100644
index 0000000..6f9748e
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl.cc
@@ -0,0 +1,150 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+
+#include <algorithm>
+
+#include "update_engine/common/utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::max;
+using std::string;
+
+namespace chromeos_update_manager {
+
+NextUpdateCheckTimePolicyImpl::NextUpdateCheckTimePolicyImpl(
+ const NextUpdateCheckPolicyConstants& constants)
+ : policy_constants_(constants) {}
+
+EvalStatus NextUpdateCheckTimePolicyImpl::UpdateCheckAllowed(
+ EvaluationContext* ec,
+ State* state,
+ string* error,
+ UpdateCheckParams* result) const {
+ // Ensure that periodic update checks are timed properly.
+ Time next_update_check;
+
+ if (NextUpdateCheckTime(
+ ec, state, error, &next_update_check, policy_constants_) !=
+ EvalStatus::kSucceeded) {
+ return EvalStatus::kFailed;
+ }
+ if (!ec->IsWallclockTimeGreaterThan(next_update_check)) {
+ LOG(INFO) << "Periodic check interval not satisfied, blocking until "
+ << chromeos_update_engine::utils::ToString(next_update_check);
+ return EvalStatus::kAskMeAgainLater;
+ }
+
+ return EvalStatus::kContinue;
+}
+
+EvalStatus NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime(
+ EvaluationContext* ec,
+ State* state,
+ string* error,
+ Time* next_update_check,
+ const NextUpdateCheckPolicyConstants& constants) {
+ UpdaterProvider* const updater_provider = state->updater_provider();
+
+ // Don't check for updates too often. We limit the update checks to once every
+ // some interval. The interval is kTimeoutInitialInterval the first time and
+ // kTimeoutPeriodicInterval for the subsequent update checks. If the update
+ // check fails, we increase the interval between the update checks
+ // exponentially until kTimeoutMaxBackoffInterval. Finally, to avoid having
+ // many chromebooks running update checks at the exact same time, we add some
+ // fuzz to the interval.
+ const Time* updater_started_time =
+ ec->GetValue(updater_provider->var_updater_started_time());
+ POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error);
+
+ const Time* last_checked_time =
+ ec->GetValue(updater_provider->var_last_checked_time());
+
+ const auto* seed = ec->GetValue(state->random_provider()->var_seed());
+ POLICY_CHECK_VALUE_AND_FAIL(seed, error);
+
+ PRNG prng(*seed);
+
+ // If this is the first attempt, compute and return an initial value.
+ if (last_checked_time == nullptr ||
+ *last_checked_time < *updater_started_time) {
+ *next_update_check = *updater_started_time +
+ FuzzedInterval(&prng,
+ constants.timeout_initial_interval,
+ constants.timeout_regular_fuzz);
+ return EvalStatus::kSucceeded;
+ }
+
+ // Check whether the server is enforcing a poll interval; if not, this value
+ // will be zero.
+ const unsigned int* server_dictated_poll_interval =
+ ec->GetValue(updater_provider->var_server_dictated_poll_interval());
+ POLICY_CHECK_VALUE_AND_FAIL(server_dictated_poll_interval, error);
+
+ int interval = *server_dictated_poll_interval;
+ int fuzz = 0;
+
+ // If no poll interval was dictated by server compute a back-off period,
+ // starting from a predetermined base periodic interval and increasing
+ // exponentially by the number of consecutive failed attempts.
+ if (interval == 0) {
+ const unsigned int* consecutive_failed_update_checks =
+ ec->GetValue(updater_provider->var_consecutive_failed_update_checks());
+ POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error);
+
+ interval = constants.timeout_periodic_interval;
+ unsigned int num_failures = *consecutive_failed_update_checks;
+ while (interval < constants.timeout_max_backoff_interval && num_failures) {
+ interval *= 2;
+ num_failures--;
+ }
+ }
+
+ // We cannot back off longer than the predetermined maximum interval.
+ if (interval > constants.timeout_max_backoff_interval)
+ interval = constants.timeout_max_backoff_interval;
+
+ // We cannot back off shorter than the predetermined periodic interval. Also,
+ // in this case set the fuzz to a predetermined regular value.
+ if (interval <= constants.timeout_periodic_interval) {
+ interval = constants.timeout_periodic_interval;
+ fuzz = constants.timeout_regular_fuzz;
+ }
+
+ // If not otherwise determined, defer to a fuzz of +/-(interval / 2).
+ if (fuzz == 0)
+ fuzz = interval;
+
+ *next_update_check =
+ *last_checked_time + FuzzedInterval(&prng, interval, fuzz);
+ return EvalStatus::kSucceeded;
+}
+
+TimeDelta NextUpdateCheckTimePolicyImpl::FuzzedInterval(PRNG* prng,
+ int interval,
+ int fuzz) {
+ DCHECK_GE(interval, 0);
+ DCHECK_GE(fuzz, 0);
+ int half_fuzz = fuzz / 2;
+ // This guarantees the output interval is non negative.
+ int interval_min = max(interval - half_fuzz, 0);
+ int interval_max = interval + half_fuzz;
+ return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max));
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/next_update_check_policy_impl.h b/update_manager/next_update_check_policy_impl.h
new file mode 100644
index 0000000..d9f3c3b
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl.h
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
+
+#include <string>
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/policy_utils.h"
+#include "update_engine/update_manager/prng.h"
+
+namespace chromeos_update_manager {
+
+// Constants that are provided to the policy implementation.
+struct NextUpdateCheckPolicyConstants {
+ // Default update check timeout interval/fuzz values used to compute the
+ // NextUpdateCheckTime(), in seconds. Actual fuzz is within +/- half of the
+ // indicated value.
+ int timeout_initial_interval;
+ int timeout_periodic_interval;
+ int timeout_max_backoff_interval;
+ int timeout_regular_fuzz;
+
+ // Maximum update attempt backoff interval and fuzz.
+ int attempt_backoff_max_interval_in_days;
+ int attempt_backoff_fuzz_in_hours;
+};
+
+// Ensure that periodic update checks are timed properly.
+class NextUpdateCheckTimePolicyImpl : public PolicyImplBase {
+ public:
+ explicit NextUpdateCheckTimePolicyImpl(
+ const NextUpdateCheckPolicyConstants& constants);
+
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override;
+
+ // A private policy implementation returning the wallclock timestamp when
+ // the next update check should happen.
+ // TODO(garnold) We should probably change that to infer a monotonic
+ // timestamp, which will make the update check intervals more resilient to
+ // clock skews. Might require switching some of the variables exported by the
+ // UpdaterProvider to report monotonic time, as well.
+ //
+ // NOTE:
+ // Exposed as a public static so that it's logic can be used to test
+ // Policy implementations that utilize this fragment for their
+ // timing, without needing to list them all with FRIEND_TEST (so that
+ // those Policy implementations can exist without modifying this
+ // class's definition.
+ //
+ // The output value from this method (|next_update_check|), isn't
+ // available via the UpdateCheckParams |result| of the Policy
+ // method, and so this timing logic needs to be otherwise exposed.
+ static EvalStatus NextUpdateCheckTime(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ base::Time* next_update_check,
+ const NextUpdateCheckPolicyConstants& constants);
+
+ // Returns a TimeDelta based on the provided |interval| seconds +/- half
+ // |fuzz| seconds. The return value is guaranteed to be a non-negative
+ // TimeDelta.
+ static base::TimeDelta FuzzedInterval(PRNG* prng, int interval, int fuzz);
+
+ protected:
+ std::string PolicyName() const override {
+ return "NextUpdateCheckTimePolicyImpl";
+ }
+
+ private:
+ const NextUpdateCheckPolicyConstants policy_constants_;
+
+ DISALLOW_COPY_AND_ASSIGN(NextUpdateCheckTimePolicyImpl);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/next_update_check_policy_impl_unittest.cc b/update_manager/next_update_check_policy_impl_unittest.cc
new file mode 100644
index 0000000..ddc88e7
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl_unittest.cc
@@ -0,0 +1,161 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+
+#include "update_engine/update_manager/policy_test_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::string;
+
+namespace chromeos_update_manager {
+
+const NextUpdateCheckPolicyConstants policy_test_constants = {
+ // these are specifically NOT the values used by real Policy
+ // implementations.
+ .timeout_initial_interval = 3 * 60,
+ .timeout_periodic_interval = 2 * 60 * 60,
+ .timeout_max_backoff_interval = 8 * 60 * 60,
+ .timeout_regular_fuzz = 5 * 60,
+ .attempt_backoff_max_interval_in_days = 12,
+ .attempt_backoff_fuzz_in_hours = 10,
+};
+
+class UmNextUpdateCheckTimePolicyImplTest : public UmPolicyTestBase {
+ protected:
+ UmNextUpdateCheckTimePolicyImplTest() {
+ policy_ =
+ std::make_unique<NextUpdateCheckTimePolicyImpl>(policy_test_constants);
+ }
+};
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest,
+ FirstCheckIsAtMostInitialIntervalAfterStart) {
+ Time next_update_check;
+
+ // Set the last update time so it'll appear as if this is a first update check
+ // in the lifetime of the current updater.
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(fake_clock_.GetWallclockTime() - TimeDelta::FromMinutes(10)));
+
+ CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ policy_test_constants);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime(), next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(
+ policy_test_constants.timeout_initial_interval +
+ policy_test_constants.timeout_regular_fuzz / 2),
+ next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest, RecurringCheckBaseIntervalAndFuzz) {
+ // Ensure that we're using the correct interval (kPeriodicInterval) and fuzz
+ // (ktimeout_regular_fuzz) as base values for period updates.
+ Time next_update_check;
+
+ CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ policy_test_constants);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(
+ policy_test_constants.timeout_periodic_interval -
+ policy_test_constants.timeout_regular_fuzz / 2),
+ next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(
+ policy_test_constants.timeout_periodic_interval +
+ policy_test_constants.timeout_regular_fuzz / 2),
+ next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest,
+ RecurringCheckBackoffIntervalAndFuzz) {
+ // Ensure that we're properly backing off and fuzzing in the presence of
+ // failed updates attempts.
+ Time next_update_check;
+
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
+ new unsigned int(2));
+
+ ExpectStatus(EvalStatus::kSucceeded,
+ NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ policy_test_constants);
+
+ int expected_interval = policy_test_constants.timeout_periodic_interval * 4;
+ EXPECT_LE(
+ fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(expected_interval - expected_interval / 2),
+ next_update_check);
+ EXPECT_GE(
+ fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(expected_interval + expected_interval / 2),
+ next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest,
+ RecurringCheckServerDictatedPollInterval) {
+ // Policy honors the server provided check poll interval.
+ Time next_update_check;
+
+ const auto kInterval = policy_test_constants.timeout_periodic_interval * 4;
+ fake_state_.updater_provider()->var_server_dictated_poll_interval()->reset(
+ new unsigned int(kInterval));
+ // We should not be backing off in this case.
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
+ new unsigned int(2));
+
+ ExpectStatus(EvalStatus::kSucceeded,
+ &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ policy_test_constants);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(kInterval - kInterval / 2),
+ next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(kInterval + kInterval / 2),
+ next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest, ExponentialBackoffIsCapped) {
+ Time next_update_check;
+
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
+ new unsigned int(100));
+
+ ExpectStatus(EvalStatus::kSucceeded,
+ &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+ &next_update_check,
+ policy_test_constants);
+
+ EXPECT_LE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(
+ policy_test_constants.timeout_max_backoff_interval -
+ policy_test_constants.timeout_max_backoff_interval / 2),
+ next_update_check);
+ EXPECT_GE(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(
+ policy_test_constants.timeout_max_backoff_interval +
+ policy_test_constants.timeout_max_backoff_interval / 2),
+ next_update_check);
+}
+
+} // namespace chromeos_update_manager
\ No newline at end of file
diff --git a/update_manager/official_build_check_policy_impl.cc b/update_manager/official_build_check_policy_impl.cc
new file mode 100644
index 0000000..096f7bf
--- /dev/null
+++ b/update_manager/official_build_check_policy_impl.cc
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/official_build_check_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Unofficial builds should not perform periodic update checks.
+EvalStatus OnlyUpdateOfficialBuildsPolicyImpl::UpdateCheckAllowed(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const {
+ const bool* is_official_build_p =
+ ec->GetValue(state->system_provider()->var_is_official_build());
+ if (is_official_build_p != nullptr && !(*is_official_build_p)) {
+ LOG(INFO) << "Unofficial build, blocking periodic update checks.";
+ return EvalStatus::kAskMeAgainLater;
+ }
+ return EvalStatus::kContinue;
+}
+
+} // namespace chromeos_update_manager
diff --git a/update_manager/official_build_check_policy_impl.h b/update_manager/official_build_check_policy_impl.h
new file mode 100644
index 0000000..deb81c3
--- /dev/null
+++ b/update_manager/official_build_check_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Unofficial builds should not perform periodic update checks.
+class OnlyUpdateOfficialBuildsPolicyImpl : public PolicyImplBase {
+ public:
+ OnlyUpdateOfficialBuildsPolicyImpl() = default;
+ ~OnlyUpdateOfficialBuildsPolicyImpl() override = default;
+
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override;
+
+ protected:
+ std::string PolicyName() const override {
+ return "OnlyUpdateOfficialBuildsPolicyImpl";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OnlyUpdateOfficialBuildsPolicyImpl);
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/policy.cc b/update_manager/policy.cc
index 151c225..5f79a68 100644
--- a/update_manager/policy.cc
+++ b/update_manager/policy.cc
@@ -30,6 +30,8 @@
return "kSucceeded";
case EvalStatus::kAskMeAgainLater:
return "kAskMeAgainLater";
+ case EvalStatus::kContinue:
+ return "kContinue";
}
return "Invalid";
}
diff --git a/update_manager/policy.h b/update_manager/policy.h
index fae1494..b60c4da 100644
--- a/update_manager/policy.h
+++ b/update_manager/policy.h
@@ -22,6 +22,7 @@
#include <vector>
#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/state.h"
@@ -32,6 +33,7 @@
kFailed,
kSucceeded,
kAskMeAgainLater,
+ kContinue,
};
std::string ToString(EvalStatus status);
@@ -204,6 +206,9 @@
if (reinterpret_cast<typeof(&Policy::UpdateCheckAllowed)>(
policy_method) == &Policy::UpdateCheckAllowed)
return class_name + "UpdateCheckAllowed";
+ if (reinterpret_cast<typeof(&Policy::UpdateCanBeApplied)>(policy_method) ==
+ &Policy::UpdateCanBeApplied)
+ return class_name + "UpdateCanBeApplied";
if (reinterpret_cast<typeof(&Policy::UpdateCanStart)>(
policy_method) == &Policy::UpdateCanStart)
return class_name + "UpdateCanStart";
@@ -235,6 +240,17 @@
EvaluationContext* ec, State* state, std::string* error,
UpdateCheckParams* result) const = 0;
+ // UpdateCanBeApplied returns whether the given |install_plan| can be acted
+ // on at this time. The reason for not applying is returned in |result|.
+ // The Policy may modify the passed-in |install_plan|, based on the
+ // implementation in the Policy and values provided by the EvaluationContext.
+ virtual EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const = 0;
+
// Returns EvalStatus::kSucceeded if either an update can start being
// processed, or the attempt needs to be aborted. In cases where the update
// needs to wait for some condition to be satisfied, but none of the values
diff --git a/update_manager/policy_test_utils.cc b/update_manager/policy_test_utils.cc
new file mode 100644
index 0000000..dfeb2d4
--- /dev/null
+++ b/update_manager/policy_test_utils.cc
@@ -0,0 +1,109 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/policy_test_utils.h"
+
+#include <tuple>
+#include <vector>
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::tuple;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+void UmPolicyTestBase::SetUp() {
+ loop_.SetAsCurrent();
+ SetUpDefaultClock();
+ eval_ctx_ = new EvaluationContext(&fake_clock_, TimeDelta::FromSeconds(5));
+ SetUpDefaultState();
+}
+
+void UmPolicyTestBase::TearDown() {
+ EXPECT_FALSE(loop_.PendingTasks());
+}
+
+// Sets the clock to fixed values.
+void UmPolicyTestBase::SetUpDefaultClock() {
+ fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
+ fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
+}
+
+void UmPolicyTestBase::SetUpDefaultState() {
+ fake_state_.updater_provider()->var_updater_started_time()->reset(
+ new Time(fake_clock_.GetWallclockTime()));
+ fake_state_.updater_provider()->var_last_checked_time()->reset(
+ new Time(fake_clock_.GetWallclockTime()));
+ fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
+ new unsigned int(0));
+ fake_state_.updater_provider()->var_server_dictated_poll_interval()->reset(
+ new unsigned int(0));
+ fake_state_.updater_provider()->var_forced_update_requested()->reset(
+ new UpdateRequestStatus{UpdateRequestStatus::kNone});
+
+ // Chosen by fair dice roll. Guaranteed to be random.
+ fake_state_.random_provider()->var_seed()->reset(new uint64_t(4));
+}
+
+// Returns a default UpdateState structure:
+UpdateState UmPolicyTestBase::GetDefaultUpdateState(
+ TimeDelta first_seen_period) {
+ Time first_seen_time = fake_clock_.GetWallclockTime() - first_seen_period;
+ UpdateState update_state = UpdateState();
+
+ // This is a non-interactive check returning a delta payload, seen for the
+ // first time (|first_seen_period| ago). Clearly, there were no failed
+ // attempts so far.
+ update_state.is_interactive = false;
+ update_state.is_delta_payload = false;
+ update_state.first_seen = first_seen_time;
+ update_state.num_checks = 1;
+ update_state.num_failures = 0;
+ update_state.failures_last_updated = Time(); // Needs to be zero.
+ // There's a single HTTP download URL with a maximum of 10 retries.
+ update_state.download_urls = vector<string>{"http://fake/url/"};
+ update_state.download_errors_max = 10;
+ // Download was never attempted.
+ update_state.last_download_url_idx = -1;
+ update_state.last_download_url_num_errors = 0;
+ // There were no download errors.
+ update_state.download_errors = vector<tuple<int, ErrorCode, Time>>();
+ // P2P is not disabled by Omaha.
+ update_state.p2p_downloading_disabled = false;
+ update_state.p2p_sharing_disabled = false;
+ // P2P was not attempted.
+ update_state.p2p_num_attempts = 0;
+ update_state.p2p_first_attempted = Time();
+ // No active backoff period, backoff is not disabled by Omaha.
+ update_state.backoff_expiry = Time();
+ update_state.is_backoff_disabled = false;
+ // There is no active scattering wait period (max 7 days allowed) nor check
+ // threshold (none allowed).
+ update_state.scatter_wait_period = TimeDelta();
+ update_state.scatter_check_threshold = 0;
+ update_state.scatter_wait_period_max = TimeDelta::FromDays(7);
+ update_state.scatter_check_threshold_min = 0;
+ update_state.scatter_check_threshold_max = 0;
+
+ return update_state;
+}
+
+} // namespace chromeos_update_manager
\ No newline at end of file
diff --git a/update_manager/policy_test_utils.h b/update_manager/policy_test_utils.h
new file mode 100644
index 0000000..09b2550
--- /dev/null
+++ b/update_manager/policy_test_utils.h
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
+
+#include <string>
+
+#include <base/time/time.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/fake_clock.h"
+#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/fake_state.h"
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+class UmPolicyTestBase : public ::testing::Test {
+ protected:
+ explicit UmPolicyTestBase() = default;
+
+ void SetUp() override;
+
+ void TearDown() override;
+
+ // Sets the clock to fixed values.
+ virtual void SetUpDefaultClock();
+
+ // Sets up the default state in fake_state_. override to add Policy-specific
+ // items, but only after calling this class's implementation.
+ virtual void SetUpDefaultState();
+
+ // Returns a default UpdateState structure:
+ virtual UpdateState GetDefaultUpdateState(base::TimeDelta first_seen_period);
+
+ // Runs the passed |method| after resetting the EvaluationContext and expects
+ // it to return the |expected| return value.
+ template <typename T, typename R, typename... Args>
+ void ExpectStatus(EvalStatus expected, T method, R* result, Args... args) {
+ std::string error = "<None>";
+ eval_ctx_->ResetEvaluation();
+ EXPECT_EQ(expected,
+ (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...))
+ << "Returned error: " << error
+ << "\nEvaluation context: " << eval_ctx_->DumpContext();
+ }
+
+ // Runs the passed |method| after resetting the EvaluationContext, in order
+ // to use the method to get a value for other testing (doesn't validate the
+ // return value, just returns it).
+ template <typename T, typename R, typename... Args>
+ EvalStatus CallMethodWithContext(T method, R* result, Args... args) {
+ std::string error = "<None>";
+ eval_ctx_->ResetEvaluation();
+ return (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...);
+ }
+
+ // Runs the passed |policy_method| on the framework policy and expects it to
+ // return the |expected| return value.
+ template <typename T, typename R, typename... Args>
+ void ExpectPolicyStatus(EvalStatus expected,
+ T policy_method,
+ R* result,
+ Args... args) {
+ std::string error = "<None>";
+ eval_ctx_->ResetEvaluation();
+ EXPECT_EQ(expected,
+ (policy_.get()->*policy_method)(
+ eval_ctx_.get(), &fake_state_, &error, result, args...))
+ << "Returned error: " << error
+ << "\nEvaluation context: " << eval_ctx_->DumpContext();
+ }
+
+ brillo::FakeMessageLoop loop_{nullptr};
+ chromeos_update_engine::FakeClock fake_clock_;
+ FakeState fake_state_;
+ scoped_refptr<EvaluationContext> eval_ctx_;
+ std::unique_ptr<Policy> policy_;
+};
+
+} // namespace chromeos_update_manager
+
+#endif // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
\ No newline at end of file
diff --git a/update_manager/policy_utils.h b/update_manager/policy_utils.h
index 960987e..e448022 100644
--- a/update_manager/policy_utils.h
+++ b/update_manager/policy_utils.h
@@ -35,4 +35,84 @@
} \
} while (false)
+namespace chromeos_update_manager {
+
+// Call the passed-in Policy method on a series of Policy implementations, until
+// one of them renders a decision by returning a value other than
+// |EvalStatus::kContinue|.
+template <typename T, typename R, typename... Args>
+EvalStatus ConsultPolicies(const std::vector<Policy const*> policies,
+ T policy_method,
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ R* result,
+ Args... args) {
+ for (auto policy : policies) {
+ EvalStatus status =
+ (policy->*policy_method)(ec, state, error, result, args...);
+ if (status != EvalStatus::kContinue) {
+ LOG(INFO) << "decision by " << policy->PolicyRequestName(policy_method);
+ return status;
+ }
+ }
+ return EvalStatus::kContinue;
+};
+
+// Base class implementation that returns |EvalStatus::kContinue| for all
+// decisions, to be used as a base-class for various Policy facets that only
+// pertain to certain situations. This might be better folded into Policy
+// instead of using pure-virtual methods on that class.
+class PolicyImplBase : public Policy {
+ public:
+ // Policy overrides.
+ EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateCheckParams* result) const override {
+ return EvalStatus::kContinue;
+ };
+
+ EvalStatus UpdateCanBeApplied(
+ EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ chromeos_update_engine::ErrorCode* result,
+ chromeos_update_engine::InstallPlan* install_plan) const override {
+ return EvalStatus::kContinue;
+ };
+
+ EvalStatus UpdateCanStart(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ UpdateDownloadParams* result,
+ UpdateState update_state) const override {
+ return EvalStatus::kContinue;
+ };
+
+ EvalStatus UpdateDownloadAllowed(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result) const override {
+ return EvalStatus::kContinue;
+ };
+
+ EvalStatus P2PEnabled(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result) const override {
+ return EvalStatus::kContinue;
+ };
+
+ EvalStatus P2PEnabledChanged(EvaluationContext* ec,
+ State* state,
+ std::string* error,
+ bool* result,
+ bool prev_result) const override {
+ return EvalStatus::kContinue;
+ };
+};
+
+} // namespace chromeos_update_manager
+
#endif // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
diff --git a/update_manager/real_updater_provider.cc b/update_manager/real_updater_provider.cc
index a085f42..efa3609 100644
--- a/update_manager/real_updater_provider.cc
+++ b/update_manager/real_updater_provider.cc
@@ -38,6 +38,7 @@
using chromeos_update_engine::OmahaRequestParams;
using chromeos_update_engine::SystemState;
using std::string;
+using update_engine::UpdateAttemptFlags;
using update_engine::UpdateEngineStatus;
namespace chromeos_update_manager {
@@ -416,40 +417,66 @@
DISALLOW_COPY_AND_ASSIGN(ForcedUpdateRequestedVariable);
};
+// A variable returning the current update restrictions that are in effect.
+class UpdateRestrictionsVariable
+ : public UpdaterVariableBase<UpdateRestrictions> {
+ public:
+ UpdateRestrictionsVariable(const string& name, SystemState* system_state)
+ : UpdaterVariableBase<UpdateRestrictions>(
+ name, kVariableModePoll, system_state) {}
+
+ private:
+ const UpdateRestrictions* GetValue(TimeDelta /* timeout */,
+ string* /* errmsg */) override {
+ UpdateAttemptFlags attempt_flags =
+ system_state()->update_attempter()->GetCurrentUpdateAttemptFlags();
+ UpdateRestrictions restriction_flags = UpdateRestrictions::kNone;
+ // Don't blindly copy the whole value, test and set bits that should
+ // transfer from one set of flags to the other.
+ if (attempt_flags & UpdateAttemptFlags::kFlagRestrictDownload) {
+ restriction_flags = static_cast<UpdateRestrictions>(
+ restriction_flags | UpdateRestrictions::kRestrictDownloading);
+ }
+
+ return new UpdateRestrictions(restriction_flags);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateRestrictionsVariable);
+};
+
// RealUpdaterProvider methods.
RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
- : system_state_(system_state),
- var_updater_started_time_("updater_started_time",
- system_state->clock()->GetWallclockTime()),
- var_last_checked_time_(
- new LastCheckedTimeVariable("last_checked_time", system_state_)),
- var_update_completed_time_(
- new UpdateCompletedTimeVariable("update_completed_time",
- system_state_)),
- var_progress_(new ProgressVariable("progress", system_state_)),
- var_stage_(new StageVariable("stage", system_state_)),
- var_new_version_(new NewVersionVariable("new_version", system_state_)),
- var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
- var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
- var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
- var_p2p_enabled_(
- new BooleanPrefVariable("p2p_enabled", system_state_->prefs(),
- chromeos_update_engine::kPrefsP2PEnabled,
- false)),
- var_cellular_enabled_(
- new BooleanPrefVariable(
- "cellular_enabled", system_state_->prefs(),
- chromeos_update_engine::kPrefsUpdateOverCellularPermission,
- false)),
- var_consecutive_failed_update_checks_(
- new ConsecutiveFailedUpdateChecksVariable(
- "consecutive_failed_update_checks", system_state_)),
- var_server_dictated_poll_interval_(
- new ServerDictatedPollIntervalVariable(
- "server_dictated_poll_interval", system_state_)),
- var_forced_update_requested_(
- new ForcedUpdateRequestedVariable(
- "forced_update_requested", system_state_)) {}
-
+ : system_state_(system_state),
+ var_updater_started_time_("updater_started_time",
+ system_state->clock()->GetWallclockTime()),
+ var_last_checked_time_(
+ new LastCheckedTimeVariable("last_checked_time", system_state_)),
+ var_update_completed_time_(new UpdateCompletedTimeVariable(
+ "update_completed_time", system_state_)),
+ var_progress_(new ProgressVariable("progress", system_state_)),
+ var_stage_(new StageVariable("stage", system_state_)),
+ var_new_version_(new NewVersionVariable("new_version", system_state_)),
+ var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
+ var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
+ var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
+ var_p2p_enabled_(
+ new BooleanPrefVariable("p2p_enabled",
+ system_state_->prefs(),
+ chromeos_update_engine::kPrefsP2PEnabled,
+ false)),
+ var_cellular_enabled_(new BooleanPrefVariable(
+ "cellular_enabled",
+ system_state_->prefs(),
+ chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+ false)),
+ var_consecutive_failed_update_checks_(
+ new ConsecutiveFailedUpdateChecksVariable(
+ "consecutive_failed_update_checks", system_state_)),
+ var_server_dictated_poll_interval_(new ServerDictatedPollIntervalVariable(
+ "server_dictated_poll_interval", system_state_)),
+ var_forced_update_requested_(new ForcedUpdateRequestedVariable(
+ "forced_update_requested", system_state_)),
+ var_update_restrictions_(new UpdateRestrictionsVariable(
+ "update_restrictions", system_state_)) {}
} // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.h b/update_manager/real_updater_provider.h
index eb8b8e6..5e3e27b 100644
--- a/update_manager/real_updater_provider.h
+++ b/update_manager/real_updater_provider.h
@@ -96,6 +96,10 @@
return var_forced_update_requested_.get();
}
+ Variable<UpdateRestrictions>* var_update_restrictions() override {
+ return var_update_restrictions_.get();
+ }
+
private:
// A pointer to the update engine's system state aggregator.
chromeos_update_engine::SystemState* system_state_;
@@ -115,6 +119,7 @@
std::unique_ptr<Variable<unsigned int>> var_consecutive_failed_update_checks_;
std::unique_ptr<Variable<unsigned int>> var_server_dictated_poll_interval_;
std::unique_ptr<Variable<UpdateRequestStatus>> var_forced_update_requested_;
+ std::unique_ptr<Variable<UpdateRestrictions>> var_update_restrictions_;
DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
};
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
index f128c77..72e664b 100644
--- a/update_manager/real_updater_provider_unittest.cc
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -38,10 +38,11 @@
using chromeos_update_engine::OmahaRequestParams;
using std::string;
using std::unique_ptr;
+using testing::_;
using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
namespace {
@@ -425,4 +426,20 @@
kPollInterval, provider_->var_server_dictated_poll_interval());
}
+TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictions) {
+ EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+ GetCurrentUpdateAttemptFlags())
+ .WillRepeatedly(Return(UpdateAttemptFlags::kFlagRestrictDownload |
+ UpdateAttemptFlags::kFlagNonInteractive));
+ UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kRestrictDownloading,
+ provider_->var_update_restrictions());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictionsNone) {
+ EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+ GetCurrentUpdateAttemptFlags())
+ .WillRepeatedly(Return(UpdateAttemptFlags::kNone));
+ UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kNone,
+ provider_->var_update_restrictions());
+}
} // namespace chromeos_update_manager
diff --git a/update_manager/update_manager.cc b/update_manager/update_manager.cc
index 8e9b221..25f3216 100644
--- a/update_manager/update_manager.cc
+++ b/update_manager/update_manager.cc
@@ -16,7 +16,11 @@
#include "update_engine/update_manager/update_manager.h"
+#ifdef __ANDROID__
+#include "update_engine/update_manager/android_things_policy.h"
+#else
#include "update_engine/update_manager/chromeos_policy.h"
+#endif // __ANDROID__
#include "update_engine/update_manager/state.h"
namespace chromeos_update_manager {
@@ -28,9 +32,11 @@
evaluation_timeout_(evaluation_timeout),
expiration_timeout_(expiration_timeout),
weak_ptr_factory_(this) {
- // TODO(deymo): Make it possible to replace this policy with a different
- // implementation with a build-time flag.
+#ifdef __ANDROID__
+ policy_.reset(new AndroidThingsPolicy());
+#else
policy_.reset(new ChromeOSPolicy());
+#endif // __ANDROID__
}
UpdateManager::~UpdateManager() {
diff --git a/update_manager/updater_provider.h b/update_manager/updater_provider.h
index 549aea9..cb62623 100644
--- a/update_manager/updater_provider.h
+++ b/update_manager/updater_provider.h
@@ -44,6 +44,12 @@
kPeriodic,
};
+// These enum values are a bit-field.
+enum UpdateRestrictions : int {
+ kNone,
+ kRestrictDownloading = (1 << 0),
+};
+
// Provider for Chrome OS update related information.
class UpdaterProvider : public Provider {
public:
@@ -105,6 +111,10 @@
// scheduled update.
virtual Variable<UpdateRequestStatus>* var_forced_update_requested() = 0;
+ // A variable that returns the update restriction flags that are set
+ // for all updates.
+ virtual Variable<UpdateRestrictions>* var_update_restrictions() = 0;
+
protected:
UpdaterProvider() {}