Merge from goog/master.

The following CLs are included in this merge:

dc873fa Fix test_http_server location.
f285857 Implement suspend, resume and cancel the download.
14dbd33 Mount the new system as 'postinstall_file' in postinstall.
390efed Parse postinstall parameters from the payload metadata.
14fd1ec Allow to Suspend/Resume the ActionProcessor.
f25eb49 Fix resuming canceled updates.
4eccae2 Fix unittest compile
63bdd87 Don't rebuild .img files on incremental builds.
c90be63 Fix Ext2FilesystemTest unittests on Brillo.
bffa060 Fix *ExtentWriterTest unittest.
279bbab Fix Subprocess unittests.
5fe0c4e Fix unittest build in x86_64.
80f70ff Build unittests in Brillo.
b3f699a Add .clang-format symlink to Brillo's clang-format.
0cd976d Disable ChromeBrowserProxyResolver behind a flag.
71102a2 Fix unittest build.
a96ddc1 Define libupdate_engine_client before using it.
2997173 Add a feature to get the last UpdateAttempt ErrorCode from update_engine

While unittests changes are not compiled in nyc-dev, this helps
cherry-pick of CLs that modify the code and the unittests in the
future without extra risk for nyc-dev.

Bug: 24277309
Bug: 25598547
Bug: 26955860
Bug: 27047026
Bug: 27121653
Bug: 27177071
TEST=`make dist` in nyc-dev

Change-Id: I023f35d4187650ce6cd1e9e3acbdda74ef8a36ea
diff --git a/.clang-format b/.clang-format
new file mode 120000
index 0000000..f412743
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+../../build/tools/brillo-clang-format
\ No newline at end of file
diff --git a/Android.mk b/Android.mk
index 0b30720..d529f70 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,9 @@
 local_use_dbus := $(if $(BRILLO_USE_DBUS),$(BRILLO_USE_DBUS),0)
 local_use_hwid_override := \
     $(if $(BRILLO_USE_HWID_OVERRIDE),$(BRILLO_USE_HWID_OVERRIDE),0)
+# "libcros" gates the LibCrosService exposed by the Chrome OS' chrome browser to
+# the system layer.
+local_use_libcros := $(if $(BRILLO_USE_LIBCROS),$(BRILLO_USE_LIBCROS),0)
 local_use_mtd := $(if $(BRILLO_USE_MTD),$(BRILLO_USE_MTD),0)
 local_use_power_management := \
     $(if $(BRILLO_USE_POWER_MANAGEMENT),$(BRILLO_USE_POWER_MANAGEMENT),0)
@@ -32,6 +35,7 @@
     -DUSE_BINDER=$(local_use_binder) \
     -DUSE_DBUS=$(local_use_dbus) \
     -DUSE_HWID_OVERRIDE=$(local_use_hwid_override) \
+    -DUSE_LIBCROS=$(local_use_libcros) \
     -DUSE_MTD=$(local_use_mtd) \
     -DUSE_POWER_MANAGEMENT=$(local_use_power_management) \
     -DUSE_WEAVE=$(local_use_weave) \
@@ -299,7 +303,6 @@
     $(ue_update_metadata_protos_exported_shared_libraries)
 LOCAL_SRC_FILES := \
     boot_control_android.cc \
-    chrome_browser_proxy_resolver.cc \
     common_service.cc \
     connection_manager.cc \
     daemon.cc \
@@ -346,6 +349,10 @@
 LOCAL_SRC_FILES += \
     weave_service.cc
 endif  # local_use_weave == 1
+ifeq ($(local_use_libcros),1)
+LOCAL_SRC_FILES += \
+    chrome_browser_proxy_resolver.cc
+endif  # local_use_libcros == 1
 include $(BUILD_STATIC_LIBRARY)
 
 else  # !defined(BRILLO)
@@ -448,6 +455,57 @@
 LOCAL_INIT_RC := update_engine.rc
 include $(BUILD_EXECUTABLE)
 
+# libupdate_engine_client (type: shared_library)
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libupdate_engine_client
+LOCAL_CFLAGS := \
+    -Wall \
+    -Werror \
+    -Wno-unused-parameter \
+    -DUSE_DBUS=$(local_use_dbus) \
+    -DUSE_BINDER=$(local_use_binder)
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+# TODO(deymo): Remove "external/cros/system_api/dbus" when dbus is not used.
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/client_library/include \
+    external/cros/system_api/dbus \
+    system \
+    external/gtest/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/client_library/include
+LOCAL_SHARED_LIBRARIES := \
+    libchrome \
+    libbrillo
+LOCAL_SRC_FILES := \
+    client_library/client.cc \
+    update_status_utils.cc
+
+# We can only compile support for one IPC mechanism. If both "binder" and "dbus"
+# are defined, we prefer binder.
+ifeq ($(local_use_binder),1)
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder_bindings
+LOCAL_SHARED_LIBRARIES += \
+    libbinder \
+    libbrillo-binder \
+    libutils
+LOCAL_SRC_FILES += \
+    binder_bindings/android/brillo/IUpdateEngine.aidl \
+    binder_bindings/android/brillo/IUpdateEngineStatusCallback.aidl \
+    client_library/client_binder.cc \
+    parcelable_update_engine_status.cc
+else  # local_use_binder != 1
+LOCAL_STATIC_LIBRARIES := \
+    update_engine_client-dbus-proxies
+LOCAL_SHARED_LIBRARIES += \
+    libchrome-dbus \
+    libbrillo-dbus
+LOCAL_SRC_FILES += \
+    client_library/client_dbus.cc
+endif  # local_use_binder == 1
+
+include $(BUILD_SHARED_LIBRARY)
+
 # update_engine_client (type: executable)
 # ========================================================
 # update_engine console client.
@@ -465,7 +523,8 @@
 LOCAL_SHARED_LIBRARIES += \
     libupdate_engine_client
 LOCAL_SRC_FILES := \
-    update_engine_client.cc
+    update_engine_client.cc \
+    common/error_code_utils.cc
 else  # !defined(BRILLO)
 #TODO(deymo): Remove external/cros/system_api/dbus once the strings are moved
 # out of the DBus interface.
@@ -623,56 +682,171 @@
 LOCAL_SRC_FILES := $(ue_delta_generator_src_files)
 include $(BUILD_EXECUTABLE)
 
-# libupdate_engine_client
+# TODO(deymo): Enable the unittest binaries in non-Brillo builds once the DBus
+# dependencies are removed or placed behind the USE_DBUS flag.
+ifdef BRILLO
+
+# Sample images for unittests.
 # ========================================================
+# Generate a prebuilt module that installs a sample image from the compressed
+# sample_images.tar.bz2 file used by the unittests.
+#
+# $(1): The filename in the sample_images.tar.bz2
+define ue-unittest-sample-image
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_MODULE := ue_unittest_$(1)) \
+    $(eval LOCAL_MODULE_CLASS := EXECUTABLES) \
+    $(eval $(ifeq $(BRILLO), 1, LOCAL_MODULE_TAGS := eng)) \
+    $(eval LOCAL_MODULE_PATH := \
+        $(TARGET_OUT_DATA_NATIVE_TESTS)/update_engine_unittests/gen) \
+    $(eval LOCAL_MODULE_STEM := $(1)) \
+    $(eval my_gen := $(call local-intermediates-dir)/gen/$(1)) \
+    $(eval $(my_gen) : PRIVATE_CUSTOM_TOOL = \
+        tar -jxf $$< -C $$(dir $$@) $$(notdir $$@) && touch $$@) \
+    $(eval $(my_gen) : $(LOCAL_PATH)/sample_images/sample_images.tar.bz2 ; \
+        $$(transform-generated-source)) \
+    $(eval LOCAL_PREBUILT_MODULE_FILE := $(my_gen)) \
+    $(eval include $(BUILD_PREBUILT))
+endef
+
+$(call ue-unittest-sample-image,disk_ext2_1k.img)
+$(call ue-unittest-sample-image,disk_ext2_4k.img)
+$(call ue-unittest-sample-image,disk_ext2_4k_empty.img)
+$(call ue-unittest-sample-image,disk_ext2_ue_settings.img)
+
+# test_http_server (type: executable)
+# ========================================================
+# Test HTTP Server.
 include $(CLEAR_VARS)
-LOCAL_MODULE := libupdate_engine_client
-LOCAL_CFLAGS := \
-    -Wall \
-    -Werror \
-    -Wno-unused-parameter \
-    -DUSE_DBUS=$(local_use_dbus) \
-    -DUSE_BINDER=$(local_use_binder)
-LOCAL_CLANG := true
+LOCAL_MODULE := test_http_server
+ifdef BRILLO
+  LOCAL_MODULE_TAGS := eng
+endif
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/update_engine_unittests
+LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_CPP_EXTENSION := .cc
-# TODO(deymo): Remove "external/cros/system_api/dbus" when dbus is not used.
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/client_library/include \
-    external/cros/system_api/dbus \
-    system \
-    external/gtest/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/client_library/include
-LOCAL_SHARED_LIBRARIES := \
-    libchrome \
-    libbrillo
+LOCAL_CLANG := true
+LOCAL_CFLAGS := $(ue_common_cflags)
+LOCAL_CPPFLAGS := $(ue_common_cppflags)
+LOCAL_LDFLAGS := $(ue_common_ldflags)
+LOCAL_C_INCLUDES := $(ue_common_c_includes)
+LOCAL_SHARED_LIBRARIES := $(ue_common_shared_libraries)
 LOCAL_SRC_FILES := \
-    client_library/client.cc \
-    update_status_utils.cc
+    common/http_common.cc \
+    test_http_server.cc
+include $(BUILD_EXECUTABLE)
 
-# We can only compile support for one IPC mechanism. If both "binder" and "dbus"
-# are defined, we prefer binder.
-ifeq ($(local_use_binder),1)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder_bindings
-LOCAL_SHARED_LIBRARIES += \
-    libbinder \
-    libbrillo-binder \
-    libutils
-LOCAL_SRC_FILES += \
-    binder_bindings/android/brillo/IUpdateEngine.aidl \
-    binder_bindings/android/brillo/IUpdateEngineStatusCallback.aidl \
-    client_library/client_binder.cc \
-    parcelable_update_engine_status.cc
-else  # local_use_binder != 1
+# update_engine_unittests (type: executable)
+# ========================================================
+# Main unittest file.
+include $(CLEAR_VARS)
+LOCAL_MODULE := update_engine_unittests
+ifdef BRILLO
+  LOCAL_MODULE_TAGS := eng
+endif
+LOCAL_REQUIRED_MODULES := \
+    ue_unittest_disk_ext2_1k.img \
+    ue_unittest_disk_ext2_4k.img \
+    ue_unittest_disk_ext2_4k_empty.img \
+    ue_unittest_disk_ext2_ue_settings.img
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CLANG := true
+LOCAL_CFLAGS := $(ue_common_cflags)
+LOCAL_CPPFLAGS := $(ue_common_cppflags)
+LOCAL_LDFLAGS := $(ue_common_ldflags)
+LOCAL_C_INCLUDES := \
+    $(ue_common_c_includes) \
+    $(ue_libupdate_engine_exported_c_includes)
 LOCAL_STATIC_LIBRARIES := \
-    update_engine_client-dbus-proxies
-LOCAL_SHARED_LIBRARIES += \
-    libchrome-dbus \
-    libbrillo-dbus
+    libupdate_engine \
+    libpayload_generator \
+    libbrillo-test-helpers \
+    libgmock \
+    libgtest \
+    libchrome_test_helpers \
+    $(ue_libupdate_engine_exported_static_libraries:-host=) \
+    $(ue_libpayload_generator_exported_static_libraries:-host=)
+LOCAL_SHARED_LIBRARIES := \
+    $(ue_common_shared_libraries) \
+    $(ue_libupdate_engine_exported_shared_libraries:-host=) \
+    $(ue_libpayload_generator_exported_shared_libraries:-host=)
+LOCAL_SRC_FILES := \
+    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/hash_calculator_unittest.cc \
+    common/http_fetcher_unittest.cc \
+    common/hwid_override_unittest.cc \
+    common/mock_http_fetcher.cc \
+    common/prefs_unittest.cc \
+    common/subprocess_unittest.cc \
+    common/terminator_unittest.cc \
+    common/test_utils.cc \
+    common/utils_unittest.cc \
+    common_service_unittest.cc \
+    connection_manager_unittest.cc \
+    fake_shill_proxy.cc \
+    fake_system_state.cc \
+    metrics_utils_unittest.cc \
+    omaha_request_action_unittest.cc \
+    omaha_request_params_unittest.cc \
+    omaha_response_handler_action_unittest.cc \
+    p2p_manager_unittest.cc \
+    payload_consumer/bzip_extent_writer_unittest.cc \
+    payload_consumer/delta_performer_integration_test.cc \
+    payload_consumer/delta_performer_unittest.cc \
+    payload_consumer/download_action_unittest.cc \
+    payload_consumer/extent_writer_unittest.cc \
+    payload_consumer/file_writer_unittest.cc \
+    payload_consumer/filesystem_verifier_action_unittest.cc \
+    payload_consumer/postinstall_runner_action_unittest.cc \
+    payload_consumer/xz_extent_writer_unittest.cc \
+    payload_generator/ab_generator_unittest.cc \
+    payload_generator/blob_file_writer_unittest.cc \
+    payload_generator/block_mapping_unittest.cc \
+    payload_generator/cycle_breaker_unittest.cc \
+    payload_generator/delta_diff_utils_unittest.cc \
+    payload_generator/ext2_filesystem_unittest.cc \
+    payload_generator/extent_ranges_unittest.cc \
+    payload_generator/extent_utils_unittest.cc \
+    payload_generator/fake_filesystem.cc \
+    payload_generator/full_update_generator_unittest.cc \
+    payload_generator/graph_utils_unittest.cc \
+    payload_generator/inplace_generator_unittest.cc \
+    payload_generator/payload_file_unittest.cc \
+    payload_generator/payload_generation_config_unittest.cc \
+    payload_generator/payload_signer_unittest.cc \
+    payload_generator/tarjan_unittest.cc \
+    payload_generator/topological_sort_unittest.cc \
+    payload_generator/zip_unittest.cc \
+    payload_state_unittest.cc \
+    update_attempter_unittest.cc \
+    update_manager/boxed_value_unittest.cc \
+    update_manager/chromeos_policy_unittest.cc \
+    update_manager/evaluation_context_unittest.cc \
+    update_manager/generic_variables_unittest.cc \
+    update_manager/prng_unittest.cc \
+    update_manager/real_config_provider_unittest.cc \
+    update_manager/real_device_policy_provider_unittest.cc \
+    update_manager/real_random_provider_unittest.cc \
+    update_manager/real_shill_provider_unittest.cc \
+    update_manager/real_system_provider_unittest.cc \
+    update_manager/real_time_provider_unittest.cc \
+    update_manager/real_updater_provider_unittest.cc \
+    update_manager/umtest_utils.cc \
+    update_manager/update_manager_unittest.cc \
+    update_manager/variable_unittest.cc \
+    testrunner.cc
+ifeq ($(local_use_libcros),1)
 LOCAL_SRC_FILES += \
-    client_library/client_dbus.cc
-endif  # local_use_binder == 1
-
-include $(BUILD_SHARED_LIBRARY)
+    chrome_browser_proxy_resolver_unittest.cc
+endif  # local_use_libcros == 1
+include $(BUILD_NATIVE_TEST)
+endif  # BRILLO
 
 # Weave schema files
 # ========================================================
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 8a91607..9cf6042 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -54,6 +54,9 @@
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
            send_member="GetPrevVersion"/>
+    <allow send_destination="org.chromium.UpdateEngine"
+           send_interface="org.chromium.UpdateEngineInterface"
+           send_member="GetLastAttemptError"/>
     <allow send_interface="org.chromium.UpdateEngineLibcrosProxyResolvedInterface" />
   </policy>
   <policy user="power">
diff --git a/binder_bindings/android/brillo/IUpdateEngine.aidl b/binder_bindings/android/brillo/IUpdateEngine.aidl
index 9399ce3..1c0a3e5 100644
--- a/binder_bindings/android/brillo/IUpdateEngine.aidl
+++ b/binder_bindings/android/brillo/IUpdateEngine.aidl
@@ -36,4 +36,5 @@
   String GetPrevVersion();
   String GetRollbackPartition();
   void RegisterStatusCallback(in IUpdateEngineStatusCallback callback);
+  int GetLastAttemptError();
 }
diff --git a/binder_service_brillo.cc b/binder_service_brillo.cc
index 45ac343..6a6a16e 100644
--- a/binder_service_brillo.cc
+++ b/binder_service_brillo.cc
@@ -186,6 +186,12 @@
   return Status::ok();
 }
 
+Status BinderUpdateEngineBrilloService::GetLastAttemptError(
+    int* out_last_attempt_error) {
+  return CallCommonHandler(&UpdateEngineService::GetLastAttemptError,
+                           out_last_attempt_error);
+}
+
 void BinderUpdateEngineBrilloService::UnregisterStatusCallback(
     IUpdateEngineStatusCallback* callback) {
   auto it = callbacks_.begin();
diff --git a/binder_service_brillo.h b/binder_service_brillo.h
index 178305b..497b1b0 100644
--- a/binder_service_brillo.h
+++ b/binder_service_brillo.h
@@ -84,6 +84,8 @@
   android::binder::Status RegisterStatusCallback(
       const android::sp<android::brillo::IUpdateEngineStatusCallback>& callback)
       override;
+  android::binder::Status GetLastAttemptError(
+      int* out_last_attempt_error) override;
 
  private:
   // Generic function for dispatching to the common service.
diff --git a/chrome_browser_proxy_resolver_unittest.cc b/chrome_browser_proxy_resolver_unittest.cc
index 7a4de3d..bb5193e 100644
--- a/chrome_browser_proxy_resolver_unittest.cc
+++ b/chrome_browser_proxy_resolver_unittest.cc
@@ -109,14 +109,14 @@
 namespace {
 void CheckResponseResolved(const deque<string>& proxies,
                            void* /* pirv_data */) {
-  EXPECT_EQ(2, proxies.size());
+  EXPECT_EQ(2U, proxies.size());
   EXPECT_EQ("socks5://192.168.52.83:5555", proxies[0]);
   EXPECT_EQ(kNoProxy, proxies[1]);
   MessageLoop::current()->BreakLoop();
 }
 
 void CheckResponseNoReply(const deque<string>& proxies, void* /* pirv_data */) {
-  EXPECT_EQ(1, proxies.size());
+  EXPECT_EQ(1U, proxies.size());
   EXPECT_EQ(kNoProxy, proxies[0]);
   MessageLoop::current()->BreakLoop();
 }
diff --git a/client_library/client_binder.cc b/client_library/client_binder.cc
index 6f9b7b6..321dfc4 100644
--- a/client_library/client_binder.cc
+++ b/client_library/client_binder.cc
@@ -215,5 +215,16 @@
   return true;
 }
 
+bool BinderUpdateEngineClient::GetLastAttemptError(
+    int32_t* last_attempt_error) const {
+  int out_as_int;
+
+  if (!service_->GetLastAttemptError(&out_as_int).isOk())
+    return false;
+
+  *last_attempt_error = out_as_int;
+  return true;
+}
+
 }  // namespace internal
 }  // namespace update_engine
diff --git a/client_library/client_binder.h b/client_library/client_binder.h
index 562cee4..72f80dd 100644
--- a/client_library/client_binder.h
+++ b/client_library/client_binder.h
@@ -80,6 +80,8 @@
   bool RegisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
   bool UnregisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
 
+  bool GetLastAttemptError(int32_t* last_attempt_error) const override;
+
  private:
   class StatusUpdateCallback :
       public android::brillo::BnUpdateEngineStatusCallback {
diff --git a/client_library/client_dbus.cc b/client_library/client_dbus.cc
index 270a987..0d6b783 100644
--- a/client_library/client_dbus.cc
+++ b/client_library/client_dbus.cc
@@ -225,5 +225,10 @@
                             nullptr);
 }
 
+bool DBusUpdateEngineClient::GetLastAttemptError(
+    int32_t* last_attempt_error) const {
+  return proxy_->GetLastAttemptError(last_attempt_error, nullptr);
+}
+
 }  // namespace internal
 }  // namespace update_engine
diff --git a/client_library/client_dbus.h b/client_library/client_dbus.h
index 507fb5c..02a7e84 100644
--- a/client_library/client_dbus.h
+++ b/client_library/client_dbus.h
@@ -73,6 +73,8 @@
   bool RegisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
   bool UnregisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
 
