Add functions to allow update over cellular (including tethered connection)
- Add an update state NEED_PERMISSION_TO_UPDATE which is broadcasted along
with the update info (version and size) when |OmahaRequestAction| aborts
update due to cellular connection. So the state transition will be:
IDLE->CHECKING_FOR_UPDATE->NEED_PERMISSION_TO_UPDATE->REPORTING_ERROR_EVENT
->IDLE
(The Chrome UI prompts an alert window showing update size and asks user
whether to proceed upon receiving this state.)
- Add a dbus interface to set update over cellular target
(kPrefsUpdateOverCellularTargetVersion and kPrefsUpdateOverCellularTargetSize).
The target is the one received by Chrome UI in NEED_PERMISSION_TO_UPDATE
broadcast. By sending the target back with the dbus call, update engine can
double check the target with the server to make sure there's no new server
push after NEED_PERMISSION_TO_UPDATE is broadcasted to Chrome UI.
(This dbus call is invoked when the user chooses to proceed to update at the
alert window. The dbus call is followed by another dbus call |AttemptUpdate|)
- So, the the decision tree as to whether to allow update over cellular
connection has changed to:
IF (device policy DeviceUpdateAllowedConnectionTypes set)
follow device policy's decision
ELSE IF (kPrefsUpdateOverCellularPermission set to true)
allow update
ELSE IF (Either kPrefsUpdateOverCellularTargetVersion or
kPrefsUpdateOverCellularTargetSize is not set, or they are set but do not
match the version and size in |OmahaResponse| retrieved by
|OmahaRequestAction|)
disallow update, and broadcast NEED_PERMISSION_TO_UPDATE
ELSE
allow update
ENDIF
- This decision making happens at |OmahaRequestAction| after |OmahaResponse| is
retrieved. Since we want to separate the device policy check with the user
preferences check which depends on |OmahaResponse| during checking for update,
we modify ConnectionManager::IsUpdateAllowedOver by moving the user preferences
check to |OmahaRequestAction|. Thus, the function by default returns true for
cellular connection if device policy is not set.
- Corner case:
Adding kPrefsUpdateOverCellularPermission and
kPrefsUpdateOverCellularTargetSize seems to complicate the logic here. But
they could effectively solve a corner case where the target does not match
|OmahaResponse| due to new server push after broadcasting
NEED_PERMISSION_TO_UPDATE. In that case, we simply broadcast
NEED_PERMISSION_TO_UPDATE again along with new update info.
CQ-DEPEND=CL:481102
BUG=chromium:691108
TEST='FEATURES=test emerge-link update_engine'
(cherry picked from commit 70063d9f7e229db8c5b42443ca96ac23a971a6dd)
Cherry-pick updated to compile on Android.
Reviewed-on: https://chromium-review.googlesource.com/479467
Commit-Ready: Weidong Guo <[email protected]>
Tested-by: Weidong Guo <[email protected]>
Reviewed-by: Weidong Guo <[email protected]>
Reviewed-by: Andrew de los Reyes <[email protected]>
Reviewed-by: Ben Chan <[email protected]>
diff --git a/common_service.cc b/common_service.cc
index 1a41b63..ee890e1 100644
--- a/common_service.cc
+++ b/common_service.cc
@@ -16,7 +16,6 @@
#include "update_engine/common_service.h"
-#include <set>
#include <string>
#include <base/location.h>
@@ -41,7 +40,6 @@
using base::StringPrintf;
using brillo::ErrorPtr;
using brillo::string_utils::ToString;
-using std::set;
using std::string;
namespace chromeos_update_engine {
@@ -248,24 +246,12 @@
bool UpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error,
bool in_allowed) {
- set<string> allowed_types;
- const policy::DevicePolicy* device_policy = system_state_->device_policy();
-
- // The device_policy is loaded in a lazy way before an update check. Load it
- // now from the libbrillo cache if it wasn't already loaded.
- if (!device_policy) {
- UpdateAttempter* update_attempter = system_state_->update_attempter();
- if (update_attempter) {
- update_attempter->RefreshDevicePolicy();
- device_policy = system_state_->device_policy();
- }
- }
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
// Check if this setting is allowed by the device policy.
- if (device_policy &&
- device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
- LogAndSetError(error,
- FROM_HERE,
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
+ LogAndSetError(error, FROM_HERE,
"Ignoring the update over cellular setting since there's "
"a device policy enforcing this setting.");
return false;
@@ -276,9 +262,9 @@
PrefsInterface* prefs = system_state_->prefs();
- if (!prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) {
- LogAndSetError(error,
- FROM_HERE,
+ if (!prefs ||
+ !prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) {
+ LogAndSetError(error, FROM_HERE,
string("Error setting the update over cellular to ") +
(in_allowed ? "true" : "false"));
return false;
@@ -286,24 +272,63 @@
return true;
}
-bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* /* error */,
- bool* out_allowed) {
- ConnectionManagerInterface* cm = system_state_->connection_manager();
+bool UpdateEngineService::SetUpdateOverCellularTarget(
+ brillo::ErrorPtr* error, const std::string &target_version,
+ int64_t target_size) {
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
- // The device_policy is loaded in a lazy way before an update check and is
- // used to determine if an update is allowed over cellular. Load the device
- // policy now from the libbrillo cache if it wasn't already loaded.
- if (!system_state_->device_policy()) {
- UpdateAttempter* update_attempter = system_state_->update_attempter();
- if (update_attempter)
- update_attempter->RefreshDevicePolicy();
+ // Check if this setting is allowed by the device policy.
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
+ LogAndSetError(error, FROM_HERE,
+ "Ignoring the update over cellular setting since there's "
+ "a device policy enforcing this setting.");
+ return false;
}
- // Return the current setting based on the same logic used while checking for
- // updates. A log message could be printed as the result of this test.
- LOG(INFO) << "Checking if updates over cellular networks are allowed:";
- *out_allowed = cm->IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown);
+ // If the policy wasn't loaded yet, then it is still OK to change the local
+ // setting because the policy will be checked again during the update check.
+
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs ||
+ !prefs->SetString(kPrefsUpdateOverCellularTargetVersion,
+ target_version) ||
+ !prefs->SetInt64(kPrefsUpdateOverCellularTargetSize, target_size)) {
+ LogAndSetError(error, FROM_HERE,
+ "Error setting the target for update over cellular.");
+ return false;
+ }
+ return true;
+}
+
+bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* error,
+ bool* out_allowed) {
+ ConnectionManagerInterface* connection_manager =
+ system_state_->connection_manager();
+
+ if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
+ // We have device policy, so ignore the user preferences.
+ *out_allowed = connection_manager->IsUpdateAllowedOver(
+ ConnectionType::kCellular, ConnectionTethering::kUnknown);
+ } else {
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
+ // Update is not allowed as user preference is not set or not available.
+ *out_allowed = false;
+ return true;
+ }
+
+ bool is_allowed;
+
+ if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed)) {
+ LogAndSetError(error, FROM_HERE,
+ "Error getting the update over cellular preference.");
+ return false;
+ }
+ *out_allowed = is_allowed;
+ }
return true;
}