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'
Change-Id: I91b07e6030f202f7d0d48fb50787115695f228e3
Reviewed-on: https://chromium-review.googlesource.com/479467
Commit-Ready: Weidong Guo <weidongg@chromium.org>
Tested-by: Weidong Guo <weidongg@chromium.org>
Reviewed-by: Weidong Guo <weidongg@chromium.org>
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
Reviewed-by: Ben Chan <benchan@chromium.org>
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 173d387..fb258c2 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -980,9 +980,11 @@
output_object.update_exists = true;
SetOutputObject(output_object);
- if (ShouldIgnoreUpdate(output_object)) {
- output_object.update_exists = false;
- completer.set_code(ErrorCode::kOmahaUpdateIgnoredPerPolicy);
+ ErrorCode error = ErrorCode::kSuccess;
+ if (ShouldIgnoreUpdate(&error, output_object)) {
+ // No need to change output_object.update_exists here, since the value
+ // has been output to the pipe.
+ completer.set_code(error);
return;
}
@@ -1439,6 +1441,7 @@
break;
case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
+ case ErrorCode::kOmahaUpdateIgnoredOverCellular:
result = metrics::CheckResult::kUpdateAvailable;
reaction = metrics::CheckReaction::kIgnored;
break;
@@ -1473,7 +1476,7 @@
}
bool OmahaRequestAction::ShouldIgnoreUpdate(
- const OmahaResponse& response) const {
+ ErrorCode* error, const OmahaResponse& response) const {
// Note: policy decision to not update to a version we rolled back from.
string rollback_version =
system_state_->payload_state()->GetRollbackVersion();
@@ -1481,11 +1484,12 @@
LOG(INFO) << "Detected previous rollback from version " << rollback_version;
if (rollback_version == response.version) {
LOG(INFO) << "Received version that we rolled back from. Ignoring.";
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
return true;
}
}
- if (!IsUpdateAllowedOverCurrentConnection()) {
+ if (!IsUpdateAllowedOverCurrentConnection(error, response)) {
LOG(INFO) << "Update is not allowed over current connection.";
return true;
}
@@ -1500,7 +1504,59 @@
return false;
}
-bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection() const {
+bool OmahaRequestAction::IsUpdateAllowedOverCellularByPrefs(
+ const OmahaResponse& response) const {
+ PrefsInterface* prefs = system_state_->prefs();
+
+ if (!prefs) {
+ LOG(INFO) << "Disabling updates over cellular as the preferences are "
+ "not available.";
+ return false;
+ }
+
+ bool is_allowed;
+
+ if (prefs->Exists(kPrefsUpdateOverCellularPermission) &&
+ prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed) &&
+ is_allowed) {
+ LOG(INFO) << "Allowing updates over cellular as permission preference is "
+ "set to true.";
+ return true;
+ }
+
+ if (!prefs->Exists(kPrefsUpdateOverCellularTargetVersion) ||
+ !prefs->Exists(kPrefsUpdateOverCellularTargetSize)) {
+ LOG(INFO) << "Disabling updates over cellular as permission preference is "
+ "set to false or does not exist while target does not exist.";
+ return false;
+ }
+
+ std::string target_version;
+ int64_t target_size;
+
+ if (!prefs->GetString(kPrefsUpdateOverCellularTargetVersion,
+ &target_version) ||
+ !prefs->GetInt64(kPrefsUpdateOverCellularTargetSize,
+ &target_size)) {
+ LOG(INFO) << "Disabling updates over cellular as the target version or "
+ "size is not accessible.";
+ return false;
+ }
+
+ if (target_version == response.version && target_size == response.size) {
+ LOG(INFO) << "Allowing updates over cellular as the target matches the"
+ "omaha response.";
+ return true;
+ } else {
+ LOG(INFO) << "Disabling updates over cellular as the target does not"
+ "match the omaha response.";
+ return false;
+ }
+}
+
+bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection(
+ ErrorCode* error,
+ const OmahaResponse& response) const {
NetworkConnectionType type;
NetworkTethering tethering;
ConnectionManagerInterface* connection_manager =
@@ -1510,7 +1566,30 @@
<< "Defaulting to allow updates.";
return true;
}
+
bool is_allowed = connection_manager->IsUpdateAllowedOver(type, tethering);
+ bool is_device_policy_set = connection_manager->
+ IsAllowedConnectionTypesForUpdateSet();
+ // Treats tethered connection as if it is cellular connection.
+ bool is_over_cellular = type == NetworkConnectionType::kCellular ||
+ tethering == NetworkTethering::kConfirmed;
+
+ if (!is_over_cellular) {
+ // There's no need to further check user preferences as we are not over
+ // cellular connection.
+ if (!is_allowed)
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
+ } else if (is_device_policy_set) {
+ // There's no need to further check user preferences as the device policy
+ // is set regarding updates over cellular.
+ if (!is_allowed)
+ *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
+ } else if (!IsUpdateAllowedOverCellularByPrefs(response)) {
+ // The user prefereces does not allow updates over cellular.
+ is_allowed = false;
+ *error = ErrorCode::kOmahaUpdateIgnoredOverCellular;
+ }
+
LOG(INFO) << "We are connected via "
<< ConnectionManager::StringForConnectionType(type)
<< ", Updates allowed: " << (is_allowed ? "Yes" : "No");