+  bool GetLastAttemptError(int32_t* last_attempt_error) const override;
+
  private:
   void DBusStatusHandlersRegistered(const std::string& interface,
                                     const std::string& signal_name,
diff --git a/client_library/include/update_engine/client.h b/client_library/include/update_engine/client.h
index dc0fb8c..62ac5fb 100644
--- a/client_library/include/update_engine/client.h
+++ b/client_library/include/update_engine/client.h
@@ -112,6 +112,9 @@
   // Unregister a status update handler
   virtual bool UnregisterStatusUpdateHandler(StatusUpdateHandler* handler) = 0;
 
+  // Get the last UpdateAttempt error code.
+  virtual bool GetLastAttemptError(int32_t* last_attempt_error) const = 0;
+
  protected:
   // Use CreateInstance().
   UpdateEngineClient() = default;
diff --git a/common/action.h b/common/action.h
index d8049ac..6c88216 100644
--- a/common/action.h
+++ b/common/action.h
@@ -124,6 +124,15 @@
   // Only the ActionProcessor should call this.
   virtual void TerminateProcessing() {}
 
+  // Called on asynchronous actions if the processing is suspended and resumed,
+  // respectively. These methods are called by the ActionProcessor and should
+  // not be explicitly called.
+  // The action may still call ActionCompleted() once the action is completed
+  // while the processing is suspended, for example if suspend/resume is not
+  // implemented for the given action.
+  virtual void SuspendAction() {}
+  virtual void ResumeAction() {}
+
   // These methods are useful for debugging. TODO(adlr): consider using
   // std::type_info for this?
   // Type() returns a string of the Action type. I.e., for DownloadAction,
diff --git a/common/action_processor.cc b/common/action_processor.cc
index 7ccdfbd..3549e08 100644
--- a/common/action_processor.cc
+++ b/common/action_processor.cc
@@ -21,14 +21,12 @@
 #include <base/logging.h>
 
 #include "update_engine/common/action.h"
+#include "update_engine/common/error_code_utils.h"
 
 using std::string;
 
 namespace chromeos_update_engine {
 
-ActionProcessor::ActionProcessor()
-    : current_action_(nullptr), delegate_(nullptr) {}
-
 ActionProcessor::~ActionProcessor() {
   if (IsRunning())
     StopProcessing();
@@ -45,8 +43,7 @@
   CHECK(!IsRunning());
   if (!actions_.empty()) {
     current_action_ = actions_.front();
-    LOG(INFO) << "ActionProcessor::StartProcessing: "
-              << current_action_->Type();
+    LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
     actions_.pop_front();
     current_action_->PerformAction();
   }
@@ -54,17 +51,59 @@
 
 void ActionProcessor::StopProcessing() {
   CHECK(IsRunning());
-  CHECK(current_action_);
-  current_action_->TerminateProcessing();
-  CHECK(current_action_);
-  current_action_->SetProcessor(nullptr);
-  LOG(INFO) << "ActionProcessor::StopProcessing: aborted "
-            << current_action_->Type();
+  if (current_action_) {
+    current_action_->TerminateProcessing();
+    current_action_->SetProcessor(nullptr);
+  }
+  LOG(INFO) << "ActionProcessor: aborted "
+            << (current_action_ ? current_action_->Type() : "")
+            << (suspended_ ? " while suspended" : "");
   current_action_ = nullptr;
+  suspended_ = false;
+  // Delete all the actions before calling the delegate.
+  for (auto action : actions_)
+    action->SetProcessor(nullptr);
+  actions_.clear();
   if (delegate_)
     delegate_->ProcessingStopped(this);
 }
 
+void ActionProcessor::SuspendProcessing() {
+  // No current_action_ when not suspended means that the action processor was
+  // never started or already finished.
+  if (suspended_ || !current_action_) {
+    LOG(WARNING) << "Called SuspendProcessing while not processing.";
+    return;
+  }
+  suspended_ = true;
+
+  // If there's a current action we should notify it that it should suspend, but
+  // the action can ignore that and terminate at any point.
+  LOG(INFO) << "ActionProcessor: suspending " << current_action_->Type();
+  current_action_->SuspendAction();
+}
+
+void ActionProcessor::ResumeProcessing() {
+  if (!suspended_) {
+    LOG(WARNING) << "Called ResumeProcessing while not suspended.";
+    return;
+  }
+  suspended_ = false;
+  if (current_action_) {
+    // The current_action_ did not call ActionComplete while suspended, so we
+    // should notify it of the resume operation.
+    LOG(INFO) << "ActionProcessor: resuming " << current_action_->Type();
+    current_action_->ResumeAction();
+  } else {
+    // The last action called ActionComplete while suspended, so there is
+    // already a log message with the type of the finished action. We simply
+    // state that we are resuming processing and the next function will log the
+    // start of the next action or processing completion.
+    LOG(INFO) << "ActionProcessor: resuming processing";
+    StartNextActionOrFinish(suspended_error_code_);
+  }
+}
+
 void ActionProcessor::ActionComplete(AbstractAction* actionptr,
                                      ErrorCode code) {
   CHECK_EQ(actionptr, current_action_);
@@ -74,17 +113,26 @@
   current_action_->ActionCompleted(code);
   current_action_->SetProcessor(nullptr);
   current_action_ = nullptr;
-  if (actions_.empty()) {
-    LOG(INFO) << "ActionProcessor::ActionComplete: finished last action of"
-                 " type " << old_type;
-  } else if (code != ErrorCode::kSuccess) {
-    LOG(INFO) << "ActionProcessor::ActionComplete: " << old_type
-              << " action failed. Aborting processing.";
+  LOG(INFO) << "ActionProcessor: finished "
+            << (actions_.empty() ? "last action " : "") << old_type
+            << (suspended_ ? " while suspended" : "")
+            << " with code " << utils::ErrorCodeToString(code);
+  if (!actions_.empty() && code != ErrorCode::kSuccess) {
+    LOG(INFO) << "ActionProcessor: Aborting processing due to failure.";
     actions_.clear();
   }
+  if (suspended_) {
+    // If an action finished while suspended we don't start the next action (or
+    // terminate the processing) until the processor is resumed. This condition
+    // will be flagged by a nullptr current_action_ while suspended_ is true.
+    suspended_error_code_ = code;
+    return;
+  }
+  StartNextActionOrFinish(code);
+}
+
+void ActionProcessor::StartNextActionOrFinish(ErrorCode code) {
   if (actions_.empty()) {
-    LOG(INFO) << "ActionProcessor::ActionComplete: finished last action of"
-                 " type " << old_type;
     if (delegate_) {
       delegate_->ProcessingDone(this, code);
     }
@@ -92,8 +140,7 @@
   }
   current_action_ = actions_.front();
   actions_.pop_front();
-  LOG(INFO) << "ActionProcessor::ActionComplete: finished " << old_type
-            << ", starting " << current_action_->Type();
+  LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
   current_action_->PerformAction();
 }
 
diff --git a/common/action_processor.h b/common/action_processor.h
index d61e12d..c9c179e 100644
--- a/common/action_processor.h
+++ b/common/action_processor.h
@@ -20,6 +20,7 @@
 #include <deque>
 
 #include <base/macros.h>
+#include <brillo/errors/error.h>
 
 #include "update_engine/common/error_code.h"
 
@@ -40,7 +41,7 @@
 
 class ActionProcessor {
  public:
-  ActionProcessor();
+  ActionProcessor() = default;
 
   virtual ~ActionProcessor();
 
@@ -50,12 +51,25 @@
   virtual void StartProcessing();
 
   // Aborts processing. If an Action is running, it will have
-  // TerminateProcessing() called on it. The Action that was running
-  // will be lost and must be re-enqueued if this Processor is to use it.
+  // TerminateProcessing() called on it. The Action that was running and all the
+  // remaining actions will be lost and must be re-enqueued if this Processor is
+  // to use it.
   void StopProcessing();
 
-  // Returns true iff an Action is currently processing.
-  bool IsRunning() const { return nullptr != current_action_; }
+  // Suspend the processing. If an Action is running, it will have the
+  // SuspendProcessing() called on it, and it should suspend operations until
+  // ResumeProcessing() is called on this class to continue. While suspended,
+  // no new actions will be started. Calling SuspendProcessing while the
+  // processing is suspended or not running this method performs no action.
+  void SuspendProcessing();
+
+  // Resume the suspended processing. If the ActionProcessor is not suspended
+  // or not running in the first place this method performs no action.
+  void ResumeProcessing();
+
+  // Returns true iff the processing was started but not yet completed nor
+  // stopped.
+  bool IsRunning() const { return current_action_ != nullptr || suspended_; }
 
   // Adds another Action to the end of the queue.
   virtual void EnqueueAction(AbstractAction* action);
@@ -75,15 +89,29 @@
   void ActionComplete(AbstractAction* actionptr, ErrorCode code);
 
  private:
+  // Continue processing actions (if any) after the last action terminated with
+  // the passed error code. If there are no more actions to process, the
+  // processing will terminate.
+  void StartNextActionOrFinish(ErrorCode code);
+
   // Actions that have not yet begun processing, in the order in which
   // they'll be processed.
   std::deque<AbstractAction*> actions_;
 
   // A pointer to the currently processing Action, if any.
-  AbstractAction* current_action_;
+  AbstractAction* current_action_{nullptr};
+
+  // The ErrorCode reported by an action that was suspended but finished while
+  // being suspended. This error code is stored here to be reported back to the
+  // delegate once the processor is resumed.
+  ErrorCode suspended_error_code_{ErrorCode::kSuccess};
+
+  // Whether the action processor is or should be suspended.
+  bool suspended_{false};
 
   // A pointer to the delegate, or null if none.
-  ActionProcessorDelegate *delegate_;
+  ActionProcessorDelegate* delegate_{nullptr};
+
   DISALLOW_COPY_AND_ASSIGN(ActionProcessor);
 };
 
diff --git a/common/action_processor_unittest.cc b/common/action_processor_unittest.cc
index 8285470..631e42d 100644
--- a/common/action_processor_unittest.cc
+++ b/common/action_processor_unittest.cc
@@ -16,9 +16,12 @@
 
 #include "update_engine/common/action_processor.h"
 
-#include <gtest/gtest.h>
 #include <string>
+
+#include <gtest/gtest.h>
+
 #include "update_engine/common/action.h"
+#include "update_engine/common/mock_action.h"
 
 using std::string;
 
@@ -51,26 +54,6 @@
   string Type() const { return "ActionProcessorTestAction"; }
 };
 
-class ActionProcessorTest : public ::testing::Test { };
-
-// This test creates two simple Actions and sends a message via an ActionPipe
-// from one to the other.
-TEST(ActionProcessorTest, SimpleTest) {
-  ActionProcessorTestAction action;
-  ActionProcessor action_processor;
-  EXPECT_FALSE(action_processor.IsRunning());
-  action_processor.EnqueueAction(&action);
-  EXPECT_FALSE(action_processor.IsRunning());
-  EXPECT_FALSE(action.IsRunning());
-  action_processor.StartProcessing();
-  EXPECT_TRUE(action_processor.IsRunning());
-  EXPECT_TRUE(action.IsRunning());
-  EXPECT_EQ(action_processor.current_action(), &action);
-  action.CompleteAction();
-  EXPECT_FALSE(action_processor.IsRunning());
-  EXPECT_FALSE(action.IsRunning());
-}
-
 namespace {
 class MyActionProcessorDelegate : public ActionProcessorDelegate {
  public:
@@ -109,53 +92,79 @@
 };
 }  // namespace
 
-TEST(ActionProcessorTest, DelegateTest) {
-  ActionProcessorTestAction action;
-  ActionProcessor action_processor;
-  MyActionProcessorDelegate delegate(&action_processor);
-  action_processor.set_delegate(&delegate);
+class ActionProcessorTest : public ::testing::Test {
+  void SetUp() override {
+    action_processor_.set_delegate(&delegate_);
+    // Silence Type() calls used for logging.
+    EXPECT_CALL(mock_action_, Type()).Times(testing::AnyNumber());
+  }
 
-  action_processor.EnqueueAction(&action);
-  action_processor.StartProcessing();
-  action.CompleteAction();
-  action_processor.set_delegate(nullptr);
-  EXPECT_TRUE(delegate.processing_done_called_);
-  EXPECT_TRUE(delegate.action_completed_called_);
+  void TearDown() override {
+    action_processor_.set_delegate(nullptr);
+  }
+
+ protected:
+  // The ActionProcessor under test.
+  ActionProcessor action_processor_;
+
+  MyActionProcessorDelegate delegate_{&action_processor_};
+
+  // Common actions used during most tests.
+  testing::StrictMock<MockAction> mock_action_;
+  ActionProcessorTestAction action_;
+};
+
+TEST_F(ActionProcessorTest, SimpleTest) {
+  EXPECT_FALSE(action_processor_.IsRunning());
+  action_processor_.EnqueueAction(&action_);
+  EXPECT_FALSE(action_processor_.IsRunning());
+  EXPECT_FALSE(action_.IsRunning());
+  action_processor_.StartProcessing();
+  EXPECT_TRUE(action_processor_.IsRunning());
+  EXPECT_TRUE(action_.IsRunning());
+  EXPECT_EQ(action_processor_.current_action(), &action_);
+  action_.CompleteAction();
+  EXPECT_FALSE(action_processor_.IsRunning());
+  EXPECT_FALSE(action_.IsRunning());
 }
 
-TEST(ActionProcessorTest, StopProcessingTest) {
-  ActionProcessorTestAction action;
-  ActionProcessor action_processor;
-  MyActionProcessorDelegate delegate(&action_processor);
-  action_processor.set_delegate(&delegate);
-
-  action_processor.EnqueueAction(&action);
-  action_processor.StartProcessing();
-  action_processor.StopProcessing();
-  action_processor.set_delegate(nullptr);
-  EXPECT_TRUE(delegate.processing_stopped_called_);
-  EXPECT_FALSE(delegate.action_completed_called_);
-  EXPECT_FALSE(action_processor.IsRunning());
-  EXPECT_EQ(nullptr, action_processor.current_action());
+TEST_F(ActionProcessorTest, DelegateTest) {
+  action_processor_.EnqueueAction(&action_);
+  action_processor_.StartProcessing();
+  action_.CompleteAction();
+  EXPECT_TRUE(delegate_.processing_done_called_);
+  EXPECT_TRUE(delegate_.action_completed_called_);
 }
 
-TEST(ActionProcessorTest, ChainActionsTest) {
+TEST_F(ActionProcessorTest, StopProcessingTest) {
+  action_processor_.EnqueueAction(&action_);
+  action_processor_.StartProcessing();
+  action_processor_.StopProcessing();
+  EXPECT_TRUE(delegate_.processing_stopped_called_);
+  EXPECT_FALSE(delegate_.action_completed_called_);
+  EXPECT_FALSE(action_processor_.IsRunning());
+  EXPECT_EQ(nullptr, action_processor_.current_action());
+}
+
+TEST_F(ActionProcessorTest, ChainActionsTest) {
+  // This test doesn't use a delegate since it terminates several actions.
+  action_processor_.set_delegate(nullptr);
+
   ActionProcessorTestAction action1, action2;
-  ActionProcessor action_processor;
-  action_processor.EnqueueAction(&action1);
-  action_processor.EnqueueAction(&action2);
-  action_processor.StartProcessing();
-  EXPECT_EQ(&action1, action_processor.current_action());
-  EXPECT_TRUE(action_processor.IsRunning());
+  action_processor_.EnqueueAction(&action1);
+  action_processor_.EnqueueAction(&action2);
+  action_processor_.StartProcessing();
+  EXPECT_EQ(&action1, action_processor_.current_action());
+  EXPECT_TRUE(action_processor_.IsRunning());
   action1.CompleteAction();
-  EXPECT_EQ(&action2, action_processor.current_action());
-  EXPECT_TRUE(action_processor.IsRunning());
+  EXPECT_EQ(&action2, action_processor_.current_action());
+  EXPECT_TRUE(action_processor_.IsRunning());
   action2.CompleteAction();
-  EXPECT_EQ(nullptr, action_processor.current_action());
-  EXPECT_FALSE(action_processor.IsRunning());
+  EXPECT_EQ(nullptr, action_processor_.current_action());
+  EXPECT_FALSE(action_processor_.IsRunning());
 }
 
-TEST(ActionProcessorTest, DtorTest) {
+TEST_F(ActionProcessorTest, DtorTest) {
   ActionProcessorTestAction action1, action2;
   {
     ActionProcessor action_processor;
@@ -169,22 +178,87 @@
   EXPECT_FALSE(action2.IsRunning());
 }
 
-TEST(ActionProcessorTest, DefaultDelegateTest) {
+TEST_F(ActionProcessorTest, DefaultDelegateTest) {
   // Just make sure it doesn't crash
-  ActionProcessorTestAction action;
-  ActionProcessor action_processor;
-  ActionProcessorDelegate delegate;
-  action_processor.set_delegate(&delegate);
+  action_processor_.EnqueueAction(&action_);
+  action_processor_.StartProcessing();
+  action_.CompleteAction();
 
-  action_processor.EnqueueAction(&action);
-  action_processor.StartProcessing();
-  action.CompleteAction();
+  action_processor_.EnqueueAction(&action_);
+  action_processor_.StartProcessing();
+  action_processor_.StopProcessing();
+}
 
-  action_processor.EnqueueAction(&action);
-  action_processor.StartProcessing();
-  action_processor.StopProcessing();
+// This test suspends and resume the action processor while running one action_.
+TEST_F(ActionProcessorTest, SuspendResumeTest) {
+  action_processor_.EnqueueAction(&mock_action_);
 
-  action_processor.set_delegate(nullptr);
+  testing::InSequence s;
+  EXPECT_CALL(mock_action_, PerformAction());
+  action_processor_.StartProcessing();
+
+  EXPECT_CALL(mock_action_, SuspendAction());
+  action_processor_.SuspendProcessing();
+  // Suspending the processor twice should not suspend the action twice.
+  action_processor_.SuspendProcessing();
+
+  // IsRunning should return whether there's is an action doing some work, even
+  // if it is suspended.
+  EXPECT_TRUE(action_processor_.IsRunning());
+  EXPECT_EQ(&mock_action_, action_processor_.current_action());
+
+  EXPECT_CALL(mock_action_, ResumeAction());
+  action_processor_.ResumeProcessing();
+
+  // Calling ResumeProcessing twice should not affect the action_.
+  action_processor_.ResumeProcessing();
+
+  action_processor_.ActionComplete(&mock_action_, ErrorCode::kSuccess);
+}
+
+// This test suspends an action that presumably doesn't support suspend/resume
+// and it finished before being resumed.
+TEST_F(ActionProcessorTest, ActionCompletedWhileSuspendedTest) {
+  action_processor_.EnqueueAction(&mock_action_);
+
+  testing::InSequence s;
+  EXPECT_CALL(mock_action_, PerformAction());
+  action_processor_.StartProcessing();
+
+  EXPECT_CALL(mock_action_, SuspendAction());
+  action_processor_.SuspendProcessing();
+
+  // Simulate the action completion while suspended. No other call to
+  // |mock_action_| is expected at this point.
+  action_processor_.ActionComplete(&mock_action_, ErrorCode::kSuccess);
+
+  // The processing should not be done since the ActionProcessor is suspended
+  // and the processing is considered to be still running until resumed.
+  EXPECT_FALSE(delegate_.processing_done_called_);
+  EXPECT_TRUE(action_processor_.IsRunning());
+
+  action_processor_.ResumeProcessing();
+  EXPECT_TRUE(delegate_.processing_done_called_);
+  EXPECT_FALSE(delegate_.processing_stopped_called_);
+}
+
+TEST_F(ActionProcessorTest, StoppedWhileSuspendedTest) {
+  action_processor_.EnqueueAction(&mock_action_);
+
+  testing::InSequence s;
+  EXPECT_CALL(mock_action_, PerformAction());
+  action_processor_.StartProcessing();
+  EXPECT_CALL(mock_action_, SuspendAction());
+  action_processor_.SuspendProcessing();
+
+  EXPECT_CALL(mock_action_, TerminateProcessing());
+  action_processor_.StopProcessing();
+  // Stopping the processing should abort the current execution no matter what.
+  EXPECT_TRUE(delegate_.processing_stopped_called_);
+  EXPECT_FALSE(delegate_.processing_done_called_);
+  EXPECT_FALSE(delegate_.action_completed_called_);
+  EXPECT_FALSE(action_processor_.IsRunning());
+  EXPECT_EQ(nullptr, action_processor_.current_action());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/common/constants.cc b/common/constants.cc
index b15c3f4..fc6df37 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -29,6 +29,8 @@
 
 const char kStatefulPartition[] = "/mnt/stateful_partition";
 
+const char kPostinstallDefaultScript[] = "postinst";
+
 // Constants defining keys for the persisted state of update engine.
 const char kPrefsAttemptInProgress[] = "attempt-in-progress";
 const char kPrefsBackoffExpiryTime[] = "backoff-expiry-time";
@@ -45,6 +47,7 @@
 const char kPrefsLastActivePingDay[] = "last-active-ping-day";
 const char kPrefsLastRollCallPingDay[] = "last-roll-call-ping-day";
 const char kPrefsManifestMetadataSize[] = "manifest-metadata-size";
+const char kPrefsManifestSignatureSize[] = "manifest-signature-size";
 const char kPrefsMetricsAttemptLastReportingTime[] =
     "metrics-attempt-last-reporting-time";
 const char kPrefsMetricsCheckLastReportingTime[] =
diff --git a/common/constants.h b/common/constants.h
index 62f61ce..25d587b 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -32,6 +32,9 @@
 // The location where we store the AU preferences (state etc).
 extern const char kPrefsSubDirectory[];
 
+// Path to the post install command, relative to the partition.
+extern const char kPostinstallDefaultScript[];
+
 // Path to the stateful partition on the root filesystem.
 extern const char kStatefulPartition[];
 
@@ -50,6 +53,7 @@
 extern const char kPrefsLastActivePingDay[];
 extern const char kPrefsLastRollCallPingDay[];
 extern const char kPrefsManifestMetadataSize[];
+extern const char kPrefsManifestSignatureSize[];
 extern const char kPrefsMetricsAttemptLastReportingTime[];
 extern const char kPrefsMetricsCheckLastReportingTime[];
 extern const char kPrefsNumReboots[];
diff --git a/common/http_common.cc b/common/http_common.cc
index 7d98889..d07ced3 100644
--- a/common/http_common.cc
+++ b/common/http_common.cc
@@ -18,6 +18,8 @@
 
 #include "update_engine/common/http_common.h"
 
+#include <cstdlib>
+
 #include <base/macros.h>
 
 namespace chromeos_update_engine {
diff --git a/common/http_common.h b/common/http_common.h
index 041cad5..6d444ed 100644
--- a/common/http_common.h
+++ b/common/http_common.h
@@ -20,8 +20,6 @@
 #ifndef UPDATE_ENGINE_COMMON_HTTP_COMMON_H_
 #define UPDATE_ENGINE_COMMON_HTTP_COMMON_H_
 
-#include <cstdlib>
-
 namespace chromeos_update_engine {
 
 // Enumeration type for HTTP response codes.
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 17e360e..5450958 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -48,6 +48,7 @@
 #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/mock_proxy_resolver.h"
 #include "update_engine/proxy_resolver.h"
 
 using brillo::MessageLoop;
@@ -56,6 +57,10 @@
 using std::string;
 using std::unique_ptr;
 using std::vector;
+using testing::DoAll;
+using testing::Return;
+using testing::SaveArg;
+using testing::_;
 
 namespace {
 
@@ -193,14 +198,19 @@
   AnyHttpFetcherTest() {}
   virtual ~AnyHttpFetcherTest() {}
 
-  virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
+  virtual HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) = 0;
+  HttpFetcher* NewLargeFetcher(size_t num_proxies) {
+    proxy_resolver_.set_num_proxies(num_proxies);
+    return NewLargeFetcher(&proxy_resolver_);
+  }
   HttpFetcher* NewLargeFetcher() {
     return NewLargeFetcher(1);
   }
 
-  virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
+  virtual HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) = 0;
   HttpFetcher* NewSmallFetcher() {
-    return NewSmallFetcher(1);
+    proxy_resolver_.set_num_proxies(1);
+    return NewSmallFetcher(&proxy_resolver_);
   }
 
   virtual string BigUrl(in_port_t port) const { return kUnusedUrl; }
@@ -227,25 +237,16 @@
  public:
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewLargeFetcher;
-  HttpFetcher* NewLargeFetcher(size_t num_proxies) override {
+  HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
     brillo::Blob big_data(1000000);
-    CHECK_GT(num_proxies, 0u);
-    proxy_resolver_.set_num_proxies(num_proxies);
     return new MockHttpFetcher(
-        big_data.data(),
-        big_data.size(),
-        reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
+        big_data.data(), big_data.size(), proxy_resolver);
   }
 
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewSmallFetcher;
-  HttpFetcher* NewSmallFetcher(size_t num_proxies) override {
-    CHECK_GT(num_proxies, 0u);
-    proxy_resolver_.set_num_proxies(num_proxies);
-    return new MockHttpFetcher(
-        "x",
-        1,
-        reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
+  HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
+    return new MockHttpFetcher("x", 1, proxy_resolver);
   }
 
   bool IsMock() const override { return true; }
@@ -260,12 +261,9 @@
  public:
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewLargeFetcher;
-  HttpFetcher* NewLargeFetcher(size_t num_proxies) override {
-    CHECK_GT(num_proxies, 0u);
-    proxy_resolver_.set_num_proxies(num_proxies);
-    LibcurlHttpFetcher *ret = new
-        LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_),
-                           &fake_hardware_);
+  HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
+    LibcurlHttpFetcher* ret =
+        new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_);
     // Speed up test execution.
     ret->set_idle_seconds(1);
     ret->set_retry_seconds(1);
@@ -275,8 +273,8 @@
 
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewSmallFetcher;
-  HttpFetcher* NewSmallFetcher(size_t num_proxies) override {
-    return NewLargeFetcher(num_proxies);
+  HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
+    return NewLargeFetcher(proxy_resolver);
   }
 
   string BigUrl(in_port_t port) const override {
@@ -307,14 +305,9 @@
  public:
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewLargeFetcher;
-  HttpFetcher* NewLargeFetcher(size_t num_proxies) override {
-    CHECK_GT(num_proxies, 0u);
-    proxy_resolver_.set_num_proxies(num_proxies);
-    ProxyResolver* resolver =
-        reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
-    MultiRangeHttpFetcher *ret =
-        new MultiRangeHttpFetcher(
-            new LibcurlHttpFetcher(resolver, &fake_hardware_));
+  HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
+    MultiRangeHttpFetcher* ret = new MultiRangeHttpFetcher(
+        new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_));
     ret->ClearRanges();
     ret->AddRange(0);
     // Speed up test execution.
@@ -326,8 +319,8 @@
 
   // Necessary to unhide the definition in the base class.
   using AnyHttpFetcherTest::NewSmallFetcher;
-  HttpFetcher* NewSmallFetcher(size_t num_proxies) override {
-    return NewLargeFetcher(num_proxies);
+  HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
+    return NewLargeFetcher(proxy_resolver);
   }
 
   bool IsMulti() const override { return true; }
@@ -517,26 +510,51 @@
 }  // namespace
 
 TYPED_TEST(HttpFetcherTest, PauseTest) {
-  {
-    PausingHttpFetcherTestDelegate delegate;
-    unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
-    delegate.paused_ = false;
-    delegate.fetcher_ = fetcher.get();
-    fetcher->set_delegate(&delegate);
+  PausingHttpFetcherTestDelegate delegate;
+  unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
+  delegate.paused_ = false;
+  delegate.fetcher_ = fetcher.get();
+  fetcher->set_delegate(&delegate);
 
-    unique_ptr<HttpServer> server(this->test_.CreateServer());
-    ASSERT_TRUE(server->started_);
+  unique_ptr<HttpServer> server(this->test_.CreateServer());
+  ASSERT_TRUE(server->started_);
 
-    MessageLoop::TaskId callback_id;
-    callback_id = this->loop_.PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&UnpausingTimeoutCallback, &delegate, &callback_id),
-        base::TimeDelta::FromMilliseconds(200));
-    fetcher->BeginTransfer(this->test_.BigUrl(server->GetPort()));
+  MessageLoop::TaskId callback_id;
+  callback_id = this->loop_.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&UnpausingTimeoutCallback, &delegate, &callback_id),
+      base::TimeDelta::FromMilliseconds(200));
+  fetcher->BeginTransfer(this->test_.BigUrl(server->GetPort()));
 
-    this->loop_.Run();
-    EXPECT_TRUE(this->loop_.CancelTask(callback_id));
-  }
+  this->loop_.Run();
+  EXPECT_TRUE(this->loop_.CancelTask(callback_id));
+}
+
+// This test will pause the fetcher while the download is not yet started
+// because it is waiting for the proxy to be resolved.
+TYPED_TEST(HttpFetcherTest, PauseWhileResolvingProxyTest) {
+  if (this->test_.IsMock())
+    return;
+  MockProxyResolver mock_resolver;
+  unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher(&mock_resolver));
+
+  // Saved arguments from the proxy call.
+  ProxiesResolvedFn proxy_callback = nullptr;
+  void* proxy_data = nullptr;
+
+  EXPECT_CALL(mock_resolver, GetProxiesForUrl("http://fake_url", _, _))
+      .WillOnce(DoAll(
+          SaveArg<1>(&proxy_callback), SaveArg<2>(&proxy_data), Return(true)));
+  fetcher->BeginTransfer("http://fake_url");
+  testing::Mock::VerifyAndClearExpectations(&mock_resolver);
+
+  // Pausing and unpausing while resolving the proxy should not affect anything.
+  fetcher->Pause();
+  fetcher->Unpause();
+  fetcher->Pause();
+  // Proxy resolver comes back after we paused the fetcher.
+  ASSERT_TRUE(proxy_callback);
+  (*proxy_callback)({1, kNoProxy}, proxy_data);
 }
 
 namespace {
@@ -650,7 +668,7 @@
     this->loop_.Run();
 
     // verify the data we get back
-    ASSERT_EQ(kBigLength, delegate.data.size());
+    ASSERT_EQ(kBigLength, static_cast<int>(delegate.data.size()));
     for (int i = 0; i < kBigLength; i += 10) {
       // Assert so that we don't flood the screen w/ EXPECT errors on failure.
       ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
@@ -831,7 +849,7 @@
   MessageLoop::current()->Run();
   if (expected_successful) {
     // verify the data we get back
-    ASSERT_EQ(kMediumLength, delegate.data.size());
+    ASSERT_EQ(static_cast<size_t>(kMediumLength), delegate.data.size());
     for (int i = 0; i < kMediumLength; i += 10) {
       // Assert so that we don't flood the screen w/ EXPECT errors on failure.
       ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
@@ -923,13 +941,13 @@
                const string& url,
                const vector<pair<off_t, off_t>>& ranges,
                const string& expected_prefix,
-               off_t expected_size,
+               size_t expected_size,
                HttpResponseCode expected_response_code) {
   MultiHttpFetcherTestDelegate delegate(expected_response_code);
   delegate.fetcher_.reset(fetcher_in);
 
   MultiRangeHttpFetcher* multi_fetcher =
-      dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
+      static_cast<MultiRangeHttpFetcher*>(fetcher_in);
   ASSERT_TRUE(multi_fetcher);
   multi_fetcher->ClearRanges();
   for (vector<pair<off_t, off_t>>::const_iterator it = ranges.begin(),
diff --git a/common/hwid_override_unittest.cc b/common/hwid_override_unittest.cc
index fff64bc..26ef30a 100644
--- a/common/hwid_override_unittest.cc
+++ b/common/hwid_override_unittest.cc
@@ -48,7 +48,7 @@
   keyval += ("=" + expected_hwid);
   ASSERT_EQ(base::WriteFile(tempdir_.path().Append("etc/lsb-release"),
                             keyval.c_str(), keyval.length()),
-            keyval.length());
+            static_cast<int>(keyval.length()));
   EXPECT_EQ(expected_hwid, HwidOverride::Read(tempdir_.path()));
 }
 
@@ -56,7 +56,7 @@
   std::string keyval("SOMETHING_ELSE=UNINTERESTING");
   ASSERT_EQ(base::WriteFile(tempdir_.path().Append("etc/lsb-release"),
                             keyval.c_str(), keyval.length()),
-            keyval.length());
+            static_cast<int>(keyval.length()));
   EXPECT_EQ(std::string(), HwidOverride::Read(tempdir_.path()));
 }
 
diff --git a/common/libcurl_http_fetcher.cc b/common/libcurl_http_fetcher.cc
index 761b74e..789f46e 100644
--- a/common/libcurl_http_fetcher.cc
+++ b/common/libcurl_http_fetcher.cc
@@ -99,6 +99,7 @@
 
   curl_handle_ = curl_easy_init();
   CHECK(curl_handle_);
+  ignore_failure_ = false;
 
   CHECK(HasProxy());
   bool is_direct = (GetCurrentProxy() == kNoProxy);
@@ -291,6 +292,12 @@
   http_response_code_ = 0;
   terminate_requested_ = false;
   sent_byte_ = false;
+
+  // If we are paused, we delay these two operations until Unpause is called.
+  if (transfer_paused_) {
+    restart_transfer_on_unpause_ = true;
+    return;
+  }
   ResumeTransfer(url_);
   CurlPerformOnce();
 }
@@ -325,96 +332,110 @@
       return;
     }
   }
-  if (0 == running_handles) {
-    GetHttpResponseCode();
-    if (http_response_code_) {
-      LOG(INFO) << "HTTP response code: " << http_response_code_;
-      no_network_retry_count_ = 0;
+
+  // If the transfer completes while paused, we should ignore the failure once
+  // the fetcher is unpaused.
+  if (running_handles == 0 && transfer_paused_ && !ignore_failure_) {
+    LOG(INFO) << "Connection closed while paused, ignoring failure.";
+    ignore_failure_ = true;
+  }
+
+  if (running_handles != 0 || transfer_paused_) {
+    // There's either more work to do or we are paused, so we just keep the
+    // file descriptors to watch up to date and exit, until we are done with the
+    // work and we are not paused.
+    SetupMessageLoopSources();
+    return;
+  }
+
+  // At this point, the transfer was completed in some way (error, connection
+  // closed or download finished).
+
+  GetHttpResponseCode();
+  if (http_response_code_) {
+    LOG(INFO) << "HTTP response code: " << http_response_code_;
+    no_network_retry_count_ = 0;
+  } else {
+    LOG(ERROR) << "Unable to get http response code.";
+  }
+
+  // we're done!
+  CleanUp();
+
+  // TODO(petkov): This temporary code tries to deal with the case where the
+  // update engine performs an update check while the network is not ready
+  // (e.g., right after resume). Longer term, we should check if the network
+  // is online/offline and return an appropriate error code.
+  if (!sent_byte_ &&
+      http_response_code_ == 0 &&
+      no_network_retry_count_ < no_network_max_retries_) {
+    no_network_retry_count_++;
+    MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
+                   base::Unretained(this)),
+        TimeDelta::FromSeconds(kNoNetworkRetrySeconds));
+    LOG(INFO) << "No HTTP response, retry " << no_network_retry_count_;
+  } else if ((!sent_byte_ && !IsHttpResponseSuccess()) ||
+             IsHttpResponseError()) {
+    // The transfer completed w/ error and we didn't get any bytes.
+    // If we have another proxy to try, try that.
+    //
+    // TODO(garnold) in fact there are two separate cases here: one case is an
+    // other-than-success return code (including no return code) and no
+    // received bytes, which is necessary due to the way callbacks are
+    // currently processing error conditions;  the second is an explicit HTTP
+    // error code, where some data may have been received (as in the case of a
+    // semi-successful multi-chunk fetch).  This is a confusing behavior and
+    // should be unified into a complete, coherent interface.
+    LOG(INFO) << "Transfer resulted in an error (" << http_response_code_
+              << "), " << bytes_downloaded_ << " bytes downloaded";
+
+    PopProxy();  // Delete the proxy we just gave up on.
+
+    if (HasProxy()) {
+      // We have another proxy. Retry immediately.
+      LOG(INFO) << "Retrying with next proxy setting";
+      MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
+                     base::Unretained(this)));
     } else {
-      LOG(ERROR) << "Unable to get http response code.";
+      // Out of proxies. Give up.
+      LOG(INFO) << "No further proxies, indicating transfer complete";
+      if (delegate_)
+        delegate_->TransferComplete(this, false);  // signal fail
     }
+  } else if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
+    if (!ignore_failure_)
+      retry_count_++;
+    LOG(INFO) << "Transfer interrupted after downloading "
+              << bytes_downloaded_ << " of " << transfer_size_ << " bytes. "
+              << transfer_size_ - bytes_downloaded_ << " bytes remaining "
+              << "after " << retry_count_ << " attempt(s)";
 
-    // we're done!
-    CleanUp();
-
-    // TODO(petkov): This temporary code tries to deal with the case where the
-    // update engine performs an update check while the network is not ready
-    // (e.g., right after resume). Longer term, we should check if the network
-    // is online/offline and return an appropriate error code.
-    if (!sent_byte_ &&
-        http_response_code_ == 0 &&
-        no_network_retry_count_ < no_network_max_retries_) {
-      no_network_retry_count_++;
+    if (retry_count_ > max_retry_count_) {
+      LOG(INFO) << "Reached max attempts (" << retry_count_ << ")";
+      if (delegate_)
+        delegate_->TransferComplete(this, false);  // signal fail
+    } else {
+      // Need to restart transfer
+      LOG(INFO) << "Restarting transfer to download the remaining bytes";
       MessageLoop::current()->PostDelayedTask(
           FROM_HERE,
           base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
                      base::Unretained(this)),
-          TimeDelta::FromSeconds(kNoNetworkRetrySeconds));
-      LOG(INFO) << "No HTTP response, retry " << no_network_retry_count_;
-      return;
-    }
-
-    if ((!sent_byte_ && !IsHttpResponseSuccess()) || IsHttpResponseError()) {
-      // The transfer completed w/ error and we didn't get any bytes.
-      // If we have another proxy to try, try that.
-      //
-      // TODO(garnold) in fact there are two separate cases here: one case is an
-      // other-than-success return code (including no return code) and no
-      // received bytes, which is necessary due to the way callbacks are
-      // currently processing error conditions;  the second is an explicit HTTP
-      // error code, where some data may have been received (as in the case of a
-      // semi-successful multi-chunk fetch).  This is a confusing behavior and
-      // should be unified into a complete, coherent interface.
-      LOG(INFO) << "Transfer resulted in an error (" << http_response_code_
-                << "), " << bytes_downloaded_ << " bytes downloaded";
-
-      PopProxy();  // Delete the proxy we just gave up on.
-
-      if (HasProxy()) {
-        // We have another proxy. Retry immediately.
-        LOG(INFO) << "Retrying with next proxy setting";
-        MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
-                       base::Unretained(this)));
-      } else {
-        // Out of proxies. Give up.
-        LOG(INFO) << "No further proxies, indicating transfer complete";
-        if (delegate_)
-          delegate_->TransferComplete(this, false);  // signal fail
-      }
-    } else if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
-      retry_count_++;
-      LOG(INFO) << "Transfer interrupted after downloading "
-                << bytes_downloaded_ << " of " << transfer_size_ << " bytes. "
-                << transfer_size_ - bytes_downloaded_ << " bytes remaining "
-                << "after " << retry_count_ << " attempt(s)";
-
-      if (retry_count_ > max_retry_count_) {
-        LOG(INFO) << "Reached max attempts (" << retry_count_ << ")";
-        if (delegate_)
-          delegate_->TransferComplete(this, false);  // signal fail
-      } else {
-        // Need to restart transfer
-        LOG(INFO) << "Restarting transfer to download the remaining bytes";
-        MessageLoop::current()->PostDelayedTask(
-            FROM_HERE,
-            base::Bind(&LibcurlHttpFetcher::RetryTimeoutCallback,
-                       base::Unretained(this)),
-            TimeDelta::FromSeconds(retry_seconds_));
-      }
-    } else {
-      LOG(INFO) << "Transfer completed (" << http_response_code_
-                << "), " << bytes_downloaded_ << " bytes downloaded";
-      if (delegate_) {
-        bool success = IsHttpResponseSuccess();
-        delegate_->TransferComplete(this, success);
-      }
+          TimeDelta::FromSeconds(retry_seconds_));
     }
   } else {
-    // set up callback
-    SetupMessageLoopSources();
+    LOG(INFO) << "Transfer completed (" << http_response_code_
+              << "), " << bytes_downloaded_ << " bytes downloaded";
+    if (delegate_) {
+      bool success = IsHttpResponseSuccess();
+      delegate_->TransferComplete(this, success);
+    }
   }
