Merge changes from topic 'nyc-mr1-ue_sideload_recovery' into nyc-mr1-dev

* changes:
  Setup a temporary directory for update_engine_sideload.
  DO NOT MERGE: Make update_engine compile in the branch.
  New setting to mark postinstall as optional.
  Report the progress of the update when sideloading.
  Compile update_engine_sideload as a static recovery program.
  Remove libcurl support from update_engine_sideload.
  Build update_engine_sideload.
  Implement a memory-based Prefs class.
  Remove unused libbrillo-http dependency.
diff --git a/Android.mk b/Android.mk
index 3bca905..3f44ecc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -62,9 +62,8 @@
     external/gtest/include \
     system
 ue_common_shared_libraries := \
-    libbrillo \
-    libbrillo-http \
     libbrillo-stream \
+    libbrillo \
     libchrome
 
 ifeq ($(local_use_dbus),1)
@@ -146,14 +145,11 @@
     $(ue_update_metadata_protos_exported_static_libraries)
 ue_libpayload_consumer_exported_shared_libraries := \
     libcrypto-host \
-    libcurl-host \
-    libssl-host \
     $(ue_update_metadata_protos_exported_shared_libraries)
 
 ue_libpayload_consumer_src_files := \
     common/action_processor.cc \
     common/boot_control_stub.cc \
-    common/certificate_checker.cc \
     common/clock.cc \
     common/constants.cc \
     common/cpu_limiter.cc \
@@ -163,7 +159,6 @@
     common/http_fetcher.cc \
     common/file_fetcher.cc \
     common/hwid_override.cc \
-    common/libcurl_http_fetcher.cc \
     common/multi_range_http_fetcher.cc \
     common/platform_constants_android.cc \
     common/prefs.cc \
@@ -259,7 +254,9 @@
     libexpat \
     libbrillo-policy \
     libhardware \
+    libcurl \
     libcutils \
+    libssl \
     $(ue_libpayload_consumer_exported_shared_libraries) \
     $(ue_update_metadata_protos_exported_shared_libraries)
 ifeq ($(local_use_binder),1)
@@ -305,6 +302,7 @@
     $(ue_update_metadata_protos_exported_shared_libraries)
 LOCAL_SRC_FILES := \
     boot_control_android.cc \
+    certificate_checker.cc \
     common_service.cc \
     connection_manager.cc \
     daemon.cc \
@@ -312,6 +310,7 @@
     hardware_android.cc \
     image_properties_android.cc \
     libcros_proxy.cc \
+    libcurl_http_fetcher.cc \
     metrics.cc \
     metrics_utils.cc \
     omaha_request_action.cc \
@@ -379,7 +378,9 @@
     libbinderwrapper \
     libbrillo-binder \
     libcutils \
+    libcurl \
     libhardware \
+    libssl \
     libutils
 
 include $(CLEAR_VARS)
@@ -408,9 +409,11 @@
     binder_bindings/android/os/IUpdateEngineCallback.aidl \
     binder_service_android.cc \
     boot_control_android.cc \
+    certificate_checker.cc \
     daemon.cc \
     daemon_state_android.cc \
     hardware_android.cc \
+    libcurl_http_fetcher.cc \
     network_selector_android.cc \
     proxy_resolver.cc \
     update_attempter_android.cc \
@@ -463,6 +466,74 @@
 LOCAL_INIT_RC := update_engine.rc
 include $(BUILD_EXECUTABLE)
 
+# update_engine_sideload (type: executable)
+# ========================================================
+# A static binary equivalent to update_engine daemon that installs an update
+# from a local file directly instead of running in the background.
+include $(CLEAR_VARS)
+LOCAL_MODULE := update_engine_sideload
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_REQUIRED_MODULES := \
+    bspatch_recovery
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CLANG := true
+LOCAL_CFLAGS := \
+    $(ue_common_cflags) \
+    -D_UE_SIDELOAD
+LOCAL_CPPFLAGS := $(ue_common_cppflags)
+LOCAL_LDFLAGS := $(ue_common_ldflags)
+LOCAL_C_INCLUDES := \
+    $(ue_common_c_includes) \
+    bootable/recovery
+#TODO(deymo): Remove external/cros/system_api/dbus once the strings are moved
+# out of the DBus interface.
+LOCAL_C_INCLUDES += \
+    external/cros/system_api/dbus
+LOCAL_SRC_FILES := \
+    boot_control_android.cc \
+    hardware_android.cc \
+    network_selector_stub.cc \
+    proxy_resolver.cc \
+    sideload_main.cc \
+    update_attempter_android.cc \
+    update_status_utils.cc \
+    utils_android.cc
+LOCAL_STATIC_LIBRARIES := \
+    libfs_mgr \
+    libpayload_consumer \
+    update_metadata-protos \
+    $(ue_libpayload_consumer_exported_static_libraries:-host=) \
+    $(ue_update_metadata_protos_exported_static_libraries)
+# We add the static versions of the shared libraries since we are forcing this
+# binary to be a static binary, so we also need to include all the static
+# library dependencies of these static libraries.
+LOCAL_STATIC_LIBRARIES += \
+    $(ue_common_shared_libraries) \
+    libcutils \
+    libcrypto_static \
+    $(ue_update_metadata_protos_exported_shared_libraries) \
+    libevent \
+    libmodpb64 \
+    liblog
+
+ifeq ($(strip $(PRODUCT_STATIC_BOOT_CONTROL_HAL)),)
+# No static boot_control HAL defined, so no sideload support. We use a fake
+# boot_control HAL to allow compiling update_engine_sideload for test purposes.
+ifeq ($(strip $(AB_OTA_UPDATER)),true)
+$(warning No PRODUCT_STATIC_BOOT_CONTROL_HAL configured but AB_OTA_UPDATER is \
+true, no update sideload support.)
+endif  # AB_OTA_UPDATER == true
+LOCAL_SRC_FILES += \
+    boot_control_recovery_stub.cc
+else  # PRODUCT_STATIC_BOOT_CONTROL_HAL != ""
+LOCAL_STATIC_LIBRARIES += \
+    $(PRODUCT_STATIC_BOOT_CONTROL_HAL)
+endif  # PRODUCT_STATIC_BOOT_CONTROL_HAL != ""
+
+include $(BUILD_EXECUTABLE)
+
 # libupdate_engine_client (type: shared_library)
 # ========================================================
 include $(CLEAR_VARS)
