Add support to update_engine_client for -app_version and -omaha_url.

These options prevent auto-detection of these parameters.
Note that this CL makes the check_for_update DBus method obsolete from
the client's point of view.

BUG=4593
TEST=unit tests, gmerged on device and tried the client with different options.

Review URL: http://codereview.chromium.org/3048008
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index fe332c0..05f0056 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -15,10 +15,13 @@
     <!-- allow explicit methods -->
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
-           send_member="GetStatus"/>
+           send_member="AttemptUpdate"/>
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
            send_member="CheckForUpdate"/>
+    <allow send_destination="org.chromium.UpdateEngine"
+           send_interface="org.chromium.UpdateEngineInterface"
+           send_member="GetStatus"/>
   </policy>
   <policy context="default">
     <deny send_destination="org.chromium.UpdateEngine" />
diff --git a/dbus_service.cc b/dbus_service.cc
index 12398cd..54dde41 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -21,7 +21,7 @@
   GObjectClass *object_class;
   object_class = G_OBJECT_CLASS(klass);
   object_class->finalize = update_engine_service_finalize;
-  
+
   status_update_signal = g_signal_new(
       "status_update",
       G_OBJECT_CLASS_TYPE(klass),
@@ -56,21 +56,33 @@
                                           GError **error) {
   string current_op;
   string new_version_str;
-  
+
   CHECK(self->update_attempter_->GetStatus(last_checked_time,
                                            progress,
                                            &current_op,
                                            &new_version_str,
                                            new_size));
-  
+
   *current_operation = strdup(current_op.c_str());
   *new_version = strdup(new_version_str.c_str());
   return TRUE;
 }
 
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+                                              gchar* app_version,
+                                              gchar* omaha_url,
+                                              GError **error) {
+  const string update_app_version = app_version ? app_version : "";
+  const string update_omaha_url = omaha_url ? omaha_url : "";
+  LOG(INFO) << "Attempt update: app_version=\"" << update_app_version << "\" "
+            << "omaha_url=\"" << update_omaha_url << "\"";
+  self->update_attempter_->CheckForUpdate(app_version, omaha_url);
+  return TRUE;
+}
+
 gboolean update_engine_service_check_for_update(UpdateEngineService* self,
                                                 GError **error) {
-  self->update_attempter_->CheckForUpdate();
+  self->update_attempter_->CheckForUpdate("", "");
   return TRUE;
 }
 