+  ignore_failure_ = false;
 }
 
 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
@@ -449,15 +470,43 @@
 }
 
 void LibcurlHttpFetcher::Pause() {
+  if (transfer_paused_) {
+    LOG(ERROR) << "Fetcher already paused.";
+    return;
+  }
+  transfer_paused_ = true;
+  if (!transfer_in_progress_) {
+    // If pause before we started a connection, we don't need to notify curl
+    // about that, we will simply not start the connection later.
+    return;
+  }
   CHECK(curl_handle_);
-  CHECK(transfer_in_progress_);
   CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_ALL), CURLE_OK);
 }
 
 void LibcurlHttpFetcher::Unpause() {
+  if (!transfer_paused_) {
+    LOG(ERROR) << "Resume attempted when fetcher not paused.";
+    return;
+  }
+  transfer_paused_ = false;
+  if (restart_transfer_on_unpause_) {
+    restart_transfer_on_unpause_ = false;
+    ResumeTransfer(url_);
+    CurlPerformOnce();
+    return;
+  }
+  if (!transfer_in_progress_) {
+    // If resumed before starting the connection, there's no need to notify
+    // anybody. We will simply start the connection once it is time.
+    return;
+  }
   CHECK(curl_handle_);
-  CHECK(transfer_in_progress_);
   CHECK_EQ(curl_easy_pause(curl_handle_, CURLPAUSE_CONT), CURLE_OK);
+  // Since the transfer is in progress, we need to dispatch a CurlPerformOnce()
+  // now to let the connection continue, otherwise it would be called by the
+  // TimeoutCallback but with a delay.
+  CurlPerformOnce();
 }
 
 // This method sets up callbacks with the MessageLoop.
@@ -537,7 +586,7 @@
 
   // Set up a timeout callback for libcurl.
   if (timeout_id_ == MessageLoop::kTaskIdNull) {
-    LOG(INFO) << "Setting up timeout source: " << idle_seconds_ << " seconds.";
+    VLOG(1) << "Setting up timeout source: " << idle_seconds_ << " seconds.";
     timeout_id_ = MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&LibcurlHttpFetcher::TimeoutCallback,
@@ -547,6 +596,10 @@
 }
 
 void LibcurlHttpFetcher::RetryTimeoutCallback() {
+  if (transfer_paused_) {
+    restart_transfer_on_unpause_ = true;
+    return;
+  }
   ResumeTransfer(url_);
   CurlPerformOnce();
 }
@@ -599,6 +652,8 @@
     curl_multi_handle_ = nullptr;
   }
   transfer_in_progress_ = false;
+  transfer_paused_ = false;
+  restart_transfer_on_unpause_ = false;
 }
 
 void LibcurlHttpFetcher::GetHttpResponseCode() {
diff --git a/common/libcurl_http_fetcher.h b/common/libcurl_http_fetcher.h
index 66dbb18..218e6cb 100644
--- a/common/libcurl_http_fetcher.h
+++ b/common/libcurl_http_fetcher.h
@@ -132,9 +132,9 @@
   // Calls into curl_multi_perform to let libcurl do its work. Returns after
   // curl_multi_perform is finished, which may actually be after more than
   // one call to curl_multi_perform. This method will set up the message
-  // loop with sources for future work that libcurl will do.
+  // loop with sources for future work that libcurl will do, if any, or complete
+  // the transfer and finish the action if no work left to do.
   // This method will not block.
-  // Returns true if we should resume immediately after this call.
   void CurlPerformOnce();
 
   // Sets up message loop sources as needed by libcurl. This is generally
@@ -192,6 +192,16 @@
   brillo::MessageLoop::TaskId timeout_id_{brillo::MessageLoop::kTaskIdNull};
 
   bool transfer_in_progress_{false};
+  bool transfer_paused_{false};
+
+  // Whether it should ignore transfer failures for the purpose of retrying the
+  // connection.
+  bool ignore_failure_{false};
+
+  // Whether we should restart the transfer once Unpause() is called. This can
+  // be caused because either the connection dropped while pause or the proxy
+  // was resolved and we never started the transfer in the first place.
+  bool restart_transfer_on_unpause_{false};
 
   // The transfer size. -1 if not known.
   off_t transfer_size_{0};
diff --git a/mock_action.h b/common/mock_action.h
similarity index 74%
rename from mock_action.h
rename to common/mock_action.h
index 0ba796d..06acad1 100644
--- a/mock_action.h
+++ b/common/mock_action.h
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-#ifndef UPDATE_ENGINE_MOCK_ACTION_H_
-#define UPDATE_ENGINE_MOCK_ACTION_H_
+#ifndef UPDATE_ENGINE_COMMON_MOCK_ACTION_H_
+#define UPDATE_ENGINE_COMMON_MOCK_ACTION_H_
 
 #include <string>
 
@@ -27,7 +27,7 @@
 
 class MockAction;
 
-template<>
+template <>
 class ActionTraits<MockAction> {
  public:
   typedef NoneType OutputObjectType;
@@ -36,10 +36,17 @@
 
 class MockAction : public Action<MockAction> {
  public:
+  MockAction() {
+    ON_CALL(*this, Type()).WillByDefault(testing::Return("MockAction"));
+  }
+
   MOCK_METHOD0(PerformAction, void());
+  MOCK_METHOD0(TerminateProcessing, void());
+  MOCK_METHOD0(SuspendAction, void());
+  MOCK_METHOD0(ResumeAction, void());
   MOCK_CONST_METHOD0(Type, std::string());
 };
 
 }  // namespace chromeos_update_engine
 
-#endif  // UPDATE_ENGINE_MOCK_ACTION_H_
+#endif  // UPDATE_ENGINE_COMMON_MOCK_ACTION_H_
diff --git a/mock_action_processor.h b/common/mock_action_processor.h
similarity index 84%
rename from mock_action_processor.h
rename to common/mock_action_processor.h
index c98ff3c..04275c1 100644
--- a/mock_action_processor.h
+++ b/common/mock_action_processor.h
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-#ifndef UPDATE_ENGINE_MOCK_ACTION_PROCESSOR_H_
-#define UPDATE_ENGINE_MOCK_ACTION_PROCESSOR_H_
+#ifndef UPDATE_ENGINE_COMMON_MOCK_ACTION_PROCESSOR_H_
+#define UPDATE_ENGINE_COMMON_MOCK_ACTION_PROCESSOR_H_
 
 #include <gmock/gmock.h>
 
@@ -31,4 +31,4 @@
 
 }  // namespace chromeos_update_engine
 
-#endif  // UPDATE_ENGINE_MOCK_ACTION_PROCESSOR_H_
+#endif  // UPDATE_ENGINE_COMMON_MOCK_ACTION_PROCESSOR_H_
diff --git a/common/platform_constants.h b/common/platform_constants.h
index d1786ff..6eaa940 100644
--- a/common/platform_constants.h
+++ b/common/platform_constants.h
@@ -50,6 +50,10 @@
 // The stateful directory used by update_engine.
 extern const char kNonVolatileDirectory[];
 
+// Options passed to the filesystem when mounting the new partition during
+// postinstall.
+extern const char kPostinstallMountOptions[];
+
 }  // namespace constants
 }  // namespace chromeos_update_engine
 
diff --git a/common/platform_constants_android.cc b/common/platform_constants_android.cc
index 4f55106..371fe26 100644
--- a/common/platform_constants_android.cc
+++ b/common/platform_constants_android.cc
@@ -31,6 +31,8 @@
 // No deadline file API support on Android.
 const char kOmahaResponseDeadlineFile[] = "";
 const char kNonVolatileDirectory[] = "/data/misc/update_engine";
+const char kPostinstallMountOptions[] =
+  "context=u:object_r:postinstall_file:s0";
 
 }  // namespace constants
 }  // namespace chromeos_update_engine
diff --git a/common/platform_constants_chromeos.cc b/common/platform_constants_chromeos.cc
index d8587ca..7c1d627 100644
--- a/common/platform_constants_chromeos.cc
+++ b/common/platform_constants_chromeos.cc
@@ -32,6 +32,7 @@
     "/tmp/update-check-response-deadline";
 // This directory is wiped during powerwash.
 const char kNonVolatileDirectory[] = "/var/lib/update_engine";
+const char kPostinstallMountOptions[] = nullptr;
 
 }  // namespace constants
 }  // namespace chromeos_update_engine
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index 967c411..d94623a 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -144,18 +144,18 @@
 
 TEST_F(PrefsTest, GetInt64Max) {
   ASSERT_TRUE(SetValue(kKey, base::StringPrintf(
-      "%" PRIi64, std::numeric_limits<uint64_t>::max())));
+      "%" PRIi64, std::numeric_limits<int64_t>::max())));
   int64_t value;
   EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
-  EXPECT_EQ(std::numeric_limits<uint64_t>::max(), value);
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
 }
 
 TEST_F(PrefsTest, GetInt64Min) {
   ASSERT_TRUE(SetValue(kKey, base::StringPrintf(
-        "%" PRIi64, std::numeric_limits<uint64_t>::min())));
+        "%" PRIi64, std::numeric_limits<int64_t>::min())));
   int64_t value;
   EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
-  EXPECT_EQ(std::numeric_limits<uint64_t>::min(), value);
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
 }
 
 TEST_F(PrefsTest, GetInt64Negative) {
diff --git a/common/subprocess_unittest.cc b/common/subprocess_unittest.cc
index b37dc91..c6cbab0 100644
--- a/common/subprocess_unittest.cc
+++ b/common/subprocess_unittest.cc
@@ -17,11 +17,7 @@
 #include "update_engine/common/subprocess.h"
 
 #include <fcntl.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
 #include <poll.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -30,6 +26,7 @@
 #include <vector>
 
 #include <base/bind.h>
+#include <base/files/scoped_temp_dir.h>
 #include <base/location.h>
 #include <base/message_loop/message_loop.h>
 #include <base/strings/string_util.h>
@@ -50,6 +47,18 @@
 using std::string;
 using std::vector;
 
+namespace {
+
+#ifdef __ANDROID__
+#define kBinPath "/system/bin"
+#define kUsrBinPath "/system/bin"
+#else
+#define kBinPath "/bin"
+#define kUsrBinPath "/usr/bin"
+#endif  // __ANDROID__
+
+}  // namespace
+
 namespace chromeos_update_engine {
 
 class SubprocessTest : public ::testing::Test {
@@ -68,8 +77,6 @@
 
 namespace {
 
-int local_server_port = 0;
-
 void ExpectedResults(int expected_return_code, const string& expected_output,
                      int return_code, const string& output) {
   EXPECT_EQ(expected_return_code, return_code);
@@ -102,28 +109,29 @@
 }
 
 TEST_F(SubprocessTest, SimpleTest) {
-  EXPECT_TRUE(subprocess_.Exec({"/bin/false"},
+  EXPECT_TRUE(subprocess_.Exec({kBinPath "/false"},
                                base::Bind(&ExpectedResults, 1, "")));
   loop_.Run();
 }
 
 TEST_F(SubprocessTest, EchoTest) {
   EXPECT_TRUE(subprocess_.Exec(
-      {"/bin/sh", "-c", "echo this is stdout; echo this is stderr >&2"},
+      {kBinPath "/sh", "-c", "echo this is stdout; echo this is stderr >&2"},
       base::Bind(&ExpectedResults, 0, "this is stdout\nthis is stderr\n")));
   loop_.Run();
 }
 
 TEST_F(SubprocessTest, StderrNotIncludedInOutputTest) {
   EXPECT_TRUE(subprocess_.ExecFlags(
-      {"/bin/sh", "-c", "echo on stdout; echo on stderr >&2"},
+      {kBinPath "/sh", "-c", "echo on stdout; echo on stderr >&2"},
       0,
       base::Bind(&ExpectedResults, 0, "on stdout\n")));
   loop_.Run();
 }
 
 TEST_F(SubprocessTest, EnvVarsAreFiltered) {
-  EXPECT_TRUE(subprocess_.Exec({"/usr/bin/env"}, base::Bind(&ExpectedEnvVars)));
+  EXPECT_TRUE(
+      subprocess_.Exec({kUsrBinPath "/env"}, base::Bind(&ExpectedEnvVars)));
   loop_.Run();
 }
 
@@ -136,9 +144,9 @@
 
 TEST_F(SubprocessTest, SynchronousEchoTest) {
   vector<string> cmd = {
-    "/bin/sh",
-    "-c",
-    "echo -n stdout-here; echo -n stderr-there > /dev/stderr"};
+      kBinPath "/sh",
+      "-c",
+      "echo -n stdout-here; echo -n stderr-there >&2"};
   int rc = -1;
   string stdout;
   ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
@@ -149,8 +157,7 @@
 TEST_F(SubprocessTest, SynchronousEchoNoOutputTest) {
   int rc = -1;
   ASSERT_TRUE(Subprocess::SynchronousExec(
-      {"/bin/sh", "-c", "echo test"},
-      &rc, nullptr));
+      {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr));
   EXPECT_EQ(0, rc);
 }
 
@@ -158,106 +165,55 @@
 void CallbackBad(int return_code, const string& output) {
   ADD_FAILURE() << "should never be called.";
 }
-
-// TODO(garnold) this test method uses test_http_server as a representative for
-// interactive processes that can be spawned/terminated at will. This causes us
-// to go through hoops when spawning this process (e.g. obtaining the port
-// number it uses so we can control it with wget). It would have been much
-// preferred to use something else and thus simplify both test_http_server
-// (doesn't have to be able to communicate through a temp file) and the test
-// code below; for example, it sounds like a brain dead sleep loop with proper
-// signal handlers could be used instead.
-void StartAndCancelInRunLoop(bool* spawned) {
-  // Create a temp file for test_http_server to communicate its port number.
-  char temp_file_name[] = "/tmp/subprocess_unittest-test_http_server-XXXXXX";
-  int temp_fd = mkstemp(temp_file_name);
-  CHECK_GE(temp_fd, 0);
-  int temp_flags = fcntl(temp_fd, F_GETFL, 0) | O_NONBLOCK;
-  CHECK_EQ(fcntl(temp_fd, F_SETFL, temp_flags), 0);
-
-  vector<string> cmd;
-  cmd.push_back("./test_http_server");
-  cmd.push_back(temp_file_name);
-  uint32_t tag = Subprocess::Get().Exec(cmd, base::Bind(&CallbackBad));
-  EXPECT_NE(0, tag);
-  *spawned = true;
-  printf("test http server spawned\n");
-  // Wait for server to be up and running
-  TimeDelta total_wait_time;
-  const TimeDelta kSleepTime = TimeDelta::FromMilliseconds(100);
-  const TimeDelta kMaxWaitTime = TimeDelta::FromSeconds(3);
-  local_server_port = 0;
-  static const char* kServerListeningMsgPrefix = "listening on port ";
-  while (total_wait_time.InMicroseconds() < kMaxWaitTime.InMicroseconds()) {
-    char line[80];
-    int line_len = read(temp_fd, line, sizeof(line) - 1);
-    if (line_len > 0) {
-      line[line_len] = '\0';
-      CHECK_EQ(strstr(line, kServerListeningMsgPrefix), line);
-      const char* listening_port_str =
-          line + strlen(kServerListeningMsgPrefix);
-      char* end_ptr;
-      long raw_port = strtol(listening_port_str,  // NOLINT(runtime/int)
-                             &end_ptr, 10);
-      CHECK(!*end_ptr || *end_ptr == '\n');
-      local_server_port = static_cast<in_port_t>(raw_port);
-      break;
-    } else if (line_len < 0 && errno != EAGAIN) {
-      LOG(INFO) << "error reading from " << temp_file_name << ": "
-                << strerror(errno);
-      break;
-    }
-    usleep(kSleepTime.InMicroseconds());
-    total_wait_time += kSleepTime;
-  }
-  close(temp_fd);
-  remove(temp_file_name);
-  CHECK_GT(local_server_port, 0);
-  LOG(INFO) << "server listening on port " << local_server_port;
-  Subprocess::Get().KillExec(tag);
-}
-
-void ExitWhenDone(bool* spawned) {
-  if (*spawned && !Subprocess::Get().SubprocessInFlight()) {
-    // tear down the sub process
-    printf("tear down time\n");
-    int status = test_utils::System(
-        base::StringPrintf("wget -O /dev/null http://127.0.0.1:%d/quitquitquit",
-                           local_server_port));
-    EXPECT_NE(-1, status) << "system() failed";
-    EXPECT_TRUE(WIFEXITED(status))
-        << "command failed to run or died abnormally";
-    MessageLoop::current()->BreakLoop();
-  } else {
-    // Re-run this callback again in 10 ms.
-    MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&ExitWhenDone, spawned),
-        TimeDelta::FromMilliseconds(10));
-  }
-}
-
 }  // namespace
 
+// Test that you can cancel a program that's already running.
 TEST_F(SubprocessTest, CancelTest) {
-  bool spawned = false;
-  loop_.PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&StartAndCancelInRunLoop, &spawned),
-      TimeDelta::FromMilliseconds(100));
-  loop_.PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&ExitWhenDone, &spawned),
-      TimeDelta::FromMilliseconds(10));
-  loop_.Run();
+  base::ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+  string fifo_path = tempdir.path().Append("fifo").value();
+  EXPECT_EQ(0, mkfifo(fifo_path.c_str(), 0666));
+
+  // Start a process, make sure it is running and try to cancel it. We write
+  // two bytes to the fifo, the first one marks that the program is running and
+  // the second one marks that the process waited for a timeout and was not
+  // killed. We should read the first byte but not the second one.
+  vector<string> cmd = {
+      kBinPath "/sh",
+      "-c",
+      base::StringPrintf(
+          "echo -n  X >\"%s\"; sleep 60; echo -n  Y >\"%s\"; exit 1",
+          fifo_path.c_str(),
+          fifo_path.c_str())};
+  uint32_t tag = Subprocess::Get().Exec(cmd, base::Bind(&CallbackBad));
+  EXPECT_NE(0U, tag);
+
+  int fifo_fd = HANDLE_EINTR(open(fifo_path.c_str(), O_RDONLY));
+  EXPECT_GE(fifo_fd, 0);
+
+  loop_.WatchFileDescriptor(FROM_HERE,
+                            fifo_fd,
+                            MessageLoop::WatchMode::kWatchRead,
+                            false,
+                            base::Bind([fifo_fd, tag] {
+                              char c;
+                              EXPECT_EQ(1, HANDLE_EINTR(read(fifo_fd, &c, 1)));
+                              EXPECT_EQ('X', c);
+                              LOG(INFO) << "Killing tag " << tag;
+                              Subprocess::Get().KillExec(tag);
+                            }));
+
   // This test would leak a callback that runs when the child process exits
   // unless we wait for it to run.
   brillo::MessageLoopRunUntil(
       &loop_,
-      TimeDelta::FromSeconds(10),
-      base::Bind([] {
-        return Subprocess::Get().subprocess_records_.empty();
-      }));
+      TimeDelta::FromSeconds(120),
+      base::Bind([] { return Subprocess::Get().subprocess_records_.empty(); }));
+  EXPECT_TRUE(Subprocess::Get().subprocess_records_.empty());
+  // Check that there isn't anything else to read from the pipe.
+  char c;
+  EXPECT_EQ(0, HANDLE_EINTR(read(fifo_fd, &c, 1)));
+  IGNORE_EINTR(close(fifo_fd));
 }
 
 }  // namespace chromeos_update_engine
diff --git a/common/test_utils.cc b/common/test_utils.cc
index c09096b..77a9141 100644
--- a/common/test_utils.cc
+++ b/common/test_utils.cc
@@ -260,7 +260,7 @@
   string loop_dev;
   loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
 
-  EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
+  EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags, "", nullptr));
   unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
 }
 
diff --git a/common/test_utils.h b/common/test_utils.h
index b5151f2..7be027a 100644
--- a/common/test_utils.h
+++ b/common/test_utils.h
@@ -162,13 +162,15 @@
 
 class ScopedTempFile {
  public:
-  ScopedTempFile() {
-    EXPECT_TRUE(utils::MakeTempFile("update_engine_test_temp_file.XXXXXX",
-                                    &path_,
-                                    nullptr));
+  ScopedTempFile() : ScopedTempFile("update_engine_test_temp_file.XXXXXX") {}
+
+  explicit ScopedTempFile(const std::string& pattern) {
+    EXPECT_TRUE(utils::MakeTempFile(pattern, &path_, nullptr));
     unlinker_.reset(new ScopedPathUnlinker(path_));
   }
-  const std::string& GetPath() { return path_; }
+
+  const std::string& path() { return path_; }
+
  private:
   std::string path_;
   std::unique_ptr<ScopedPathUnlinker> unlinker_;
diff --git a/common/utils.cc b/common/utils.cc
index 91dcfc8..912bc96 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -613,19 +613,27 @@
 
 bool MountFilesystem(const string& device,
                      const string& mountpoint,
-                     unsigned long mountflags) {  // NOLINT(runtime/int)
-  // TODO(sosa): Remove "ext3" once crbug.com/208022 is resolved.
-  const vector<const char*> fstypes{"ext2", "ext3", "ext4", "squashfs"};
+                     unsigned long mountflags,  // NOLINT(runtime/int)
+                     const string& type,
+                     const string& fs_mount_options) {
+  vector<const char*> fstypes;
+  if (type.empty()) {
+    fstypes = {"ext2", "ext3", "ext4", "squashfs"};
+  } else {
+    fstypes = {type.c_str()};
+  }
   for (const char* fstype : fstypes) {
     int rc = mount(device.c_str(), mountpoint.c_str(), fstype, mountflags,
-                   nullptr);
+                   fs_mount_options.c_str());
     if (rc == 0)
       return true;
 
     PLOG(WARNING) << "Unable to mount destination device " << device
                   << " on " << mountpoint << " as " << fstype;
   }
-  LOG(ERROR) << "Unable to mount " << device << " with any supported type";
+  if (!type.empty()) {
+    LOG(ERROR) << "Unable to mount " << device << " with any supported type";
+  }
   return false;
 }
 
diff --git a/common/utils.h b/common/utils.h
index 5bf1422..df06ef1 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -171,10 +171,14 @@
 std::string MakePartitionNameForMount(const std::string& part_name);
 
 // Synchronously mount or unmount a filesystem. Return true on success.
-// When mounting, it will attempt to mount the the device as "ext3", "ext2" and
-// "squashfs", with the passed |flags| options.
-bool MountFilesystem(const std::string& device, const std::string& mountpoint,
-                     unsigned long flags);  // NOLINT(runtime/int)
+// When mounting, it will attempt to mount the device as the passed filesystem
+// type |type|, with the passed |flags| options. If |type| is empty, "ext2",
+// "ext3", "ext4" and "squashfs" will be tried.
+bool MountFilesystem(const std::string& device,
+                     const std::string& mountpoint,
+                     unsigned long flags,  // NOLINT(runtime/int)
+                     const std::string& type,
+                     const std::string& fs_mount_options);
 bool UnmountFilesystem(const std::string& mountpoint);
 
 // Returns the block count and the block byte size of the file system on
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index fde89e8..f840a75 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -181,11 +181,11 @@
 }
 
 TEST(UtilsTest, FuzzIntTest) {
-  static const unsigned int kRanges[] = { 0, 1, 2, 20 };
-  for (unsigned int range : kRanges) {
+  static const uint32_t kRanges[] = { 0, 1, 2, 20 };
+  for (uint32_t range : kRanges) {
     const int kValue = 50;
     for (int tries = 0; tries < 100; ++tries) {
-      int value = utils::FuzzInt(kValue, range);
+      uint32_t value = utils::FuzzInt(kValue, range);
       EXPECT_GE(value, kValue - range / 2);
       EXPECT_LE(value, kValue + range - range / 2);
     }
@@ -280,10 +280,10 @@
 void GetFileFormatTester(const string& expected,
                          const vector<uint8_t>& contents) {
   test_utils::ScopedTempFile file;
-  ASSERT_TRUE(utils::WriteFile(file.GetPath().c_str(),
+  ASSERT_TRUE(utils::WriteFile(file.path().c_str(),
                                reinterpret_cast<const char*>(contents.data()),
                                contents.size()));
-  EXPECT_EQ(expected, utils::GetFileFormat(file.GetPath()));
+  EXPECT_EQ(expected, utils::GetFileFormat(file.path()));
 }
 }  // namespace
 
@@ -413,7 +413,8 @@
   string contents;
   EXPECT_TRUE(utils::ReadFile(path.value(), &contents));
   EXPECT_EQ(contents, expected_contents);
-  EXPECT_EQ(utils::FileSize(path.value()), expected_contents.size());
+  EXPECT_EQ(static_cast<off_t>(expected_contents.size()),
+            utils::FileSize(path.value()));
 }
 
 TEST(UtilsTest, ConvertToOmahaInstallDate) {
@@ -493,7 +494,7 @@
 
   EXPECT_TRUE(store.LoadFromString("PAYLOAD_MINOR_VERSION=123\n"));
   EXPECT_TRUE(utils::GetMinorVersion(store, &minor_version));
-  EXPECT_EQ(minor_version, 123);
+  EXPECT_EQ(123U, minor_version);
 }
 
 static bool BoolMacroTestHelper() {
diff --git a/common_service.cc b/common_service.cc
index 3c77c93..f0b818f 100644
--- a/common_service.cc
+++ b/common_service.cc
@@ -35,6 +35,7 @@
 #include "update_engine/omaha_request_params.h"
 #include "update_engine/p2p_manager.h"
 #include "update_engine/update_attempter.h"
+#include "update_engine/payload_state_interface.h"
 
 using base::StringPrintf;
 using brillo::ErrorPtr;
@@ -318,4 +319,10 @@
   return true;
 }
 
+bool UpdateEngineService::GetLastAttemptError(ErrorPtr* /* error */,
+                                              int32_t* out_last_attempt_error) {
+  ErrorCode error_code = system_state_->payload_state()->GetAttemptErrorCode();
+  *out_last_attempt_error = static_cast<int>(error_code);
+  return true;
+}
 }  // namespace chromeos_update_engine
diff --git a/common_service.h b/common_service.h
index e08b4fd..4ad8862 100644
--- a/common_service.h
+++ b/common_service.h
@@ -127,6 +127,10 @@
   bool GetRollbackPartition(brillo::ErrorPtr* error,
                             std::string* out_rollback_partition_name);
 
+  // Returns the last UpdateAttempt error.
+  bool GetLastAttemptError(brillo::ErrorPtr* error,
+                           int32_t* out_last_attempt_error);
+
  private:
   SystemState* system_state_;
 };
diff --git a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml b/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
index bc4ec36..02287de 100644
--- a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
+++ b/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
@@ -80,5 +80,8 @@
     <method name="GetRollbackPartition">
       <arg type="s" name="rollback_partition_name" direction="out" />
     </method>
+    <method name="GetLastAttemptError">
+      <arg type="i" name="last_attempt_error" direction="out" />
+    </method>
   </interface>
 </node>
diff --git a/dbus_service.cc b/dbus_service.cc
index 0ab0ac0..392555f 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -132,6 +132,11 @@
   return common_->GetRollbackPartition(error, out_rollback_partition_name);
 }
 
+bool DBusUpdateEngineService::GetLastAttemptError(
+    ErrorPtr* error, int32_t* out_last_attempt_error){
+ return common_->GetLastAttemptError(error, out_last_attempt_error);
+}
+
 UpdateEngineAdaptor::UpdateEngineAdaptor(SystemState* system_state,
                                          const scoped_refptr<dbus::Bus>& bus)
     : org::chromium::UpdateEngineInterfaceAdaptor(&dbus_service_),