@@ -827,10 +898,10 @@
     $(ue_libupdate_engine_exported_shared_libraries:-host=) \
     $(ue_libpayload_generator_exported_shared_libraries:-host=)
 LOCAL_SRC_FILES := \
+    certificate_checker_unittest.cc \
     common/action_pipe_unittest.cc \
     common/action_processor_unittest.cc \
     common/action_unittest.cc \
-    common/certificate_checker_unittest.cc \
     common/cpu_limiter_unittest.cc \
     common/fake_prefs.cc \
     common/file_fetcher_unittest.cc \
diff --git a/boot_control_android.cc b/boot_control_android.cc
index ba6b559..d096a1b 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -28,6 +28,14 @@
 
 using std::string;
 
+#ifdef _UE_SIDELOAD
+// When called from update_engine_sideload, we don't attempt to dynamically load
+// the right boot_control HAL, instead we use the only HAL statically linked in
+// via the PRODUCT_STATIC_BOOT_CONTROL_HAL make variable and access the module
+// struct directly.
+extern const hw_module_t HAL_MODULE_INFO_SYM;
+#endif  // _UE_SIDELOAD
+
 namespace chromeos_update_engine {
 
 namespace boot_control {
@@ -47,7 +55,18 @@
   const hw_module_t* hw_module;
   int ret;
 
+#ifdef _UE_SIDELOAD
+  // For update_engine_sideload, we simulate the hw_get_module() by accessing it
+  // from the current process directly.
+  hw_module = &HAL_MODULE_INFO_SYM;
+  ret = 0;
+  if (!hw_module ||
+      strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
+    ret = -EINVAL;
+  }
+#else  // !_UE_SIDELOAD
   ret = hw_get_module(BOOT_CONTROL_HARDWARE_MODULE_ID, &hw_module);
+#endif  // _UE_SIDELOAD
   if (ret != 0) {
     LOG(ERROR) << "Error loading boot_control HAL implementation.";
     return false;
diff --git a/boot_control_recovery_stub.cc b/boot_control_recovery_stub.cc
new file mode 100644
index 0000000..129c5d0
--- /dev/null
+++ b/boot_control_recovery_stub.cc
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2016 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 <hardware/hardware.h>
+
+hw_module_t HAL_MODULE_INFO_SYM = {
+  .id = "stub",
+};
diff --git a/common/certificate_checker.cc b/certificate_checker.cc
similarity index 98%
rename from common/certificate_checker.cc
rename to certificate_checker.cc
index 86df950..6e886e7 100644
--- a/common/certificate_checker.cc
+++ b/certificate_checker.cc
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 
 #include <string>
 
diff --git a/common/certificate_checker.h b/certificate_checker.h
similarity index 97%
rename from common/certificate_checker.h
rename to certificate_checker.h
index c785192..5d0b5ba 100644
--- a/common/certificate_checker.h
+++ b/certificate_checker.h
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-#ifndef UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
-#define UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
+#ifndef UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
+#define UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
 
 #include <curl/curl.h>
 #include <openssl/ssl.h>
@@ -172,4 +172,4 @@
 
 }  // namespace chromeos_update_engine
 
-#endif  // UPDATE_ENGINE_COMMON_CERTIFICATE_CHECKER_H_
+#endif  // UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
diff --git a/common/certificate_checker_unittest.cc b/certificate_checker_unittest.cc
similarity index 97%
rename from common/certificate_checker_unittest.cc
rename to certificate_checker_unittest.cc
index c30acc5..20efce9 100644
--- a/common/certificate_checker_unittest.cc
+++ b/certificate_checker_unittest.cc
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 
 #include <string>
 
@@ -24,8 +24,8 @@
 #include <gtest/gtest.h>
 
 #include "update_engine/common/constants.h"
-#include "update_engine/common/mock_certificate_checker.h"
 #include "update_engine/common/mock_prefs.h"
+#include "update_engine/mock_certificate_checker.h"
 
 using ::testing::DoAll;
 using ::testing::Return;
diff --git a/common/file_fetcher.cc b/common/file_fetcher.cc
index 77dadd1..d0a109b 100644
--- a/common/file_fetcher.cc
+++ b/common/file_fetcher.cc
@@ -27,7 +27,6 @@
 #include <base/strings/stringprintf.h>
 #include <brillo/streams/file_stream.h>
 
-#include "update_engine/common/certificate_checker.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/platform_constants.h"
 
diff --git a/common/hash_calculator_unittest.cc b/common/hash_calculator_unittest.cc
index 27dbc56..436e6a7 100644
--- a/common/hash_calculator_unittest.cc
+++ b/common/hash_calculator_unittest.cc
@@ -25,7 +25,6 @@
 #include <brillo/secure_blob.h>
 #include <gtest/gtest.h>
 
-#include "update_engine/common/libcurl_http_fetcher.h"
 #include "update_engine/common/utils.h"
 
 using std::string;
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 9bc4373..f99007f 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -44,11 +44,11 @@
 #include "update_engine/common/fake_hardware.h"
 #include "update_engine/common/file_fetcher.h"
 #include "update_engine/common/http_common.h"
-#include "update_engine/common/libcurl_http_fetcher.h"
 #include "update_engine/common/mock_http_fetcher.h"
 #include "update_engine/common/multi_range_http_fetcher.h"
 #include "update_engine/common/test_utils.h"
 #include "update_engine/common/utils.h"
+#include "update_engine/libcurl_http_fetcher.h"
 #include "update_engine/mock_proxy_resolver.h"
 #include "update_engine/proxy_resolver.h"
 
diff --git a/common/prefs.cc b/common/prefs.cc
index a4b97d0..12d06c0 100644
--- a/common/prefs.cc
+++ b/common/prefs.cc
@@ -29,31 +29,12 @@
 
 namespace chromeos_update_engine {
 
-bool Prefs::Init(const base::FilePath& prefs_dir) {
-  prefs_dir_ = prefs_dir;
-  return true;
+bool PrefsBase::GetString(const string& key, string* value) const {
+  return storage_->GetKey(key, value);
 }
 
-bool Prefs::GetString(const string& key, string* value) const {
-  base::FilePath filename;
-  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
-  if (!base::ReadFileToString(filename, value)) {
-    LOG(INFO) << key << " not present in " << prefs_dir_.value();
-    return false;
-  }
-  return true;
-}
-
-bool Prefs::SetString(const string& key, const string& value) {
-  base::FilePath filename;
-  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
-  if (!base::DirectoryExists(filename.DirName())) {
-    // Only attempt to create the directory if it doesn't exist to avoid calls
-    // to parent directories where we might not have permission to write to.
-    TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
-  }
-  TEST_AND_RETURN_FALSE(base::WriteFile(filename, value.data(), value.size()) ==
-                        static_cast<int>(value.size()));
+bool PrefsBase::SetString(const string& key, const string& value) {
+  TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
     std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -63,7 +44,7 @@
   return true;
 }
 
-bool Prefs::GetInt64(const string& key, int64_t* value) const {
+bool PrefsBase::GetInt64(const string& key, int64_t* value) const {
   string str_value;
   if (!GetString(key, &str_value))
     return false;
@@ -72,11 +53,11 @@
   return true;
 }
 
-bool Prefs::SetInt64(const string& key, const int64_t value) {
+bool PrefsBase::SetInt64(const string& key, const int64_t value) {
   return SetString(key, base::Int64ToString(value));
 }
 
-bool Prefs::GetBoolean(const string& key, bool* value) const {
+bool PrefsBase::GetBoolean(const string& key, bool* value) const {
   string str_value;
   if (!GetString(key, &str_value))
     return false;
@@ -92,20 +73,16 @@
   return false;
 }
 
-bool Prefs::SetBoolean(const string& key, const bool value) {
+bool PrefsBase::SetBoolean(const string& key, const bool value) {
   return SetString(key, value ? "true" : "false");
 }
 
-bool Prefs::Exists(const string& key) const {
-  base::FilePath filename;
-  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
-  return base::PathExists(filename);
+bool PrefsBase::Exists(const string& key) const {
+  return storage_->KeyExists(key);
 }
 
-bool Prefs::Delete(const string& key) {
-  base::FilePath filename;
-  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
-  TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
+bool PrefsBase::Delete(const string& key) {
+  TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
     std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -115,11 +92,11 @@
   return true;
 }
 
-void Prefs::AddObserver(const string& key, ObserverInterface* observer) {
+void PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
   observers_[key].push_back(observer);
 }
 
-void Prefs::RemoveObserver(const string& key, ObserverInterface* observer) {
+void PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
   std::vector<ObserverInterface*>& observers_for_key = observers_[key];
   auto observer_it =
       std::find(observers_for_key.begin(), observers_for_key.end(), observer);
@@ -127,8 +104,55 @@
     observers_for_key.erase(observer_it);
 }
 
-bool Prefs::GetFileNameForKey(const string& key,
-                              base::FilePath* filename) const {
+// Prefs
+
+bool Prefs::Init(const base::FilePath& prefs_dir) {
+  return file_storage_.Init(prefs_dir);
+}
+
+bool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
+  prefs_dir_ = prefs_dir;
+  return true;
+}
+
+bool Prefs::FileStorage::GetKey(const string& key, string* value) const {
+  base::FilePath filename;
+  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
+  if (!base::ReadFileToString(filename, value)) {
+    LOG(INFO) << key << " not present in " << prefs_dir_.value();
+    return false;
+  }
+  return true;
+}
+
+bool Prefs::FileStorage::SetKey(const string& key, const string& value) {
+  base::FilePath filename;
+  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
+  if (!base::DirectoryExists(filename.DirName())) {
+    // Only attempt to create the directory if it doesn't exist to avoid calls
+    // to parent directories where we might not have permission to write to.
+    TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
+  }
+  TEST_AND_RETURN_FALSE(base::WriteFile(filename, value.data(), value.size()) ==
+                        static_cast<int>(value.size()));
+  return true;
+}
+
+bool Prefs::FileStorage::KeyExists(const string& key) const {
+  base::FilePath filename;
+  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
+  return base::PathExists(filename);
+}
+
+bool Prefs::FileStorage::DeleteKey(const string& key) {
+  base::FilePath filename;
+  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
+  TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
+  return true;
+}
+
+bool Prefs::FileStorage::GetFileNameForKey(const string& key,
+                                           base::FilePath* filename) const {
   // Allows only non-empty keys containing [A-Za-z0-9_-].
   TEST_AND_RETURN_FALSE(!key.empty());
   for (size_t i = 0; i < key.size(); ++i) {
@@ -140,4 +164,33 @@
   return true;
 }
 
+// MemoryPrefs
+
+bool MemoryPrefs::MemoryStorage::GetKey(const string& key,
+                                        string* value) const {
+  auto it = values_.find(key);
+  if (it == values_.end())
+    return false;
+  *value = it->second;
+  return true;
+}
+
+bool MemoryPrefs::MemoryStorage::SetKey(const string& key,
+                                        const string& value) {
+  values_[key] = value;
+  return true;
+}
+
+bool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
+  return values_.find(key) != values_.end();
+}
+
+bool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
+  auto it = values_.find(key);
+  if (it == values_.end())
+    return false;
+  values_.erase(it);
+  return true;
+}
+
 }  // namespace chromeos_update_engine
diff --git a/common/prefs.h b/common/prefs.h
index f11abc3..0116454 100644
--- a/common/prefs.h
+++ b/common/prefs.h
@@ -28,18 +28,36 @@
 
 namespace chromeos_update_engine {
 
-// Implements a preference store by storing the value associated with
-// a key in a separate file named after the key under a preference
-// store directory.
-
-class Prefs : public PrefsInterface {
+// Implements a preference store by storing the value associated with a key
+// in a given storage passed during construction.
+class PrefsBase : public PrefsInterface {
  public:
-  Prefs() = default;
+  // Storage interface used to set and retrieve keys.
+  class StorageInterface {
+   public:
+    StorageInterface() = default;
+    virtual ~StorageInterface() = default;
 
-  // Initializes the store by associating this object with |prefs_dir|
-  // as the preference store directory. Returns true on success, false
-  // otherwise.
-  bool Init(const base::FilePath& prefs_dir);
+    // Get the key named |key| and store its value in the referenced |value|.
+    // Returns whether the operation succeeded.
+    virtual bool GetKey(const std::string& key, std::string* value) const = 0;
+
+    // Set the value of the key named |key| to |value| regardless of the
+    // previous value. Returns whether the operation succeeded.
+    virtual bool SetKey(const std::string& key, const std::string& value) = 0;
+
+    // Returns whether the key named |key| exists.
+    virtual bool KeyExists(const std::string& key) const = 0;
+
+    // Deletes the value associated with the key name |key|. Returns whether the
+    // key was deleted.
+    virtual bool DeleteKey(const std::string& key) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(StorageInterface);
+  };
+
+  explicit PrefsBase(StorageInterface* storage) : storage_(storage) {}
 
   // PrefsInterface methods.
   bool GetString(const std::string& key, std::string* value) const override;
@@ -58,24 +76,93 @@
                       ObserverInterface* observer) override;
 
  private:
+  // The registered observers watching for changes.
+  std::map<std::string, std::vector<ObserverInterface*>> observers_;
+
+  // The concrete implementation of the storage used for the keys.
+  StorageInterface* storage_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefsBase);
+};
+
+// Implements a preference store by storing the value associated with
+// a key in a separate file named after the key under a preference
+// store directory.
+
+class Prefs : public PrefsBase {
+ public:
+  Prefs() : PrefsBase(&file_storage_) {}
+
+  // Initializes the store by associating this object with |prefs_dir|
+  // as the preference store directory. Returns true on success, false
+  // otherwise.
+  bool Init(const base::FilePath& prefs_dir);
+
+ private:
   FRIEND_TEST(PrefsTest, GetFileNameForKey);
   FRIEND_TEST(PrefsTest, GetFileNameForKeyBadCharacter);
   FRIEND_TEST(PrefsTest, GetFileNameForKeyEmpty);
 
-  // Sets |filename| to the full path to the file containing the data
-  // associated with |key|. Returns true on success, false otherwise.
-  bool GetFileNameForKey(const std::string& key,
-                         base::FilePath* filename) const;
+  class FileStorage : public PrefsBase::StorageInterface {
+   public:
+    FileStorage() = default;
 
-  // Preference store directory.
-  base::FilePath prefs_dir_;
+    bool Init(const base::FilePath& prefs_dir);
 
-  // The registered observers watching for changes.
-  std::map<std::string, std::vector<ObserverInterface*>> observers_;
+    // PrefsBase::StorageInterface overrides.
+    bool GetKey(const std::string& key, std::string* value) const override;
+    bool SetKey(const std::string& key, const std::string& value) override;
+    bool KeyExists(const std::string& key) const override;
+    bool DeleteKey(const std::string& key) override;
+
+   private:
+    FRIEND_TEST(PrefsTest, GetFileNameForKey);
+    FRIEND_TEST(PrefsTest, GetFileNameForKeyBadCharacter);
+    FRIEND_TEST(PrefsTest, GetFileNameForKeyEmpty);
+
+    // Sets |filename| to the full path to the file containing the data
+    // associated with |key|. Returns true on success, false otherwise.
+    bool GetFileNameForKey(const std::string& key,
+                           base::FilePath* filename) const;
+
+    // Preference store directory.
+    base::FilePath prefs_dir_;
+  };
+
+  // The concrete file storage implementation.
+  FileStorage file_storage_;
 
   DISALLOW_COPY_AND_ASSIGN(Prefs);
 };
 
+// Implements a preference store in memory. The stored values are lost when the
+// object is destroyed.
+
+class MemoryPrefs : public PrefsBase {
+ public:
+  MemoryPrefs() : PrefsBase(&mem_storage_) {}
+
+ private:
+  class MemoryStorage : public PrefsBase::StorageInterface {
+   public:
+    MemoryStorage() = default;
+
+    // PrefsBase::StorageInterface overrides.
+    bool GetKey(const std::string& key, std::string* value) const override;
+    bool SetKey(const std::string& key, const std::string& value) override;
+    bool KeyExists(const std::string& key) const override;
+    bool DeleteKey(const std::string& key) override;
+
+   private:
+    // The std::map holding the values in memory.
+    std::map<std::string, std::string> values_;
+  };
+
+  // The concrete memory storage implementation.
+  MemoryStorage mem_storage_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPrefs);
+};
 }  // namespace chromeos_update_engine
 
 #endif  // UPDATE_ENGINE_COMMON_PREFS_H_
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index d94623a..0822599 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -18,6 +18,7 @@
 
 #include <inttypes.h>
 
+#include <limits>
 #include <string>
 
 #include <base/files/file_util.h>
@@ -62,18 +63,18 @@
   const char kAllvalidCharsKey[] =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-";
   base::FilePath path;
-  EXPECT_TRUE(prefs_.GetFileNameForKey(kAllvalidCharsKey, &path));
+  EXPECT_TRUE(prefs_.file_storage_.GetFileNameForKey(kAllvalidCharsKey, &path));
   EXPECT_EQ(prefs_dir_.Append(kAllvalidCharsKey).value(), path.value());
 }
 
 TEST_F(PrefsTest, GetFileNameForKeyBadCharacter) {
   base::FilePath path;
-  EXPECT_FALSE(prefs_.GetFileNameForKey("ABC abc", &path));
+  EXPECT_FALSE(prefs_.file_storage_.GetFileNameForKey("ABC abc", &path));
 }
 
 TEST_F(PrefsTest, GetFileNameForKeyEmpty) {
   base::FilePath path;
-  EXPECT_FALSE(prefs_.GetFileNameForKey("", &path));
+  EXPECT_FALSE(prefs_.file_storage_.GetFileNameForKey("", &path));
 }
 
 TEST_F(PrefsTest, GetString) {
@@ -338,4 +339,24 @@
   prefs_.RemoveObserver(kInvalidKey, &mock_obserser);
 }
 
+class MemoryPrefsTest : public ::testing::Test {
+ protected:
+  MemoryPrefs prefs_;
+};
+
+TEST_F(MemoryPrefsTest, BasicTest) {
+  EXPECT_FALSE(prefs_.Exists(kKey));
+  int64_t value = 0;
+  EXPECT_FALSE(prefs_.GetInt64(kKey, &value));
+
+  EXPECT_TRUE(prefs_.SetInt64(kKey, 1234));
+  EXPECT_TRUE(prefs_.Exists(kKey));
+  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
+  EXPECT_EQ(1234, value);
+
+  EXPECT_TRUE(prefs_.Delete(kKey));
+  EXPECT_FALSE(prefs_.Exists(kKey));
+  EXPECT_FALSE(prefs_.Delete(kKey));
+}
+
 }  // namespace chromeos_update_engine
diff --git a/common/utils.cc b/common/utils.cc
index 19c63c0..166cfb4 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -87,6 +87,11 @@
 // The path to the kernel's boot_id.
 const char kBootIdPath[] = "/proc/sys/kernel/random/boot_id";
 
+// A pointer to a null-terminated string containing the root directory where all
+// the temporary files should be created. If null, the system default is used
+// instead.
+const char* root_temp_dir = nullptr;
+
 // Return true if |disk_name| is an MTD or a UBI device. Note that this test is
 // simply based on the name of the device.
 bool IsMtdDeviceName(const string& disk_name) {
@@ -143,13 +148,17 @@
   }
 
   base::FilePath temp_dir;
+  if (root_temp_dir) {
+    temp_dir = base::FilePath(root_temp_dir);
+  } else {
 #ifdef __ANDROID__
-  temp_dir = base::FilePath(constants::kNonVolatileDirectory).Append("tmp");
+    temp_dir = base::FilePath(constants::kNonVolatileDirectory).Append("tmp");
+#else
+    TEST_AND_RETURN_FALSE(base::GetTempDir(&temp_dir));
+#endif  // __ANDROID__
+  }
   if (!base::PathExists(temp_dir))
     TEST_AND_RETURN_FALSE(base::CreateDirectory(temp_dir));
-#else
-  TEST_AND_RETURN_FALSE(base::GetTempDir(&temp_dir));
-#endif  // __ANDROID__
   *template_path = temp_dir.Append(path);
   return true;
 }
@@ -158,6 +167,10 @@
 
 namespace utils {
 
+void SetRootTempDir(const char* new_root_temp_dir) {
+  root_temp_dir = new_root_temp_dir;
+}
+
 string ParseECVersion(string input_line) {
   base::TrimWhitespaceASCII(input_line, base::TRIM_ALL, &input_line);
 
diff --git a/common/utils.h b/common/utils.h
index 63328b6..24bf702 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -131,6 +131,13 @@
 // only returns true if "/dev/ubi%d_0" becomes available in |timeout| seconds.
 bool TryAttachingUbiVolume(int volume_num, int timeout);
 
+// Setup the directory |new_root_temp_dir| to be used as the root directory for
+// temporary files instead of the system's default. If the directory doesn't
+// exists, it will be created when first used.
+// NOTE: The memory pointed by |new_root_temp_dir| must be available until this
+// function is called again with a different value.
+void SetRootTempDir(const char* new_root_temp_dir);
+
 // If |base_filename_template| is neither absolute (starts with "/") nor
 // explicitly relative to the current working directory (starts with "./" or
 // "../"), then it is prepended the system's temporary directory. On success,
diff --git a/daemon_state_android.h b/daemon_state_android.h
index 69180bc..928a14e 100644
--- a/daemon_state_android.h
+++ b/daemon_state_android.h
@@ -20,8 +20,8 @@
 #include <memory>
 #include <set>
 
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/certificate_checker.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/prefs_interface.h"
 #include "update_engine/daemon_state_interface.h"
@@ -43,7 +43,7 @@
   void AddObserver(ServiceObserverInterface* observer) override;
   void RemoveObserver(ServiceObserverInterface* observer) override;
 
-  const std::set<ServiceObserverInterface*>& service_observers() {
+  const std::set<ServiceObserverInterface*>& service_observers() override {
     return service_observers_;
   }
 
diff --git a/daemon_state_interface.h b/daemon_state_interface.h
index a0944aa..2356816 100644
--- a/daemon_state_interface.h
+++ b/daemon_state_interface.h
@@ -20,6 +20,7 @@
 #include "update_engine/service_observer_interface.h"
 
 #include <memory>
+#include <set>
 
 namespace chromeos_update_engine {
 
@@ -36,6 +37,9 @@
   virtual void AddObserver(ServiceObserverInterface* observer) = 0;
   virtual void RemoveObserver(ServiceObserverInterface* observer) = 0;
 
+  // Return the set of current observers.
+  virtual const std::set<ServiceObserverInterface*>& service_observers() = 0;
+
  protected:
   DaemonStateInterface() = default;
 };
diff --git a/common/libcurl_http_fetcher.cc b/libcurl_http_fetcher.cc
similarity index 99%
rename from common/libcurl_http_fetcher.cc
rename to libcurl_http_fetcher.cc
index b2dffc2..04d5c06 100644
--- a/common/libcurl_http_fetcher.cc
+++ b/libcurl_http_fetcher.cc
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-#include "update_engine/common/libcurl_http_fetcher.h"
+#include "update_engine/libcurl_http_fetcher.h"
 
 #include <algorithm>
 #include <string>
@@ -26,7 +26,7 @@
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/platform_constants.h"
 
diff --git a/common/libcurl_http_fetcher.h b/libcurl_http_fetcher.h
similarity index 97%
rename from common/libcurl_http_fetcher.h
rename to libcurl_http_fetcher.h
index d126171..199c495 100644
--- a/common/libcurl_http_fetcher.h
+++ b/libcurl_http_fetcher.h
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-#ifndef UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
-#define UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
+#ifndef UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_
+#define UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_
 
 #include <map>
 #include <memory>
@@ -28,7 +28,7 @@
 #include <base/macros.h>
 #include <brillo/message_loops/message_loop.h>
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/http_fetcher.h"
 
@@ -266,4 +266,4 @@
 
 }  // namespace chromeos_update_engine
 
-#endif  // UPDATE_ENGINE_COMMON_LIBCURL_HTTP_FETCHER_H_
+#endif  // UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_
diff --git a/metrics.h b/metrics.h
index bb9fa5e..7c369ee 100644
--- a/metrics.h
+++ b/metrics.h
@@ -19,7 +19,7 @@
 
 #include <base/time/time.h>
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/constants.h"
 #include "update_engine/common/error_code.h"
 
diff --git a/common/mock_certificate_checker.h b/mock_certificate_checker.h
similarity index 81%
rename from common/mock_certificate_checker.h
rename to mock_certificate_checker.h
index 1f55ca1..c86f502 100644
--- a/common/mock_certificate_checker.h
+++ b/mock_certificate_checker.h
@@ -14,13 +14,13 @@
 // limitations under the License.
 //
 
-#ifndef UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_
-#define UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_
+#ifndef UPDATE_ENGINE_MOCK_CERTIFICATE_CHECKER_H_
+#define UPDATE_ENGINE_MOCK_CERTIFICATE_CHECKER_H_
 
 #include <gmock/gmock.h>
 #include <openssl/ssl.h>
 
-#include "update_engine/common/certificate_checker.h"
+#include "update_engine/certificate_checker.h"
 
 namespace chromeos_update_engine {
 
@@ -35,4 +35,4 @@
 
 }  // namespace chromeos_update_engine
 
-#endif  // UPDATE_ENGINE_COMMON_MOCK_CERTIFICATE_CHECKER_H_
+#endif  // UPDATE_ENGINE_MOCK_CERTIFICATE_CHECKER_H_
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 4b9e528..a156132 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -844,6 +844,7 @@
           (partition.has_postinstall_path() ? partition.postinstall_path()
                                             : kPostinstallDefaultScript);
       install_part.filesystem_type = partition.filesystem_type();
+      install_part.postinstall_optional = partition.postinstall_optional();
     }
 
     if (partition.has_old_partition_info()) {
diff --git a/payload_consumer/download_action.h b/payload_consumer/download_action.h
index fc32068..285930a 100644
--- a/payload_consumer/download_action.h
+++ b/payload_consumer/download_action.h
@@ -24,8 +24,6 @@
 #include <memory>
 #include <string>
 
-#include <curl/curl.h>
-
 #include "update_engine/common/action.h"
 #include "update_engine/common/boot_control_interface.h"
 #include "update_engine/common/http_fetcher.h"
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 51e85b3..b04da74 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -115,7 +115,8 @@
           target_hash == that.target_hash &&
           run_postinstall == that.run_postinstall &&
           postinstall_path == that.postinstall_path &&
-          filesystem_type == that.filesystem_type);
+          filesystem_type == that.filesystem_type &&
+          postinstall_optional == that.postinstall_optional);
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index 454dd78..f15775e 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -95,6 +95,7 @@
     bool run_postinstall{false};
     std::string postinstall_path;
     std::string filesystem_type;
+    bool postinstall_optional{false};
   };
   std::vector<Partition> partitions;
 
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 09f5096..84f1edf 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -301,7 +301,14 @@
       // to get back to FW A.
       error_code = ErrorCode::kPostinstallFirmwareRONotUpdatable;
     }
-    return CompletePostinstall(error_code);
+
+    // If postinstall script for this partition is optional we can ignore the
+    // result.
+    if (install_plan_.partitions[current_partition_].postinstall_optional) {
+      LOG(INFO) << "Ignoring postinstall failure since it is optional";
+    } else {
+      return CompletePostinstall(error_code);
+    }
   }
   accumulated_weight_ += partition_weight_[current_partition_];
   current_partition_++;
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index de81a39..2f95b21 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -138,6 +138,7 @@
           partition->set_postinstall_path(part.postinstall.path);
         if (!part.postinstall.filesystem_type.empty())
           partition->set_filesystem_type(part.postinstall.filesystem_type);
+        partition->set_postinstall_optional(part.postinstall.optional);
       }
       for (const AnnotatedOperation& aop : part.aops) {
         *partition->add_operations() = aop.op;
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index dc2ced6..8ef30a0 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -27,7 +27,7 @@
 namespace chromeos_update_engine {
 
 bool PostInstallConfig::IsEmpty() const {
-  return run == false && path.empty() && filesystem_type.empty();
+  return !run && path.empty() && filesystem_type.empty() && !optional;
 }
 
 bool PartitionConfig::ValidateExists() const {
@@ -95,6 +95,8 @@
     store.GetString("POSTINSTALL_PATH_" + part.name, &part.postinstall.path);
     store.GetString("FILESYSTEM_TYPE_" + part.name,
                     &part.postinstall.filesystem_type);
+    store.GetBoolean("POSTINSTALL_OPTIONAL_" + part.name,
+                     &part.postinstall.optional);
   }
   if (!found_postinstall) {
     LOG(ERROR) << "No valid postinstall config found.";
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 2601821..373c7cd 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -46,6 +46,9 @@
   // The filesystem type used to mount the partition in order to run the
   // post-install program.
   std::string filesystem_type;
+
+  // Whether this postinstall script should be ignored if it fails.
+  bool optional = false;
 };
 
 struct PartitionConfig {
diff --git a/payload_generator/payload_generation_config_unittest.cc b/payload_generator/payload_generation_config_unittest.cc
index 122d94a..3545056 100644
--- a/payload_generator/payload_generation_config_unittest.cc
+++ b/payload_generator/payload_generation_config_unittest.cc
@@ -29,12 +29,14 @@
   EXPECT_TRUE(
       store.LoadFromString("RUN_POSTINSTALL_root=true\n"
                            "POSTINSTALL_PATH_root=postinstall\n"
-                           "FILESYSTEM_TYPE_root=ext4"));
+                           "FILESYSTEM_TYPE_root=ext4\n"
+                           "POSTINSTALL_OPTIONAL_root=true"));
   EXPECT_TRUE(image_config.LoadPostInstallConfig(store));
   EXPECT_FALSE(image_config.partitions[0].postinstall.IsEmpty());
   EXPECT_EQ(true, image_config.partitions[0].postinstall.run);
   EXPECT_EQ("postinstall", image_config.partitions[0].postinstall.path);
   EXPECT_EQ("ext4", image_config.partitions[0].postinstall.filesystem_type);
+  EXPECT_TRUE(image_config.partitions[0].postinstall.optional);
 }
 
 TEST_F(PayloadGenerationConfigTest, LoadPostInstallConfigNameMismatchTest) {
diff --git a/real_system_state.h b/real_system_state.h
index 071e3e0..480b4b7 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -20,6 +20,7 @@
 #include "update_engine/system_state.h"
 
 #include <memory>
+#include <set>
 
 #include <debugd/dbus-proxies.h>
 #include <metrics/metrics_library.h>
@@ -27,8 +28,8 @@
 #include <power_manager/dbus-proxies.h>
 #include <session_manager/dbus-proxies.h>
 
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/certificate_checker.h"
 #include "update_engine/common/clock.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/prefs.h"
@@ -63,6 +64,10 @@
 
   void AddObserver(ServiceObserverInterface* observer) override;
   void RemoveObserver(ServiceObserverInterface* observer) override;
+  const std::set<ServiceObserverInterface*>& service_observers() override {
+    CHECK(update_attempter_.get());
+    return update_attempter_->service_observers();
+  }
 
   // SystemState overrides.
   inline void set_device_policy(
diff --git a/sideload_main.cc b/sideload_main.cc
new file mode 100644
index 0000000..35ed11b
--- /dev/null
+++ b/sideload_main.cc
@@ -0,0 +1,227 @@
+//
+// Copyright (C) 2016 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 <xz.h>
+
+#include <string>
+#include <vector>
+
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/string_split.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/asynchronous_signal_handler.h>
+#include <brillo/flag_helper.h>
+#include <brillo/make_unique_ptr.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/streams/file_stream.h>
+#include <brillo/streams/stream.h>
+
+#include "update_engine/common/boot_control.h"
+#include "update_engine/common/error_code_utils.h"
+#include "update_engine/common/hardware.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/common/subprocess.h"
+#include "update_engine/common/terminator.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/update_attempter_android.h"
+
+using std::string;
+using std::vector;
+using update_engine::UpdateStatus;
+
+namespace {
+// The root directory used for temporary files in update_engine_sideload.
+const char kSideloadRootTempDir[] = "/tmp/update_engine_sideload";
+}  // namespace
+
+namespace chromeos_update_engine {
+namespace {
+
+void SetupLogging() {
+  string log_file;
+  logging::LoggingSettings log_settings;
+  log_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
+  log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
+  log_settings.log_file = nullptr;
+  log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+
+  logging::InitLogging(log_settings);
+}
+
+class SideloadDaemonState : public DaemonStateInterface,
+                            public ServiceObserverInterface {
+ public:
+  explicit SideloadDaemonState(brillo::StreamPtr status_stream)
+      : status_stream_(std::move(status_stream)) {
+    // Add this class as the only observer.
+    observers_.insert(this);
+  }
+  ~SideloadDaemonState() override = default;
+
+  // DaemonStateInterface overrides.
+  bool StartUpdater() override { return true; }
+  void AddObserver(ServiceObserverInterface* observer) override {}
+  void RemoveObserver(ServiceObserverInterface* observer) override {}
+  const std::set<ServiceObserverInterface*>& service_observers() override {
+    return observers_;
+  }
+
+  // ServiceObserverInterface overrides.
+  void SendStatusUpdate(int64_t last_checked_time,
+                        double progress,
+                        UpdateStatus status,
+                        const string& new_version,
+                        int64_t new_size) override {
+    if (status_ != status && (status == UpdateStatus::DOWNLOADING ||
+                              status == UpdateStatus::FINALIZING)) {
+      // Split the progress bar in two parts for the two stages DOWNLOADING and
+      // FINALIZING.
+      ReportStatus(base::StringPrintf(
+          "ui_print Step %d/2", status == UpdateStatus::DOWNLOADING ? 1 : 2));
+      ReportStatus(base::StringPrintf("progress 0.5 0"));
+    }
+    if (status_ != status || fabs(progress - progress_) > 0.005) {
+      ReportStatus(base::StringPrintf("set_progress %.lf", progress));
+    }
+    progress_ = progress;
+    status_ = status;
+  }
+
+  void SendPayloadApplicationComplete(ErrorCode error_code) override {
+    if (error_code != ErrorCode::kSuccess) {
+      ReportStatus(
+          base::StringPrintf("ui_print Error applying update: %d (%s)",
+                             error_code,
+                             utils::ErrorCodeToString(error_code).c_str()));
+    }
+    error_code_ = error_code;
+    brillo::MessageLoop::current()->BreakLoop();
+  }
+
+  void SendChannelChangeUpdate(const string& tracking_channel) override {}
+
+  // Getters.
+  UpdateStatus status() { return status_; }
+  ErrorCode error_code() { return error_code_; }
+
+ private:
+  // Report a status message in the status_stream_, if any. These messages
+  // should conform to the specification defined in the Android recovery.
+  void ReportStatus(const string& message) {
+    if (!status_stream_)
+      return;
+    string status_line = message + "\n";
+    status_stream_->WriteAllBlocking(
+        status_line.data(), status_line.size(), nullptr);
+  }
+
+  std::set<ServiceObserverInterface*> observers_;
+  brillo::StreamPtr status_stream_;
+
+  // The last status and error code reported.
+  UpdateStatus status_{UpdateStatus::IDLE};
+  ErrorCode error_code_{ErrorCode::kSuccess};
+  double progress_{-1.};
+};
+
+// Apply an update payload directly from the given payload URI.
+bool ApplyUpdatePayload(const string& payload,
+                        int64_t payload_offset,
+                        int64_t payload_size,
+                        const vector<string>& headers,
+                        int64_t status_fd) {
+  base::MessageLoopForIO base_loop;
+  brillo::BaseMessageLoop loop(&base_loop);
+  loop.SetAsCurrent();
+
+  // Setup the subprocess handler.
+  brillo::AsynchronousSignalHandler handler;
+  handler.Init();
+  Subprocess subprocess;
+  subprocess.Init(&handler);
+
+  SideloadDaemonState sideload_daemon_state(
+      brillo::FileStream::FromFileDescriptor(status_fd, true, nullptr));
+
+  // During the sideload we don't access the prefs persisted on disk but instead
+  // use a temporary memory storage.
+  MemoryPrefs prefs;
+
+  std::unique_ptr<BootControlInterface> boot_control =
+      boot_control::CreateBootControl();
+  if (!boot_control) {
+    LOG(ERROR) << "Error initializing the BootControlInterface.";
+    return false;
+  }
+
+  std::unique_ptr<HardwareInterface> hardware = hardware::CreateHardware();
+  if (!hardware) {
+    LOG(ERROR) << "Error initializing the HardwareInterface.";
+    return false;
+  }
+
+  UpdateAttempterAndroid update_attempter(
+      &sideload_daemon_state, &prefs, boot_control.get(), hardware.get());
+  update_attempter.Init();
+
+  TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload(
+      payload, payload_offset, payload_size, headers, nullptr));
+
+  loop.Run();
+  return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT;
+}
+
+}  // namespace
+}  // namespace chromeos_update_engine
+
+int main(int argc, char** argv) {
+  DEFINE_string(payload,
+                "file:///data/payload.bin",
+                "The URI to the update payload to use.");
+  DEFINE_int64(
+      offset, 0, "The offset in the payload where the CrAU update starts. ");
+  DEFINE_int64(size,
+               0,
+               "The size of the CrAU part of the payload. If 0 is passed, it "
+               "will be autodetected.");
+  DEFINE_string(headers,
+                "",
+                "A list of key-value pairs, one element of the list per line.");
+  DEFINE_int64(status_fd, -1, "A file descriptor to notify the update status.");
+
+  chromeos_update_engine::Terminator::Init();
+  chromeos_update_engine::SetupLogging();
+  brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload");
+
+  LOG(INFO) << "Update Engine Sideloading starting";
+
+  // xz-embedded requires to initialize its CRC-32 table once on startup.
+  xz_crc32_init();
+
+  // When called from recovery, /data is not accessible, so we need to use
+  // /tmp for temporary files.
+  chromeos_update_engine::utils::SetRootTempDir(kSideloadRootTempDir);
+
+  vector<string> headers = base::SplitString(
+      FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+  if (!chromeos_update_engine::ApplyUpdatePayload(
+          FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd))
+    return 1;
+
+  return 0;
+}
diff --git a/update_attempter.cc b/update_attempter.cc
index 4cafd00..c773063 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -41,18 +41,18 @@
 #include <power_manager/dbus-proxies.h>
 #include <update_engine/dbus-constants.h>
 
+#include "update_engine/certificate_checker.h"
 #include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/certificate_checker.h"
 #include "update_engine/common/clock_interface.h"
 #include "update_engine/common/constants.h"
 #include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/libcurl_http_fetcher.h"
 #include "update_engine/common/multi_range_http_fetcher.h"
 #include "update_engine/common/platform_constants.h"
 #include "update_engine/common/prefs_interface.h"
 #include "update_engine/common/subprocess.h"
 #include "update_engine/common/utils.h"
 #include "update_engine/dbus_service.h"
+#include "update_engine/libcurl_http_fetcher.h"
 #include "update_engine/metrics.h"
 #include "update_engine/omaha_request_action.h"
 #include "update_engine/omaha_request_params.h"
diff --git a/update_attempter.h b/update_attempter.h
index b045614..92683e6 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -31,9 +31,9 @@
 
 #include "debugd/dbus-proxies.h"
 #include "update_engine/chrome_browser_proxy_resolver.h"
+#include "update_engine/certificate_checker.h"
 #include "update_engine/client_library/include/update_engine/update_status.h"
 #include "update_engine/common/action_processor.h"
-#include "update_engine/common/certificate_checker.h"
 #include "update_engine/common/cpu_limiter.h"
 #include "update_engine/libcros_proxy.h"
 #include "update_engine/omaha_request_params.h"
@@ -244,6 +244,10 @@
     service_observers_.erase(observer);
   }
 
+  const std::set<ServiceObserverInterface*>& service_observers() {
+    return service_observers_;
+  }
+
   // Remove all the observers.
   void ClearObservers() { service_observers_.clear(); }
 
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 699ea97..c42b266 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -29,16 +29,21 @@
 
 #include "update_engine/common/constants.h"
 #include "update_engine/common/file_fetcher.h"
-#include "update_engine/common/libcurl_http_fetcher.h"
 #include "update_engine/common/multi_range_http_fetcher.h"
 #include "update_engine/common/utils.h"
-#include "update_engine/daemon_state_android.h"
+#include "update_engine/daemon_state_interface.h"
 #include "update_engine/network_selector.h"
 #include "update_engine/payload_consumer/download_action.h"
 #include "update_engine/payload_consumer/filesystem_verifier_action.h"
 #include "update_engine/payload_consumer/postinstall_runner_action.h"
 #include "update_engine/update_status_utils.h"
 
+#ifndef _UE_SIDELOAD
+// Do not include support for external HTTP(s) urls when building
+// update_engine_sideload.
+#include "update_engine/libcurl_http_fetcher.h"
+#endif
+
 using base::Bind;
 using base::TimeDelta;
 using base::TimeTicks;
@@ -72,7 +77,7 @@
 }  // namespace
 
 UpdateAttempterAndroid::UpdateAttempterAndroid(
-    DaemonStateAndroid* daemon_state,
+    DaemonStateInterface* daemon_state,
     PrefsInterface* prefs,
     BootControlInterface* boot_control,
     HardwareInterface* hardware)