diff --git a/dbus_service.h b/dbus_service.h
index 40cb987..4b760ce 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -57,6 +57,11 @@
 gboolean update_engine_service_check_for_update(UpdateEngineService* self,
                                                 GError **error);
 
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+                                              gchar* app_version,
+                                              gchar* omaha_url,
+                                              GError **error);
+
 gboolean update_engine_service_emit_status_update(
     UpdateEngineService* self,
     gint64 last_checked_time,
diff --git a/main.cc b/main.cc
index 268bcc0..204c525 100644
--- a/main.cc
+++ b/main.cc
@@ -40,7 +40,7 @@
 
 gboolean PeriodicallyUpdate(void* arg) {
   PeriodicallyUpdateArgs* args = reinterpret_cast<PeriodicallyUpdateArgs*>(arg);
-  args->update_attempter->Update();
+  args->update_attempter->Update("", "");
   return args->should_repeat;
 }
 
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 97c1ea9..cca2094 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -20,13 +20,6 @@
 
 namespace chromeos_update_engine {
 
-const char* const OmahaRequestParams::kAppId(
-    "{87efface-864d-49a5-9bb3-4b050a7c227a}");
-const char* const OmahaRequestParams::kOsPlatform("Chrome OS");
-const char* const OmahaRequestParams::kOsVersion("Indy");
-const char* const OmahaRequestParams::kUpdateUrl(
-    "https://tools.google.com/service/update2");
-
 namespace {
 
 const string kGupdateVersion("ChromeOSUpdateEngine-0.1.0.0");
diff --git a/omaha_request_params.cc b/omaha_request_params.cc
index 1ab6f2c..33281ee 100644
--- a/omaha_request_params.cc
+++ b/omaha_request_params.cc
@@ -27,27 +27,37 @@
 
 namespace chromeos_update_engine {
 
-bool OmahaRequestDeviceParams::Init() {
+const char* const OmahaRequestParams::kAppId(
+    "{87efface-864d-49a5-9bb3-4b050a7c227a}");
+const char* const OmahaRequestParams::kOsPlatform("Chrome OS");
+const char* const OmahaRequestParams::kOsVersion("Indy");
+const char* const OmahaRequestParams::kUpdateUrl(
+    "https://tools.google.com/service/update2");
+
+bool OmahaRequestDeviceParams::Init(const std::string& in_app_version,
+                                    const std::string& in_update_url) {
   TEST_AND_RETURN_FALSE(GetMachineId(&machine_id));
   user_id = machine_id;
   os_platform = OmahaRequestParams::kOsPlatform;
   os_version = OmahaRequestParams::kOsVersion;
-  app_version = GetLsbValue("CHROMEOS_RELEASE_VERSION", "");
+  app_version = in_app_version.empty() ?
+      GetLsbValue("CHROMEOS_RELEASE_VERSION", "") : in_app_version;
   os_sp = app_version + "_" + GetMachineType();
   os_board = GetLsbValue("CHROMEOS_RELEASE_BOARD", "");
   app_id = OmahaRequestParams::kAppId;
   app_lang = "en-US";
   app_track = GetLsbValue("CHROMEOS_RELEASE_TRACK", "");
   struct stat stbuf;
-  
+
   // Deltas are only okay if the /.nodelta file does not exist.
   // If we don't know (i.e. stat() returns some unexpected error),
   // then err on the side of caution and say deltas are not okay
   delta_okay = (stat((root_ + "/.nodelta").c_str(), &stbuf) < 0) &&
                (errno == ENOENT);
 
-  update_url = GetLsbValue("CHROMEOS_AUSERVER",
-                           OmahaRequestParams::kUpdateUrl);
+  update_url = in_update_url.empty() ?
+      GetLsbValue("CHROMEOS_AUSERVER", OmahaRequestParams::kUpdateUrl) :
+      in_update_url;
   return true;
 }
 
diff --git a/omaha_request_params.h b/omaha_request_params.h
index fb4196e..16def25 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -67,11 +67,13 @@
 
 class OmahaRequestDeviceParams : public OmahaRequestParams {
  public:
-  explicit OmahaRequestDeviceParams() {}
+  OmahaRequestDeviceParams() {}
 
-  // Initializes all the data in the object. Returns true on success,
-  // false otherwise.
-  bool Init();
+  // Initializes all the data in the object. Non-empty
+  // |in_app_version| or |in_update_url| prevents automatic detection
+  // of the parameter. Returns true on success, false otherwise.
+  bool Init(const std::string& in_app_version,
+            const std::string& in_update_url);
 
   // For unit-tests.
   void set_root(const std::string& root) { root_ = root; }
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index 200b23b..07615a2 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -15,20 +15,34 @@
 namespace chromeos_update_engine {
 
 class OmahaRequestDeviceParamsTest : public ::testing::Test {
- public:
+ protected:
   // Return true iff the OmahaRequestDeviceParams::Init succeeded. If
   // out is non-NULL, it's set w/ the generated data.
-  bool DoTest(OmahaRequestParams* out);
+  bool DoTest(OmahaRequestParams* out, const string& app_version,
+              const string& omaha_url);
+
+  virtual void SetUp() {
+    ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
+    ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
+                        utils::kStatefulPartition + "/etc"));
+  }
+
+  virtual void TearDown() {
+    EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
+  }
+
   static const string kTestDir;
 };
 
 const string OmahaRequestDeviceParamsTest::kTestDir =
     "omaha_request_device_params-test";
 
-bool OmahaRequestDeviceParamsTest::DoTest(OmahaRequestParams* out) {
+bool OmahaRequestDeviceParamsTest::DoTest(OmahaRequestParams* out,
+                                          const string& app_version,
+                                          const string& omaha_url) {
   OmahaRequestDeviceParams params;
   params.set_root(string("./") + kTestDir);
-  bool success = params.Init();
+  bool success = params.Init(app_version, omaha_url);
   if (out)
     *out = params;
   return success;
@@ -77,94 +91,75 @@
 }  // namespace {}
 
 TEST_F(OmahaRequestDeviceParamsTest, SimpleTest) {
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
-                      utils::kStatefulPartition + "/etc"));
-  {
-    ASSERT_TRUE(WriteFileString(
-        kTestDir + "/etc/lsb-release",
-        "CHROMEOS_RELEASE_BOARD=arm-generic\n"
-        "CHROMEOS_RELEASE_FOO=bar\n"
-        "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
-        "CHROMEOS_RELEASE_TRACK=footrack"));
-    OmahaRequestParams out;
-    EXPECT_TRUE(DoTest(&out));
-    EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
-    // for now we're just using the machine id here
-    EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
-    EXPECT_EQ("Chrome OS", out.os_platform);
-    EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
-    EXPECT_EQ("arm-generic", out.os_board);
-    EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
-    EXPECT_EQ("0.2.2.3", out.app_version);
-    EXPECT_EQ("en-US", out.app_lang);
-    EXPECT_TRUE(out.delta_okay);
-    EXPECT_EQ("footrack", out.app_track);
-  }
-  EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_BOARD=arm-generic\n"
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+      "CHROMEOS_RELEASE_TRACK=footrack\n"
+      "CHROMEOS_AUSERVER=http://www.google.com"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("arm-generic", out.os_board);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("0.2.2.3", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_TRUE(out.delta_okay);
+  EXPECT_EQ("footrack", out.app_track);
+  EXPECT_EQ("http://www.google.com", out.update_url);
 }
 
 TEST_F(OmahaRequestDeviceParamsTest, MissingTrackTest) {
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
-                      utils::kStatefulPartition + "/etc"));
-  {
-    ASSERT_TRUE(WriteFileString(
-        kTestDir + "/etc/lsb-release",
-        "CHROMEOS_RELEASE_FOO=bar\n"
-        "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
-        "CHROMEOS_RELEASE_TRXCK=footrack"));
-    OmahaRequestParams out;
-    EXPECT_TRUE(DoTest(&out));
-    EXPECT_TRUE(IsValidGuid(out.machine_id));
-    // for now we're just using the machine id here
-    EXPECT_TRUE(IsValidGuid(out.user_id));
-    EXPECT_EQ("Chrome OS", out.os_platform);
-    EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
-    EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
-    EXPECT_EQ("0.2.2.3", out.app_version);
-    EXPECT_EQ("en-US", out.app_lang);
-    EXPECT_EQ("", out.app_track);
-  }
-  EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+      "CHROMEOS_RELEASE_TRXCK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id));
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id));
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("0.2.2.3", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_EQ("", out.app_track);
 }
 
 TEST_F(OmahaRequestDeviceParamsTest, ConfusingReleaseTest) {
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
-                      utils::kStatefulPartition + "/etc"));
-  {
-    ASSERT_TRUE(WriteFileString(
-        kTestDir + "/etc/lsb-release",
-        "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
-        "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
-        "CHROMEOS_RELEASE_TRXCK=footrack"));
-    OmahaRequestParams out;
-    EXPECT_TRUE(DoTest(&out));
-    EXPECT_TRUE(IsValidGuid(out.machine_id)) << out.machine_id;
-    // for now we're just using the machine id here
-    EXPECT_TRUE(IsValidGuid(out.user_id));
-    EXPECT_EQ("Chrome OS", out.os_platform);
-    EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
-    EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
-    EXPECT_EQ("0.2.2.3", out.app_version);
-    EXPECT_EQ("en-US", out.app_lang);
-    EXPECT_EQ("", out.app_track);
-  }
-  EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
+      "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+      "CHROMEOS_RELEASE_TRXCK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id));
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("0.2.2.3", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_EQ("", out.app_track);
 }
 
 TEST_F(OmahaRequestDeviceParamsTest, MachineIdPersistsTest) {
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
-                      utils::kStatefulPartition + "/etc"));
   ASSERT_TRUE(WriteFileString(
       kTestDir + "/etc/lsb-release",
       "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
       "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
       "CHROMEOS_RELEASE_TRXCK=footrack"));
   OmahaRequestParams out1;
