update_engine: Allow `cros flash` on base images.

A goal of the upcoming debugd dev tools (crbug.com/403170), is to
enable a path to modify a base image such that a developer could run
`cros flash` on it.

Currently update_engine disallows custom omaha URLs and forces a hash
check for base builds, which breaks `cros flash`. This CL relaxes the
restriction slightly to allow use on a base build as long as the system
is in dev mode and the debugd dev tools are also enabled (dev tools are
currently enabled only in dev mode when there is no owner).

The check is done in update_attempter.cc, which only allows an unofficial
Omaha URL if these conditions hold true (unofficial meaning not the main
AU server or the AU test server). The other main change is
AreHashChecksMandatory() in omaha_response_handler_action.cc, which now
allows skipping hash checks for unofficial Omaha URLs.

BUG=chromium:428053
TEST=Ran unit tests, `cros flash` on base images in various states.
CQ-DEPEND=CL:227431

Change-Id: I8583ce6aa70feac8fe74b7a3992e8a4e761833c3
Reviewed-on: https://chromium-review.googlesource.com/228293
Reviewed-by: Alex Deymo <deymo@chromium.org>
Trybot-Ready: David Pursell <dpursell@chromium.org>
Commit-Queue: David Pursell <dpursell@chromium.org>
Tested-by: David Pursell <dpursell@chromium.org>
diff --git a/update_attempter.cc b/update_attempter.cc
index f523839..a6aa2b5 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -72,8 +72,14 @@
 namespace {
 const int kMaxConsecutiveObeyProxyRequests = 20;
 
-const char* kUpdateCompletedMarker =
+const char kUpdateCompletedMarker[] =
     "/var/run/update_engine_autoupdate_completed";
+
+// By default autest bypasses scattering. If we want to test scattering,
+// use kScheduledAUTestURLRequest. The URL used is same in both cases, but
+// different params are passed to CheckForUpdate().
+const char kAUTestURLRequest[] = "autest";
+const char kScheduledAUTestURLRequest[] = "autest-scheduled";
 }  // namespace
 
 const char* UpdateStatusToString(UpdateStatus status) {
@@ -810,8 +816,26 @@
                                      const string& omaha_url,
                                      bool interactive) {
   LOG(INFO) << "Forced update check requested.";
-  forced_app_version_ = app_version;
-  forced_omaha_url_ = omaha_url;
+  forced_app_version_.clear();
+  forced_omaha_url_.clear();
+
+  // Certain conditions must be met to allow setting custom version and update
+  // server URLs. However, kScheduledAUTestURLRequest and kAUTestURLRequest are
+  // always allowed regardless of device state.
+  if (IsAnyUpdateSourceAllowed()) {
+    forced_app_version_ = app_version;
+    forced_omaha_url_ = omaha_url;
+  }
+  if (omaha_url == kScheduledAUTestURLRequest) {
+    forced_omaha_url_ = chromeos_update_engine::kAUTestOmahaUrl;
+    // Pretend that it's not user-initiated even though it is,
+    // so as to test scattering logic, etc. which get kicked off
+    // only in scheduled update checks.
+    interactive = false;
+  } else if (omaha_url == kAUTestURLRequest) {
+    forced_omaha_url_ = chromeos_update_engine::kAUTestOmahaUrl;
+  }
+
   if (forced_update_pending_callback_.get()) {
     // Make sure that a scheduling request is made prior to calling the forced
     // update pending callback.
@@ -1603,4 +1627,50 @@
           waiting_for_scheduled_check_);
 }
 
+bool UpdateAttempter::IsAnyUpdateSourceAllowed() {
+  // Non-official (dev or test) builds can always use a custom update source.
+  if (!system_state_->hardware()->IsOfficialBuild()) {
+    LOG(INFO) << "Non-official build; allowing any update source.";
+    return true;
+  }
+
+  // Official images not in devmode are never allowed a custom update source.
+  if (system_state_->hardware()->IsNormalBootMode()) {
+    LOG(INFO) << "Not in devmode; disallowing custom update sources.";
+    return false;
+  }
+
+  // Official images in devmode are allowed a custom update source iff the
+  // debugd dev tools are enabled.
+  GError* error = nullptr;
+  DBusGConnection* bus = dbus_iface_->BusGet(DBUS_BUS_SYSTEM, &error);
+  if (!bus) {
+    LOG(ERROR) << "Failed to get system bus: "
+               << utils::GetAndFreeGError(&error);
+    return false;
+  }
+
+  gint dev_features = debugd::DEV_FEATURES_DISABLED;
+  DBusGProxy* proxy = dbus_iface_->ProxyNewForName(
+      bus,
+      debugd::kDebugdServiceName,
+      debugd::kDebugdServicePath,
+      debugd::kDebugdInterface);
+  const gboolean success = dbus_iface_->ProxyCall_0_1(
+      proxy,
+      debugd::kQueryDevFeatures,
+      &error,
+      &dev_features);
+  dbus_iface_->ProxyUnref(proxy);
+
+  // Some boards may not include debugd so it's expected that this may fail,
+  // in which case we default to disallowing custom update sources.
+  if (success && !(dev_features & debugd::DEV_FEATURES_DISABLED)) {
+    LOG(INFO) << "Debugd dev tools enabled; allowing any update source.";
+    return true;
+  }
+  LOG(INFO) << "Debugd dev tools disabled; disallowing custom update sources.";
+  return false;
+}
+
 }  // namespace chromeos_update_engine