@@ -300,7 +305,7 @@
     default:
       // Ignore all other error codes.
       break;
- }
+  }
 
   TerminateUpdateAndNotify(code);
 }
@@ -433,10 +438,14 @@
     DLOG(INFO) << "Using FileFetcher for file URL.";
     download_fetcher = new FileFetcher();
   } else {
+#ifdef _UE_SIDELOAD
+    LOG(FATAL) << "Unsupported sideload URI: " << url;
+#else
     LibcurlHttpFetcher* libcurl_fetcher =
         new LibcurlHttpFetcher(&proxy_resolver_, hardware_);
     libcurl_fetcher->set_server_to_check(ServerToCheck::kDownload);
     download_fetcher = libcurl_fetcher;
+#endif  // _UE_SIDELOAD
   }
   shared_ptr<DownloadAction> download_action(new DownloadAction(
       prefs_,
diff --git a/update_attempter_android.h b/update_attempter_android.h
index 9e91dca..2617318 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -31,6 +31,7 @@
 #include "update_engine/common/cpu_limiter.h"
 #include "update_engine/common/hardware_interface.h"
 #include "update_engine/common/prefs_interface.h"
+#include "update_engine/daemon_state_interface.h"
 #include "update_engine/network_selector_interface.h"
 #include "update_engine/payload_consumer/download_action.h"
 #include "update_engine/payload_consumer/postinstall_runner_action.h"
@@ -39,8 +40,6 @@
 
 namespace chromeos_update_engine {
 
-class DaemonStateAndroid;
-
 class UpdateAttempterAndroid
     : public ServiceDelegateAndroidInterface,
       public ActionProcessorDelegate,
@@ -49,7 +48,7 @@
  public:
   using UpdateStatus = update_engine::UpdateStatus;
 
-  UpdateAttempterAndroid(DaemonStateAndroid* daemon_state,
+  UpdateAttempterAndroid(DaemonStateInterface* daemon_state,
                          PrefsInterface* prefs,
                          BootControlInterface* boot_control_,
                          HardwareInterface* hardware_);
@@ -123,7 +122,7 @@
   // Returns whether an update was completed in the current boot.
   bool UpdateCompletedOnThisBoot();
 
-  DaemonStateAndroid* daemon_state_;
+  DaemonStateInterface* daemon_state_;
 
   // DaemonStateAndroid pointers.
   PrefsInterface* prefs_;
diff --git a/update_metadata.proto b/update_metadata.proto
index 222542f..454c736 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -235,6 +235,10 @@
   // associated operation blobs (in operations[i].data_offset, data_length)
   // should be stored contiguously and in the same order.
   repeated InstallOperation operations = 8;
+
+  // Whether a failure in the postinstall step for this partition should be
+  // ignored.
+  optional bool postinstall_optional = 9;
 }
 
 message DeltaArchiveManifest {