-  EXPECT_TRUE(DoTest(&out1));
+  EXPECT_TRUE(DoTest(&out1, "", ""));
   string machine_id;
   EXPECT_TRUE(utils::ReadFileToString(
       kTestDir +
@@ -172,15 +167,99 @@
       &machine_id));
   EXPECT_EQ(machine_id, out1.machine_id);
   OmahaRequestParams out2;
-  EXPECT_TRUE(DoTest(&out2));
+  EXPECT_TRUE(DoTest(&out2, "", ""));
   EXPECT_EQ(machine_id, out2.machine_id);
-  EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
+}
+
+TEST_F(OmahaRequestDeviceParamsTest, MissingVersionTest) {
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_BOARD=arm-generic\n"
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_TRACK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("arm-generic", out.os_board);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_TRUE(out.delta_okay);
+  EXPECT_EQ("footrack", out.app_track);
+}
+
+TEST_F(OmahaRequestDeviceParamsTest, ForceVersionTest) {
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_BOARD=arm-generic\n"
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_TRACK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "ForcedVersion", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("ForcedVersion_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("arm-generic", out.os_board);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("ForcedVersion", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_TRUE(out.delta_okay);
+  EXPECT_EQ("footrack", out.app_track);
+}
+
+TEST_F(OmahaRequestDeviceParamsTest, ForcedURLTest) {
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_BOARD=arm-generic\n"
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+      "CHROMEOS_RELEASE_TRACK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", "http://forced.google.com"));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("arm-generic", out.os_board);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("0.2.2.3", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_TRUE(out.delta_okay);
+  EXPECT_EQ("footrack", out.app_track);
+  EXPECT_EQ("http://forced.google.com", out.update_url);
+}
+
+TEST_F(OmahaRequestDeviceParamsTest, MissingURLTest) {
+  ASSERT_TRUE(WriteFileString(
+      kTestDir + "/etc/lsb-release",
+      "CHROMEOS_RELEASE_BOARD=arm-generic\n"
+      "CHROMEOS_RELEASE_FOO=bar\n"
+      "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+      "CHROMEOS_RELEASE_TRACK=footrack"));
+  OmahaRequestParams out;
+  EXPECT_TRUE(DoTest(&out, "", ""));
+  EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
+  // for now we're just using the machine id here
+  EXPECT_TRUE(IsValidGuid(out.user_id)) << "id: " << out.user_id;
+  EXPECT_EQ("Chrome OS", out.os_platform);
+  EXPECT_EQ(string("0.2.2.3_") + GetMachineType(), out.os_sp);
+  EXPECT_EQ("arm-generic", out.os_board);
+  EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", out.app_id);
+  EXPECT_EQ("0.2.2.3", out.app_version);
+  EXPECT_EQ("en-US", out.app_lang);
+  EXPECT_TRUE(out.delta_okay);
+  EXPECT_EQ("footrack", out.app_track);
+  EXPECT_EQ(OmahaRequestParams::kUpdateUrl, out.update_url);
 }
 
 TEST_F(OmahaRequestDeviceParamsTest, NoDeltasTest) {
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir + "/etc"));
-  ASSERT_EQ(0, System(string("mkdir -p ") + kTestDir +
-                      utils::kStatefulPartition + "/etc"));
   ASSERT_TRUE(WriteFileString(
       kTestDir + "/etc/lsb-release",
       "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
@@ -188,9 +267,8 @@
       "CHROMEOS_RELEASE_TRXCK=footrack"));
   ASSERT_TRUE(WriteFileString(kTestDir + "/.nodelta", ""));
   OmahaRequestParams out;
-  EXPECT_TRUE(DoTest(&out));
+  EXPECT_TRUE(DoTest(&out, "", ""));
   EXPECT_FALSE(out.delta_okay);
-  EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
 }
 
 }  // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 5cf32e4..014f822 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -114,7 +114,8 @@
   return code;
 }
 