diff --git a/dbus_service.h b/dbus_service.h
index b0c68e5..1486e3c 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -129,6 +129,10 @@
   bool GetRollbackPartition(brillo::ErrorPtr* error,
                             std::string* out_rollback_partition_name) override;
 
+  // Returns the last UpdateAttempt error. If not updated yet, default success
+  // ErrorCode will be returned.
+  bool GetLastAttemptError(brillo::ErrorPtr* error,
+                           int32_t* out_last_attempt_error) override;
  private:
   std::unique_ptr<UpdateEngineService> common_;
 };
diff --git a/include/debugd/dbus-constants.h b/include/debugd/dbus-constants.h
deleted file mode 100644
index 3427a99..0000000
--- a/include/debugd/dbus-constants.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SYSTEM_API_DBUS_DEBUGD_DBUS_CONSTANTS_H_
-#define SYSTEM_API_DBUS_DEBUGD_DBUS_CONSTANTS_H_
-
-namespace debugd {
-const char kDebugdInterface[] = "org.chromium.debugd";
-const char kDebugdServicePath[] = "/org/chromium/debugd";
-const char kDebugdServiceName[] = "org.chromium.debugd";
-
-// Methods.
-const char kDumpDebugLogs[] = "DumpDebugLogs";
-const char kGetDebugLogs[] = "GetDebugLogs";
-const char kGetInterfaces[] = "GetInterfaces";
-const char kGetModemStatus[] = "GetModemStatus";
-const char kGetNetworkStatus[] = "GetNetworkStatus";
-const char kGetPerfOutput[] = "GetPerfOutput";
-const char kGetRandomPerfOutput[] = "GetRandomPerfOutput";
-const char kGetRichPerfData[] = "GetRichPerfData";
-const char kGetRoutes[] = "GetRoutes";
-const char kGetWiMaxStatus[] = "GetWiMaxStatus";
-const char kSetDebugMode[] = "SetDebugMode";
-const char kSystraceStart[] = "SystraceStart";
-const char kSystraceStop[] = "SystraceStop";
-const char kSystraceStatus[] = "SystraceStatus";
-const char kGetLog[] = "GetLog";
-const char kGetAllLogs[] = "GetAllLogs";
-const char kGetUserLogFiles[] = "GetUserLogFiles";
-const char kGetFeedbackLogs[] = "GetFeedbackLogs";
-const char kTestICMP[] = "TestICMP";
-const char kTestICMPWithOptions[] = "TestICMPWithOptions";
-const char kLogKernelTaskStates[] = "LogKernelTaskStates";
-const char kUploadCrashes[] = "UploadCrashes";
-const char kRemoveRootfsVerification[] = "RemoveRootfsVerification";
-const char kEnableChromeRemoteDebugging[] = "EnableChromeRemoteDebugging";
-const char kEnableBootFromUsb[] = "EnableBootFromUsb";
-const char kConfigureSshServer[] = "ConfigureSshServer";
-const char kSetUserPassword[] = "SetUserPassword";
-const char kEnableChromeDevFeatures[] = "EnableChromeDevFeatures";
-const char kQueryDevFeatures[] = "QueryDevFeatures";
-
-// Values.
-enum DevFeatureFlag {
-  DEV_FEATURES_DISABLED = 1 << 0,
-  DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED = 1 << 1,
-  DEV_FEATURE_BOOT_FROM_USB_ENABLED = 1 << 2,
-  DEV_FEATURE_SSH_SERVER_CONFIGURED = 1 << 3,
-  DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET = 1 << 4,
-  DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET = 1 << 5,
-  DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED = 1 << 6,
-};
-}  // namespace debugd
-
-#endif  // SYSTEM_API_DBUS_DEBUGD_DBUS_CONSTANTS_H_
diff --git a/include/libcros/dbus-proxy-mocks.h b/include/libcros/dbus-proxy-mocks.h
new file mode 100644
index 0000000..97f614f
--- /dev/null
+++ b/include/libcros/dbus-proxy-mocks.h
@@ -0,0 +1,69 @@
+// Automatic generation of D-Bus interface mock proxies for:
+//  - org.chromium.LibCrosServiceInterface
+//  - org.chromium.UpdateEngineLibcrosProxyResolvedInterface
+#ifndef ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_LIBCROS_DBUS_PROXY_MOCKS_H
+#define ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_LIBCROS_DBUS_PROXY_MOCKS_H
+#include <string>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <brillo/any.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <gmock/gmock.h>
+
+#include "libcros/dbus-proxies.h"
+
+namespace org {
+namespace chromium {
+
+// Mock object for LibCrosServiceInterfaceProxyInterface.
+class LibCrosServiceInterfaceProxyMock : public LibCrosServiceInterfaceProxyInterface {
+ public:
+  LibCrosServiceInterfaceProxyMock() = default;
+
+  MOCK_METHOD5(ResolveNetworkProxy,
+               bool(const std::string& /*in_source_url*/,
+                    const std::string& /*in_signal_interface*/,
+                    const std::string& /*in_signal_name*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD6(ResolveNetworkProxyAsync,
+               void(const std::string& /*in_source_url*/,
+                    const std::string& /*in_signal_interface*/,
+                    const std::string& /*in_signal_name*/,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LibCrosServiceInterfaceProxyMock);
+};
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+
+// Mock object for UpdateEngineLibcrosProxyResolvedInterfaceProxyInterface.
+class UpdateEngineLibcrosProxyResolvedInterfaceProxyMock : public UpdateEngineLibcrosProxyResolvedInterfaceProxyInterface {
+ public:
+  UpdateEngineLibcrosProxyResolvedInterfaceProxyMock() = default;
+
+  MOCK_METHOD2(RegisterProxyResolvedSignalHandler,
+               void(const base::Callback<void(const std::string&,
+                                              const std::string&,
+                                              const std::string&)>& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UpdateEngineLibcrosProxyResolvedInterfaceProxyMock);
+};
+}  // namespace chromium
+}  // namespace org
+
+#endif  // ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_LIBCROS_DBUS_PROXY_MOCKS_H
diff --git a/include/power_manager/dbus-constants.h b/include/power_manager/dbus-constants.h
deleted file mode 100644
index fa42cb1..0000000
--- a/include/power_manager/dbus-constants.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SYSTEM_API_DBUS_POWER_MANAGER_DBUS_CONSTANTS_H_
-#define SYSTEM_API_DBUS_POWER_MANAGER_DBUS_CONSTANTS_H_
-
-namespace power_manager {
-// powerd
-const char kPowerManagerInterface[] = "org.chromium.PowerManager";
-const char kPowerManagerServicePath[] = "/org/chromium/PowerManager";
-const char kPowerManagerServiceName[] = "org.chromium.PowerManager";
-// Methods exposed by powerd.
-const char kDecreaseScreenBrightnessMethod[] = "DecreaseScreenBrightness";
-const char kIncreaseScreenBrightnessMethod[] = "IncreaseScreenBrightness";
-const char kGetScreenBrightnessPercentMethod[] = "GetScreenBrightnessPercent";
-const char kSetScreenBrightnessPercentMethod[] = "SetScreenBrightnessPercent";
-const char kDecreaseKeyboardBrightnessMethod[] = "DecreaseKeyboardBrightness";
-const char kIncreaseKeyboardBrightnessMethod[] = "IncreaseKeyboardBrightness";
-const char kRequestRestartMethod[] = "RequestRestart";
-const char kRequestShutdownMethod[] = "RequestShutdown";
-const char kRequestSuspendMethod[] = "RequestSuspend";
-const char kGetPowerSupplyPropertiesMethod[] = "GetPowerSupplyProperties";
-const char kHandleUserActivityMethod[] = "HandleUserActivity";
-const char kHandleVideoActivityMethod[] = "HandleVideoActivity";
-const char kSetIsProjectingMethod[] = "SetIsProjecting";
-const char kSetPolicyMethod[] = "SetPolicy";
-const char kSetPowerSourceMethod[] = "SetPowerSource";
-const char kRegisterSuspendDelayMethod[] = "RegisterSuspendDelay";
-const char kUnregisterSuspendDelayMethod[] = "UnregisterSuspendDelay";
-const char kHandleSuspendReadinessMethod[] = "HandleSuspendReadiness";
-const char kRegisterDarkSuspendDelayMethod[] = "RegisterDarkSuspendDelay";
-const char kUnregisterDarkSuspendDelayMethod[] = "UnregisterDarkSuspendDelay";
-const char kHandleDarkSuspendReadinessMethod[] = "HandleDarkSuspendReadiness";
-const char kHandlePowerButtonAcknowledgmentMethod[] =
-    "HandlePowerButtonAcknowledgment";
-const char kRecordDarkResumeWakeReasonMethod[] = "RecordDarkResumeWakeReason";
-// Signals emitted by powerd.
-const char kBrightnessChangedSignal[] = "BrightnessChanged";
-const char kKeyboardBrightnessChangedSignal[] = "KeyboardBrightnessChanged";
-const char kPeripheralBatteryStatusSignal[] = "PeripheralBatteryStatus";
-const char kPowerSupplyPollSignal[] = "PowerSupplyPoll";
-const char kSuspendImminentSignal[] = "SuspendImminent";
-const char kDarkSuspendImminentSignal[] = "DarkSuspendImminent";
-const char kSuspendDoneSignal[] = "SuspendDone";
-const char kInputEventSignal[] = "InputEvent";
-const char kIdleActionImminentSignal[] = "IdleActionImminent";
-const char kIdleActionDeferredSignal[] = "IdleActionDeferred";
-// Values
-const int kBrightnessTransitionGradual = 1;
-const int kBrightnessTransitionInstant = 2;
-enum UserActivityType {
-  USER_ACTIVITY_OTHER = 0,
-  USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS = 1,
-  USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS = 2,
-  USER_ACTIVITY_VOLUME_UP_KEY_PRESS = 3,
-  USER_ACTIVITY_VOLUME_DOWN_KEY_PRESS = 4,
-  USER_ACTIVITY_VOLUME_MUTE_KEY_PRESS = 5,
-};
-enum RequestRestartReason {
-  REQUEST_RESTART_FOR_USER = 0,
-  REQUEST_RESTART_FOR_UPDATE = 1,
-};
-}  // namespace power_manager
-
-#endif  // SYSTEM_API_DBUS_POWER_MANAGER_DBUS_CONSTANTS_H_
diff --git a/include/shill/dbus-proxy-mocks.h b/include/shill/dbus-proxy-mocks.h
new file mode 100644
index 0000000..e5d52f7
--- /dev/null
+++ b/include/shill/dbus-proxy-mocks.h
@@ -0,0 +1,549 @@
+// Automatic generation of D-Bus interface mock proxies for:
+//  - org.chromium.flimflam.Manager
+//  - org.chromium.flimflam.Service
+#ifndef ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_SHILL_DBUS_PROXY_MOCKS_H
+#define ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_SHILL_DBUS_PROXY_MOCKS_H
+#include <string>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <brillo/any.h>
+#include <brillo/errors/error.h>
+#include <brillo/variant_dictionary.h>
+#include <gmock/gmock.h>
+
+#include "shill/dbus-proxies.h"
+
+namespace org {
+namespace chromium {
+namespace flimflam {
+
+// Mock object for ManagerProxyInterface.
+class ManagerProxyMock : public ManagerProxyInterface {
+ public:
+  ManagerProxyMock() = default;
+
+  MOCK_METHOD3(GetProperties,
+               bool(brillo::VariantDictionary*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetPropertiesAsync,
+               void(const base::Callback<void(const brillo::VariantDictionary&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetProperty,
+               bool(const std::string&,
+                    const brillo::Any&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(SetPropertyAsync,
+               void(const std::string&,
+                    const brillo::Any&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetState,
+               bool(std::string*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetStateAsync,
+               void(const base::Callback<void(const std::string&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(CreateProfile,
+               bool(const std::string&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(CreateProfileAsync,
+               void(const std::string&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(RemoveProfile,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(RemoveProfileAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(PushProfile,
+               bool(const std::string&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(PushProfileAsync,
+               void(const std::string&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(InsertUserProfile,
+               bool(const std::string&,
+                    const std::string&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(InsertUserProfileAsync,
+               void(const std::string&,
+                    const std::string&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(PopProfile,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(PopProfileAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(PopAnyProfile,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(PopAnyProfileAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(PopAllUserProfiles,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(PopAllUserProfilesAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(RecheckPortal,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(RecheckPortalAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(RequestScan,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(RequestScanAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(EnableTechnology,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(EnableTechnologyAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(DisableTechnology,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(DisableTechnologyAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetService,
+               bool(const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetServiceAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetWifiService,
+               bool(const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetWifiServiceAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ConfigureService,
+               bool(const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ConfigureServiceAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(ConfigureServiceForProfile,
+               bool(const dbus::ObjectPath&,
+                    const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(ConfigureServiceForProfileAsync,
+               void(const dbus::ObjectPath&,
+                    const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(FindMatchingService,
+               bool(const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(FindMatchingServiceAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetVPNService,
+               bool(const brillo::VariantDictionary&,
+                    dbus::ObjectPath*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(GetVPNServiceAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void(const dbus::ObjectPath&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetDebugLevel,
+               bool(int32_t*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetDebugLevelAsync,
+               void(const base::Callback<void(int32_t)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetDebugLevel,
+               bool(int32_t,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetDebugLevelAsync,
+               void(int32_t,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetServiceOrder,
+               bool(std::string*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetServiceOrderAsync,
+               void(const base::Callback<void(const std::string&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetServiceOrder,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetServiceOrderAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetDebugTags,
+               bool(std::string*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetDebugTagsAsync,
+               void(const base::Callback<void(const std::string&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetDebugTags,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetDebugTagsAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ListDebugTags,
+               bool(std::string*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ListDebugTagsAsync,
+               void(const base::Callback<void(const std::string&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetNetworksForGeolocation,
+               bool(brillo::VariantDictionary*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetNetworksForGeolocationAsync,
+               void(const base::Callback<void(const brillo::VariantDictionary&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD10(VerifyDestination,
+                bool(const std::string& /*in_certificate*/,
+                     const std::string& /*in_public_key*/,
+                     const std::string& /*in_nonce*/,
+                     const std::string& /*in_signed_data*/,
+                     const std::string& /*in_destination_udn*/,
+                     const std::string& /*in_hotspot_ssid*/,
+                     const std::string& /*in_hotspot_bssid*/,
+                     bool*,
+                     brillo::ErrorPtr* /*error*/,
+                     int /*timeout_ms*/));
+  MOCK_METHOD10(VerifyDestinationAsync,
+                void(const std::string& /*in_certificate*/,
+                     const std::string& /*in_public_key*/,
+                     const std::string& /*in_nonce*/,
+                     const std::string& /*in_signed_data*/,
+                     const std::string& /*in_destination_udn*/,
+                     const std::string& /*in_hotspot_ssid*/,
+                     const std::string& /*in_hotspot_bssid*/,
+                     const base::Callback<void(bool)>& /*success_callback*/,
+                     const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                     int /*timeout_ms*/));
+  bool VerifyAndEncryptCredentials(const std::string& /*in_certificate*/,
+                                   const std::string& /*in_public_key*/,
+                                   const std::string& /*in_nonce*/,
+                                   const std::string& /*in_signed_data*/,
+                                   const std::string& /*in_destination_udn*/,
+                                   const std::string& /*in_hotspot_ssid*/,
+                                   const std::string& /*in_hotspot_bssid*/,
+                                   const dbus::ObjectPath& /*in_network*/,
+                                   std::string*,
+                                   brillo::ErrorPtr* /*error*/,
+                                   int /*timeout_ms*/) override {
+    LOG(WARNING) << "VerifyAndEncryptCredentials(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+    return false;
+  }
+  void VerifyAndEncryptCredentialsAsync(const std::string& /*in_certificate*/,
+                                        const std::string& /*in_public_key*/,
+                                        const std::string& /*in_nonce*/,
+                                        const std::string& /*in_signed_data*/,
+                                        const std::string& /*in_destination_udn*/,
+                                        const std::string& /*in_hotspot_ssid*/,
+                                        const std::string& /*in_hotspot_bssid*/,
+                                        const dbus::ObjectPath& /*in_network*/,
+                                        const base::Callback<void(const std::string&)>& /*success_callback*/,
+                                        const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                                        int /*timeout_ms*/) override {
+    LOG(WARNING) << "VerifyAndEncryptCredentialsAsync(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+  }
+  bool VerifyAndEncryptData(const std::string& /*in_certificate*/,
+                            const std::string& /*in_public_key*/,
+                            const std::string& /*in_nonce*/,
+                            const std::string& /*in_signed_data*/,
+                            const std::string& /*in_destination_udn*/,
+                            const std::string& /*in_hotspot_ssid*/,
+                            const std::string& /*in_hotspot_bssid*/,
+                            const std::string& /*in_data*/,
+                            std::string*,
+                            brillo::ErrorPtr* /*error*/,
+                            int /*timeout_ms*/) override {
+    LOG(WARNING) << "VerifyAndEncryptData(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+    return false;
+  }
+  void VerifyAndEncryptDataAsync(const std::string& /*in_certificate*/,
+                                 const std::string& /*in_public_key*/,
+                                 const std::string& /*in_nonce*/,
+                                 const std::string& /*in_signed_data*/,
+                                 const std::string& /*in_destination_udn*/,
+                                 const std::string& /*in_hotspot_ssid*/,
+                                 const std::string& /*in_hotspot_bssid*/,
+                                 const std::string& /*in_data*/,
+                                 const base::Callback<void(const std::string&)>& /*success_callback*/,
+                                 const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                                 int /*timeout_ms*/) override {
+    LOG(WARNING) << "VerifyAndEncryptDataAsync(): gmock can't handle methods with 11 arguments. You can override this method in a subclass if you need to.";
+  }
+  MOCK_METHOD2(ConnectToBestServices,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ConnectToBestServicesAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(CreateConnectivityReport,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(CreateConnectivityReportAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ClaimInterface,
+               bool(const std::string& /*in_claimer_name*/,
+                    const std::string& /*in_interface_name*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(ClaimInterfaceAsync,
+               void(const std::string& /*in_claimer_name*/,
+                    const std::string& /*in_interface_name*/,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ReleaseInterface,
+               bool(const std::string& /*in_claimer_name*/,
+                    const std::string& /*in_interface_name*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(ReleaseInterfaceAsync,
+               void(const std::string& /*in_claimer_name*/,
+                    const std::string& /*in_interface_name*/,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetSchedScan,
+               bool(bool,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetSchedScanAsync,
+               void(bool,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetupApModeInterface,
+               bool(std::string* /*out_interface_name*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetupApModeInterfaceAsync,
+               void(const base::Callback<void(const std::string& /*interface_name*/)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetupStationModeInterface,
+               bool(std::string* /*out_interface_name*/,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetupStationModeInterfaceAsync,
+               void(const base::Callback<void(const std::string& /*interface_name*/)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(RegisterPropertyChangedSignalHandler,
+               void(const base::Callback<void(const std::string&,
+                                              const brillo::Any&)>& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_METHOD2(RegisterStateChangedSignalHandler,
+               void(const base::Callback<void(const std::string&)>& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ManagerProxyMock);
+};
+}  // namespace flimflam
+}  // namespace chromium
+}  // namespace org
+
+namespace org {
+namespace chromium {
+namespace flimflam {
+
+// Mock object for ServiceProxyInterface.
+class ServiceProxyMock : public ServiceProxyInterface {
+ public:
+  ServiceProxyMock() = default;
+
+  MOCK_METHOD3(GetProperties,
+               bool(brillo::VariantDictionary*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetPropertiesAsync,
+               void(const base::Callback<void(const brillo::VariantDictionary&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetProperty,
+               bool(const std::string&,
+                    const brillo::Any&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD5(SetPropertyAsync,
+               void(const std::string&,
+                    const brillo::Any&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(SetProperties,
+               bool(const brillo::VariantDictionary&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(SetPropertiesAsync,
+               void(const brillo::VariantDictionary&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ClearProperty,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ClearPropertyAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ClearProperties,
+               bool(const std::vector<std::string>&,
+                    std::vector<bool>*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ClearPropertiesAsync,
+               void(const std::vector<std::string>&,
+                    const base::Callback<void(const std::vector<bool>&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(Connect,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ConnectAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(Disconnect,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(DisconnectAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(Remove,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(RemoveAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(ActivateCellularModem,
+               bool(const std::string&,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD4(ActivateCellularModemAsync,
+               void(const std::string&,
+                    const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(CompleteCellularActivation,
+               bool(brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(CompleteCellularActivationAsync,
+               void(const base::Callback<void()>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetLoadableProfileEntries,
+               bool(std::map<dbus::ObjectPath, std::string>*,
+                    brillo::ErrorPtr* /*error*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD3(GetLoadableProfileEntriesAsync,
+               void(const base::Callback<void(const std::map<dbus::ObjectPath, std::string>&)>& /*success_callback*/,
+                    const base::Callback<void(brillo::Error*)>& /*error_callback*/,
+                    int /*timeout_ms*/));
+  MOCK_METHOD2(RegisterPropertyChangedSignalHandler,
+               void(const base::Callback<void(const std::string&,
+                                              const brillo::Any&)>& /*signal_callback*/,
+                    dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));
+  MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ServiceProxyMock);
+};
+}  // namespace flimflam
+}  // namespace chromium
+}  // namespace org
+
+#endif  // ____CHROMEOS_DBUS_BINDING___UPDATE_ENGINE_INCLUDE_SHILL_DBUS_PROXY_MOCKS_H
diff --git a/include/update_engine/dbus-constants.h b/include/update_engine/dbus-constants.h
deleted file mode 100644
index 94e35f1..0000000
--- a/include/update_engine/dbus-constants.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SYSTEM_API_DBUS_UPDATE_ENGINE_DBUS_CONSTANTS_H_
-#define SYSTEM_API_DBUS_UPDATE_ENGINE_DBUS_CONSTANTS_H_
-
-namespace update_engine {
-const char kUpdateEngineInterface[] = "org.chromium.UpdateEngineInterface";
-const char kUpdateEngineServicePath[] = "/org/chromium/UpdateEngine";
-const char kUpdateEngineServiceName[] = "org.chromium.UpdateEngine";
-
-// Generic UpdateEngine D-Bus error.
-static const char* const kUpdateEngineServiceErrorFailed =
-    "org.chromium.UpdateEngine.Error.Failed";
-
-// Methods.
-const char kAttemptUpdate[] = "AttemptUpdate";
-const char kGetStatus[] = "GetStatus";
-const char kRebootIfNeeded[] = "RebootIfNeeded";
-const char kSetChannel[] = "SetChannel";
-const char kGetChannel[] = "GetChannel";
-const char kAttemptRollback[] = "AttemptRollback";
-const char kCanRollback[] = "CanRollback";
-
-// Signals.
-const char kStatusUpdate[] = "StatusUpdate";
-
-// Flags used in the AttemptUpdateWithFlags() D-Bus method.
-typedef enum {
-  kAttemptUpdateFlagNonInteractive = (1<<0)
-} AttemptUpdateFlags;
-
-// Operations contained in StatusUpdate signals.
-const char kUpdateStatusIdle[] = "UPDATE_STATUS_IDLE";
-const char kUpdateStatusCheckingForUpdate[] =
-    "UPDATE_STATUS_CHECKING_FOR_UPDATE";
-const char kUpdateStatusUpdateAvailable[] = "UPDATE_STATUS_UPDATE_AVAILABLE";
-const char kUpdateStatusDownloading[] = "UPDATE_STATUS_DOWNLOADING";
-const char kUpdateStatusVerifying[] = "UPDATE_STATUS_VERIFYING";
-const char kUpdateStatusFinalizing[] = "UPDATE_STATUS_FINALIZING";
-const char kUpdateStatusUpdatedNeedReboot[] =
-    "UPDATE_STATUS_UPDATED_NEED_REBOOT";
-const char kUpdateStatusReportingErrorEvent[] =
-    "UPDATE_STATUS_REPORTING_ERROR_EVENT";
-const char kUpdateStatusAttemptingRollback[] =
-    "UPDATE_STATUS_ATTEMPTING_ROLLBACK";
-const char kUpdateStatusDisabled[] = "UPDATE_STATUS_DISABLED";
-}  // namespace update_engine
-
-#endif  // SYSTEM_API_DBUS_UPDATE_ENGINE_DBUS_CONSTANTS_H_
diff --git a/include/update_includes.sh b/include/update_includes.sh
new file mode 100755
index 0000000..6008d59
--- /dev/null
+++ b/include/update_includes.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+DBUS_GENERATOR=$(which dbus-binding-generator)
+MY_DIR=$(dirname "$0")
+
+if [[ -z "${ANDROID_HOST_OUT}" ]]; then
+  echo "You must run envsetup.sh and lunch first." >&2
+  exit 1
+fi
+
+if [[ -z "${DBUS_GENERATOR}" ]]; then
+  echo "DBus bindings generator not found." >&2
+  exit 1
+fi
+
+set -e
+
+# generate <kind> <dir> <xml> [xml ...]
+# Generate a DBus proxy and/or proxy mock in the passed |dir| for the provided
+# |xml| service files.
+# The parameter |kind| determines whether it should generate the mock only
+# (mock), the proxy only (proxy) or both (both).
+generate() {
+  local kind="$1"
+  local dir="$2"
+  local xmls=("${@:3}")
+
+  mkdir -p "${MY_DIR}/${dir}"
+  local outdir=$(realpath "${MY_DIR}/${dir}")
+  local proxyh="${outdir}/dbus-proxies.h"
+  local mockh="${outdir}/dbus-proxy-mocks.h"
+
+  ${DBUS_GENERATOR} "${xmls[@]}" --mock="${mockh}" --proxy="${proxyh}"
+
+  # Fix the include path to the dbus-proxies.h to include ${dir}.
+  sed "s,include \"dbus-proxies.h\",include \"${dir}/dbus-proxies.h\"," \
+    -i "${mockh}"
+
+  # Fix the header guards to be independent from the checkout location.
+  local guard=$(realpath "${MY_DIR}/../.." | tr '[:lower:]/ ' '[:upper:]__')
+  for header in "${mockh}" "${proxyh}"; do
+    sed "s,___CHROMEOS_DBUS_BINDING__${guard},___CHROMEOS_DBUS_BINDING__," \
+      -i "${header}"
+  done
+
+  # Remove the files not requested.
+  if [[ "${kind}" ==  "mock" ]]; then
+    rm -f "${proxyh}"
+  elif [[ "${kind}" == "proxy" ]]; then
+    rm -f "${mockh}"
+  fi
+}
+
+UE_DIR=$(realpath "${MY_DIR}/..")
+SHILL_DIR=$(realpath "${UE_DIR}/../connectivity/shill")
+
+generate mock "libcros" \
+  "${UE_DIR}/dbus_bindings/org.chromium.LibCrosService.dbus-xml"
+
+generate mock "shill" \
+  "${SHILL_DIR}"/dbus_bindings/org.chromium.flimflam.{Manager,Service}.dbus-xml
+
+echo "Done."
diff --git a/mock_payload_state.h b/mock_payload_state.h
index 728f274..2f654c7 100644
--- a/mock_payload_state.h
+++ b/mock_payload_state.h
@@ -74,6 +74,7 @@
   MOCK_CONST_METHOD0(GetUsingP2PForSharing, bool());
   MOCK_METHOD0(GetScatteringWaitPeriod, base::TimeDelta());
   MOCK_CONST_METHOD0(GetP2PUrl, std::string());
+  MOCK_CONST_METHOD0(GetAttemptErrorCode, ErrorCode());
 };
 
 }  // namespace chromeos_update_engine
diff --git a/mock_proxy_resolver.h b/mock_proxy_resolver.h
new file mode 100644
index 0000000..0595f5a
--- /dev/null
+++ b/mock_proxy_resolver.h
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+#ifndef UPDATE_ENGINE_MOCK_PROXY_RESOLVER_H_
+#define UPDATE_ENGINE_MOCK_PROXY_RESOLVER_H_
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "update_engine/proxy_resolver.h"
+
+namespace chromeos_update_engine {
+
+class MockProxyResolver : public ProxyResolver {
+ public:
+  MOCK_METHOD3(GetProxiesForUrl,
+               bool(const std::string& url,
+                    ProxiesResolvedFn callback,
+                    void* data));
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // UPDATE_ENGINE_MOCK_PROXY_RESOLVER_H_
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 1b0c2fe..bc84c9f 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -1074,18 +1074,23 @@
   // safe-guards). See http://crbug.com/297170 for an example)
   size_t minimum_size = 0;
   int64_t manifest_metadata_size = 0;
+  int64_t manifest_signature_size = 0;
   int64_t next_data_offset = 0;
   int64_t next_data_length = 0;
   if (system_state_ &&
       system_state_->prefs()->GetInt64(kPrefsManifestMetadataSize,
                                        &manifest_metadata_size) &&
       manifest_metadata_size != -1 &&
+      system_state_->prefs()->GetInt64(kPrefsManifestSignatureSize,
+                                       &manifest_signature_size) &&
+      manifest_signature_size != -1 &&
       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataOffset,
                                        &next_data_offset) &&
       next_data_offset != -1 &&
       system_state_->prefs()->GetInt64(kPrefsUpdateStateNextDataLength,
                                        &next_data_length)) {
-    minimum_size = manifest_metadata_size + next_data_offset + next_data_length;
+    minimum_size = manifest_metadata_size + manifest_signature_size +
+                   next_data_offset + next_data_length;
   }
 
   string file_id = utils::CalculateP2PFileId(response.hash, response.size);
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 81a7378..3f455f3 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -1524,7 +1524,7 @@
                       metrics::DownloadErrorCode::kUnset,
                       nullptr,
                       &post_data));
-  EXPECT_EQ(post_data.size(), 0);
+  EXPECT_EQ(0U, post_data.size());
 }
 
 TEST_F(OmahaRequestActionTest, BackInTimePingTest) {
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index b996d38..4917162 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -154,14 +154,15 @@
     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
     EXPECT_EQ(in.hash, install_plan.payload_hash);
-    EXPECT_EQ(1, install_plan.target_slot);
+    EXPECT_EQ(1U, install_plan.target_slot);
     string deadline;
     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
     EXPECT_EQ("20101020", deadline);
     struct stat deadline_stat;
     EXPECT_EQ(0, stat(test_deadline_file.c_str(), &deadline_stat));
-    EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
-              deadline_stat.st_mode);
+    EXPECT_EQ(
+        static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),
+        deadline_stat.st_mode);
     EXPECT_EQ(in.version, install_plan.version);
   }
   {
@@ -179,7 +180,7 @@
     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
     EXPECT_EQ(in.hash, install_plan.payload_hash);
-    EXPECT_EQ(0, install_plan.target_slot);
+    EXPECT_EQ(0U, install_plan.target_slot);
     string deadline;
     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline) &&
                 deadline.empty());
@@ -200,7 +201,7 @@
     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
     EXPECT_EQ(in.hash, install_plan.payload_hash);
-    EXPECT_EQ(1, install_plan.target_slot);
+    EXPECT_EQ(1U, install_plan.target_slot);
     string deadline;
     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
     EXPECT_EQ("some-deadline", deadline);
diff --git a/payload_consumer/bzip_extent_writer_unittest.cc b/payload_consumer/bzip_extent_writer_unittest.cc
index a52a286..8ac3e59 100644
--- a/payload_consumer/bzip_extent_writer_unittest.cc
+++ b/payload_consumer/bzip_extent_writer_unittest.cc
@@ -17,9 +17,6 @@
 #include "update_engine/payload_consumer/bzip_extent_writer.h"
 
 #include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 #include <algorithm>
 #include <string>
@@ -38,28 +35,23 @@
 namespace chromeos_update_engine {
 
 namespace {
-const char kPathTemplate[] = "./BzipExtentWriterTest-file.XXXXXX";
 const uint32_t kBlockSize = 4096;
 }
 
 class BzipExtentWriterTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
     fd_.reset(new EintrSafeFileDescriptor);
-    int fd = mkstemp(path_);
-    ASSERT_TRUE(fd_->Open(path_, O_RDWR, 0600));
-    close(fd);
+    ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
   }
   void TearDown() override {
     fd_->Close();
-    unlink(path_);
   }
   void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
   void TestZeroPad(bool aligned_size);
 
   FileDescriptorPtr fd_;
-  char path_[sizeof(kPathTemplate)];
+  test_utils::ScopedTempFile temp_file_{"BzipExtentWriterTest-file.XXXXXX"};
 };
 
 TEST_F(BzipExtentWriterTest, SimpleTest) {
@@ -85,39 +77,37 @@
   EXPECT_TRUE(bzip_writer.End());
 
   brillo::Blob buf;
-  EXPECT_TRUE(utils::ReadFile(path_, &buf));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &buf));
   EXPECT_EQ(strlen(test_uncompressed), buf.size());
   EXPECT_EQ(string(buf.begin(), buf.end()), string(test_uncompressed));
 }
 
 TEST_F(BzipExtentWriterTest, ChunkedTest) {
-  const brillo::Blob::size_type kDecompressedLength = 2048 * 1024;  // 2 MiB
-  string decompressed_path;
-  ASSERT_TRUE(utils::MakeTempFile("BzipExtentWriterTest-decompressed-XXXXXX",
-                                  &decompressed_path, nullptr));
-  string compressed_path;
-  ASSERT_TRUE(utils::MakeTempFile("BzipExtentWriterTest-compressed-XXXXXX",
-                                  &compressed_path, nullptr));
+  // Generated with:
+  //   yes "ABC" | head -c 819200 | bzip2 -9 |
+  //     hexdump -v -e '"      " 11/1 "0x%02x, " "\n"'
+  static const uint8_t kCompressedData[] = {
+      0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xbe,
+      0x1c, 0xda, 0xee, 0x03, 0x1f, 0xff, 0xc4, 0x00, 0x00, 0x10, 0x38,
+      0x00, 0x20, 0x00, 0x50, 0x66, 0x9a, 0x05, 0x28, 0x38, 0x00, 0x11,
+      0x60, 0x00, 0x22, 0xd0, 0x00, 0x45, 0xc0, 0x00, 0x8b, 0xc5, 0xdc,
+      0x91, 0x4e, 0x14, 0x24, 0x2f, 0x87, 0x36, 0xbb, 0x80};
+  brillo::Blob compressed_data(std::begin(kCompressedData),
+                               std::end(kCompressedData));
+
+  const brillo::Blob::size_type kDecompressedLength = 800 * 1024;  // 800 KiB
   const size_t kChunkSize = 3;
 
+  brillo::Blob decompressed_data(kDecompressedLength);
+  for (size_t i = 0; i < decompressed_data.size(); ++i)
+    decompressed_data[i] = static_cast<uint8_t>("ABC\n"[i % 4]);
+
   vector<Extent> extents;
   Extent extent;
   extent.set_start_block(0);
-  extent.set_num_blocks(kDecompressedLength / kBlockSize + 1);
+  extent.set_num_blocks((kDecompressedLength + kBlockSize - 1) / kBlockSize);
   extents.push_back(extent);
 
-  brillo::Blob decompressed_data(kDecompressedLength);
-  test_utils::FillWithData(&decompressed_data);
-
-  EXPECT_TRUE(test_utils::WriteFileVector(
-      decompressed_path, decompressed_data));
-
-  EXPECT_EQ(0, test_utils::System(
-      string("cat ") + decompressed_path + "|bzip2>" + compressed_path));
-
-  brillo::Blob compressed_data;
-  EXPECT_TRUE(utils::ReadFile(compressed_path, &compressed_data));
-
   BzipExtentWriter bzip_writer(
       brillo::make_unique_ptr(new DirectExtentWriter()));
   EXPECT_TRUE(bzip_writer.Init(fd_, extents, kBlockSize));
@@ -134,12 +124,9 @@
   test_utils::ExpectVectorsEq(original_compressed_data, compressed_data);
 
   brillo::Blob output;
-  EXPECT_TRUE(utils::ReadFile(path_, &output));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &output));
   EXPECT_EQ(kDecompressedLength, output.size());
   test_utils::ExpectVectorsEq(decompressed_data, output);
-
-  unlink(decompressed_path.c_str());
-  unlink(compressed_path.c_str());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index cb3cdb5..f490c08 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -578,6 +578,9 @@
     LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize,
                                       metadata_size_))
         << "Unable to save the manifest metadata size.";
+    LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestSignatureSize,
+                                      metadata_signature_size_))
+        << "Unable to save the manifest signature size.";
 
     if (!PrimeUpdateState()) {
       *error = ErrorCode::kDownloadStateInitializationError;
@@ -686,8 +689,10 @@
   }
 
   // In major version 2, we don't add dummy operation to the payload.
+  // If we already extracted the signature we should skip this step.
   if (major_payload_version_ == kBrilloMajorPayloadVersion &&
-      manifest_.has_signatures_offset() && manifest_.has_signatures_size()) {
+      manifest_.has_signatures_offset() && manifest_.has_signatures_size() &&
+      signatures_message_data_.empty()) {
     if (manifest_.signatures_offset() != buffer_offset_) {
       LOG(ERROR) << "Payload signatures offset points to blob offset "
                  << manifest_.signatures_offset()
@@ -706,6 +711,10 @@
       return false;
     }
     DiscardBuffer(true, 0);
+    // Since we extracted the SignatureMessage we need to advance the
+    // checkpoint, otherwise we would reload the signature and try to extract
+    // it again.
+    CheckpointUpdateProgress();
   }
 
   return true;
@@ -781,6 +790,12 @@
     install_part.name = partition.partition_name();
     install_part.run_postinstall =
         partition.has_run_postinstall() && partition.run_postinstall();
+    if (install_part.run_postinstall) {
+      install_part.postinstall_path =
+          (partition.has_postinstall_path() ? partition.postinstall_path()
+                                            : kPostinstallDefaultScript);
+      install_part.filesystem_type = partition.filesystem_type();
+    }
 
     if (partition.has_old_partition_info()) {
       const PartitionInfo& info = partition.old_partition_info();
@@ -1666,8 +1681,10 @@
     return false;
 
   int64_t resumed_update_failures;
-  if (!(prefs->GetInt64(kPrefsResumedUpdateFailures, &resumed_update_failures)
-        && resumed_update_failures > kMaxResumedUpdateFailures))
+  // Note that storing this value is optional, but if it is there it should not
+  // be more than the limit.
+  if (prefs->GetInt64(kPrefsResumedUpdateFailures, &resumed_update_failures) &&
+      resumed_update_failures > kMaxResumedUpdateFailures)
     return false;
 
   // Sanity check the rest.
@@ -1686,6 +1703,12 @@
         manifest_metadata_size > 0))
     return false;
 
+  int64_t manifest_signature_size = 0;
+  if (!(prefs->GetInt64(kPrefsManifestSignatureSize,
+                        &manifest_signature_size) &&
+        manifest_signature_size >= 0))
+    return false;
+
   return true;
 }
 
@@ -1700,6 +1723,7 @@
     prefs->SetString(kPrefsUpdateStateSignedSHA256Context, "");
     prefs->SetString(kPrefsUpdateStateSignatureBlob, "");
     prefs->SetInt64(kPrefsManifestMetadataSize, -1);
+    prefs->SetInt64(kPrefsManifestSignatureSize, -1);
     prefs->SetInt64(kPrefsResumedUpdateFailures, 0);
   }
   return true;
@@ -1786,6 +1810,12 @@
                         manifest_metadata_size > 0);
   metadata_size_ = manifest_metadata_size;
 
+  int64_t manifest_signature_size = 0;
+  TEST_AND_RETURN_FALSE(
+      prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size) &&
+      manifest_signature_size >= 0);
+  metadata_signature_size_ = manifest_signature_size;
+
   // Advance the download progress to reflect what doesn't need to be
   // re-downloaded.
   total_bytes_received_ += buffer_offset_;
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 9b7854b..3d7f8fa 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -58,7 +58,7 @@
 extern const char* kUnittestPrivateKey2Path;
 extern const char* kUnittestPublicKey2Path;
 
-static const int kDefaultKernelSize = 4096;  // Something small for a test
+static const uint32_t kDefaultKernelSize = 4096;  // Something small for a test
 static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
                                    'n', 'e', 'w', ' ', 'd', 'a', 't', 'a', '.'};
 
@@ -124,7 +124,7 @@
 
 static void CompareFilesByBlock(const string& a_file, const string& b_file,
                                 size_t image_size) {
-  EXPECT_EQ(0, image_size % kBlockSize);
+  EXPECT_EQ(0U, image_size % kBlockSize);
 
   brillo::Blob a_data, b_data;
   EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
@@ -133,7 +133,7 @@
   EXPECT_GE(a_data.size(), image_size);
   EXPECT_GE(b_data.size(), image_size);
   for (size_t i = 0; i < image_size; i += kBlockSize) {
-    EXPECT_EQ(0, i % kBlockSize);
+    EXPECT_EQ(0U, i % kBlockSize);
     brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
     brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
     EXPECT_TRUE(a_sub == b_sub) << "Block " << (i/kBlockSize) << " differs";
@@ -350,7 +350,7 @@
                                  hardtocompress.size()));
 
     brillo::Blob zeros(16 * 1024, 0);
-    EXPECT_EQ(zeros.size(),
+    EXPECT_EQ(static_cast<int>(zeros.size()),
               base::WriteFile(base::FilePath(base::StringPrintf(
                                   "%s/move-to-sparse", a_mnt.c_str())),
                               reinterpret_cast<const char*>(zeros.data()),
@@ -416,7 +416,7 @@
                         16 * 1024));
 
     brillo::Blob zeros(16 * 1024, 0);
-    EXPECT_EQ(zeros.size(),
+    EXPECT_EQ(static_cast<int>(zeros.size()),
               base::WriteFile(base::FilePath(base::StringPrintf(
                                   "%s/move-from-sparse", b_mnt.c_str())),
                               reinterpret_cast<const char*>(zeros.data()),
@@ -543,10 +543,12 @@
   // Extend the "partitions" holding the file system a bit.
   EXPECT_EQ(0, HANDLE_EINTR(truncate(state->a_img.c_str(),
                                      state->image_size + 1024 * 1024)));
-  EXPECT_EQ(state->image_size + 1024 * 1024, utils::FileSize(state->a_img));
+  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+            utils::FileSize(state->a_img));
   EXPECT_EQ(0, HANDLE_EINTR(truncate(state->b_img.c_str(),
                                      state->image_size + 1024 * 1024)));
-  EXPECT_EQ(state->image_size + 1024 * 1024, utils::FileSize(state->b_img));
+  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+            utils::FileSize(state->b_img));
 
   if (signature_test == kSignatureGeneratedPlaceholder ||
       signature_test == kSignatureGeneratedPlaceholderMismatch) {
@@ -614,7 +616,7 @@
       else
         EXPECT_EQ(1, sigs_message.signatures_size());
       const Signatures_Signature& signature = sigs_message.signatures(0);
-      EXPECT_EQ(1, signature.version());
+      EXPECT_EQ(1U, signature.version());
 
       uint64_t expected_sig_data_length = 0;
       vector<string> key_paths{kUnittestPrivateKeyPath};
@@ -691,6 +693,8 @@
   MockPrefs prefs;
   EXPECT_CALL(prefs, SetInt64(kPrefsManifestMetadataSize,
                               state->metadata_size)).WillOnce(Return(true));
+  EXPECT_CALL(prefs, SetInt64(kPrefsManifestSignatureSize, 0))
+      .WillOnce(Return(true));
   EXPECT_CALL(prefs, SetInt64(kPrefsUpdateStateNextOperation, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
@@ -745,7 +749,7 @@
   (*performer)->set_public_key_path(kUnittestPublicKeyPath);
   DeltaPerformerIntegrationTest::SetSupportedVersion(*performer, minor_version);
 
-  EXPECT_EQ(state->image_size,
+  EXPECT_EQ(static_cast<off_t>(state->image_size),
             HashCalculator::RawHashOfFile(
                 state->a_img,
                 state->image_size,
@@ -880,7 +884,7 @@
                          updated_kernel_partition.begin()));
 
   const auto& partitions = state->install_plan.partitions;
-  EXPECT_EQ(2, partitions.size());
+  EXPECT_EQ(2U, partitions.size());
   EXPECT_EQ(kLegacyPartitionNameRoot, partitions[0].name);
   EXPECT_EQ(kLegacyPartitionNameKernel, partitions[1].name);
 
@@ -892,7 +896,7 @@
 
   EXPECT_EQ(state->image_size, partitions[0].target_size);
   brillo::Blob expected_new_rootfs_hash;
-  EXPECT_EQ(state->image_size,
+  EXPECT_EQ(static_cast<off_t>(state->image_size),
             HashCalculator::RawHashOfFile(state->b_img,
                                           state->image_size,
                                           &expected_new_rootfs_hash));
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index dabe138..98a378b 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -16,6 +16,7 @@
 
 #include "update_engine/payload_consumer/delta_performer.h"
 
+#include <endian.h>
 #include <inttypes.h>
 
 #include <string>
@@ -649,7 +650,7 @@
   EXPECT_EQ(kBrilloMajorPayloadVersion, performer_.GetMajorVersion());
   uint64_t manifest_offset;
   EXPECT_TRUE(performer_.GetManifestOffset(&manifest_offset));
-  EXPECT_EQ(24, manifest_offset);  // 4 + 8 + 8 + 4
+  EXPECT_EQ(24U, manifest_offset);  // 4 + 8 + 8 + 4
   EXPECT_EQ(manifest_offset + manifest_size, performer_.GetMetadataSize());
   EXPECT_EQ(metadata_signature_size, performer_.metadata_signature_size_);
 }
diff --git a/payload_consumer/download_action.cc b/payload_consumer/download_action.cc
index 6a71fdb..fdbbd72 100644
--- a/payload_consumer/download_action.cc
+++ b/payload_consumer/download_action.cc
@@ -232,6 +232,14 @@
   http_fetcher_->BeginTransfer(install_plan_.download_url);
 }
 
+void DownloadAction::SuspendAction() {
+  http_fetcher_->Pause();
+}
+
+void DownloadAction::ResumeAction() {
+  http_fetcher_->Unpause();
+}
+
 void DownloadAction::TerminateProcessing() {
   if (writer_) {
     writer_->Close();
diff --git a/payload_consumer/download_action.h b/payload_consumer/download_action.h
index d000c67..fc32068 100644
--- a/payload_consumer/download_action.h
+++ b/payload_consumer/download_action.h
@@ -68,6 +68,9 @@
 class DownloadAction : public InstallPlanAction,
                        public HttpFetcherDelegate {
  public:
+  // Debugging/logging
+  static std::string StaticType() { return "DownloadAction"; }
+
   // Takes ownership of the passed in HttpFetcher. Useful for testing.
   // A good calling pattern is:
   // DownloadAction(prefs, boot_contol, hardware, system_state,
@@ -78,8 +81,13 @@
                  SystemState* system_state,
                  HttpFetcher* http_fetcher);
   ~DownloadAction() override;
+
+  // InstallPlanAction overrides.
   void PerformAction() override;
+  void SuspendAction() override;
+  void ResumeAction() override;
   void TerminateProcessing() override;
+  std::string Type() const override { return StaticType(); }
 
   // Testing
   void SetTestFileWriter(FileWriter* writer) {
@@ -88,10 +96,6 @@
 
   int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
 
-  // Debugging/logging
-  static std::string StaticType() { return "DownloadAction"; }
-  std::string Type() const override { return StaticType(); }
-
   // HttpFetcherDelegate methods (see http_fetcher.h)
   void ReceivedBytes(HttpFetcher* fetcher,
                      const void* bytes, size_t length) override;
diff --git a/payload_consumer/download_action_unittest.cc b/payload_consumer/download_action_unittest.cc
index 979776f..4ffd35c 100644
--- a/payload_consumer/download_action_unittest.cc
+++ b/payload_consumer/download_action_unittest.cc
@@ -135,9 +135,8 @@
   // TODO(adlr): see if we need a different file for build bots
   ScopedTempFile output_temp_file;
   TestDirectFileWriter writer;
-  EXPECT_EQ(0, writer.Open(output_temp_file.GetPath().c_str(),
-                           O_WRONLY | O_CREAT,
-                           0));
+  EXPECT_EQ(
+      0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
   writer.set_fail_write(fail_write);
 
   // We pull off the first byte from data and seek past it.
@@ -183,7 +182,7 @@
     expected_code = ErrorCode::kDownloadWriteError;
   DownloadActionTestProcessorDelegate delegate(expected_code);
   delegate.expected_data_ = brillo::Blob(data.begin() + 1, data.end());
-  delegate.path_ = output_temp_file.GetPath();
+  delegate.path_ = output_temp_file.path();
   ActionProcessor processor;
   processor.set_delegate(&delegate);
   processor.EnqueueAction(&feeder_action);
@@ -268,9 +267,7 @@
   ScopedTempFile temp_file;
   {
     DirectFileWriter writer;
-    EXPECT_EQ(0, writer.Open(temp_file.GetPath().c_str(),
-                             O_WRONLY | O_CREAT,
-                             0));
+    EXPECT_EQ(0, writer.Open(temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
 
     // takes ownership of passed in HttpFetcher
     ObjectFeederAction<InstallPlan> feeder_action;
@@ -304,10 +301,11 @@
   }
 
   // 1 or 0 chunks should have come through
-  const off_t resulting_file_size(utils::FileSize(temp_file.GetPath()));
+  const off_t resulting_file_size(utils::FileSize(temp_file.path()));
   EXPECT_GE(resulting_file_size, 0);
   if (resulting_file_size != 0)
-    EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
+    EXPECT_EQ(kMockHttpFetcherChunkSize,
+              static_cast<size_t>(resulting_file_size));
 }
 
 }  // namespace
@@ -451,9 +449,8 @@
 
     ScopedTempFile output_temp_file;
     TestDirectFileWriter writer;
-    EXPECT_EQ(0, writer.Open(output_temp_file.GetPath().c_str(),
-                             O_WRONLY | O_CREAT,
-                             0));
+    EXPECT_EQ(
+        0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
     InstallPlan install_plan;
     install_plan.payload_size = data_.length();
     install_plan.payload_hash = "1234hash";
@@ -474,7 +471,7 @@
     DownloadActionTestProcessorDelegate delegate(ErrorCode::kSuccess);
     delegate.expected_data_ = brillo::Blob(data_.begin() + start_at_offset_,
                                            data_.end());
-    delegate.path_ = output_temp_file.GetPath();
+    delegate.path_ = output_temp_file.path();
     processor_.set_delegate(&delegate);
     processor_.EnqueueAction(&feeder_action);
     processor_.EnqueueAction(download_action_.get());
@@ -532,8 +529,10 @@
   // Check the p2p file and its content matches what was sent.
   string file_id = download_action_->p2p_file_id();
   EXPECT_NE("", file_id);
-  EXPECT_EQ(data_.length(), p2p_manager_->FileGetSize(file_id));
-  EXPECT_EQ(data_.length(), p2p_manager_->FileGetExpectedSize(file_id));
+  EXPECT_EQ(static_cast<int>(data_.length()),
+            p2p_manager_->FileGetSize(file_id));
+  EXPECT_EQ(static_cast<int>(data_.length()),
+            p2p_manager_->FileGetExpectedSize(file_id));
   string p2p_file_contents;
   EXPECT_TRUE(ReadFileToString(p2p_manager_->FileGetPath(file_id),
                                &p2p_file_contents));
@@ -580,8 +579,10 @@
   // DownloadAction should convey the same file_id and the file should
   // have the expected size.
   EXPECT_EQ(download_action_->p2p_file_id(), file_id);
-  EXPECT_EQ(p2p_manager_->FileGetSize(file_id), data_.length());
-  EXPECT_EQ(p2p_manager_->FileGetExpectedSize(file_id), data_.length());
+  EXPECT_EQ(static_cast<ssize_t>(data_.length()),
+            p2p_manager_->FileGetSize(file_id));
+  EXPECT_EQ(static_cast<ssize_t>(data_.length()),
+            p2p_manager_->FileGetExpectedSize(file_id));
   string p2p_file_contents;
   // Check that the first 1000 bytes wasn't touched and that we
   // appended the remaining as appropriate.
@@ -611,14 +612,14 @@
                       1000), 1000);
 
   // Check that the file is there.
-  EXPECT_EQ(p2p_manager_->FileGetSize(file_id), 1000);
-  EXPECT_EQ(p2p_manager_->CountSharedFiles(), 1);
+  EXPECT_EQ(1000, p2p_manager_->FileGetSize(file_id));
+  EXPECT_EQ(1, p2p_manager_->CountSharedFiles());
 
   StartDownload(false);  // use_p2p_to_share
 
   // DownloadAction should have deleted the p2p file. Check that it's gone.
-  EXPECT_EQ(p2p_manager_->FileGetSize(file_id), -1);
-  EXPECT_EQ(p2p_manager_->CountSharedFiles(), 0);
+  EXPECT_EQ(-1, p2p_manager_->FileGetSize(file_id));
+  EXPECT_EQ(0, p2p_manager_->CountSharedFiles());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/extent_writer_unittest.cc b/payload_consumer/extent_writer_unittest.cc
index efeab09..24d238e 100644
--- a/payload_consumer/extent_writer_unittest.cc
+++ b/payload_consumer/extent_writer_unittest.cc
@@ -17,9 +17,6 @@
 #include "update_engine/payload_consumer/extent_writer.h"
 
 #include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 #include <algorithm>
 #include <string>
@@ -43,22 +40,17 @@
 static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
 
 namespace {
-const char kPathTemplate[] = "./ExtentWriterTest-file.XXXXXX";
 const size_t kBlockSize = 4096;
 }
 
 class ExtentWriterTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    memcpy(path_, kPathTemplate, sizeof(kPathTemplate));
     fd_.reset(new EintrSafeFileDescriptor);
-    int fd = mkstemp(path_);
-    ASSERT_TRUE(fd_->Open(path_, O_RDWR, 0600));
-    close(fd);
+    ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
   }
   void TearDown() override {
     fd_->Close();
-    unlink(path_);
   }
 
   // Writes data to an extent writer in 'chunk_size' chunks with
@@ -69,7 +61,7 @@
   void TestZeroPad(bool aligned_size);
 
   FileDescriptorPtr fd_;
-  char path_[sizeof(kPathTemplate)];
+  test_utils::ScopedTempFile temp_file_{"ExtentWriterTest-file.XXXXXX"};
 };
 
 TEST_F(ExtentWriterTest, SimpleTest) {
@@ -86,10 +78,11 @@
   EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
   EXPECT_TRUE(direct_writer.End());
 
-  EXPECT_EQ(kBlockSize + bytes.size(), utils::FileSize(path_));
+  EXPECT_EQ(static_cast<off_t>(kBlockSize + bytes.size()),
+            utils::FileSize(temp_file_.path()));
 
   brillo::Blob result_file;
-  EXPECT_TRUE(utils::ReadFile(path_, &result_file));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
 
   brillo::Blob expected_file(kBlockSize);
   expected_file.insert(expected_file.end(),
@@ -153,10 +146,11 @@
   }
   EXPECT_TRUE(direct_writer.End());
 
-  EXPECT_EQ(data.size(), utils::FileSize(path_));
+  EXPECT_EQ(static_cast<off_t>(data.size()),
+            utils::FileSize(temp_file_.path()));
 
   brillo::Blob result_file;
-  EXPECT_TRUE(utils::ReadFile(path_, &result_file));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
 
   brillo::Blob expected_file;
   expected_file.insert(expected_file.end(),
@@ -202,10 +196,11 @@
   ASSERT_TRUE(zero_pad_writer.Write(data.data(), bytes_to_write));
   EXPECT_TRUE(zero_pad_writer.End());
 
-  EXPECT_EQ(data.size(), utils::FileSize(path_));
+  EXPECT_EQ(static_cast<off_t>(data.size()),
+            utils::FileSize(temp_file_.path()));
 
   brillo::Blob result_file;
-  EXPECT_TRUE(utils::ReadFile(path_, &result_file));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
 
   brillo::Blob expected_file;
   expected_file.insert(expected_file.end(),
@@ -251,10 +246,11 @@
   EXPECT_TRUE(direct_writer.End());
 
   // check file size, then data inside
-  ASSERT_EQ(2 * kBlockSize, utils::FileSize(path_));
+  ASSERT_EQ(static_cast<off_t>(2 * kBlockSize),
+            utils::FileSize(temp_file_.path()));
 
   brillo::Blob resultant_data;
-  EXPECT_TRUE(utils::ReadFile(path_, &resultant_data));
+  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &resultant_data));
 
   // Create expected data
   brillo::Blob expected_data(on_disk_count * kBlockSize);
diff --git a/payload_consumer/filesystem_verifier_action_unittest.cc b/payload_consumer/filesystem_verifier_action_unittest.cc
index 10daaa8..cdf7fc0 100644
--- a/payload_consumer/filesystem_verifier_action_unittest.cc
+++ b/payload_consumer/filesystem_verifier_action_unittest.cc
@@ -120,7 +120,7 @@
 // failures and whether or not they are due to the test setup or an inherent
 // issue with the chroot environment, library versions we use, etc.
 TEST_F(FilesystemVerifierActionTest, DISABLED_RunAsRootSimpleTest) {
-  ASSERT_EQ(0, getuid());
+  ASSERT_EQ(0U, getuid());
   bool test = DoTest(false, false, VerifierMode::kComputeSourceHash);
   EXPECT_TRUE(test);
   if (!test)
@@ -309,18 +309,18 @@
 }
 
 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashTest) {
-  ASSERT_EQ(0, getuid());
+  ASSERT_EQ(0U, getuid());
   EXPECT_TRUE(DoTest(false, false, VerifierMode::kVerifyTargetHash));
   EXPECT_TRUE(DoTest(false, false, VerifierMode::kComputeSourceHash));
 }
 
 TEST_F(FilesystemVerifierActionTest, RunAsRootVerifyHashFailTest) {
-  ASSERT_EQ(0, getuid());
+  ASSERT_EQ(0U, getuid());
   EXPECT_TRUE(DoTest(false, true, VerifierMode::kVerifyTargetHash));
 }
 
 TEST_F(FilesystemVerifierActionTest, RunAsRootTerminateEarlyTest) {
-  ASSERT_EQ(0, getuid());
+  ASSERT_EQ(0U, getuid());
   EXPECT_TRUE(DoTest(true, false, VerifierMode::kVerifyTargetHash));
   // TerminateEarlyTest may leak some null callbacks from the Stream class.
   while (loop_.RunOnce(false)) {}
@@ -366,13 +366,13 @@
   loop_.Run();
   install_plan = collector_action.object();
 
-  ASSERT_EQ(2, install_plan.partitions.size());
+  ASSERT_EQ(2U, install_plan.partitions.size());
   // When computing the size of the rootfs on legacy delta updates we use the
   // size of the filesystem, but when updating the kernel we use the whole
   // partition.
-  EXPECT_EQ(10 * 1024 * 1024, install_plan.partitions[0].source_size);
+  EXPECT_EQ(10U << 20, install_plan.partitions[0].source_size);
   EXPECT_EQ(kLegacyPartitionNameRoot, install_plan.partitions[0].name);
-  EXPECT_EQ(20 * 1024 * 1024, install_plan.partitions[1].source_size);
+  EXPECT_EQ(20U << 20, install_plan.partitions[1].source_size);
   EXPECT_EQ(kLegacyPartitionNameKernel, install_plan.partitions[1].name);
 }
 
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 572ff41..51e85b3 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -59,9 +59,13 @@
 void InstallPlan::Dump() const {
   string partitions_str;
   for (const auto& partition : partitions) {
-    partitions_str += base::StringPrintf(
-        ", part: %s (source_size: %" PRIu64 ", target_size %" PRIu64 ")",
-        partition.name.c_str(), partition.source_size, partition.target_size);
+    partitions_str +=
+        base::StringPrintf(", part: %s (source_size: %" PRIu64
+                           ", target_size %" PRIu64 ", postinst:%s)",
+                           partition.name.c_str(),
+                           partition.source_size,
+                           partition.target_size,
+                           utils::ToString(partition.run_postinstall).c_str());
   }
 
   LOG(INFO) << "InstallPlan: "
@@ -109,7 +113,9 @@
           target_path == that.target_path &&
           target_size == that.target_size &&
           target_hash == that.target_hash &&
-          run_postinstall == that.run_postinstall);
+          run_postinstall == that.run_postinstall &&
+          postinstall_path == that.postinstall_path &&
+          filesystem_type == that.filesystem_type);
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index d2f15fa..454dd78 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -90,8 +90,11 @@
     uint64_t target_size{0};
     brillo::Blob target_hash;
 
-    // Whether we should run the postinstall script from this partition.
+    // Whether we should run the postinstall script from this partition and the
+    // postinstall parameters.
     bool run_postinstall{false};
+    std::string postinstall_path;
+    std::string filesystem_type;
   };
   std::vector<Partition> partitions;
 
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 84ca398..d57ef4e 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -23,9 +23,11 @@
 #include <base/bind.h>
 #include <base/files/file_path.h>
 #include <base/files/file_util.h>
+#include <base/strings/string_util.h>
 
 #include "update_engine/common/action_processor.h"
 #include "update_engine/common/boot_control_interface.h"
+#include "update_engine/common/platform_constants.h"
 #include "update_engine/common/subprocess.h"
 #include "update_engine/common/utils.h"
 
@@ -34,16 +36,6 @@
 using std::string;
 using std::vector;
 
-namespace {
-// The absolute path to the post install command.
-const char kPostinstallScript[] = "/postinst";
-
-// Path to the binary file used by kPostinstallScript. Used to get and log the
-// file format of the binary to debug issues when the ELF format on the update
-// doesn't match the one on the current system. This path is not executed.
-const char kDebugPostinstallBinaryPath[] = "/usr/bin/cros_installer";
-}
-
 void PostinstallRunnerAction::PerformAction() {
   CHECK(HasInputObject());
   install_plan_ = GetInputObject();
@@ -60,6 +52,11 @@
 }
 
 void PostinstallRunnerAction::PerformPartitionPostinstall() {
+  if (install_plan_.download_url.empty()) {
+    LOG(INFO) << "Skipping post-install during rollback";
+    return CompletePostinstall(ErrorCode::kSuccess);
+  }
+
   // Skip all the partitions that don't have a post-install step.
   while (current_partition_ < install_plan_.partitions.size() &&
          !install_plan_.partitions[current_partition_].run_postinstall) {
@@ -83,38 +80,45 @@
   // Perform post-install for the current_partition_ partition. At this point we
   // need to call CompletePartitionPostinstall to complete the operation and
   // cleanup.
+#ifdef __ANDROID__
+  fs_mount_dir_ = "/postinstall";
+#else   // __ANDROID__
   TEST_AND_RETURN(
-      utils::MakeTempDirectory("au_postint_mount.XXXXXX", &temp_rootfs_dir_));
+      utils::MakeTempDirectory("au_postint_mount.XXXXXX", &fs_mount_dir_));
+#endif  // __ANDROID__
 
-  if (!utils::MountFilesystem(mountable_device, temp_rootfs_dir_, MS_RDONLY)) {
+  string abs_path = base::FilePath(fs_mount_dir_)
+                        .AppendASCII(partition.postinstall_path)
+                        .value();
+  if (!base::StartsWith(
+          abs_path, fs_mount_dir_, base::CompareCase::SENSITIVE)) {
+    LOG(ERROR) << "Invalid relative postinstall path: "
+               << partition.postinstall_path;
+    return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
+  }
+
+  if (!utils::MountFilesystem(mountable_device,
+                              fs_mount_dir_,
+                              MS_RDONLY,
+                              partition.filesystem_type,
+                              constants::kPostinstallMountOptions)) {
     return CompletePartitionPostinstall(
         1, "Error mounting the device " + mountable_device);
   }
 
-  LOG(INFO) << "Performing postinst (" << kPostinstallScript
-            << ") installed on device " << partition.target_path
+  LOG(INFO) << "Performing postinst (" << partition.postinstall_path << " at "
+            << abs_path << ") installed on device " << partition.target_path
             << " and mountable device " << mountable_device;
 
   // Logs the file format of the postinstall script we are about to run. This
   // will help debug when the postinstall script doesn't match the architecture
   // of our build.
-  LOG(INFO) << "Format file for new " <<  kPostinstallScript << " is: "
-            << utils::GetFileFormat(temp_rootfs_dir_ + kPostinstallScript);
-  LOG(INFO) << "Format file for new " <<  kDebugPostinstallBinaryPath << " is: "
-            << utils::GetFileFormat(
-                temp_rootfs_dir_ + kDebugPostinstallBinaryPath);
+  LOG(INFO) << "Format file for new " << partition.postinstall_path
+            << " is: " << utils::GetFileFormat(abs_path);
 
   // Runs the postinstall script asynchronously to free up the main loop while
   // it's running.
-  vector<string> command;
-  if (!install_plan_.download_url.empty()) {
-    command.push_back(temp_rootfs_dir_ + kPostinstallScript);
-  } else {
-    // TODO(sosa): crbug.com/366207.
-    // If we're doing a rollback, just run our own postinstall.
-    command.push_back(kPostinstallScript);
-  }
-  command.push_back(partition.target_path);
+  vector<string> command = {abs_path, partition.target_path};
   if (!Subprocess::Get().Exec(
           command,
           base::Bind(
@@ -127,11 +131,13 @@
 void PostinstallRunnerAction::CompletePartitionPostinstall(
     int return_code,
     const string& output) {
-  utils::UnmountFilesystem(temp_rootfs_dir_);
-  if (!base::DeleteFile(base::FilePath(temp_rootfs_dir_), false)) {
-    PLOG(WARNING) << "Not removing mountpoint " << temp_rootfs_dir_;
+  utils::UnmountFilesystem(fs_mount_dir_);
+#ifndef ANDROID
+  if (!base::DeleteFile(base::FilePath(fs_mount_dir_), false)) {
+    PLOG(WARNING) << "Not removing temporary mountpoint " << fs_mount_dir_;
   }
-  temp_rootfs_dir_.clear();
+#endif  // !ANDROID
+  fs_mount_dir_.clear();
 
   if (return_code != 0) {
     LOG(ERROR) << "Postinst command failed with code: " << return_code;
diff --git a/payload_consumer/postinstall_runner_action.h b/payload_consumer/postinstall_runner_action.h
index ab267b8..b4defae 100644
--- a/payload_consumer/postinstall_runner_action.h
+++ b/payload_consumer/postinstall_runner_action.h
@@ -63,7 +63,9 @@
   void CompletePostinstall(ErrorCode error_code);
 
   InstallPlan install_plan_;
-  std::string temp_rootfs_dir_;
+
+  // The path where the filesystem will be mounted during post-install.
+  std::string fs_mount_dir_;
 
   // The partition being processed on the list of partitions specified in the
   // InstallPlan.
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index beed4f1..85535d7 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -121,8 +121,8 @@
     bool do_losetup,
     int err_code,
     bool powerwash_required) {
-  ASSERT_EQ(0, getuid()) << "Run me as root. Ideally don't run other tests "
-                         << "as root, tho.";
+  ASSERT_EQ(0U, getuid()) << "Run me as root. Ideally don't run other tests "
+                          << "as root, tho.";
   // True if the post-install action is expected to succeed.
   bool should_succeed = do_losetup && !err_code;
 
@@ -191,6 +191,7 @@
   part.name = "part";
   part.target_path = dev;
   part.run_postinstall = true;
+  part.postinstall_path = kPostinstallDefaultScript;
   InstallPlan install_plan;
   install_plan.partitions = {part};
   install_plan.download_url = "http://devserver:8080/update";
@@ -215,7 +216,7 @@
   EXPECT_TRUE(delegate.code_set_);
   EXPECT_EQ(should_succeed, delegate.code_ == ErrorCode::kSuccess);
   if (should_succeed)
-    EXPECT_TRUE(install_plan == collector_action.object());
+    EXPECT_EQ(install_plan, collector_action.object());
 
   const base::FilePath kPowerwashMarkerPath(powerwash_marker_file);
   string actual_cmd;
@@ -251,7 +252,7 @@
 
 // Death tests don't seem to be working on Hardy
 TEST_F(PostinstallRunnerActionTest, DISABLED_RunAsRootDeathTest) {
-  ASSERT_EQ(0, getuid());
+  ASSERT_EQ(0U, getuid());
   PostinstallRunnerAction runner_action(&fake_boot_control_);
   ASSERT_DEATH({ runner_action.TerminateProcessing(); },
                "postinstall_runner_action.h:.*] Check failed");
diff --git a/payload_generator/ab_generator_unittest.cc b/payload_generator/ab_generator_unittest.cc
index 632fc64..60bdf26 100644
--- a/payload_generator/ab_generator_unittest.cc
+++ b/payload_generator/ab_generator_unittest.cc
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <string>
+#include <random>
 #include <vector>
 
 #include <gtest/gtest.h>
@@ -128,7 +129,7 @@
   InstallOperation_Type expected_type =
       compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE;
 
-  ASSERT_EQ(2, result_ops.size());
+  ASSERT_EQ(2U, result_ops.size());
 
   EXPECT_EQ("SplitTestOp:0", result_ops[0].name);
   InstallOperation first_op = result_ops[0].op;
@@ -156,7 +157,7 @@
                               first_op.data_length(),
                               first_op.data_offset(),
                               &bytes_read));
-  ASSERT_EQ(bytes_read, first_op.data_length());
+  ASSERT_EQ(bytes_read, static_cast<ssize_t>(first_op.data_length()));
   EXPECT_EQ(first_expected_blob, first_data_blob);
 
   EXPECT_EQ("SplitTestOp:1", result_ops[1].name);
@@ -184,7 +185,7 @@
                               second_op.data_length(),
                               second_op.data_offset(),
                               &bytes_read));
-  ASSERT_EQ(bytes_read, second_op.data_length());
+  ASSERT_EQ(bytes_read, static_cast<ssize_t>(second_op.data_length()));
   EXPECT_EQ(second_expected_blob, second_data_blob);
 
   // Check relative layout of data blobs.
@@ -193,7 +194,7 @@
   EXPECT_EQ(second_op.data_offset() + second_op.data_length(), data_file_size);
   // If we split a REPLACE into multiple ones, ensure reuse of preexisting blob.
   if (!compressible && orig_type == InstallOperation::REPLACE) {
-    EXPECT_EQ(0, first_op.data_offset());
+    EXPECT_EQ(0U, first_op.data_offset());
   }
 }
 
@@ -293,7 +294,7 @@
   // Check the result.
   InstallOperation_Type expected_op_type =
       compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE;
-  EXPECT_EQ(1, aops.size());
+  EXPECT_EQ(1U, aops.size());
   InstallOperation new_op = aops[0].op;
   EXPECT_EQ(expected_op_type, new_op.type());
   EXPECT_FALSE(new_op.has_src_length());
@@ -312,7 +313,8 @@
     expected_blob = expected_data;
   }
   ASSERT_EQ(expected_blob.size(), new_op.data_length());
-  ASSERT_EQ(blob_data.size() + expected_blob.size(), data_file_size);
+  ASSERT_EQ(blob_data.size() + expected_blob.size(),
+            static_cast<size_t>(data_file_size));
   brillo::Blob new_op_blob(new_op.data_length());
   ssize_t bytes_read;
   ASSERT_TRUE(utils::PReadAll(data_fd,
@@ -320,7 +322,7 @@
                               new_op.data_length(),
                               new_op.data_offset(),
                               &bytes_read));
-  ASSERT_EQ(new_op.data_length(), bytes_read);
+  ASSERT_EQ(static_cast<ssize_t>(new_op.data_length()), bytes_read);
   EXPECT_EQ(expected_blob, new_op_blob);
 }
 
@@ -343,47 +345,47 @@
   aop.name = "SplitSourceCopyTestOp";
   vector<AnnotatedOperation> result_ops;
   EXPECT_TRUE(ABGenerator::SplitSourceCopy(aop, &result_ops));
-  EXPECT_EQ(result_ops.size(), 3);
+  EXPECT_EQ(3U, result_ops.size());
 
   EXPECT_EQ("SplitSourceCopyTestOp:0", result_ops[0].name);
   InstallOperation first_op = result_ops[0].op;
   EXPECT_EQ(InstallOperation::SOURCE_COPY, first_op.type());
   EXPECT_EQ(kBlockSize * 2, first_op.src_length());
   EXPECT_EQ(1, first_op.src_extents().size());
-  EXPECT_EQ(2, first_op.src_extents(0).start_block());
-  EXPECT_EQ(2, first_op.src_extents(0).num_blocks());
+  EXPECT_EQ(2U, first_op.src_extents(0).start_block());
+  EXPECT_EQ(2U, first_op.src_extents(0).num_blocks());
   EXPECT_EQ(kBlockSize * 2, first_op.dst_length());
   EXPECT_EQ(1, first_op.dst_extents().size());
-  EXPECT_EQ(10, first_op.dst_extents(0).start_block());
-  EXPECT_EQ(2, first_op.dst_extents(0).num_blocks());
+  EXPECT_EQ(10U, first_op.dst_extents(0).start_block());
+  EXPECT_EQ(2U, first_op.dst_extents(0).num_blocks());
 
   EXPECT_EQ("SplitSourceCopyTestOp:1", result_ops[1].name);
   InstallOperation second_op = result_ops[1].op;
   EXPECT_EQ(InstallOperation::SOURCE_COPY, second_op.type());
   EXPECT_EQ(kBlockSize * 3, second_op.src_length());
   EXPECT_EQ(3, second_op.src_extents().size());
-  EXPECT_EQ(4, second_op.src_extents(0).start_block());
-  EXPECT_EQ(1, second_op.src_extents(0).num_blocks());
-  EXPECT_EQ(6, second_op.src_extents(1).start_block());
-  EXPECT_EQ(1, second_op.src_extents(1).num_blocks());
-  EXPECT_EQ(8, second_op.src_extents(2).start_block());
-  EXPECT_EQ(1, second_op.src_extents(2).num_blocks());
+  EXPECT_EQ(4U, second_op.src_extents(0).start_block());
+  EXPECT_EQ(1U, second_op.src_extents(0).num_blocks());
+  EXPECT_EQ(6U, second_op.src_extents(1).start_block());
+  EXPECT_EQ(1U, second_op.src_extents(1).num_blocks());
+  EXPECT_EQ(8U, second_op.src_extents(2).start_block());
+  EXPECT_EQ(1U, second_op.src_extents(2).num_blocks());
   EXPECT_EQ(kBlockSize * 3, second_op.dst_length());
   EXPECT_EQ(1, second_op.dst_extents().size());
-  EXPECT_EQ(14, second_op.dst_extents(0).start_block());
-  EXPECT_EQ(3, second_op.dst_extents(0).num_blocks());
+  EXPECT_EQ(14U, second_op.dst_extents(0).start_block());
+  EXPECT_EQ(3U, second_op.dst_extents(0).num_blocks());
 
   EXPECT_EQ("SplitSourceCopyTestOp:2", result_ops[2].name);
   InstallOperation third_op = result_ops[2].op;
   EXPECT_EQ(InstallOperation::SOURCE_COPY, third_op.type());
   EXPECT_EQ(kBlockSize * 3, third_op.src_length());
   EXPECT_EQ(1, third_op.src_extents().size());
-  EXPECT_EQ(9, third_op.src_extents(0).start_block());
-  EXPECT_EQ(3, third_op.src_extents(0).num_blocks());
+  EXPECT_EQ(9U, third_op.src_extents(0).start_block());
+  EXPECT_EQ(3U, third_op.src_extents(0).num_blocks());
   EXPECT_EQ(kBlockSize * 3, third_op.dst_length());
   EXPECT_EQ(1, third_op.dst_extents().size());
-  EXPECT_EQ(18, third_op.dst_extents(0).start_block());
-  EXPECT_EQ(3, third_op.dst_extents(0).num_blocks());
+  EXPECT_EQ(18U, third_op.dst_extents(0).start_block());
+  EXPECT_EQ(3U, third_op.dst_extents(0).num_blocks());
 }
 
 TEST_F(ABGeneratorTest, SplitReplaceTest) {
@@ -429,7 +431,7 @@
   aops.push_back(third_aop);
 
   ABGenerator::SortOperationsByDestination(&aops);
-  EXPECT_EQ(aops.size(), 3);
+  EXPECT_EQ(3U, aops.size());
   EXPECT_EQ(third_aop.name, aops[0].name);
   EXPECT_EQ(first_aop.name, aops[1].name);
   EXPECT_EQ(second_aop.name, aops[2].name);
@@ -475,7 +477,7 @@
   BlobFileWriter blob_file(0, nullptr);
   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, 5, "", &blob_file));
 
-  EXPECT_EQ(aops.size(), 1);
+  EXPECT_EQ(1U, aops.size());
   InstallOperation first_result_op = aops[0].op;
   EXPECT_EQ(InstallOperation::SOURCE_COPY, first_result_op.type());
   EXPECT_EQ(kBlockSize * 5, first_result_op.src_length());
@@ -548,7 +550,7 @@
   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, 4, "", &blob_file));
 
   // No operations were merged, the number of ops is the same.
-  EXPECT_EQ(aops.size(), 4);
+  EXPECT_EQ(4U, aops.size());
 }
 
 TEST_F(ABGeneratorTest, AddSourceHashTest) {
diff --git a/payload_generator/block_mapping_unittest.cc b/payload_generator/block_mapping_unittest.cc
index 18e48c4..4d09710 100644
--- a/payload_generator/block_mapping_unittest.cc
+++ b/payload_generator/block_mapping_unittest.cc
@@ -97,7 +97,7 @@
       EXPECT_FALSE(ublock.block_data.empty());
       // The block was loaded from disk only 4 times, and after that the counter
       // is not updated anymore.
-      EXPECT_EQ(4, ublock.times_read);
+      EXPECT_EQ(4U, ublock.times_read);
     }
   }
 }
diff --git a/payload_generator/cycle_breaker_unittest.cc b/payload_generator/cycle_breaker_unittest.cc
index 4053cf3..e92bc30 100644
--- a/payload_generator/cycle_breaker_unittest.cc
+++ b/payload_generator/cycle_breaker_unittest.cc
@@ -91,7 +91,7 @@
               utils::SetContainsKey(broken_edges, make_pair(n_e, n_c)));
   EXPECT_TRUE(utils::SetContainsKey(broken_edges, make_pair(n_g, n_h)) ||
               utils::SetContainsKey(broken_edges, make_pair(n_h, n_g)));
-  EXPECT_EQ(3, broken_edges.size());
+  EXPECT_EQ(3U, broken_edges.size());
 }
 
 namespace {
@@ -127,7 +127,7 @@
 // the algorithm to cut cycles (t) instead, since they are closer to the
 // root, and that can massively speed up cycle cutting.
 TEST(CycleBreakerTest, AggressiveCutTest) {
-  int counter = 0;
+  size_t counter = 0;
 
   const int kNodesPerGroup = 4;
   const int kGroups = 33;
@@ -176,7 +176,7 @@
 }
 
 TEST(CycleBreakerTest, WeightTest) {
-  int counter = 0;
+  size_t counter = 0;
   const Vertex::Index n_a = counter++;
   const Vertex::Index n_b = counter++;
   const Vertex::Index n_c = counter++;
@@ -225,7 +225,7 @@
 }
 
 TEST(CycleBreakerTest, UnblockGraphTest) {
-  int counter = 0;
+  size_t counter = 0;
   const Vertex::Index n_a = counter++;
   const Vertex::Index n_b = counter++;
   const Vertex::Index n_c = counter++;
@@ -253,7 +253,7 @@
 }
 
 TEST(CycleBreakerTest, SkipOpsTest) {
-  int counter = 0;
+  size_t counter = 0;
   const Vertex::Index n_a = counter++;
   const Vertex::Index n_b = counter++;
   const Vertex::Index n_c = counter++;
@@ -272,7 +272,7 @@
   set<Edge> broken_edges;
   breaker.BreakCycles(graph, &broken_edges);
 
-  EXPECT_EQ(2, breaker.skipped_ops());
+  EXPECT_EQ(2U, breaker.skipped_ops());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_generator/delta_diff_utils_unittest.cc b/payload_generator/delta_diff_utils_unittest.cc
index 4dc5981..72349d8 100644
--- a/payload_generator/delta_diff_utils_unittest.cc
+++ b/payload_generator/delta_diff_utils_unittest.cc
@@ -17,6 +17,7 @@
 #include "update_engine/payload_generator/delta_diff_utils.h"
 
 #include <algorithm>
+#include <random>
 #include <string>
 #include <vector>
 
@@ -193,7 +194,7 @@
   EXPECT_EQ(kBlockSize, op.dst_length());
   EXPECT_EQ(BlocksInExtents(op.src_extents()),
             BlocksInExtents(op.dst_extents()));
-  EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
+  EXPECT_EQ(1U, BlocksInExtents(op.dst_extents()));
 }
 
 TEST_F(DeltaDiffUtilsTest, MoveWithSameBlock) {
@@ -263,7 +264,7 @@
   EXPECT_EQ(num_blocks * kBlockSize, op.src_length());
   EXPECT_EQ(num_blocks * kBlockSize, op.dst_length());
 
-  EXPECT_EQ(old_extents.size(), op.src_extents_size());
+  EXPECT_EQ(old_extents.size(), static_cast<size_t>(op.src_extents_size()));
   for (int i = 0; i < op.src_extents_size(); i++) {
     EXPECT_EQ(old_extents[i].start_block(), op.src_extents(i).start_block())
         << "i == " << i;
@@ -271,7 +272,7 @@
         << "i == " << i;
   }
 
-  EXPECT_EQ(new_extents.size(), op.dst_extents_size());
+  EXPECT_EQ(new_extents.size(), static_cast<size_t>(op.dst_extents_size()));
   for (int i = 0; i < op.dst_extents_size(); i++) {
     EXPECT_EQ(new_extents[i].start_block(), op.dst_extents(i).start_block())
         << "i == " << i;
@@ -318,7 +319,7 @@
   EXPECT_EQ(kBlockSize, op.dst_length());
   EXPECT_EQ(BlocksInExtents(op.src_extents()),
             BlocksInExtents(op.dst_extents()));
-  EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
+  EXPECT_EQ(1U, BlocksInExtents(op.dst_extents()));
 }
 
 TEST_F(DeltaDiffUtilsTest, BsdiffNotAllowedTest) {
@@ -432,7 +433,7 @@
     EXPECT_FALSE(op.has_src_length());
     EXPECT_EQ(1, op.dst_extents_size());
     EXPECT_EQ(data_to_test.size(), op.dst_length());
-    EXPECT_EQ(1, BlocksInExtents(op.dst_extents()));
+    EXPECT_EQ(1U, BlocksInExtents(op.dst_extents()));
   }
 }
 
@@ -552,8 +553,8 @@
   EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(-1,  // chunk_blocks
                                          false));  // src_ops_allowed
 
-  EXPECT_EQ(0, old_visited_blocks_.blocks());
-  EXPECT_EQ(0, new_visited_blocks_.blocks());
+  EXPECT_EQ(0U, old_visited_blocks_.blocks());
+  EXPECT_EQ(0U, new_visited_blocks_.blocks());
   EXPECT_EQ(0, blob_size_);
   EXPECT_TRUE(aops_.empty());
 }
@@ -662,7 +663,7 @@
   // source extents should cover only the first copy of the source file since
   // we prefer to re-read files (maybe cached) instead of continue reading the
   // rest of the partition.
-  EXPECT_EQ(1, aops_.size());
+  EXPECT_EQ(1U, aops_.size());
   const AnnotatedOperation& aop = aops_[0];
   EXPECT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
   EXPECT_EQ(5, aop.op.src_extents_size());
@@ -759,7 +760,7 @@
   EXPECT_EQ(permutation.size(), new_visited_blocks_.blocks());
 
   // There should be only one SOURCE_COPY, with a complicate list of extents.
-  EXPECT_EQ(1, aops_.size());
+  EXPECT_EQ(1U, aops_.size());
   const AnnotatedOperation& aop = aops_[0];
   EXPECT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
   vector<Extent> aop_src_extents;
diff --git a/payload_generator/ext2_filesystem_unittest.cc b/payload_generator/ext2_filesystem_unittest.cc
index df8b98f..f7d25da 100644
--- a/payload_generator/ext2_filesystem_unittest.cc
+++ b/payload_generator/ext2_filesystem_unittest.cc
@@ -34,7 +34,6 @@
 #include "update_engine/common/utils.h"
 #include "update_engine/payload_generator/extent_utils.h"
 
-using chromeos_update_engine::test_utils::System;
 using std::map;
 using std::set;
 using std::string;
@@ -52,31 +51,20 @@
 // Checks that all the blocks in |extents| are in the range [0, total_blocks).
 void ExpectBlocksInRange(const vector<Extent>& extents, uint64_t total_blocks) {
   for (const Extent& extent : extents) {
-    EXPECT_LE(0, extent.start_block());
+    EXPECT_LE(0U, extent.start_block());
     EXPECT_LE(extent.start_block() + extent.num_blocks(), total_blocks);
   }
 }
 
 }  // namespace
 
-
-class Ext2FilesystemTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(utils::MakeTempFile("Ext2FilesystemTest-XXXXXX",
-                                    &fs_filename_, nullptr));
-    ASSERT_EQ(0, truncate(fs_filename_.c_str(), kDefaultFilesystemSize));
-  }
-
-  void TearDown() override {
-    unlink(fs_filename_.c_str());
-  }
-
-  string fs_filename_;
-};
+class Ext2FilesystemTest : public ::testing::Test {};
 
 TEST_F(Ext2FilesystemTest, InvalidFilesystem) {
-  unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(fs_filename_);
+  test_utils::ScopedTempFile fs_filename_{"Ext2FilesystemTest-XXXXXX"};
+  ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kDefaultFilesystemSize));
+  unique_ptr<Ext2Filesystem> fs =
+      Ext2Filesystem::CreateFromFile(fs_filename_.path());
   ASSERT_EQ(nullptr, fs.get());
 
   fs = Ext2Filesystem::CreateFromFile("/path/to/invalid/file");
@@ -84,10 +72,9 @@
 }
 
 TEST_F(Ext2FilesystemTest, EmptyFilesystem) {
-  EXPECT_EQ(0, System(base::StringPrintf(
-      "/sbin/mkfs.ext2 -q -b %" PRIuS " -F %s",
-      kDefaultFilesystemBlockSize, fs_filename_.c_str())));
-  unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(fs_filename_);
+  base::FilePath path =
+      test_utils::GetBuildArtifactsPath().Append("gen/disk_ext2_4k_empty.img");
+  unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(path.value());
 
   ASSERT_NE(nullptr, fs.get());
   EXPECT_EQ(kDefaultFilesystemBlockCount, fs->GetBlockCount());
@@ -103,7 +90,7 @@
     map_files[file.name] = file;
     ExpectBlocksInRange(file.extents, fs->GetBlockCount());
   }
-  EXPECT_EQ(2, map_files["/"].file_stat.st_ino);
+  EXPECT_EQ(2U, map_files["/"].file_stat.st_ino);
   EXPECT_FALSE(map_files["<free-space>"].extents.empty());
 }
 
@@ -169,7 +156,7 @@
 
     // Small symlinks don't actually have data blocks.
     EXPECT_TRUE(map_files["/link-short_symlink"].extents.empty());
-    EXPECT_EQ(1, BlocksInExtents(map_files["/link-long_symlink"].extents));
+    EXPECT_EQ(1U, BlocksInExtents(map_files["/link-long_symlink"].extents));
 
     // Hard-links report the same list of blocks.
     EXPECT_EQ(map_files["/link-hard-regular-16k"].extents,
@@ -179,13 +166,14 @@
     // The number of blocks in these files doesn't depend on the
     // block size.
     EXPECT_TRUE(map_files["/empty-file"].extents.empty());
-    EXPECT_EQ(1, BlocksInExtents(map_files["/regular-small"].extents));
-    EXPECT_EQ(1, BlocksInExtents(map_files["/regular-with_net_cap"].extents));
+    EXPECT_EQ(1U, BlocksInExtents(map_files["/regular-small"].extents));
+    EXPECT_EQ(1U, BlocksInExtents(map_files["/regular-with_net_cap"].extents));
     EXPECT_TRUE(map_files["/sparse_empty-10k"].extents.empty());
     EXPECT_TRUE(map_files["/sparse_empty-2blocks"].extents.empty());
-    EXPECT_EQ(1, BlocksInExtents(map_files["/sparse-16k-last_block"].extents));
-    EXPECT_EQ(1, BlocksInExtents(map_files["/sparse-16k-first_block"].extents));
-    EXPECT_EQ(2, BlocksInExtents(map_files["/sparse-16k-holes"].extents));
+    EXPECT_EQ(1U, BlocksInExtents(map_files["/sparse-16k-last_block"].extents));
+    EXPECT_EQ(1U,
+              BlocksInExtents(map_files["/sparse-16k-first_block"].extents));
+    EXPECT_EQ(2U, BlocksInExtents(map_files["/sparse-16k-holes"].extents));
   }
 }
 
@@ -193,6 +181,7 @@
   base::FilePath path = test_utils::GetBuildArtifactsPath().Append(
       "gen/disk_ext2_1k.img");
   unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(path.value());
+  ASSERT_NE(nullptr, fs.get());
 
   brillo::KeyValueStore store;
   // disk_ext2_1k.img doesn't have the /etc/update_engine.conf file.
@@ -203,6 +192,7 @@
   base::FilePath path = test_utils::GetBuildArtifactsPath().Append(
       "gen/disk_ext2_ue_settings.img");
   unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(path.value());
+  ASSERT_NE(nullptr, fs.get());
 
   brillo::KeyValueStore store;
   EXPECT_TRUE(fs->LoadSettings(&store));
diff --git a/payload_generator/extent_ranges_unittest.cc b/payload_generator/extent_ranges_unittest.cc
index 8b39040..3705bac 100644
--- a/payload_generator/extent_ranges_unittest.cc
+++ b/payload_generator/extent_ranges_unittest.cc
@@ -250,7 +250,7 @@
   ranges.SubtractExtents(vector<Extent>(1, ExtentForRange(20, 10)));
   *rep_field.Mutable(0) = ExtentForRange(50, 10);
   ranges.SubtractRepeatedExtents(rep_field);
-  EXPECT_EQ(40, ranges.blocks());
+  EXPECT_EQ(40U, ranges.blocks());
 
   for (int i = 0; i < 2; i++) {
     vector<Extent> expected(2);
diff --git a/payload_generator/extent_utils_unittest.cc b/payload_generator/extent_utils_unittest.cc
index 62c8ff1..d470e7b 100644
--- a/payload_generator/extent_utils_unittest.cc
+++ b/payload_generator/extent_utils_unittest.cc
@@ -34,43 +34,43 @@
 TEST(ExtentUtilsTest, AppendSparseToExtentsTest) {
   vector<Extent> extents;
 
-  EXPECT_EQ(0, extents.size());
+  EXPECT_EQ(0U, extents.size());
   AppendBlockToExtents(&extents, kSparseHole);
-  EXPECT_EQ(1, extents.size());
+  EXPECT_EQ(1U, extents.size());
   AppendBlockToExtents(&extents, 0);
-  EXPECT_EQ(2, extents.size());
+  EXPECT_EQ(2U, extents.size());
   AppendBlockToExtents(&extents, kSparseHole);
   AppendBlockToExtents(&extents, kSparseHole);
 
-  ASSERT_EQ(3, extents.size());
+  ASSERT_EQ(3U, extents.size());
   EXPECT_EQ(kSparseHole, extents[0].start_block());
-  EXPECT_EQ(1, extents[0].num_blocks());
-  EXPECT_EQ(0, extents[1].start_block());
-  EXPECT_EQ(1, extents[1].num_blocks());
+  EXPECT_EQ(1U, extents[0].num_blocks());
+  EXPECT_EQ(0U, extents[1].start_block());
+  EXPECT_EQ(1U, extents[1].num_blocks());
   EXPECT_EQ(kSparseHole, extents[2].start_block());
-  EXPECT_EQ(2, extents[2].num_blocks());
+  EXPECT_EQ(2U, extents[2].num_blocks());
 }
 
 TEST(ExtentUtilsTest, BlocksInExtentsTest) {
   {
     vector<Extent> extents;
-    EXPECT_EQ(0, BlocksInExtents(extents));
+    EXPECT_EQ(0U, BlocksInExtents(extents));
     extents.push_back(ExtentForRange(0, 1));
-    EXPECT_EQ(1, BlocksInExtents(extents));
+    EXPECT_EQ(1U, BlocksInExtents(extents));
     extents.push_back(ExtentForRange(23, 55));
-    EXPECT_EQ(56, BlocksInExtents(extents));
+    EXPECT_EQ(56U, BlocksInExtents(extents));
     extents.push_back(ExtentForRange(1, 2));
-    EXPECT_EQ(58, BlocksInExtents(extents));
+    EXPECT_EQ(58U, BlocksInExtents(extents));
   }
   {
     google::protobuf::RepeatedPtrField<Extent> extents;
-    EXPECT_EQ(0, BlocksInExtents(extents));
+    EXPECT_EQ(0U, BlocksInExtents(extents));
     *extents.Add() = ExtentForRange(0, 1);
-    EXPECT_EQ(1, BlocksInExtents(extents));
+    EXPECT_EQ(1U, BlocksInExtents(extents));
     *extents.Add() = ExtentForRange(23, 55);
-    EXPECT_EQ(56, BlocksInExtents(extents));
+    EXPECT_EQ(56U, BlocksInExtents(extents));
     *extents.Add() = ExtentForRange(1, 2);
-    EXPECT_EQ(58, BlocksInExtents(extents));
+    EXPECT_EQ(58U, BlocksInExtents(extents));
   }
 }
 
@@ -96,11 +96,11 @@
   // Make sure it works when there's just one extent.
   vector<Extent> extents;
   NormalizeExtents(&extents);
-  EXPECT_EQ(0, extents.size());
+  EXPECT_EQ(0U, extents.size());
 
   extents = { ExtentForRange(0, 3) };
   NormalizeExtents(&extents);
-  EXPECT_EQ(1, extents.size());
+  EXPECT_EQ(1U, extents.size());
   EXPECT_EQ(ExtentForRange(0, 3), extents[0]);
 }
 
@@ -114,7 +114,7 @@
       ExtentForRange(14, 2)
   };
   NormalizeExtents(&extents);
-  EXPECT_EQ(3, extents.size());
+  EXPECT_EQ(3U, extents.size());
   EXPECT_EQ(ExtentForRange(0, 6), extents[0]);
   EXPECT_EQ(ExtentForRange(8, 4), extents[1]);
   EXPECT_EQ(ExtentForRange(13, 3), extents[2]);
diff --git a/payload_generator/fake_filesystem.cc b/payload_generator/fake_filesystem.cc
index 3a6458d..c765286 100644
--- a/payload_generator/fake_filesystem.cc
+++ b/payload_generator/fake_filesystem.cc
@@ -44,7 +44,7 @@
   file.name = filename;
   file.extents = extents;
   for (const Extent& extent : extents) {
-    EXPECT_LE(0, extent.start_block());
+    EXPECT_LE(0U, extent.start_block());
     EXPECT_LE(extent.start_block() + extent.num_blocks(), block_count_);
   }
   files_.push_back(file);
diff --git a/payload_generator/full_update_generator_unittest.cc b/payload_generator/full_update_generator_unittest.cc
index d46346d..d5af9d0 100644
--- a/payload_generator/full_update_generator_unittest.cc
+++ b/payload_generator/full_update_generator_unittest.cc
@@ -83,10 +83,10 @@
                                             blob_file_.get(),
                                             &aops));
   int64_t new_part_chunks = new_part_conf.size / config_.hard_chunk_size;
-  EXPECT_EQ(new_part_chunks, aops.size());
+  EXPECT_EQ(new_part_chunks, static_cast<int64_t>(aops.size()));
   for (off_t i = 0; i < new_part_chunks; ++i) {
     EXPECT_EQ(1, aops[i].op.dst_extents_size());
-    EXPECT_EQ(i * config_.hard_chunk_size / config_.block_size,
+    EXPECT_EQ(static_cast<uint64_t>(i * config_.hard_chunk_size / config_.block_size),
               aops[i].op.dst_extents(0).start_block()) << "i = " << i;
     EXPECT_EQ(config_.hard_chunk_size / config_.block_size,
               aops[i].op.dst_extents(0).num_blocks());
@@ -112,7 +112,7 @@
                                             blob_file_.get(),
                                             &aops));
   // new_part has one chunk and a half.
-  EXPECT_EQ(2, aops.size());
+  EXPECT_EQ(2U, aops.size());
   EXPECT_EQ(config_.hard_chunk_size / config_.block_size,
             BlocksInExtents(aops[0].op.dst_extents()));
   EXPECT_EQ((new_part.size() - config_.hard_chunk_size) / config_.block_size,
@@ -134,7 +134,7 @@
                                             &aops));
 
   // new_part has less than one chunk.
-  EXPECT_EQ(1, aops.size());
+  EXPECT_EQ(1U, aops.size());
   EXPECT_EQ(new_part.size() / config_.block_size,
             BlocksInExtents(aops[0].op.dst_extents()));
 }
diff --git a/payload_generator/graph_utils_unittest.cc b/payload_generator/graph_utils_unittest.cc
index 7d3dbe3..dddf815 100644
--- a/payload_generator/graph_utils_unittest.cc
+++ b/payload_generator/graph_utils_unittest.cc
@@ -39,21 +39,21 @@
 
   vector<Extent>& extents = graph[0].out_edges[1].extents;
 
-  EXPECT_EQ(0, extents.size());
+  EXPECT_EQ(0U, extents.size());
   AppendBlockToExtents(&extents, 0);
-  EXPECT_EQ(1, extents.size());
+  EXPECT_EQ(1U, extents.size());
   AppendBlockToExtents(&extents, 1);
   AppendBlockToExtents(&extents, 2);
-  EXPECT_EQ(1, extents.size());
+  EXPECT_EQ(1U, extents.size());
   AppendBlockToExtents(&extents, 4);
 
-  EXPECT_EQ(2, extents.size());
-  EXPECT_EQ(0, extents[0].start_block());
-  EXPECT_EQ(3, extents[0].num_blocks());
-  EXPECT_EQ(4, extents[1].start_block());
-  EXPECT_EQ(1, extents[1].num_blocks());
+  EXPECT_EQ(2U, extents.size());
+  EXPECT_EQ(0U, extents[0].start_block());
+  EXPECT_EQ(3U, extents[0].num_blocks());
+  EXPECT_EQ(4U, extents[1].start_block());
+  EXPECT_EQ(1U, extents[1].num_blocks());
 
-  EXPECT_EQ(4, graph_utils::EdgeWeight(graph, make_pair(0, 1)));
+  EXPECT_EQ(4U, graph_utils::EdgeWeight(graph, make_pair(0, 1)));
 }
 
 
@@ -61,35 +61,35 @@
   Graph graph(3);
 
   graph_utils::AddReadBeforeDep(&graph[0], 1, 3);
-  EXPECT_EQ(1, graph[0].out_edges.size());
+  EXPECT_EQ(1U, graph[0].out_edges.size());
   {
     Extent& extent = graph[0].out_edges[1].extents[0];
-    EXPECT_EQ(3, extent.start_block());
-    EXPECT_EQ(1, extent.num_blocks());
+    EXPECT_EQ(3U, extent.start_block());
+    EXPECT_EQ(1U, extent.num_blocks());
   }
   graph_utils::AddReadBeforeDep(&graph[0], 1, 4);
-  EXPECT_EQ(1, graph[0].out_edges.size());
+  EXPECT_EQ(1U, graph[0].out_edges.size());
   {
     Extent& extent = graph[0].out_edges[1].extents[0];
-    EXPECT_EQ(3, extent.start_block());
-    EXPECT_EQ(2, extent.num_blocks());
+    EXPECT_EQ(3U, extent.start_block());
+    EXPECT_EQ(2U, extent.num_blocks());
   }
   graph_utils::AddReadBeforeDepExtents(&graph[2], 1,
     vector<Extent>(1, ExtentForRange(5, 2)));
-  EXPECT_EQ(1, graph[2].out_edges.size());
+  EXPECT_EQ(1U, graph[2].out_edges.size());
   {
     Extent& extent = graph[2].out_edges[1].extents[0];
-    EXPECT_EQ(5, extent.start_block());
-    EXPECT_EQ(2, extent.num_blocks());
+    EXPECT_EQ(5U, extent.start_block());
+    EXPECT_EQ(2U, extent.num_blocks());
   }
   // Change most recent edge from read-before to write-before
   graph[2].out_edges[1].write_extents.swap(graph[2].out_edges[1].extents);
   graph_utils::DropWriteBeforeDeps(&graph[2].out_edges);
-  EXPECT_EQ(0, graph[2].out_edges.size());
+  EXPECT_EQ(0U, graph[2].out_edges.size());
 
-  EXPECT_EQ(1, graph[0].out_edges.size());
+  EXPECT_EQ(1U, graph[0].out_edges.size());
   graph_utils::DropIncomingEdgesTo(&graph, 1);
-  EXPECT_EQ(0, graph[0].out_edges.size());
+  EXPECT_EQ(0U, graph[0].out_edges.size());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_generator/inplace_generator_unittest.cc b/payload_generator/inplace_generator_unittest.cc
index 9932ef9..cde4bfc 100644
--- a/payload_generator/inplace_generator_unittest.cc
+++ b/payload_generator/inplace_generator_unittest.cc
@@ -153,20 +153,20 @@
   InplaceGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
 
   EXPECT_EQ(7, op.src_extents_size());
-  EXPECT_EQ(11, op.src_extents(0).start_block());
-  EXPECT_EQ(1, op.src_extents(0).num_blocks());
-  EXPECT_EQ(13, op.src_extents(1).start_block());
-  EXPECT_EQ(1, op.src_extents(1).num_blocks());
-  EXPECT_EQ(6, op.src_extents(2).start_block());
-  EXPECT_EQ(1, op.src_extents(2).num_blocks());
+  EXPECT_EQ(11U, op.src_extents(0).start_block());
+  EXPECT_EQ(1U, op.src_extents(0).num_blocks());
+  EXPECT_EQ(13U, op.src_extents(1).start_block());
+  EXPECT_EQ(1U, op.src_extents(1).num_blocks());
+  EXPECT_EQ(6U, op.src_extents(2).start_block());
+  EXPECT_EQ(1U, op.src_extents(2).num_blocks());
   EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
-  EXPECT_EQ(4, op.src_extents(3).num_blocks());
-  EXPECT_EQ(10, op.src_extents(4).start_block());
-  EXPECT_EQ(1, op.src_extents(4).num_blocks());
-  EXPECT_EQ(14, op.src_extents(5).start_block());
-  EXPECT_EQ(1, op.src_extents(5).num_blocks());
-  EXPECT_EQ(8, op.src_extents(6).start_block());
-  EXPECT_EQ(2, op.src_extents(6).num_blocks());
+  EXPECT_EQ(4U, op.src_extents(3).num_blocks());
+  EXPECT_EQ(10U, op.src_extents(4).start_block());
+  EXPECT_EQ(1U, op.src_extents(4).num_blocks());
+  EXPECT_EQ(14U, op.src_extents(5).start_block());
+  EXPECT_EQ(1U, op.src_extents(5).num_blocks());
+  EXPECT_EQ(8U, op.src_extents(6).start_block());
+  EXPECT_EQ(2U, op.src_extents(6).num_blocks());
 }
 
 TEST_F(InplaceGeneratorTest, CutEdgesTest) {
@@ -229,58 +229,58 @@
   set<Edge> cut_edges;
   cycle_breaker.BreakCycles(graph, &cut_edges);
 
-  EXPECT_EQ(1, cut_edges.size());
+  EXPECT_EQ(1U, cut_edges.size());
   EXPECT_TRUE(cut_edges.end() != cut_edges.find(
       std::pair<Vertex::Index, Vertex::Index>(1, 0)));
 
   vector<CutEdgeVertexes> cuts;
   EXPECT_TRUE(InplaceGenerator::CutEdges(&graph, cut_edges, &cuts));
 
-  EXPECT_EQ(3, graph.size());
+  EXPECT_EQ(3U, graph.size());
 
   // Check new node in graph:
   EXPECT_EQ(InstallOperation::MOVE, graph.back().aop.op.type());
   EXPECT_EQ(2, graph.back().aop.op.src_extents_size());
   EXPECT_EQ(1, graph.back().aop.op.dst_extents_size());
   EXPECT_EQ(kTempBlockStart, graph.back().aop.op.dst_extents(0).start_block());
-  EXPECT_EQ(2, graph.back().aop.op.dst_extents(0).num_blocks());
+  EXPECT_EQ(2U, graph.back().aop.op.dst_extents(0).num_blocks());
   EXPECT_TRUE(graph.back().out_edges.empty());
 
   // Check that old node reads from new blocks
   EXPECT_EQ(2, graph[0].aop.op.src_extents_size());
   EXPECT_EQ(kTempBlockStart, graph[0].aop.op.src_extents(0).start_block());
-  EXPECT_EQ(2, graph[0].aop.op.src_extents(0).num_blocks());
-  EXPECT_EQ(7, graph[0].aop.op.src_extents(1).start_block());
-  EXPECT_EQ(1, graph[0].aop.op.src_extents(1).num_blocks());
+  EXPECT_EQ(2U, graph[0].aop.op.src_extents(0).num_blocks());
+  EXPECT_EQ(7U, graph[0].aop.op.src_extents(1).start_block());
+  EXPECT_EQ(1U, graph[0].aop.op.src_extents(1).num_blocks());
 
   // And that the old dst extents haven't changed
   EXPECT_EQ(2, graph[0].aop.op.dst_extents_size());
-  EXPECT_EQ(1, graph[0].aop.op.dst_extents(0).start_block());
-  EXPECT_EQ(2, graph[0].aop.op.dst_extents(0).num_blocks());
-  EXPECT_EQ(4, graph[0].aop.op.dst_extents(1).start_block());
-  EXPECT_EQ(1, graph[0].aop.op.dst_extents(1).num_blocks());
+  EXPECT_EQ(1U, graph[0].aop.op.dst_extents(0).start_block());
+  EXPECT_EQ(2U, graph[0].aop.op.dst_extents(0).num_blocks());
+  EXPECT_EQ(4U, graph[0].aop.op.dst_extents(1).start_block());
+  EXPECT_EQ(1U, graph[0].aop.op.dst_extents(1).num_blocks());
 
   // Ensure it only depends on the next node and the new temp node
-  EXPECT_EQ(2, graph[0].out_edges.size());
+  EXPECT_EQ(2U, graph[0].out_edges.size());
   EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
   EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
                                                                   1));
 
   // Check second node has unchanged extents
   EXPECT_EQ(2, graph[1].aop.op.src_extents_size());
-  EXPECT_EQ(1, graph[1].aop.op.src_extents(0).start_block());
-  EXPECT_EQ(2, graph[1].aop.op.src_extents(0).num_blocks());
-  EXPECT_EQ(4, graph[1].aop.op.src_extents(1).start_block());
-  EXPECT_EQ(1, graph[1].aop.op.src_extents(1).num_blocks());
+  EXPECT_EQ(1U, graph[1].aop.op.src_extents(0).start_block());
+  EXPECT_EQ(2U, graph[1].aop.op.src_extents(0).num_blocks());
+  EXPECT_EQ(4U, graph[1].aop.op.src_extents(1).start_block());
+  EXPECT_EQ(1U, graph[1].aop.op.src_extents(1).num_blocks());
 
   EXPECT_EQ(2, graph[1].aop.op.dst_extents_size());
-  EXPECT_EQ(3, graph[1].aop.op.dst_extents(0).start_block());
-  EXPECT_EQ(1, graph[1].aop.op.dst_extents(0).num_blocks());
-  EXPECT_EQ(5, graph[1].aop.op.dst_extents(1).start_block());
-  EXPECT_EQ(2, graph[1].aop.op.dst_extents(1).num_blocks());
+  EXPECT_EQ(3U, graph[1].aop.op.dst_extents(0).start_block());
+  EXPECT_EQ(1U, graph[1].aop.op.dst_extents(0).num_blocks());
+  EXPECT_EQ(5U, graph[1].aop.op.dst_extents(1).start_block());
+  EXPECT_EQ(2U, graph[1].aop.op.dst_extents(1).num_blocks());
 
   // Ensure it only depends on the next node
-  EXPECT_EQ(1, graph[1].out_edges.size());
+  EXPECT_EQ(1U, graph[1].out_edges.size());
   EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
 }
 
@@ -384,8 +384,8 @@
   EXPECT_FALSE(graph[6].valid);
   EXPECT_FALSE(graph[7].valid);
   EXPECT_EQ(1, graph[1].aop.op.src_extents_size());
-  EXPECT_EQ(2, graph[1].aop.op.src_extents(0).start_block());
-  EXPECT_EQ(1, graph[1].aop.op.src_extents(0).num_blocks());
+  EXPECT_EQ(2U, graph[1].aop.op.src_extents(0).start_block());
+  EXPECT_EQ(1U, graph[1].aop.op.src_extents(0).num_blocks());
   EXPECT_EQ(InstallOperation::REPLACE_BZ, graph[5].aop.op.type());
 }
 
@@ -547,7 +547,7 @@
             InstallOperation::MOVE);
   expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
 
-  EXPECT_EQ(12, graph.size());
+  EXPECT_EQ(12U, graph.size());
   EXPECT_FALSE(graph.back().valid);
   for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
     EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
@@ -563,11 +563,11 @@
   Vertex vertex;
   InplaceGenerator::CreateScratchNode(12, 34, &vertex);
   EXPECT_EQ(InstallOperation::REPLACE_BZ, vertex.aop.op.type());
-  EXPECT_EQ(0, vertex.aop.op.data_offset());
-  EXPECT_EQ(0, vertex.aop.op.data_length());
+  EXPECT_EQ(0U, vertex.aop.op.data_offset());
+  EXPECT_EQ(0U, vertex.aop.op.data_length());
   EXPECT_EQ(1, vertex.aop.op.dst_extents_size());
-  EXPECT_EQ(12, vertex.aop.op.dst_extents(0).start_block());
-  EXPECT_EQ(34, vertex.aop.op.dst_extents(0).num_blocks());
+  EXPECT_EQ(12U, vertex.aop.op.dst_extents(0).start_block());
+  EXPECT_EQ(34U, vertex.aop.op.dst_extents(0).num_blocks());
 }
 
 TEST_F(InplaceGeneratorTest, ApplyMapTest) {
@@ -635,16 +635,18 @@
       if (aop.op.type() != InstallOperation::MOVE)
         continue;
       for (const Extent& extent : aop.op.src_extents()) {
-        EXPECT_NE(0, extent.start_block()) << "On src extents for aop: " << aop;
+        EXPECT_NE(0U, extent.start_block())
+            << "On src extents for aop: " << aop;
       }
       for (const Extent& extent : aop.op.dst_extents()) {
-        EXPECT_NE(0, extent.start_block()) << "On dst extents for aop: " << aop;
+        EXPECT_NE(0U, extent.start_block())
+            << "On dst extents for aop: " << aop;
       }
     }
 
     // If there's extra space in the partition, it should not use a new full
     // operation for it.
-    EXPECT_EQ(part_blocks == num_blocks ? 2 : 1, full_ops);
+    EXPECT_EQ(part_blocks == num_blocks ? 2U : 1U, full_ops);
 
     if (HasNonfatalFailure()) {
       LOG(INFO) << "Result operation list:";
diff --git a/payload_generator/payload_file_unittest.cc b/payload_generator/payload_file_unittest.cc
index 4d18adf..e8e7e14 100644
--- a/payload_generator/payload_file_unittest.cc
+++ b/payload_generator/payload_file_unittest.cc
@@ -80,15 +80,15 @@
   // Kernel blobs should appear at the end.
   EXPECT_EQ("bcdakernel", new_data);
 
-  EXPECT_EQ(2, part0_aops.size());
-  EXPECT_EQ(0, part0_aops[0].op.data_offset());
-  EXPECT_EQ(3, part0_aops[0].op.data_length());
-  EXPECT_EQ(3, part0_aops[1].op.data_offset());
-  EXPECT_EQ(1, part0_aops[1].op.data_length());
+  EXPECT_EQ(2U, part0_aops.size());
+  EXPECT_EQ(0U, part0_aops[0].op.data_offset());
+  EXPECT_EQ(3U, part0_aops[0].op.data_length());
+  EXPECT_EQ(3U, part0_aops[1].op.data_offset());
+  EXPECT_EQ(1U, part0_aops[1].op.data_length());
 
-  EXPECT_EQ(1, part1_aops.size());
-  EXPECT_EQ(4, part1_aops[0].op.data_offset());
-  EXPECT_EQ(6, part1_aops[0].op.data_length());
+  EXPECT_EQ(1U, part1_aops.size());
+  EXPECT_EQ(4U, part1_aops[0].op.data_offset());
+  EXPECT_EQ(6U, part1_aops[0].op.data_length());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index eadbc59..ebdd280 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -103,7 +103,7 @@
                          std::begin(kDataToSign) + strlen(kDataToSign));
   uint64_t length = 0;
   EXPECT_TRUE(PayloadSigner::SignatureBlobLength(private_keys, &length));
-  EXPECT_GT(length, 0);
+  EXPECT_GT(length, 0U);
   brillo::Blob hash_blob;
   EXPECT_TRUE(HashCalculator::RawHashOfBytes(data_blob.data(),
                                              data_blob.size(),
@@ -170,7 +170,7 @@
                                         signature_blob.size()));
   EXPECT_EQ(1, signatures.signatures_size());
   const Signatures_Signature& signature = signatures.signatures(0);
-  EXPECT_EQ(1, signature.version());
+  EXPECT_EQ(1U, signature.version());
   const string sig_data = signature.data();
   ASSERT_EQ(arraysize(kDataSignature), sig_data.size());
   for (size_t i = 0; i < arraysize(kDataSignature); i++) {
diff --git a/payload_generator/tarjan_unittest.cc b/payload_generator/tarjan_unittest.cc
index e40a7ff..c29cbdc 100644
--- a/payload_generator/tarjan_unittest.cc
+++ b/payload_generator/tarjan_unittest.cc
@@ -65,7 +65,7 @@
     vector<Vertex::Index> vertex_indexes;
     tarjan.Execute(i, &graph, &vertex_indexes);
 
-    EXPECT_EQ(5, vertex_indexes.size());
+    EXPECT_EQ(5U, vertex_indexes.size());
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_a));
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_b));
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_c));
@@ -77,7 +77,7 @@
     vector<Vertex::Index> vertex_indexes;
     tarjan.Execute(n_f, &graph, &vertex_indexes);
 
-    EXPECT_EQ(1, vertex_indexes.size());
+    EXPECT_EQ(1U, vertex_indexes.size());
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_f));
   }
 
@@ -85,7 +85,7 @@
     vector<Vertex::Index> vertex_indexes;
     tarjan.Execute(i, &graph, &vertex_indexes);
 
-    EXPECT_EQ(2, vertex_indexes.size());
+    EXPECT_EQ(2U, vertex_indexes.size());
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_g));
     EXPECT_TRUE(utils::VectorContainsValue(vertex_indexes, n_h));
   }
diff --git a/payload_generator/zip_unittest.cc b/payload_generator/zip_unittest.cc
index 49b08b0..0c95a8f 100644
--- a/payload_generator/zip_unittest.cc
+++ b/payload_generator/zip_unittest.cc
@@ -74,7 +74,7 @@
   brillo::Blob out;
   EXPECT_TRUE(this->ZipCompressString(in, &out));
   EXPECT_LT(out.size(), in.size());
-  EXPECT_GT(out.size(), 0);
+  EXPECT_GT(out.size(), 0U);
   brillo::Blob decompressed;
   EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
   EXPECT_EQ(in.size(), decompressed.size());
@@ -105,10 +105,10 @@
   string in;
   brillo::Blob out;
   EXPECT_TRUE(this->ZipDecompressString(in, &out));
-  EXPECT_EQ(0, out.size());
+  EXPECT_EQ(0U, out.size());
 
   EXPECT_TRUE(this->ZipCompressString(in, &out));
-  EXPECT_EQ(0, out.size());
+  EXPECT_EQ(0U, out.size());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_state.cc b/payload_state.cc
index 4b5b5fd..04b6579 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -62,6 +62,7 @@
       url_switch_count_(0),
       attempt_num_bytes_downloaded_(0),
       attempt_connection_type_(metrics::ConnectionType::kUnknown),
+      attempt_error_code_(ErrorCode::kSuccess),
       attempt_type_(AttemptType::kUpdate) {
   for (int i = 0; i <= kNumDownloadSources; i++)
     total_bytes_downloaded_[i] = current_bytes_downloaded_[i] = 0;
@@ -232,6 +233,7 @@
                                      metrics::RollbackResult::kSuccess);
       break;
   }
+  attempt_error_code_ = ErrorCode::kSuccess;
 
   // Reset the number of responses seen since it counts from the last
   // successful update, e.g. now.
@@ -265,6 +267,8 @@
       break;
   }
 
+  attempt_error_code_ = base_error;
+
   switch (base_error) {
     // Errors which are good indicators of a problem with a particular URL or
     // the protocol used in the URL or entities in the communication channel
diff --git a/payload_state.h b/payload_state.h
index bec5823..46711b6 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -147,6 +147,10 @@
     return p2p_url_;
   }
 
+  inline ErrorCode GetAttemptErrorCode() const override {
+    return attempt_error_code_;
+  }
+
  private:
   enum class AttemptType {
     kUpdate,
@@ -559,6 +563,9 @@
   // The connection type when the attempt started.
   metrics::ConnectionType attempt_connection_type_;
 
+  // The attempt error code when the attempt finished.
+  ErrorCode attempt_error_code_;
+
   // Whether we're currently rolling back.
   AttemptType attempt_type_;
 
diff --git a/payload_state_interface.h b/payload_state_interface.h
index 40a13dd..68798ee 100644
--- a/payload_state_interface.h
+++ b/payload_state_interface.h
@@ -192,6 +192,7 @@
   // Sets/gets the P2P download URL, if one is to be used.
   virtual void SetP2PUrl(const std::string& url) = 0;
   virtual std::string GetP2PUrl() const = 0;
+  virtual ErrorCode GetAttemptErrorCode() const = 0;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index 4490637..b671722 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -139,8 +139,8 @@
                                   "Disable Payload Backoff = 0\n";
   EXPECT_EQ(expected_response_sign, stored_response_sign);
   EXPECT_EQ("", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
   EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
 }
 
@@ -191,8 +191,8 @@
                                   "Disable Payload Backoff = 0\n";
   EXPECT_EQ(expected_response_sign, stored_response_sign);
   EXPECT_EQ("https://single.url.test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
   EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
 }
 
@@ -242,8 +242,8 @@
                                   "Disable Payload Backoff = 0\n";
   EXPECT_EQ(expected_response_sign, stored_response_sign);
   EXPECT_EQ("http://multiple.url.test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
   EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
 }
 
@@ -298,7 +298,7 @@
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
 
   // Verify that we switched URLs three times
-  EXPECT_EQ(3, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(3U, payload_state.GetUrlSwitchCount());
 }
 
 TEST(PayloadStateTest, NewResponseResetsPayloadState) {
@@ -321,7 +321,7 @@
   ErrorCode error = ErrorCode::kDownloadMetadataSignatureMismatch;
   payload_state.UpdateFailed(error);
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // Now, slightly change the response and set it again.
   SetupPayloadStateWith2Urls("Hash8225", true, &payload_state, &response);
@@ -330,7 +330,7 @@
   // Fake an error again.
   payload_state.UpdateFailed(error);
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // Return a third different response.
   SetupPayloadStateWith2Urls("Hash9999", true, &payload_state, &response);
@@ -338,15 +338,15 @@
 
   // Make sure the url index was reset to 0 because of the new response.
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U,
             payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0, payload_state.GetCurrentBytesDownloaded(
-                 kDownloadSourceHttpsServer));
-  EXPECT_EQ(0,
+  EXPECT_EQ(
+      0U, payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
+  EXPECT_EQ(0U,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
 }
 
@@ -412,24 +412,24 @@
   EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // This should advance the failure count only.
   payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
   EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // This should advance the failure count only.
   payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
   EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(2, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(2U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // This should advance the URL index as we've reached the
   // max failure count and reset the failure count for the new URL index.
@@ -439,8 +439,8 @@
   EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(2, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(2U, payload_state.GetUrlSwitchCount());
   EXPECT_TRUE(payload_state.ShouldBackoffDownload());
 
   // This should advance the URL index.
@@ -448,8 +448,8 @@
   EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(3, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(3U, payload_state.GetUrlSwitchCount());
   EXPECT_TRUE(payload_state.ShouldBackoffDownload());
 
   // This should advance the URL index and payload attempt number due to
@@ -458,8 +458,8 @@
   EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
   EXPECT_TRUE(payload_state.ShouldBackoffDownload());
 
   // This HTTP error code should only increase the failure count.
@@ -468,8 +468,8 @@
   EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
   EXPECT_TRUE(payload_state.ShouldBackoffDownload());
 
   // And that failure count should be reset when we download some bytes
@@ -478,8 +478,8 @@
   EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(4, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
   EXPECT_TRUE(payload_state.ShouldBackoffDownload());
 
   // Now, slightly change the response and set it again.
@@ -490,8 +490,8 @@
   EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
   EXPECT_FALSE(payload_state.ShouldBackoffDownload());
 }
 
@@ -532,8 +532,8 @@
   EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
 }
 
 TEST(PayloadStateTest, PayloadAttemptNumberIncreasesOnSuccessfulDeltaDownload) {
@@ -572,8 +572,8 @@
   EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
 }
 
 TEST(PayloadStateTest, SetResponseResetsInvalidUrlIndex) {
@@ -592,8 +592,8 @@
   EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
 
   // Now, simulate a corrupted url index on persisted store which gets
   // loaded when update_engine restarts. Using a different prefs object
@@ -625,8 +625,8 @@
   EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
   EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
 }
 
 TEST(PayloadStateTest, NoBackoffInteractiveChecks) {
@@ -780,8 +780,8 @@
   response.disable_payload_backoff = true;
   PayloadState payload_state;
   FakeSystemState fake_system_state;
-  int https_total = 0;
-  int http_total = 0;
+  uint64_t https_total = 0;
+  uint64_t http_total = 0;
 
   EXPECT_TRUE(payload_state.Initialize(&fake_system_state));
   SetupPayloadStateWith2Urls("Hash3286", true, &payload_state, &response);
@@ -789,7 +789,7 @@
 
   // Simulate a previous attempt with in order to set an initial non-zero value
   // for the total bytes downloaded for HTTP.
-  int prev_chunk = 323456789;
+  uint64_t prev_chunk = 323456789;
   http_total += prev_chunk;
   payload_state.DownloadProgress(prev_chunk);
 
@@ -805,7 +805,7 @@
   EXPECT_EQ(2, payload_state.GetNumResponsesSeen());
 
   // First, simulate successful download of a few bytes over HTTP.
-  int first_chunk = 5000000;
+  uint64_t first_chunk = 5000000;
   http_total += first_chunk;
   payload_state.DownloadProgress(first_chunk);
   // Test that first all progress is made on HTTP and none on HTTPS.
@@ -813,7 +813,7 @@
             payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
   EXPECT_EQ(http_total,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0, payload_state.GetCurrentBytesDownloaded(
+  EXPECT_EQ(0U, payload_state.GetCurrentBytesDownloaded(
                  kDownloadSourceHttpsServer));
   EXPECT_EQ(https_total,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
@@ -823,7 +823,7 @@
   payload_state.UpdateFailed(error);
 
   // Test that no new progress is made on HTTP and new progress is on HTTPS.
-  int second_chunk = 23456789;
+  uint64_t second_chunk = 23456789;
   https_total += second_chunk;
   payload_state.DownloadProgress(second_chunk);
   EXPECT_EQ(first_chunk,
@@ -837,8 +837,8 @@
 
   // Simulate error to go back to http.
   payload_state.UpdateFailed(error);
-  int third_chunk = 32345678;
-  int http_chunk = first_chunk + third_chunk;
+  uint64_t third_chunk = 32345678;
+  uint64_t http_chunk = first_chunk + third_chunk;
   http_total += third_chunk;
   payload_state.DownloadProgress(third_chunk);
 
@@ -856,7 +856,7 @@
   // then do 42MB worth of progress
   payload_state.UpdateFailed(error);
   payload_state.SetUsingP2PForDownloading(true);
-  int p2p_total = 42 * 1000 * 1000;
+  uint64_t p2p_total = 42 * 1000 * 1000;
   payload_state.DownloadProgress(p2p_total);
 
   EXPECT_EQ(p2p_total,
@@ -886,13 +886,13 @@
   payload_state.UpdateSucceeded();
 
   // Make sure the metrics are reset after a successful update.
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0, payload_state.GetCurrentBytesDownloaded(
+  EXPECT_EQ(0U, payload_state.GetCurrentBytesDownloaded(
                  kDownloadSourceHttpsServer));
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
   EXPECT_EQ(0, payload_state.GetNumResponsesSeen());
 }
@@ -906,7 +906,7 @@
   SetupPayloadStateWith2Urls("Hash3286", true, &payload_state, &response);
 
   // Simulate progress in order to mark HTTP as one of the sources used.
-  int num_bytes = 42 * 1000 * 1000;
+  uint64_t num_bytes = 42 * 1000 * 1000;
   payload_state.DownloadProgress(num_bytes);
 
   // Check that this was done via HTTP.
@@ -936,20 +936,20 @@
   // Set the first response.
   SetupPayloadStateWith2Urls("Hash5823", true, &payload_state, &response);
 
-  int num_bytes = 10000;
+  uint64_t num_bytes = 10000;
   payload_state.DownloadProgress(num_bytes);
   EXPECT_EQ(num_bytes,
             payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
   EXPECT_EQ(num_bytes,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-  EXPECT_EQ(0, payload_state.GetCurrentBytesDownloaded(
+  EXPECT_EQ(0U, payload_state.GetCurrentBytesDownloaded(
                  kDownloadSourceHttpsServer));
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
 
   payload_state.UpdateRestarted();
   // Make sure the current bytes downloaded is reset, but not the total bytes.
-  EXPECT_EQ(0,
+  EXPECT_EQ(0U,
             payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
   EXPECT_EQ(num_bytes,
             payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
@@ -966,21 +966,21 @@
   EXPECT_TRUE(payload_state.Initialize(&fake_system_state));
 
   payload_state.UpdateRestarted();
-  EXPECT_EQ(0, payload_state.GetNumReboots());
+  EXPECT_EQ(0U, payload_state.GetNumReboots());
 
   fake_system_state.set_system_rebooted(true);
   payload_state.UpdateResumed();
   // Num reboots should be incremented because system rebooted detected.
-  EXPECT_EQ(1, payload_state.GetNumReboots());
+  EXPECT_EQ(1U, payload_state.GetNumReboots());
 
   fake_system_state.set_system_rebooted(false);
   payload_state.UpdateResumed();
   // Num reboots should now be 1 as reboot was not detected.
-  EXPECT_EQ(1, payload_state.GetNumReboots());
+  EXPECT_EQ(1U, payload_state.GetNumReboots());
 
   // Restart the update again to verify we set the num of reboots back to 0.
   payload_state.UpdateRestarted();
-  EXPECT_EQ(0, payload_state.GetNumReboots());
+  EXPECT_EQ(0U, payload_state.GetNumReboots());
 }
 
 TEST(PayloadStateTest, RollbackVersion) {
@@ -1267,7 +1267,7 @@
 
   // Check that we still skip the HTTP URL and use only the HTTPS url.
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
 
   // Now, slightly change the response and set it again.
   SetupPayloadStateWith2Urls("Hash2399", false, &payload_state, &response);
@@ -1290,14 +1290,14 @@
 
   // Check that we use the HTTP URL now and the failure count is reset.
   EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
 
   // Fake a failure and see if we're moving over to the HTTPS url and update
   // the URL switch count properly.
   payload_state.UpdateFailed(error);
   EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-  EXPECT_EQ(1, payload_state.GetUrlSwitchCount());
-  EXPECT_EQ(0, payload_state.GetUrlFailureCount());
+  EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
+  EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
 }
 
 TEST(PayloadStateTest, PayloadTypeMetricWhenTypeIsDelta) {
diff --git a/sample_images/generate_images.sh b/sample_images/generate_images.sh
index 70fc14b..1c2a83c 100755
--- a/sample_images/generate_images.sh
+++ b/sample_images/generate_images.sh
@@ -156,6 +156,8 @@
     default)
       add_files_default "${mntdir}" "${block_size}"
       ;;
+    empty)
+      ;;
   esac
 
   cleanup "${mntdir}"
@@ -176,6 +178,7 @@
   # Add more sample images here.
   generate_image disk_ext2_1k default 16777216 1024
   generate_image disk_ext2_4k default 16777216 4096
+  generate_image disk_ext2_4k_empty empty $((1024 * 4096)) 4096
   generate_image disk_ext2_ue_settings ue_settings 16777216 4096
 
   # Generate the tarball and delete temporary images.
diff --git a/sample_images/sample_images.tar.bz2 b/sample_images/sample_images.tar.bz2
index 0982271..83141ab 100644
--- a/sample_images/sample_images.tar.bz2
+++ b/sample_images/sample_images.tar.bz2
Binary files differ
diff --git a/update_attempter.cc b/update_attempter.cc
index aeb433b..cfd2425 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -125,7 +125,9 @@
     : processor_(new ActionProcessor()),
       system_state_(system_state),
       cert_checker_(cert_checker),
+#if USE_LIBCROS
       chrome_proxy_resolver_(libcros_proxy),
+#endif  // USE_LIBCROS
       debugd_proxy_(debugd_proxy) {
 }
 
@@ -155,7 +157,9 @@
   else
     status_ = UpdateStatus::IDLE;
 
+#if USE_LIBCROS
   chrome_proxy_resolver_.Init();
+#endif  // USE_LIBCROS
 }
 
 void UpdateAttempter::ScheduleUpdates() {
@@ -1376,14 +1380,17 @@
   if (response_handler_action_->install_plan().is_resume) {
     // Resuming an update so fetch the update manifest metadata first.
     int64_t manifest_metadata_size = 0;
+    int64_t manifest_signature_size = 0;
     prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
-    fetcher->AddRange(0, manifest_metadata_size);
+    prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size);
+    fetcher->AddRange(0, manifest_metadata_size + manifest_signature_size);
     // If there're remaining unprocessed data blobs, fetch them. Be careful not
     // to request data beyond the end of the payload to avoid 416 HTTP response
     // error codes.
     int64_t next_data_offset = 0;
     prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
-    uint64_t resume_offset = manifest_metadata_size + next_data_offset;
+    uint64_t resume_offset =
+        manifest_metadata_size + manifest_signature_size + next_data_offset;
     if (resume_offset < response_handler_action_->install_plan().payload_size) {
       fetcher->AddRange(resume_offset);
     }
diff --git a/update_attempter.h b/update_attempter.h
index 8f6fd18..bbc4b4e 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -306,9 +306,13 @@
   void MarkDeltaUpdateFailure();
 
   ProxyResolver* GetProxyResolver() {
+#if USE_LIBCROS
     return obeying_proxies_ ?
         reinterpret_cast<ProxyResolver*>(&chrome_proxy_resolver_) :
         reinterpret_cast<ProxyResolver*>(&direct_proxy_resolver_);
+#else
+    return &direct_proxy_resolver_;
+#endif  // USE_LIBCROS
   }
 
   // Sends a ping to Omaha.
@@ -454,7 +458,9 @@
 
   // Our two proxy resolvers
   DirectProxyResolver direct_proxy_resolver_;
+#if USE_LIBCROS
   ChromeBrowserProxyResolver chrome_proxy_resolver_;
+#endif  // USE_LIBCROS
 
   // Originally, both of these flags are false. Once UpdateBootFlags is called,
   // |update_boot_flags_running_| is set to true. As soon as UpdateBootFlags
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index cc478a4..6f88ee7 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -173,6 +173,7 @@
   SetupDownload();
   cpu_limiter_.StartLimiter();
   SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
+  ongoing_update_ = true;
 
   // Just in case we didn't update boot flags yet, make sure they're updated
   // before any update processing starts. This will start the update process.
@@ -181,23 +182,24 @@
 }
 
 bool UpdateAttempterAndroid::SuspendUpdate(brillo::ErrorPtr* error) {
-  // TODO(deymo): Implement suspend/resume.
-  return LogAndSetError(error, FROM_HERE, "Suspend/resume not implemented");
+  if (!ongoing_update_)
+    return LogAndSetError(error, FROM_HERE, "No ongoing update to suspend.");
+  processor_->SuspendProcessing();
+  return true;
 }
 
 bool UpdateAttempterAndroid::ResumeUpdate(brillo::ErrorPtr* error) {
-  // TODO(deymo): Implement suspend/resume.
-  return LogAndSetError(error, FROM_HERE, "Suspend/resume not implemented");
+  if (!ongoing_update_)
+    return LogAndSetError(error, FROM_HERE, "No ongoing update to resume.");
+  processor_->ResumeProcessing();
+  return true;
 }
 
 bool UpdateAttempterAndroid::CancelUpdate(brillo::ErrorPtr* error) {
-  if (status_ == UpdateStatus::IDLE ||
-      status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
+  if (!ongoing_update_)
     return LogAndSetError(error, FROM_HERE, "No ongoing update to cancel.");
-  }
-
-  // TODO(deymo): Implement cancel.
-  return LogAndSetError(error, FROM_HERE, "Cancel not implemented");
+  processor_->StopProcessing();
+  return true;
 }
 
 bool UpdateAttempterAndroid::ResetStatus(brillo::ErrorPtr* error) {
@@ -412,14 +414,18 @@
   if (install_plan_.is_resume) {
     // Resuming an update so fetch the update manifest metadata first.
     int64_t manifest_metadata_size = 0;
+    int64_t manifest_signature_size = 0;
     prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
-    fetcher->AddRange(base_offset_, manifest_metadata_size);
+    prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size);
+    fetcher->AddRange(base_offset_,
+                      manifest_metadata_size + manifest_signature_size);
     // If there're remaining unprocessed data blobs, fetch them. Be careful not
     // to request data beyond the end of the payload to avoid 416 HTTP response
     // error codes.
     int64_t next_data_offset = 0;
     prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
-    uint64_t resume_offset = manifest_metadata_size + next_data_offset;
+    uint64_t resume_offset =
+        manifest_metadata_size + manifest_signature_size + next_data_offset;
     if (!install_plan_.payload_size) {
       fetcher->AddRange(base_offset_ + resume_offset);
     } else if (resume_offset < install_plan_.payload_size) {
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index e77b571..35bd206 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -38,6 +38,8 @@
 #include "libcros/dbus-proxy-mocks.h"
 #include "update_engine/common/fake_clock.h"
 #include "update_engine/common/fake_prefs.h"
+#include "update_engine/common/mock_action.h"
+#include "update_engine/common/mock_action_processor.h"
 #include "update_engine/common/mock_http_fetcher.h"
 #include "update_engine/common/mock_prefs.h"
 #include "update_engine/common/platform_constants.h"
@@ -45,8 +47,6 @@
 #include "update_engine/common/test_utils.h"
 #include "update_engine/common/utils.h"
 #include "update_engine/fake_system_state.h"
-#include "update_engine/mock_action.h"
-#include "update_engine/mock_action_processor.h"
 #include "update_engine/mock_p2p_manager.h"
 #include "update_engine/mock_payload_state.h"
 #include "update_engine/payload_consumer/filesystem_verifier_action.h"
@@ -254,7 +254,7 @@
   attempter_.ActionCompleted(nullptr, &action, ErrorCode::kSuccess);
   EXPECT_EQ(500, attempter_.http_response_code());
   EXPECT_EQ(UpdateStatus::IDLE, attempter_.status());
-  EXPECT_EQ(234, attempter_.server_dictated_poll_interval_);
+  EXPECT_EQ(234U, attempter_.server_dictated_poll_interval_);
   ASSERT_TRUE(attempter_.error_event_.get() == nullptr);
 }
 
@@ -429,9 +429,10 @@
   }
   EXPECT_EQ(attempter_.response_handler_action_.get(),
             attempter_.actions_[1].get());
-  DownloadAction* download_action =
-      dynamic_cast<DownloadAction*>(attempter_.actions_[4].get());
-  ASSERT_NE(nullptr, download_action);
+  AbstractAction* action_4 = attempter_.actions_[4].get();
+  ASSERT_NE(nullptr, action_4);
+  ASSERT_EQ(DownloadAction::StaticType(), action_4->Type());
+  DownloadAction* download_action = static_cast<DownloadAction*>(action_4);
   EXPECT_EQ(&attempter_, download_action->delegate());
   EXPECT_EQ(UpdateStatus::CHECKING_FOR_UPDATE, attempter_.status());
   loop_.BreakLoop();
@@ -501,10 +502,13 @@
     EXPECT_EQ(kRollbackActionTypes[i], attempter_.actions_[i]->Type());
   }
   EXPECT_EQ(UpdateStatus::ATTEMPTING_ROLLBACK, attempter_.status());
+  AbstractAction* action_0 = attempter_.actions_[0].get();
+  ASSERT_NE(nullptr, action_0);
+  ASSERT_EQ(InstallPlanAction::StaticType(), action_0->Type());
   InstallPlanAction* install_plan_action =
-        dynamic_cast<InstallPlanAction*>(attempter_.actions_[0].get());
+      static_cast<InstallPlanAction*>(action_0);
   InstallPlan* install_plan = install_plan_action->install_plan();
-  EXPECT_EQ(0, install_plan->partitions.size());
+  EXPECT_EQ(0U, install_plan->partitions.size());
   EXPECT_EQ(install_plan->powerwash_required, true);
   loop_.BreakLoop();
 }
diff --git a/update_engine.gyp b/update_engine.gyp
index ab20243..07e6f6c 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -26,6 +26,7 @@
       'USE_binder%': '0',
       'USE_dbus%': '1',
       'USE_hwid_override%': '0',
+      'USE_libcros%': '1',
       'USE_mtd%': '0',
       'USE_power_management%': '0',
       'USE_buffet%': '0',
@@ -52,6 +53,7 @@
       'USE_BINDER=<(USE_binder)',
       'USE_DBUS=<(USE_dbus)',
       'USE_HWID_OVERRIDE=<(USE_hwid_override)',
+      'USE_LIBCROS=<(USE_libcros)',
       'USE_MTD=<(USE_mtd)',
       'USE_POWER_MANAGEMENT=<(USE_power_management)',
       'USE_WEAVE=<(USE_buffet)',
@@ -246,7 +248,6 @@
       },
       'sources': [
         'boot_control_chromeos.cc',
-        'chrome_browser_proxy_resolver.cc',
         'common_service.cc',
         'connection_manager.cc',
         'daemon.cc',
@@ -293,6 +294,14 @@
             ],
           },
         }],
+        ['USE_libcros == 1', {
+          'dependencies': [
+            'update_engine-other-dbus-proxies',
+          ],
+          'sources': [
+            'chrome_browser_proxy_resolver.cc',
+          ],
+        }],
       ],
     },
     # update_engine daemon.
@@ -333,8 +342,9 @@
         'libupdate_engine_client',
       ],
       'sources': [
+        'common/error_code_utils.cc',
         'update_engine_client.cc',
-      ],
+     ],
     },
     # server-side code. This is used for delta_generator and unittests but not
     # for any client code.
@@ -440,8 +450,8 @@
         {
           'target_name': 'test_http_server',
           'type': 'executable',
-          'dependencies': ['libupdate_engine'],
           'sources': [
+            'common/http_common.cc',
             'test_http_server.cc',
           ],
         },
@@ -467,7 +477,6 @@
           'includes': ['../../../platform2/common-mk/common_test.gypi'],
           'sources': [
             'boot_control_chromeos_unittest.cc',
-            'chrome_browser_proxy_resolver_unittest.cc',
             'common/action_pipe_unittest.cc',
             'common/action_processor_unittest.cc',
             'common/action_unittest.cc',
@@ -539,6 +548,13 @@
             # Main entry point for runnning tests.
             'testrunner.cc',
           ],
+          'conditions': [
+            ['USE_libcros == 1', {
+              'sources': [
+                'chrome_browser_proxy_resolver_unittest.cc',
+              ],
+            }],
+          ],
         },
       ],
     }],
diff --git a/update_engine_client.cc b/update_engine_client.cc
index eabc546..22fe6a6 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -29,12 +29,15 @@
 #include <brillo/daemons/daemon.h>
 #include <brillo/flag_helper.h>
 
+#include "update_engine/common/error_code.h"
+#include "update_engine/common/error_code_utils.h"
 #include "update_engine/client.h"
 #include "update_engine/status_update_handler.h"
 #include "update_engine/update_status.h"
 #include "update_engine/update_status_utils.h"
 
 using chromeos_update_engine::UpdateStatusToString;
+using chromeos_update_engine::ErrorCode;
 using std::string;
 using std::unique_ptr;
 using std::vector;
@@ -262,6 +265,7 @@
               "Listen for status updates and print them to the screen.");
   DEFINE_bool(prev_version, false,
               "Show the previous OS version used before the update reboot.");
+  DEFINE_bool(last_attempt_error, false, "Show the last attempt error.");
 
   // Boilerplate init commands.
   base::CommandLine::Init(argc_, argv_);
@@ -509,6 +513,19 @@
     return kContinueRunning;
   }
 
+  if (FLAGS_last_attempt_error) {
+    int last_attempt_error;
+    if (!client_->GetLastAttemptError(&last_attempt_error)) {
+      LOG(ERROR) << "Error getting last attempt error.";
+    } else {
+      ErrorCode code = static_cast<ErrorCode>(last_attempt_error);
+      string error_msg = chromeos_update_engine::utils::ErrorCodeToString(code);
+      printf("ERROR_CODE=%i\n"
+             "ERROR_MESSAGE=%s\n",
+             last_attempt_error, error_msg.c_str());
+    }
+ }
+
   return 0;
 }
 
diff --git a/update_manager/update_manager_unittest.cc b/update_manager/update_manager_unittest.cc
index 4cc738d..03f1610 100644
--- a/update_manager/update_manager_unittest.cc
+++ b/update_manager/update_manager_unittest.cc
@@ -253,9 +253,9 @@
 
   umut_->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
   // The callback should wait until we run the main loop for it to be executed.
-  EXPECT_EQ(0, calls.size());
+  EXPECT_EQ(0U, calls.size());
   MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-  EXPECT_EQ(1, calls.size());
+  EXPECT_EQ(1U, calls.size());
 }
 
 TEST_F(UmUpdateManagerTest, AsyncPolicyRequestTimeoutDoesNotFire) {
@@ -273,14 +273,14 @@
   // to the default.
   MessageLoopRunMaxIterations(MessageLoop::current(), 100);
   EXPECT_EQ(1, num_called);
-  ASSERT_EQ(1, calls.size());
+  ASSERT_EQ(1U, calls.size());
   EXPECT_EQ(EvalStatus::kSucceeded, calls[0].first);
   // Wait for the timeout to expire, run the main loop again, ensure that
   // nothing happened.
   test_clock_.Advance(TimeDelta::FromSeconds(2));
   MessageLoopRunMaxIterations(MessageLoop::current(), 10);
   EXPECT_EQ(1, num_called);
-  EXPECT_EQ(1, calls.size());
+  EXPECT_EQ(1U, calls.size());
 }
 
 TEST_F(UmUpdateManagerTest, AsyncPolicyRequestTimesOut) {
@@ -301,7 +301,7 @@
   // was not invoked.
   MessageLoopRunMaxIterations(MessageLoop::current(), 100);
   EXPECT_EQ(1, num_called);
-  EXPECT_EQ(0, calls.size());
+  EXPECT_EQ(0U, calls.size());
   // Wait for the expiration timeout to expire, run the main loop again,
   // ensure that reevaluation occurred but callback was not invoked (i.e.
   // default policy was not consulted).
@@ -310,7 +310,7 @@
                                TimeDelta::FromSeconds(2));
   MessageLoopRunMaxIterations(MessageLoop::current(), 10);
   EXPECT_EQ(2, num_called);
-  EXPECT_EQ(0, calls.size());
+  EXPECT_EQ(0U, calls.size());
   // Wait for reevaluation due to delay to happen, ensure that it occurs and
   // that the callback is invoked.
   test_clock_.Advance(TimeDelta::FromSeconds(2));
@@ -318,7 +318,7 @@
                                TimeDelta::FromSeconds(2));
   MessageLoopRunMaxIterations(MessageLoop::current(), 10);
   EXPECT_EQ(3, num_called);
-  ASSERT_EQ(1, calls.size());
+  ASSERT_EQ(1U, calls.size());
   EXPECT_EQ(EvalStatus::kSucceeded, calls[0].first);
 }
 
diff --git a/update_manager/variable_unittest.cc b/update_manager/variable_unittest.cc
index 13cceb1..144002a 100644
--- a/update_manager/variable_unittest.cc
+++ b/update_manager/variable_unittest.cc
@@ -99,13 +99,13 @@
   DefaultVariable<int> var("var", kVariableModeAsync);
   BaseVariableObserver observer;
   var.AddObserver(&observer);
-  EXPECT_EQ(var.observer_list_.size(), 1);
+  EXPECT_EQ(1U, var.observer_list_.size());
   var.AddObserver(&observer);
-  EXPECT_EQ(var.observer_list_.size(), 1);
+  EXPECT_EQ(1U, var.observer_list_.size());
   var.RemoveObserver(&observer);
-  EXPECT_EQ(var.observer_list_.size(), 0);
+  EXPECT_EQ(0U, var.observer_list_.size());
   var.RemoveObserver(&observer);
-  EXPECT_EQ(var.observer_list_.size(), 0);
+  EXPECT_EQ(0U, var.observer_list_.size());
 }
 
 TEST_F(UmBaseVariableTest, NotifyValueChangedTest) {
@@ -114,10 +114,10 @@
   var.AddObserver(&observer1);
   // Simulate a value change on the variable's implementation.
   var.NotifyValueChanged();
-  ASSERT_EQ(0, observer1.calls_.size());
+  ASSERT_EQ(0U, observer1.calls_.size());
   MessageLoopRunMaxIterations(MessageLoop::current(), 100);
 
-  ASSERT_EQ(1, observer1.calls_.size());
+  ASSERT_EQ(1U, observer1.calls_.size());
   // Check that the observer is called with the right argument.
   EXPECT_EQ(&var, observer1.calls_[0]);
 
@@ -127,8 +127,8 @@
   MessageLoopRunMaxIterations(MessageLoop::current(), 100);
 
   // Check that all the observers are called.
-  EXPECT_EQ(2, observer1.calls_.size());
-  EXPECT_EQ(1, observer2.calls_.size());
+  EXPECT_EQ(2U, observer1.calls_.size());
+  EXPECT_EQ(1U, observer2.calls_.size());
 
   var.RemoveObserver(&observer1);
   var.RemoveObserver(&observer2);