-void UpdateAttempter::Update() {
+void UpdateAttempter::Update(const std::string& app_version,
+                             const std::string& omaha_url) {
   if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
     LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
               << "reboot";
@@ -124,7 +125,7 @@
     // Update in progress. Do nothing
     return;
   }
-  if (!omaha_request_params_.Init()) {
+  if (!omaha_request_params_.Init(app_version, omaha_url)) {
     LOG(ERROR) << "Unable to initialize Omaha request device params.";
     return;
   }
@@ -210,13 +211,14 @@
   processor_.StartProcessing();
 }
 
-void UpdateAttempter::CheckForUpdate() {
+void UpdateAttempter::CheckForUpdate(const std::string& app_version,
+                                     const std::string& omaha_url) {
   if (status_ != UPDATE_STATUS_IDLE) {
     LOG(INFO) << "Check for update requested, but status is "
               << UpdateStatusToString(status_) << ", so not checking.";
     return;
   }
-  Update();
+  Update(app_version, omaha_url);
 }
 
 // Delegate methods:
diff --git a/update_attempter.h b/update_attempter.h
index 269edec..3e47969 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -51,7 +51,10 @@
     if (utils::FileExists(kUpdateCompletedMarker))
       status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
   }
-  void Update();
+  // Checks for update and, if a newer version is available, attempts
+  // to update the system. Non-empty |in_app_version| or
+  // |in_update_url| prevents automatic detection of the parameter.
+  void Update(const std::string& app_version, const std::string& omaha_url);
 
   // ActionProcessorDelegate methods:
   void ProcessingDone(const ActionProcessor* processor, ActionExitCode code);
@@ -78,7 +81,10 @@
     dbus_service_ = dbus_service;
   }
 
-  void CheckForUpdate();
+  // This is the D-Bus service entry point for going through an
+  // update. If the current status is idle invokes Update.
+  void CheckForUpdate(const std::string& app_version,
+                      const std::string& omaha_url);
 
   // DownloadActionDelegate method
   void BytesReceived(uint64_t bytes_received, uint64_t total);
diff --git a/update_engine.xml b/update_engine.xml
index f5faaeb..9cd9d42 100644
--- a/update_engine.xml
+++ b/update_engine.xml
@@ -16,6 +16,10 @@
     </method>
     <method name="CheckForUpdate">
     </method>
+    <method name="AttemptUpdate">
+      <arg type="s" name="app_version" />
+      <arg type="s" name="omaha_url" />
+    </method>
     <signal name="StatusUpdate">
       <arg type="x" name="last_checked_time" />
       <arg type="d" name="progress" />
diff --git a/update_engine_client.cc b/update_engine_client.cc
index e68a7aa..bb4beaa 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <string>
+
 #include <gflags/gflags.h>
 #include <glib.h>
 
@@ -18,12 +20,17 @@
 using chromeos_update_engine::kUpdateEngineServicePath;
 using chromeos_update_engine::kUpdateEngineServiceInterface;
 using chromeos_update_engine::utils::GetGErrorMessage;
+using std::string;
 
-DEFINE_bool(status, false, "Print the status to stdout.");
-DEFINE_bool(force_update, false,
-            "Force an update, even over an expensive network.");
+DEFINE_string(app_version, "",
+              "Force the current app version.");
 DEFINE_bool(check_for_update, false,
             "Initiate check for updates.");
+DEFINE_bool(force_update, false,
+            "Force an update, even over an expensive network.");
+DEFINE_string(omaha_url, "",
+              "The URL of the Omaha update server.");
+DEFINE_bool(status, false, "Print the status to stdout.");
 DEFINE_bool(watch_for_updates, false,
             "Listen for status updates and print them to the screen.");
 
@@ -134,14 +141,18 @@
   g_main_loop_unref(loop);
 }
 
-bool CheckForUpdates(bool force) {
+bool CheckForUpdates(bool force, const string& app_version,
+                     const string& omaha_url) {
   DBusGProxy* proxy;
   GError* error = NULL;
 
   CHECK(GetProxy(&proxy));
 
   gboolean rc =
-      org_chromium_UpdateEngineInterface_check_for_update(proxy, &error);
+      org_chromium_UpdateEngineInterface_attempt_update(proxy,
+                                                        app_version.c_str(),
+                                                        omaha_url.c_str(),
+                                                        &error);
   CHECK_EQ(rc, TRUE) << "Error checking for update: "
                      << GetGErrorMessage(error);
   return true;
@@ -164,12 +175,14 @@
     }
     return 0;
   }
-  if (FLAGS_force_update || FLAGS_check_for_update) {
+  if (FLAGS_force_update || FLAGS_check_for_update ||
+      !FLAGS_app_version.empty() || !FLAGS_omaha_url.empty()) {
     LOG(INFO) << "Initiating update check and install.";
     if (FLAGS_force_update) {
       LOG(INFO) << "Will not abort due to being on expensive network.";
     }
-    CHECK(CheckForUpdates(FLAGS_force_update))
+    CHECK(CheckForUpdates(FLAGS_force_update, FLAGS_app_version,
+                          FLAGS_omaha_url))
         << "Update check/initiate update failed.";
     return 0;
   }