Merge remote-tracking branch 'aosp/upstream-master' into merge

It's a merge from chrome OS with some reverts.
1. the fd watcher change, because the libbrillo version isn't
compatible in aosp.
commit 6955bcc4ffe4cc9d62a88186b9a7e75d095a7897
commit 493fecb3f48c8478fd3ef244d631d857730dd14d
2. two libcurl unittest. Because the RunOnce() of the fake message
loop seems to have different behavior in aosp.
commit d3d84218cafbc1a95e7d6bbb775b495d1bebf4d2

Put preprocessor guards to use the old code in aosp. And we can
switch to the new code in the other path after adopting the new
libbrillo & libchrome.

Test: unit tests pass, apply an OTA
Change-Id: Id613599834b0f44f92841dbeae6303601db5490d
diff --git a/common/constants.cc b/common/constants.cc
index 5bfb2b6..fa13a38 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -18,6 +18,10 @@
 
 namespace chromeos_update_engine {
 
+const char kExclusionPrefsSubDir[] = "exclusion";
+
+const char kDlcPrefsSubDir[] = "dlc";
+
 const char kPowerwashSafePrefsSubDirectory[] = "update_engine/prefs";
 
 const char kPrefsSubDirectory[] = "prefs";
@@ -55,11 +59,16 @@
 const char kPrefsOmahaCohort[] = "omaha-cohort";
 const char kPrefsOmahaCohortHint[] = "omaha-cohort-hint";
 const char kPrefsOmahaCohortName[] = "omaha-cohort-name";
-const char kPrefsOmahaEolStatus[] = "omaha-eol-status";
+const char kPrefsOmahaEolDate[] = "omaha-eol-date";
 const char kPrefsP2PEnabled[] = "p2p-enabled";
 const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp";
 const char kPrefsP2PNumAttempts[] = "p2p-num-attempts";
 const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number";
+// Keep |kPrefsPingActive| in sync with |kDlcMetadataFilePingActive| in
+// dlcservice.
+const char kPrefsPingActive[] = "active";
+const char kPrefsPingLastActive[] = "date_last_active";
+const char kPrefsPingLastRollcall[] = "date_last_rollcall";
 const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
 const char kPrefsPreviousVersion[] = "previous-version";
 const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
@@ -123,4 +132,12 @@
 // The default is 1 (always run post install).
 const char kPayloadPropertyRunPostInstall[] = "RUN_POST_INSTALL";
 
+const char kOmahaUpdaterVersion[] = "0.1.0.0";
+
+// X-Goog-Update headers.
+const char kXGoogleUpdateInteractivity[] = "X-Goog-Update-Interactivity";
+const char kXGoogleUpdateAppId[] = "X-Goog-Update-AppId";
+const char kXGoogleUpdateUpdater[] = "X-Goog-Update-Updater";
+const char kXGoogleUpdateSessionId[] = "X-Goog-SessionId";
+
 }  // namespace chromeos_update_engine
diff --git a/common/constants.h b/common/constants.h
index af1c0ab..eb489fc 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -19,6 +19,12 @@
 
 namespace chromeos_update_engine {
 
+// The root path of all exclusion prefs.
+extern const char kExclusionPrefsSubDir[];
+
+// The root path of all DLC metadata.
+extern const char kDlcPrefsSubDir[];
+
 // Directory for AU prefs that are preserved across powerwash.
 extern const char kPowerwashSafePrefsSubDirectory[];
 
@@ -56,11 +62,14 @@
 extern const char kPrefsOmahaCohort[];
 extern const char kPrefsOmahaCohortHint[];
 extern const char kPrefsOmahaCohortName[];
-extern const char kPrefsOmahaEolStatus[];
+extern const char kPrefsOmahaEolDate[];
 extern const char kPrefsP2PEnabled[];
 extern const char kPrefsP2PFirstAttemptTimestamp[];
 extern const char kPrefsP2PNumAttempts[];
 extern const char kPrefsPayloadAttemptNumber[];
+extern const char kPrefsPingActive[];
+extern const char kPrefsPingLastActive[];
+extern const char kPrefsPingLastRollcall[];
 extern const char kPrefsPostInstallSucceeded[];
 extern const char kPrefsPreviousVersion[];
 extern const char kPrefsResumedUpdateFailures[];
@@ -108,6 +117,14 @@
 extern const char kPayloadPropertySwitchSlotOnReboot[];
 extern const char kPayloadPropertyRunPostInstall[];
 
+extern const char kOmahaUpdaterVersion[];
+
+// X-Goog-Update headers.
+extern const char kXGoogleUpdateInteractivity[];
+extern const char kXGoogleUpdateAppId[];
+extern const char kXGoogleUpdateUpdater[];
+extern const char kXGoogleUpdateSessionId[];
+
 // A download source is any combination of protocol and server (that's of
 // interest to us when looking at UMA metrics) using which we may download
 // the payload.
diff --git a/common/cpu_limiter.cc b/common/cpu_limiter.cc
index 1d14764..5f1ae6f 100644
--- a/common/cpu_limiter.cc
+++ b/common/cpu_limiter.cc
@@ -67,7 +67,7 @@
   if (shares_ == shares)
     return true;
 
-  std::string string_shares = base::IntToString(static_cast<int>(shares));
+  std::string string_shares = base::NumberToString(static_cast<int>(shares));
   LOG(INFO) << "Setting cgroup cpu shares to  " << string_shares;
   if (!utils::WriteFile(
           kCGroupSharesPath, string_shares.c_str(), string_shares.size())) {
diff --git a/common/cpu_limiter.h b/common/cpu_limiter.h
index c7add89..e6d7331 100644
--- a/common/cpu_limiter.h
+++ b/common/cpu_limiter.h
@@ -30,10 +30,6 @@
   kLow = 2,
 };
 
-// Sets the current process shares to |shares|. Returns true on
-// success, false otherwise.
-bool SetCpuShares(CpuShares shares);
-
 class CPULimiter {
  public:
   CPULimiter() = default;
diff --git a/common/dlcservice.h b/common/dlcservice.h
deleted file mode 100644
index 9dae560..0000000
--- a/common/dlcservice.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// Copyright (C) 2018 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_COMMON_DLCSERVICE_H_
-#define UPDATE_ENGINE_COMMON_DLCSERVICE_H_
-
-#include <memory>
-
-#include "update_engine/common/dlcservice_interface.h"
-
-namespace chromeos_update_engine {
-
-// This factory function creates a new DlcServiceInterface instance for the
-// current platform.
-std::unique_ptr<DlcServiceInterface> CreateDlcService();
-
-}  // namespace chromeos_update_engine
-
-#endif  // UPDATE_ENGINE_COMMON_DLCSERVICE_H_
diff --git a/common/dlcservice_interface.h b/common/dlcservice_interface.h
index aa24105..7b57710 100644
--- a/common/dlcservice_interface.h
+++ b/common/dlcservice_interface.h
@@ -17,6 +17,7 @@
 #ifndef UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
 #define UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -30,9 +31,17 @@
  public:
   virtual ~DlcServiceInterface() = default;
 
-  // Returns true and a list of installed DLC module ids in |dlc_module_ids|.
+  // Returns true and a list of installed DLC ids in |dlc_ids|.
   // On failure it returns false.
-  virtual bool GetInstalled(std::vector<std::string>* dlc_module_ids) = 0;
+  virtual bool GetDlcsToUpdate(std::vector<std::string>* dlc_ids) = 0;
+
+  // Returns true if dlcservice successfully handled the install completion
+  // method call, otherwise false.
+  virtual bool InstallCompleted(const std::vector<std::string>& dlc_ids) = 0;
+
+  // Returns true if dlcservice successfully handled the update completion
+  // method call, otherwise false.
+  virtual bool UpdateCompleted(const std::vector<std::string>& dlc_ids) = 0;
 
  protected:
   DlcServiceInterface() = default;
@@ -41,6 +50,10 @@
   DISALLOW_COPY_AND_ASSIGN(DlcServiceInterface);
 };
 
+// This factory function creates a new DlcServiceInterface instance for the
+// current platform.
+std::unique_ptr<DlcServiceInterface> CreateDlcService();
+
 }  // namespace chromeos_update_engine
 
 #endif  // UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
diff --git a/common/dlcservice_stub.cc b/common/dlcservice_stub.cc
index c5f9306..2447147 100644
--- a/common/dlcservice_stub.cc
+++ b/common/dlcservice_stub.cc
@@ -27,9 +27,16 @@
   return std::make_unique<DlcServiceStub>();
 }
 
-bool DlcServiceStub::GetInstalled(std::vector<std::string>* dlc_module_ids) {
-  if (dlc_module_ids)
-    dlc_module_ids->clear();
+bool DlcServiceStub::GetDlcsToUpdate(vector<string>* dlc_ids) {
+  if (dlc_ids)
+    dlc_ids->clear();
+  return true;
+}
+
+bool DlcServiceStub::InstallCompleted(const vector<string>& dlc_ids) {
+  return true;
+}
+bool DlcServiceStub::UpdateCompleted(const vector<string>& dlc_ids) {
   return true;
 }
 
diff --git a/common/dlcservice_stub.h b/common/dlcservice_stub.h
index 4e12c11..bc803e8 100644
--- a/common/dlcservice_stub.h
+++ b/common/dlcservice_stub.h
@@ -31,7 +31,9 @@
   ~DlcServiceStub() = default;
 
   // BootControlInterface overrides.
-  bool GetInstalled(std::vector<std::string>* dlc_module_ids) override;
+  bool GetDlcsToUpdate(std::vector<std::string>* dlc_ids) override;
+  bool InstallCompleted(const std::vector<std::string>& dlc_ids) override;
+  bool UpdateCompleted(const std::vector<std::string>& dlc_ids) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DlcServiceStub);
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index 3fbf0fe..64df24a 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -175,7 +175,7 @@
       // error codes which should be added here.
   }
 
-  return "Unknown error: " + base::UintToString(static_cast<unsigned>(code));
+  return "Unknown error: " + base::NumberToString(static_cast<unsigned>(code));
 }
 
 }  // namespace utils
diff --git a/common/excluder_interface.h b/common/excluder_interface.h
new file mode 100644
index 0000000..3985bba
--- /dev/null
+++ b/common/excluder_interface.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2020 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_COMMON_EXCLUDER_INTERFACE_H_
+#define UPDATE_ENGINE_COMMON_EXCLUDER_INTERFACE_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+namespace chromeos_update_engine {
+
+class PrefsInterface;
+
+class ExcluderInterface {
+ public:
+  virtual ~ExcluderInterface() = default;
+
+  // Returns true on successfuly excluding |name|, otherwise false. On a
+  // successful |Exclude()| the passed in |name| will be considered excluded
+  // and calls to |IsExcluded()| will return true. The exclusions are persisted.
+  virtual bool Exclude(const std::string& name) = 0;
+
+  // Returns true if |name| reached the exclusion limit, otherwise false.
+  virtual bool IsExcluded(const std::string& name) = 0;
+
+  // Returns true on sucessfully reseting the entire exclusion state, otherwise
+  // false. On a successful |Reset()| there will be no excluded |name| in the
+  // exclusion state.
+  virtual bool Reset() = 0;
+
+  // Not copyable or movable
+  ExcluderInterface(const ExcluderInterface&) = delete;
+  ExcluderInterface& operator=(const ExcluderInterface&) = delete;
+  ExcluderInterface(ExcluderInterface&&) = delete;
+  ExcluderInterface& operator=(ExcluderInterface&&) = delete;
+
+ protected:
+  ExcluderInterface() = default;
+};
+
+std::unique_ptr<ExcluderInterface> CreateExcluder(PrefsInterface* prefs);
+
+}  // namespace chromeos_update_engine
+
+#endif  // UPDATE_ENGINE_COMMON_EXCLUDER_INTERFACE_H_
diff --git a/common/excluder_stub.cc b/common/excluder_stub.cc
new file mode 100644
index 0000000..a251765
--- /dev/null
+++ b/common/excluder_stub.cc
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/common/excluder_stub.h"
+
+#include <memory>
+
+#include "update_engine/common/prefs_interface.h"
+
+using std::string;
+
+namespace chromeos_update_engine {
+
+std::unique_ptr<ExcluderInterface> CreateExcluder(PrefsInterface* prefs) {
+  return std::make_unique<ExcluderStub>();
+}
+
+bool ExcluderStub::Exclude(const string& name) {
+  return true;
+}
+
+bool ExcluderStub::IsExcluded(const string& name) {
+  return false;
+}
+
+bool ExcluderStub::Reset() {
+  return true;
+}
+
+}  // namespace chromeos_update_engine
diff --git a/common/excluder_stub.h b/common/excluder_stub.h
new file mode 100644
index 0000000..2d5372a
--- /dev/null
+++ b/common/excluder_stub.h
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2020 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_COMMON_EXCLUDER_STUB_H_
+#define UPDATE_ENGINE_COMMON_EXCLUDER_STUB_H_
+
+#include <string>
+
+#include "update_engine/common/excluder_interface.h"
+
+namespace chromeos_update_engine {
+
+// An implementation of the |ExcluderInterface| that does nothing.
+class ExcluderStub : public ExcluderInterface {
+ public:
+  ExcluderStub() = default;
+  ~ExcluderStub() = default;
+
+  // |ExcluderInterface| overrides.
+  bool Exclude(const std::string& name) override;
+  bool IsExcluded(const std::string& name) override;
+  bool Reset() override;
+
+  // Not copyable or movable.
+  ExcluderStub(const ExcluderStub&) = delete;
+  ExcluderStub& operator=(const ExcluderStub&) = delete;
+  ExcluderStub(ExcluderStub&&) = delete;
+  ExcluderStub& operator=(ExcluderStub&&) = delete;
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // UPDATE_ENGINE_COMMON_EXCLUDER_STUB_H_
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 0b232da..2a8e81d 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -77,6 +77,10 @@
 
   std::string GetECVersion() const override { return ec_version_; }
 
+  std::string GetDeviceRequisition() const override {
+    return device_requisition_;
+  }
+
   int GetMinKernelKeyVersion() const override {
     return min_kernel_key_version_;
   }
@@ -104,15 +108,15 @@
 
   int GetPowerwashCount() const override { return powerwash_count_; }
 
-  bool SchedulePowerwash(bool is_rollback) override {
+  bool SchedulePowerwash(bool save_rollback_data) override {
     powerwash_scheduled_ = true;
-    is_rollback_powerwash_ = is_rollback;
+    save_rollback_data_ = save_rollback_data;
     return true;
   }
 
   bool CancelPowerwash() override {
     powerwash_scheduled_ = false;
-    is_rollback_powerwash_ = false;
+    save_rollback_data_ = false;
     return true;
   }
 
@@ -175,6 +179,10 @@
 
   void SetECVersion(const std::string& ec_version) { ec_version_ = ec_version; }
 
+  void SetDeviceRequisition(const std::string& requisition) {
+    device_requisition_ = requisition;
+  }
+
   void SetMinKernelKeyVersion(int min_kernel_key_version) {
     min_kernel_key_version_ = min_kernel_key_version;
   }
@@ -197,7 +205,7 @@
   int GetMaxKernelKeyRollforward() const { return kernel_max_rollforward_; }
 
   bool GetIsRollbackPowerwashScheduled() const {
-    return powerwash_scheduled_ && is_rollback_powerwash_;
+    return powerwash_scheduled_ && save_rollback_data_;
   }
 
  private:
@@ -211,13 +219,14 @@
   std::string hardware_class_{"Fake HWID BLAH-1234"};
   std::string firmware_version_{"Fake Firmware v1.0.1"};
   std::string ec_version_{"Fake EC v1.0a"};
+  std::string device_requisition_{"fake_requisition"};
   int min_kernel_key_version_{kMinKernelKeyVersion};
   int min_firmware_key_version_{kMinFirmwareKeyVersion};
   int kernel_max_rollforward_{kKernelMaxRollforward};
   int firmware_max_rollforward_{kFirmwareMaxRollforward};
   int powerwash_count_{kPowerwashCountNotSet};
   bool powerwash_scheduled_{false};
-  bool is_rollback_powerwash_{false};
+  bool save_rollback_data_{false};
   int64_t build_timestamp_{0};
   bool first_active_omaha_ping_sent_{false};
   bool warm_reset_{false};
diff --git a/common/fake_prefs.cc b/common/fake_prefs.cc
index c446e06..73559c5 100644
--- a/common/fake_prefs.cc
+++ b/common/fake_prefs.cc
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 
 using std::string;
+using std::vector;
 
 using chromeos_update_engine::FakePrefs;
 
@@ -105,6 +106,13 @@
   return true;
 }
 
+bool FakePrefs::GetSubKeys(const string& ns, vector<string>* keys) const {
+  for (const auto& pr : values_)
+    if (pr.first.compare(0, ns.length(), ns) == 0)
+      keys->push_back(pr.first);
+  return true;
+}
+
 string FakePrefs::GetTypeName(PrefType type) {
   switch (type) {
     case PrefType::kString:
diff --git a/common/fake_prefs.h b/common/fake_prefs.h
index b1c5b71..b24ff4d 100644
--- a/common/fake_prefs.h
+++ b/common/fake_prefs.h
@@ -49,6 +49,9 @@
   bool Exists(const std::string& key) const override;
   bool Delete(const std::string& key) override;
 
+  bool GetSubKeys(const std::string& ns,
+                  std::vector<std::string>* keys) const override;
+
   void AddObserver(const std::string& key,
                    ObserverInterface* observer) override;
   void RemoveObserver(const std::string& key,
diff --git a/common/file_fetcher.h b/common/file_fetcher.h
index fbdfc32..bd39007 100644
--- a/common/file_fetcher.h
+++ b/common/file_fetcher.h
@@ -59,6 +59,12 @@
   void SetHeader(const std::string& header_name,
                  const std::string& header_value) override {}
 
+  bool GetHeader(const std::string& header_name,
+                 std::string* header_value) const override {
+    header_value->clear();
+    return false;
+  }
+
   // Suspend the asynchronous file read.
   void Pause() override;
 
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index d92a6fc..4f0305f 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -70,6 +70,10 @@
   // running a custom chrome os ec.
   virtual std::string GetECVersion() const = 0;
 
+  // Returns the OEM device requisition or an empty string if the system does
+  // not have a requisition, or if not running Chrome OS.
+  virtual std::string GetDeviceRequisition() const = 0;
+
   // Returns the minimum kernel key version that verified boot on Chrome OS
   // will allow to boot. This is the value of crossystem tpm_kernver. Returns
   // -1 on error, or if not running on Chrome OS.
@@ -102,9 +106,9 @@
   virtual int GetPowerwashCount() const = 0;
 
   // Signals that a powerwash (stateful partition wipe) should be performed
-  // after reboot. If |is_rollback| is true additional state is preserved
-  // during shutdown that can be restored after the powerwash.
-  virtual bool SchedulePowerwash(bool is_rollback) = 0;
+  // after reboot. If |save_rollback_data| is true additional state is
+  // preserved during shutdown that can be restored after the powerwash.
+  virtual bool SchedulePowerwash(bool save_rollback_data) = 0;
 
   // Cancel the powerwash operation scheduled to be performed on next boot.
   virtual bool CancelPowerwash() = 0;
diff --git a/common/http_common.cc b/common/http_common.cc
index 5f234b0..c8bac47 100644
--- a/common/http_common.cc
+++ b/common/http_common.cc
@@ -21,6 +21,7 @@
 #include <cstdlib>
 
 #include <base/macros.h>
+#include <base/stl_util.h>
 
 namespace chromeos_update_engine {
 
@@ -56,7 +57,7 @@
 
   bool is_found = false;
   size_t i;
-  for (i = 0; i < arraysize(http_response_table); i++)
+  for (i = 0; i < base::size(http_response_table); i++)
     if ((is_found = (http_response_table[i].code == code)))
       break;
 
@@ -77,7 +78,7 @@
 
   bool is_found = false;
   size_t i;
-  for (i = 0; i < arraysize(http_content_type_table); i++)
+  for (i = 0; i < base::size(http_content_type_table); i++)
     if ((is_found = (http_content_type_table[i].type == type)))
       break;
 
diff --git a/common/http_fetcher.h b/common/http_fetcher.h
index 2b4fc83..f74a0f0 100644
--- a/common/http_fetcher.h
+++ b/common/http_fetcher.h
@@ -29,6 +29,7 @@
 
 #include "update_engine/common/http_common.h"
 #include "update_engine/common/proxy_resolver.h"
+#include "update_engine/metrics_constants.h"
 
 // This class is a simple wrapper around an HTTP library (libcurl). We can
 // easily mock out this interface for testing.
@@ -58,6 +59,12 @@
   HttpFetcherDelegate* delegate() const { return delegate_; }
   int http_response_code() const { return http_response_code_; }
 
+  // Returns additional error code that can't be expressed in terms of an HTTP
+  // response code. For example, if there was a specific internal error code in
+  // the objects used in the implementation of this class (like libcurl) that we
+  // are interested about, we can communicate it through this value.
+  ErrorCode GetAuxiliaryErrorCode() const { return auxiliary_error_code_; }
+
   // Optional: Post data to the server. The HttpFetcher should make a copy
   // of this data and upload it via HTTP POST during the transfer. The type of
   // the data is necessary for properly setting the Content-Type HTTP header.
@@ -99,6 +106,14 @@
   virtual void SetHeader(const std::string& header_name,
                          const std::string& header_value) = 0;
 
+  // Only used for testing.
+  // If |header_name| is set, the value will be set into |header_value|.
+  // On success the boolean true will be returned, hoewever on failture to find
+  // the |header_name| in the header the return value will be false. The state
+  // in which |header_value| is left in for failures is an empty string.
+  virtual bool GetHeader(const std::string& header_name,
+                         std::string* header_value) const = 0;
+
   // If data is coming in too quickly, you can call Pause() to pause the
   // transfer. The delegate will not have ReceivedBytes() called while
   // an HttpFetcher is paused.
@@ -150,6 +165,10 @@
   // set to the response code when the transfer is complete.
   int http_response_code_;
 
+  // Set when there is an error that can't be expressed in the form of
+  // |http_response_code_|.
+  ErrorCode auxiliary_error_code_{ErrorCode::kSuccess};
+
   // The delegate; may be null.
   HttpFetcherDelegate* delegate_;
 
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 237ea20..589579e 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -29,6 +29,7 @@
 #include <base/location.h>
 #include <base/logging.h>
 #include <base/message_loop/message_loop.h>
+#include <base/stl_util.h>
 #include <base/strings/string_number_conversions.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
@@ -1049,7 +1050,7 @@
   unique_ptr<HttpServer> server(this->test_.CreateServer());
   ASSERT_TRUE(server->started_);
 
-  for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
+  for (size_t c = 0; c < base::size(kRedirectCodes); ++c) {
     const string url = base::StringPrintf(
         "/redirect/%d/download/%d", kRedirectCodes[c], kMediumLength);
     RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
@@ -1066,7 +1067,7 @@
   string url;
   for (int r = 0; r < kDownloadMaxRedirects; r++) {
     url += base::StringPrintf("/redirect/%d",
-                              kRedirectCodes[r % arraysize(kRedirectCodes)]);
+                              kRedirectCodes[r % base::size(kRedirectCodes)]);
   }
   url += base::StringPrintf("/download/%d", kMediumLength);
   RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
@@ -1082,7 +1083,7 @@
   string url;
   for (int r = 0; r < kDownloadMaxRedirects + 1; r++) {
     url += base::StringPrintf("/redirect/%d",
-                              kRedirectCodes[r % arraysize(kRedirectCodes)]);
+                              kRedirectCodes[r % base::size(kRedirectCodes)]);
   }
   url += base::StringPrintf("/download/%d", kMediumLength);
   RedirectTest(server.get(), false, url, this->test_.NewLargeFetcher());
diff --git a/common/hwid_override.cc b/common/hwid_override.cc
index 8800e94..1bb0f8f 100644
--- a/common/hwid_override.cc
+++ b/common/hwid_override.cc
@@ -16,14 +16,12 @@
 
 #include "update_engine/common/hwid_override.h"
 
-#include <map>
 #include <string>
 
 #include <base/files/file_path.h>
 #include <base/files/file_util.h>
 #include <brillo/key_value_store.h>
 
-using std::map;
 using std::string;
 
 namespace chromeos_update_engine {
diff --git a/common/mock_excluder.h b/common/mock_excluder.h
new file mode 100644
index 0000000..bc54772
--- /dev/null
+++ b/common/mock_excluder.h
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2020 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_APP_EXCLUDER_H_
+#define UPDATE_ENGINE_MOCK_APP_EXCLUDER_H_
+
+#include "update_engine/common/excluder_interface.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+namespace chromeos_update_engine {
+
+class MockExcluder : public ExcluderInterface {
+ public:
+  MOCK_METHOD(bool, Exclude, (const std::string&), (override));
+  MOCK_METHOD(bool, IsExcluded, (const std::string&), (override));
+  MOCK_METHOD(bool, Reset, (), (override));
+};
+
+}  // namespace chromeos_update_engine
+
+#endif  // UPDATE_ENGINE_MOCK_APP_EXCLUDER_H_
diff --git a/common/mock_http_fetcher.h b/common/mock_http_fetcher.h
index 492e6ce..0f04319 100644
--- a/common/mock_http_fetcher.h
+++ b/common/mock_http_fetcher.h
@@ -89,6 +89,12 @@
   void SetHeader(const std::string& header_name,
                  const std::string& header_value) override;
 
+  bool GetHeader(const std::string& header_name,
+                 std::string* header_value) const override {
+    header_value->clear();
+    return false;
+  }
+
   // Return the value of the header |header_name| or the empty string if not
   // set.
   std::string GetHeader(const std::string& header_name) const;
diff --git a/common/mock_prefs.h b/common/mock_prefs.h
index 2582e19..62417a8 100644
--- a/common/mock_prefs.h
+++ b/common/mock_prefs.h
@@ -18,6 +18,7 @@
 #define UPDATE_ENGINE_COMMON_MOCK_PREFS_H_
 
 #include <string>
+#include <vector>
 
 #include <gmock/gmock.h>
 
@@ -41,6 +42,9 @@
   MOCK_CONST_METHOD1(Exists, bool(const std::string& key));
   MOCK_METHOD1(Delete, bool(const std::string& key));
 
+  MOCK_CONST_METHOD2(GetSubKeys,
+                     bool(const std::string&, std::vector<std::string>*));
+
   MOCK_METHOD2(AddObserver, void(const std::string& key, ObserverInterface*));
   MOCK_METHOD2(RemoveObserver,
                void(const std::string& key, ObserverInterface*));
diff --git a/common/multi_range_http_fetcher.h b/common/multi_range_http_fetcher.h
index f57ea7f..ef32f0d 100644
--- a/common/multi_range_http_fetcher.h
+++ b/common/multi_range_http_fetcher.h
@@ -83,6 +83,11 @@
     base_fetcher_->SetHeader(header_name, header_value);
   }
 
+  bool GetHeader(const std::string& header_name,
+                 std::string* header_value) const override {
+    return base_fetcher_->GetHeader(header_name, header_value);
+  }
+
   void Pause() override { base_fetcher_->Pause(); }
 
   void Unpause() override { base_fetcher_->Unpause(); }
diff --git a/common/prefs.cc b/common/prefs.cc
index 12d06c0..615014f 100644
--- a/common/prefs.cc
+++ b/common/prefs.cc
@@ -18,17 +18,37 @@
 
 #include <algorithm>
 
+#include <base/files/file_enumerator.h>
 #include <base/files/file_util.h>
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 
 #include "update_engine/common/utils.h"
 
 using std::string;
+using std::vector;
 
 namespace chromeos_update_engine {
 
+namespace {
+
+const char kKeySeparator = '/';
+
+void DeleteEmptyDirectories(const base::FilePath& path) {
+  base::FileEnumerator path_enum(
+      path, false /* recursive */, base::FileEnumerator::DIRECTORIES);
+  for (base::FilePath dir_path = path_enum.Next(); !dir_path.empty();
+       dir_path = path_enum.Next()) {
+    DeleteEmptyDirectories(dir_path);
+    if (base::IsDirectoryEmpty(dir_path))
+      base::DeleteFile(dir_path, false);
+  }
+}
+
+}  // namespace
+
 bool PrefsBase::GetString(const string& key, string* value) const {
   return storage_->GetKey(key, value);
 }
@@ -54,7 +74,7 @@
 }
 
 bool PrefsBase::SetInt64(const string& key, const int64_t value) {
-  return SetString(key, base::Int64ToString(value));
+  return SetString(key, base::NumberToString(value));
 }
 
 bool PrefsBase::GetBoolean(const string& key, bool* value) const {
@@ -92,6 +112,10 @@
   return true;
 }
 
+bool PrefsBase::GetSubKeys(const string& ns, vector<string>* keys) const {
+  return storage_->GetSubKeys(ns, keys);
+}
+
 void PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
   observers_[key].push_back(observer);
 }
@@ -104,6 +128,10 @@
     observers_for_key.erase(observer_it);
 }
 
+string PrefsInterface::CreateSubKey(const vector<string>& ns_and_key) {
+  return base::JoinString(ns_and_key, string(1, kKeySeparator));
+}
+
 // Prefs
 
 bool Prefs::Init(const base::FilePath& prefs_dir) {
@@ -112,6 +140,8 @@
 
 bool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
   prefs_dir_ = prefs_dir;
+  // Delete empty directories. Ignore errors when deleting empty directories.
+  DeleteEmptyDirectories(prefs_dir_);
   return true;
 }
 
@@ -119,12 +149,29 @@
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
   if (!base::ReadFileToString(filename, value)) {
-    LOG(INFO) << key << " not present in " << prefs_dir_.value();
     return false;
   }
   return true;
 }
 
+bool Prefs::FileStorage::GetSubKeys(const string& ns,
+                                    vector<string>* keys) const {
+  base::FilePath filename;
+  TEST_AND_RETURN_FALSE(GetFileNameForKey(ns, &filename));
+  base::FileEnumerator namespace_enum(
+      prefs_dir_, true, base::FileEnumerator::FILES);
+  for (base::FilePath f = namespace_enum.Next(); !f.empty();
+       f = namespace_enum.Next()) {
+    auto filename_str = filename.value();
+    if (f.value().compare(0, filename_str.length(), filename_str) == 0) {
+      // Only return the key portion excluding the |prefs_dir_| with slash.
+      keys->push_back(f.value().substr(
+          prefs_dir_.AsEndingWithSeparator().value().length()));
+    }
+  }
+  return true;
+}
+
 bool Prefs::FileStorage::SetKey(const string& key, const string& value) {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
@@ -153,13 +200,11 @@
 
 bool Prefs::FileStorage::GetFileNameForKey(const string& key,
                                            base::FilePath* filename) const {
-  // Allows only non-empty keys containing [A-Za-z0-9_-].
+  // Allows only non-empty keys containing [A-Za-z0-9_-/].
   TEST_AND_RETURN_FALSE(!key.empty());
-  for (size_t i = 0; i < key.size(); ++i) {
-    char c = key.at(i);
+  for (char c : key)
     TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
-                          c == '_' || c == '-');
-  }
+                          c == '_' || c == '-' || c == kKeySeparator);
   *filename = prefs_dir_.Append(key);
   return true;
 }
@@ -175,6 +220,24 @@
   return true;
 }
 
+bool MemoryPrefs::MemoryStorage::GetSubKeys(const string& ns,
+                                            vector<string>* keys) const {
+  using value_type = decltype(values_)::value_type;
+  using key_type = decltype(values_)::key_type;
+  auto lower_comp = [](const value_type& pr, const key_type& ns) {
+    return pr.first.substr(0, ns.length()) < ns;
+  };
+  auto upper_comp = [](const key_type& ns, const value_type& pr) {
+    return ns < pr.first.substr(0, ns.length());
+  };
+  auto lower_it =
+      std::lower_bound(begin(values_), end(values_), ns, lower_comp);
+  auto upper_it = std::upper_bound(lower_it, end(values_), ns, upper_comp);
+  while (lower_it != upper_it)
+    keys->push_back((lower_it++)->first);
+  return true;
+}
+
 bool MemoryPrefs::MemoryStorage::SetKey(const string& key,
                                         const string& value) {
   values_[key] = value;
@@ -187,9 +250,8 @@
 
 bool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
   auto it = values_.find(key);
-  if (it == values_.end())
-    return false;
-  values_.erase(it);
+  if (it != values_.end())
+    values_.erase(it);
   return true;
 }
 
diff --git a/common/prefs.h b/common/prefs.h
index 0116454..3fc1d89 100644
--- a/common/prefs.h
+++ b/common/prefs.h
@@ -42,6 +42,11 @@
     // Returns whether the operation succeeded.
     virtual bool GetKey(const std::string& key, std::string* value) const = 0;
 
+    // Get the keys stored within the namespace. If there are no keys in the
+    // namespace, |keys| will be empty. Returns whether the operation succeeded.
+    virtual bool GetSubKeys(const std::string& ns,
+                            std::vector<std::string>* keys) const = 0;
+
     // Set the value of the key named |key| to |value| regardless of the
     // previous value. Returns whether the operation succeeded.
     virtual bool SetKey(const std::string& key, const std::string& value) = 0;
@@ -70,6 +75,9 @@
   bool Exists(const std::string& key) const override;
   bool Delete(const std::string& key) override;
 
+  bool GetSubKeys(const std::string& ns,
+                  std::vector<std::string>* keys) const override;
+
   void AddObserver(const std::string& key,
                    ObserverInterface* observer) override;
   void RemoveObserver(const std::string& key,
@@ -111,6 +119,8 @@
 
     // PrefsBase::StorageInterface overrides.
     bool GetKey(const std::string& key, std::string* value) const override;
+    bool GetSubKeys(const std::string& ns,
+                    std::vector<std::string>* keys) const override;
     bool SetKey(const std::string& key, const std::string& value) override;
     bool KeyExists(const std::string& key) const override;
     bool DeleteKey(const std::string& key) override;
@@ -149,6 +159,8 @@
 
     // PrefsBase::StorageInterface overrides.
     bool GetKey(const std::string& key, std::string* value) const override;
+    bool GetSubKeys(const std::string& ns,
+                    std::vector<std::string>* keys) const override;
     bool SetKey(const std::string& key, const std::string& value) override;
     bool KeyExists(const std::string& key) const override;
     bool DeleteKey(const std::string& key) override;
diff --git a/common/prefs_interface.h b/common/prefs_interface.h
index 03ae3ec..1311cb4 100644
--- a/common/prefs_interface.h
+++ b/common/prefs_interface.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <vector>
 
 namespace chromeos_update_engine {
 
@@ -79,6 +80,13 @@
   // this key. Calling with non-existent keys does nothing.
   virtual bool Delete(const std::string& key) = 0;
 
+  // Creates a key which is part of a sub preference.
+  static std::string CreateSubKey(const std::vector<std::string>& ns_with_key);
+
+  // Returns a list of keys within the namespace.
+  virtual bool GetSubKeys(const std::string& ns,
+                          std::vector<std::string>* keys) const = 0;
+
   // Add an observer to watch whenever the given |key| is modified. The
   // OnPrefSet() and OnPrefDelete() methods will be called whenever any of the
   // Set*() methods or the Delete() method are called on the given key,
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index cb6fc70..6dd26c0 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -20,6 +20,7 @@
 
 #include <limits>
 #include <string>
+#include <vector>
 
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
@@ -30,8 +31,11 @@
 #include <gtest/gtest.h>
 
 using std::string;
+using std::vector;
 using testing::_;
+using testing::ElementsAre;
 using testing::Eq;
+using testing::UnorderedElementsAre;
 
 namespace {
 // Test key used along the tests.
@@ -40,12 +44,92 @@
 
 namespace chromeos_update_engine {
 
-class PrefsTest : public ::testing::Test {
+class BasePrefsTest : public ::testing::Test {
+ protected:
+  void MultiNamespaceKeyTest() {
+    ASSERT_TRUE(common_prefs_);
+    auto key0 = common_prefs_->CreateSubKey({"ns1", "key"});
+    // Corner case for "ns1".
+    auto key0corner = common_prefs_->CreateSubKey({"ns11", "key"});
+    auto key1A = common_prefs_->CreateSubKey({"ns1", "nsA", "keyA"});
+    auto key1B = common_prefs_->CreateSubKey({"ns1", "nsA", "keyB"});
+    auto key2 = common_prefs_->CreateSubKey({"ns1", "nsB", "key"});
+    // Corner case for "ns1/nsB".
+    auto key2corner = common_prefs_->CreateSubKey({"ns1", "nsB1", "key"});
+    EXPECT_FALSE(common_prefs_->Exists(key0));
+    EXPECT_FALSE(common_prefs_->Exists(key1A));
+    EXPECT_FALSE(common_prefs_->Exists(key1B));
+    EXPECT_FALSE(common_prefs_->Exists(key2));
+
+    EXPECT_TRUE(common_prefs_->SetString(key0, ""));
+    EXPECT_TRUE(common_prefs_->SetString(key0corner, ""));
+    EXPECT_TRUE(common_prefs_->SetString(key1A, ""));
+    EXPECT_TRUE(common_prefs_->SetString(key1B, ""));
+    EXPECT_TRUE(common_prefs_->SetString(key2, ""));
+    EXPECT_TRUE(common_prefs_->SetString(key2corner, ""));
+
+    EXPECT_TRUE(common_prefs_->Exists(key0));
+    EXPECT_TRUE(common_prefs_->Exists(key0corner));
+    EXPECT_TRUE(common_prefs_->Exists(key1A));
+    EXPECT_TRUE(common_prefs_->Exists(key1B));
+    EXPECT_TRUE(common_prefs_->Exists(key2));
+    EXPECT_TRUE(common_prefs_->Exists(key2corner));
+
+    vector<string> keys2;
+    EXPECT_TRUE(common_prefs_->GetSubKeys("ns1/nsB/", &keys2));
+    EXPECT_THAT(keys2, ElementsAre(key2));
+    for (const auto& key : keys2)
+      EXPECT_TRUE(common_prefs_->Delete(key));
+    EXPECT_TRUE(common_prefs_->Exists(key0));
+    EXPECT_TRUE(common_prefs_->Exists(key0corner));
+    EXPECT_TRUE(common_prefs_->Exists(key1A));
+    EXPECT_TRUE(common_prefs_->Exists(key1B));
+    EXPECT_FALSE(common_prefs_->Exists(key2));
+    EXPECT_TRUE(common_prefs_->Exists(key2corner));
+
+    vector<string> keys2corner;
+    EXPECT_TRUE(common_prefs_->GetSubKeys("ns1/nsB", &keys2corner));
+    EXPECT_THAT(keys2corner, ElementsAre(key2corner));
+    for (const auto& key : keys2corner)
+      EXPECT_TRUE(common_prefs_->Delete(key));
+    EXPECT_FALSE(common_prefs_->Exists(key2corner));
+
+    vector<string> keys1;
+    EXPECT_TRUE(common_prefs_->GetSubKeys("ns1/nsA/", &keys1));
+    EXPECT_THAT(keys1, UnorderedElementsAre(key1A, key1B));
+    for (const auto& key : keys1)
+      EXPECT_TRUE(common_prefs_->Delete(key));
+    EXPECT_TRUE(common_prefs_->Exists(key0));
+    EXPECT_TRUE(common_prefs_->Exists(key0corner));
+    EXPECT_FALSE(common_prefs_->Exists(key1A));
+    EXPECT_FALSE(common_prefs_->Exists(key1B));
+
+    vector<string> keys0;
+    EXPECT_TRUE(common_prefs_->GetSubKeys("ns1/", &keys0));
+    EXPECT_THAT(keys0, ElementsAre(key0));
+    for (const auto& key : keys0)
+      EXPECT_TRUE(common_prefs_->Delete(key));
+    EXPECT_FALSE(common_prefs_->Exists(key0));
+    EXPECT_TRUE(common_prefs_->Exists(key0corner));
+
+    vector<string> keys0corner;
+    EXPECT_TRUE(common_prefs_->GetSubKeys("ns1", &keys0corner));
+    EXPECT_THAT(keys0corner, ElementsAre(key0corner));
+    for (const auto& key : keys0corner)
+      EXPECT_TRUE(common_prefs_->Delete(key));
+    EXPECT_FALSE(common_prefs_->Exists(key0corner));
+  }
+
+  PrefsInterface* common_prefs_;
+};
+
+class PrefsTest : public BasePrefsTest {
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     prefs_dir_ = temp_dir_.GetPath();
     ASSERT_TRUE(prefs_.Init(prefs_dir_));
+    common_prefs_ = &prefs_;
   }
 
   bool SetValue(const string& key, const string& value) {
@@ -59,6 +143,31 @@
   Prefs prefs_;
 };
 
+TEST(Prefs, Init) {
+  Prefs prefs;
+  const string ns1 = "ns1";
+  const string ns2A = "ns2A";
+  const string ns2B = "ns2B";
+  const string sub_pref = "sp";
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  auto ns1_path = temp_dir.GetPath().Append(ns1);
+  auto ns2A_path = ns1_path.Append(ns2A);
+  auto ns2B_path = ns1_path.Append(ns2B);
+  auto sub_pref_path = ns2A_path.Append(sub_pref);
+
+  EXPECT_TRUE(base::CreateDirectory(ns2B_path));
+  EXPECT_TRUE(base::PathExists(ns2B_path));
+
+  EXPECT_TRUE(base::CreateDirectory(sub_pref_path));
+  EXPECT_TRUE(base::PathExists(sub_pref_path));
+
+  EXPECT_TRUE(base::PathExists(ns1_path));
+  ASSERT_TRUE(prefs.Init(temp_dir.GetPath()));
+  EXPECT_FALSE(base::PathExists(ns1_path));
+}
+
 TEST_F(PrefsTest, GetFileNameForKey) {
   const char kAllvalidCharsKey[] =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-";
@@ -77,6 +186,18 @@
   EXPECT_FALSE(prefs_.file_storage_.GetFileNameForKey("", &path));
 }
 
+TEST_F(PrefsTest, CreateSubKey) {
+  const string name_space = "ns";
+  const string sub_pref1 = "sp1";
+  const string sub_pref2 = "sp2";
+  const string sub_key = "sk";
+
+  EXPECT_EQ(PrefsInterface::CreateSubKey({name_space, sub_pref1, sub_key}),
+            "ns/sp1/sk");
+  EXPECT_EQ(PrefsInterface::CreateSubKey({name_space, sub_pref2, sub_key}),
+            "ns/sp2/sk");
+}
+
 TEST_F(PrefsTest, GetString) {
   const string test_data = "test data";
   ASSERT_TRUE(SetValue(kKey, test_data));
@@ -279,6 +400,29 @@
   EXPECT_FALSE(prefs_.Exists(kKey));
 }
 
+TEST_F(PrefsTest, SetDeleteSubKey) {
+  const string name_space = "ns";
+  const string sub_pref = "sp";
+  const string sub_key1 = "sk1";
+  const string sub_key2 = "sk2";
+  auto key1 = prefs_.CreateSubKey({name_space, sub_pref, sub_key1});
+  auto key2 = prefs_.CreateSubKey({name_space, sub_pref, sub_key2});
+  base::FilePath sub_pref_path = prefs_dir_.Append(name_space).Append(sub_pref);
+
+  ASSERT_TRUE(prefs_.SetInt64(key1, 0));
+  ASSERT_TRUE(prefs_.SetInt64(key2, 0));
+  EXPECT_TRUE(base::PathExists(sub_pref_path.Append(sub_key1)));
+  EXPECT_TRUE(base::PathExists(sub_pref_path.Append(sub_key2)));
+
+  ASSERT_TRUE(prefs_.Delete(key1));
+  EXPECT_FALSE(base::PathExists(sub_pref_path.Append(sub_key1)));
+  EXPECT_TRUE(base::PathExists(sub_pref_path.Append(sub_key2)));
+  ASSERT_TRUE(prefs_.Delete(key2));
+  EXPECT_FALSE(base::PathExists(sub_pref_path.Append(sub_key2)));
+  prefs_.Init(prefs_dir_);
+  EXPECT_FALSE(base::PathExists(prefs_dir_.Append(name_space)));
+}
+
 class MockPrefsObserver : public PrefsInterface::ObserverInterface {
  public:
   MOCK_METHOD1(OnPrefSet, void(const string&));
@@ -299,6 +443,19 @@
   prefs_.Delete(kKey);
   testing::Mock::VerifyAndClearExpectations(&mock_obserser);
 
+  auto key1 = prefs_.CreateSubKey({"ns", "sp1", "key1"});
+  prefs_.AddObserver(key1, &mock_obserser);
+
+  EXPECT_CALL(mock_obserser, OnPrefSet(key1));
+  EXPECT_CALL(mock_obserser, OnPrefDeleted(_)).Times(0);
+  prefs_.SetString(key1, "value");
+  testing::Mock::VerifyAndClearExpectations(&mock_obserser);
+
+  EXPECT_CALL(mock_obserser, OnPrefSet(_)).Times(0);
+  EXPECT_CALL(mock_obserser, OnPrefDeleted(Eq(key1)));
+  prefs_.Delete(key1);
+  testing::Mock::VerifyAndClearExpectations(&mock_obserser);
+
   prefs_.RemoveObserver(kKey, &mock_obserser);
 }
 
@@ -341,8 +498,14 @@
   prefs_.RemoveObserver(kInvalidKey, &mock_obserser);
 }
 
-class MemoryPrefsTest : public ::testing::Test {
+TEST_F(PrefsTest, MultiNamespaceKeyTest) {
+  MultiNamespaceKeyTest();
+}
+
+class MemoryPrefsTest : public BasePrefsTest {
  protected:
+  void SetUp() override { common_prefs_ = &prefs_; }
+
   MemoryPrefs prefs_;
 };
 
@@ -358,7 +521,16 @@
 
   EXPECT_TRUE(prefs_.Delete(kKey));
   EXPECT_FALSE(prefs_.Exists(kKey));
-  EXPECT_FALSE(prefs_.Delete(kKey));
+  EXPECT_TRUE(prefs_.Delete(kKey));
+
+  auto key = prefs_.CreateSubKey({"ns", "sp", "sk"});
+  ASSERT_TRUE(prefs_.SetInt64(key, 0));
+  EXPECT_TRUE(prefs_.Exists(key));
+  EXPECT_TRUE(prefs_.Delete(kKey));
+}
+
+TEST_F(MemoryPrefsTest, MultiNamespaceKeyTest) {
+  MultiNamespaceKeyTest();
 }
 
 }  // namespace chromeos_update_engine
diff --git a/common/subprocess.cc b/common/subprocess.cc
index 0131f10..298a65c 100644
--- a/common/subprocess.cc
+++ b/common/subprocess.cc
@@ -29,6 +29,7 @@
 #include <base/bind.h>
 #include <base/logging.h>
 #include <base/posix/eintr_wrapper.h>
+#include <base/stl_util.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <brillo/process.h>
@@ -95,6 +96,7 @@
   proc->RedirectUsingPipe(STDOUT_FILENO, false);
   proc->SetPreExecCallback(base::Bind(&SetupChild, env, flags));
 
+  LOG(INFO) << "Running \"" << base::JoinString(cmd, " ") << "\"";
   return proc->Start();
 }
 
@@ -122,13 +124,17 @@
     bytes_read = 0;
     bool eof;
     bool ok = utils::ReadAll(
-        record->stdout_fd, buf, arraysize(buf), &bytes_read, &eof);
+        record->stdout_fd, buf, base::size(buf), &bytes_read, &eof);
     record->stdout.append(buf, bytes_read);
     if (!ok || eof) {
       // There was either an error or an EOF condition, so we are done watching
       // the file descriptor.
+#ifdef __ANDROID__
       MessageLoop::current()->CancelTask(record->stdout_task_id);
       record->stdout_task_id = MessageLoop::kTaskIdNull;
+#else
+      record->stdout_controller.reset();
+#endif  // __ANDROID__
       return;
     }
   } while (bytes_read);
@@ -143,8 +149,12 @@
   // Make sure we read any remaining process output and then close the pipe.
   OnStdoutReady(record);
 
+#ifdef __ANDROID__
   MessageLoop::current()->CancelTask(record->stdout_task_id);
   record->stdout_task_id = MessageLoop::kTaskIdNull;
+#else
+  record->stdout_controller.reset();
+#endif  // __ANDROID__
 
   // Don't print any log if the subprocess exited with exit code 0.
   if (info.si_code != CLD_EXITED) {
@@ -199,12 +209,18 @@
                << record->stdout_fd << ".";
   }
 
+#ifdef __ANDROID__
   record->stdout_task_id = MessageLoop::current()->WatchFileDescriptor(
       FROM_HERE,
       record->stdout_fd,
       MessageLoop::WatchMode::kWatchRead,
       true,
       base::Bind(&Subprocess::OnStdoutReady, record.get()));
+#else
+  record->stdout_controller = base::FileDescriptorWatcher::WatchReadable(
+      record->stdout_fd,
+      base::BindRepeating(&Subprocess::OnStdoutReady, record.get()));
+#endif  // __ANDROID__
 
   subprocess_records_[pid] = std::move(record);
   return pid;
@@ -234,22 +250,20 @@
 
 bool Subprocess::SynchronousExec(const vector<string>& cmd,
                                  int* return_code,
-                                 string* stdout) {
-  // The default for SynchronousExec is to use kSearchPath since the code relies
-  // on that.
-  return SynchronousExecFlags(
-      cmd, kRedirectStderrToStdout | kSearchPath, return_code, stdout);
+                                 string* stdout,
+                                 string* stderr) {
+  // The default for |SynchronousExec| is to use |kSearchPath| since the code
+  // relies on that.
+  return SynchronousExecFlags(cmd, kSearchPath, return_code, stdout, stderr);
 }
 
 bool Subprocess::SynchronousExecFlags(const vector<string>& cmd,
                                       uint32_t flags,
                                       int* return_code,
-                                      string* stdout) {
+                                      string* stdout,
+                                      string* stderr) {
   brillo::ProcessImpl proc;
-  // It doesn't make sense to redirect some pipes in the synchronous case
-  // because we won't be reading on our end, so we don't expose the output_pipes
-  // in this case.
-  if (!LaunchProcess(cmd, flags, {}, &proc)) {
+  if (!LaunchProcess(cmd, flags, {STDERR_FILENO}, &proc)) {
     LOG(ERROR) << "Failed to launch subprocess";
     return false;
   }
@@ -257,21 +271,39 @@
   if (stdout) {
     stdout->clear();
   }
+  if (stderr) {
+    stderr->clear();
+  }
 
-  int fd = proc.GetPipe(STDOUT_FILENO);
+  // Read from both stdout and stderr individually.
+  int stdout_fd = proc.GetPipe(STDOUT_FILENO);
+  int stderr_fd = proc.GetPipe(STDERR_FILENO);
   vector<char> buffer(32 * 1024);
-  while (true) {
-    int rc = HANDLE_EINTR(read(fd, buffer.data(), buffer.size()));
-    if (rc < 0) {
-      PLOG(ERROR) << "Reading from child's output";
-      break;
-    } else if (rc == 0) {
-      break;
-    } else {
-      if (stdout)
+  bool stdout_closed = false, stderr_closed = false;
+  while (!stdout_closed || !stderr_closed) {
+    if (!stdout_closed) {
+      int rc = HANDLE_EINTR(read(stdout_fd, buffer.data(), buffer.size()));
+      if (rc <= 0) {
+        stdout_closed = true;
+        if (rc < 0)
+          PLOG(ERROR) << "Reading from child's stdout";
+      } else if (stdout != nullptr) {
         stdout->append(buffer.data(), rc);
+      }
+    }
+
+    if (!stderr_closed) {
+      int rc = HANDLE_EINTR(read(stderr_fd, buffer.data(), buffer.size()));
+      if (rc <= 0) {
+        stderr_closed = true;
+        if (rc < 0)
+          PLOG(ERROR) << "Reading from child's stderr";
+      } else if (stderr != nullptr) {
+        stderr->append(buffer.data(), rc);
+      }
     }
   }
+
   // At this point, the subprocess already closed the output, so we only need to
   // wait for it to finish.
   int proc_return_code = proc.Wait();
diff --git a/common/subprocess.h b/common/subprocess.h
index bc19d16..f1b9f1f 100644
--- a/common/subprocess.h
+++ b/common/subprocess.h
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include <base/callback.h>
+#include <base/files/file_descriptor_watcher_posix.h>
 #include <base/logging.h>
 #include <base/macros.h>
 #include <brillo/asynchronous_signal_handler_interface.h>
@@ -87,14 +88,16 @@
 
   // Executes a command synchronously. Returns true on success. If |stdout| is
   // non-null, the process output is stored in it, otherwise the output is
-  // logged. Note that stderr is redirected to stdout.
+  // logged.
   static bool SynchronousExec(const std::vector<std::string>& cmd,
                               int* return_code,
-                              std::string* stdout);
+                              std::string* stdout,
+                              std::string* stderr);
   static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
                                    uint32_t flags,
                                    int* return_code,
-                                   std::string* stdout);
+                                   std::string* stdout,
+                                   std::string* stderr);
 
   // Gets the one instance.
   static Subprocess& Get() { return *subprocess_singleton_; }
@@ -120,8 +123,12 @@
 
     // These are used to monitor the stdout of the running process, including
     // the stderr if it was redirected.
+#ifdef __ANDROID__
     brillo::MessageLoop::TaskId stdout_task_id{
         brillo::MessageLoop::kTaskIdNull};
+#else
+    std::unique_ptr<base::FileDescriptorWatcher::Controller> stdout_controller;
+#endif  // __ANDROID__
     int stdout_fd{-1};
     std::string stdout;
   };
diff --git a/common/subprocess_unittest.cc b/common/subprocess_unittest.cc
index 104ef41..bc52b83 100644
--- a/common/subprocess_unittest.cc
+++ b/common/subprocess_unittest.cc
@@ -45,6 +45,7 @@
 using base::TimeDelta;
 using brillo::MessageLoop;
 using std::string;
+using std::unique_ptr;
 using std::vector;
 
 namespace {
@@ -73,6 +74,10 @@
   brillo::BaseMessageLoop loop_{&base_loop_};
   brillo::AsynchronousSignalHandler async_signal_handler_;
   Subprocess subprocess_;
+#ifndef __ANDROID__
+  unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
+#endif  // __ANDROID__
+
 };
 
 namespace {
@@ -193,7 +198,7 @@
 TEST_F(SubprocessTest, SynchronousTrueSearchsOnPath) {
   int rc = -1;
   EXPECT_TRUE(Subprocess::SynchronousExecFlags(
-      {"true"}, Subprocess::kSearchPath, &rc, nullptr));
+      {"true"}, Subprocess::kSearchPath, &rc, nullptr, nullptr));
   EXPECT_EQ(0, rc);
 }
 
@@ -201,16 +206,17 @@
   vector<string> cmd = {
       kBinPath "/sh", "-c", "echo -n stdout-here; echo -n stderr-there >&2"};
   int rc = -1;
-  string stdout;
-  ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
+  string stdout, stderr;
+  ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout, &stderr));
   EXPECT_EQ(0, rc);
-  EXPECT_EQ("stdout-herestderr-there", stdout);
+  EXPECT_EQ("stdout-here", stdout);
+  EXPECT_EQ("stderr-there", stderr);
 }
 
 TEST_F(SubprocessTest, SynchronousEchoNoOutputTest) {
   int rc = -1;
   ASSERT_TRUE(Subprocess::SynchronousExec(
-      {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr));
+      {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr, nullptr));
   EXPECT_EQ(0, rc);
 }
 
@@ -255,6 +261,7 @@
   int fifo_fd = HANDLE_EINTR(open(fifo_path.c_str(), O_RDONLY));
   EXPECT_GE(fifo_fd, 0);
 
+#ifdef __ANDROID__
   loop_.WatchFileDescriptor(FROM_HERE,
                             fifo_fd,
                             MessageLoop::WatchMode::kWatchRead,
@@ -270,6 +277,25 @@
                                 },
                                 fifo_fd,
                                 tag));
+#else
+  watcher_ = base::FileDescriptorWatcher::WatchReadable(
+      fifo_fd,
+      base::Bind(
+          [](unique_ptr<base::FileDescriptorWatcher::Controller>* watcher,
+             int fifo_fd,
+             uint32_t 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);
+            *watcher = nullptr;
+          },
+          // watcher_ is no longer used outside the clousure.
+          base::Unretained(&watcher_),
+          fifo_fd,
+          tag));
+#endif  // __ANDROID__
 
   // This test would leak a callback that runs when the child process exits
   // unless we wait for it to run.
diff --git a/common/utils.cc b/common/utils.cc
index fc89040..3e3d830 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -84,49 +84,6 @@
 // The path to the kernel's boot_id.
 const char kBootIdPath[] = "/proc/sys/kernel/random/boot_id";
 
-// Return true if |disk_name| is an MTD or a UBI device. Note that this test is
-// simply based on the name of the device.
-bool IsMtdDeviceName(const string& disk_name) {
-  return base::StartsWith(
-             disk_name, "/dev/ubi", base::CompareCase::SENSITIVE) ||
-         base::StartsWith(disk_name, "/dev/mtd", base::CompareCase::SENSITIVE);
-}
-
-// Return the device name for the corresponding partition on a NAND device.
-// WARNING: This function returns device names that are not mountable.
-string MakeNandPartitionName(int partition_num) {
-  switch (partition_num) {
-    case 2:
-    case 4:
-    case 6: {
-      return base::StringPrintf("/dev/mtd%d", partition_num);
-    }
-    default: {
-      return base::StringPrintf("/dev/ubi%d_0", partition_num);
-    }
-  }
-}
-
-// Return the device name for the corresponding partition on a NAND device that
-// may be mountable (but may not be writable).
-string MakeNandPartitionNameForMount(int partition_num) {
-  switch (partition_num) {
-    case 2:
-    case 4:
-    case 6: {
-      return base::StringPrintf("/dev/mtd%d", partition_num);
-    }
-    case 3:
-    case 5:
-    case 7: {
-      return base::StringPrintf("/dev/ubiblock%d_0", partition_num);
-    }
-    default: {
-      return base::StringPrintf("/dev/ubi%d_0", partition_num);
-    }
-  }
-}
-
 // If |path| is absolute, or explicit relative to the current working directory,
 // leaves it as is. Otherwise, uses the system's temp directory, as defined by
 // base::GetTempDir() and prepends it to |path|. On success stores the full
@@ -474,22 +431,6 @@
     return false;
   }
 
-  size_t partition_name_len = string::npos;
-  if (partition_name[last_nondigit_pos] == '_') {
-    // NAND block devices have weird naming which could be something
-    // like "/dev/ubiblock2_0". We discard "_0" in such a case.
-    size_t prev_nondigit_pos =
-        partition_name.find_last_not_of("0123456789", last_nondigit_pos - 1);
-    if (prev_nondigit_pos == string::npos ||
-        (prev_nondigit_pos + 1) == last_nondigit_pos) {
-      LOG(ERROR) << "Unable to parse partition device name: " << partition_name;
-      return false;
-    }
-
-    partition_name_len = last_nondigit_pos - prev_nondigit_pos;
-    last_nondigit_pos = prev_nondigit_pos;
-  }
-
   if (out_disk_name) {
     // Special case for MMC devices which have the following naming scheme:
     // mmcblk0p2
@@ -502,8 +443,7 @@
   }
 
   if (out_partition_num) {
-    string partition_str =
-        partition_name.substr(last_nondigit_pos + 1, partition_name_len);
+    string partition_str = partition_name.substr(last_nondigit_pos + 1);
     *out_partition_num = atoi(partition_str.c_str());
   }
   return true;
@@ -520,13 +460,6 @@
     return string();
   }
 
-  if (IsMtdDeviceName(disk_name)) {
-    // Special case for UBI block devices.
-    //   1. ubiblock is not writable, we need to use plain "ubi".
-    //   2. There is a "_0" suffix.
-    return MakeNandPartitionName(partition_num);
-  }
-
   string partition_name = disk_name;
   if (isdigit(partition_name.back())) {
     // Special case for devices with names ending with a digit.
@@ -540,17 +473,6 @@
   return partition_name;
 }
 
-string MakePartitionNameForMount(const string& part_name) {
-  if (IsMtdDeviceName(part_name)) {
-    int partition_num;
-    if (!SplitPartitionName(part_name, nullptr, &partition_num)) {
-      return "";
-    }
-    return MakeNandPartitionNameForMount(partition_num);
-  }
-  return part_name;
-}
-
 string ErrnoNumberAsString(int err) {
   char buf[100];
   buf[0] = '\0';
@@ -567,33 +489,6 @@
   return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
 }
 
-bool TryAttachingUbiVolume(int volume_num, int timeout) {
-  const string volume_path = base::StringPrintf("/dev/ubi%d_0", volume_num);
-  if (FileExists(volume_path.c_str())) {
-    return true;
-  }
-
-  int exit_code;
-  vector<string> cmd = {"ubiattach",
-                        "-m",
-                        base::StringPrintf("%d", volume_num),
-                        "-d",
-                        base::StringPrintf("%d", volume_num)};
-  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &exit_code, nullptr));
-  TEST_AND_RETURN_FALSE(exit_code == 0);
-
-  cmd = {"ubiblock", "--create", volume_path};
-  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &exit_code, nullptr));
-  TEST_AND_RETURN_FALSE(exit_code == 0);
-
-  while (timeout > 0 && !FileExists(volume_path.c_str())) {
-    sleep(1);
-    timeout--;
-  }
-
-  return FileExists(volume_path.c_str());
-}
-
 bool MakeTempFile(const string& base_filename_template,
                   string* filename,
                   int* fd) {
@@ -1083,6 +978,10 @@
   return str;
 }
 
+string GetExclusionName(const string& str_to_convert) {
+  return base::NumberToString(base::StringPieceHash()(str_to_convert));
+}
+
 }  // namespace utils
 
 }  // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index c6c34f4..23ac03d 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -128,11 +128,6 @@
 // Returns true if |path| exists and is a symbolic link.
 bool IsSymlink(const char* path);
 
-// Try attaching UBI |volume_num|. If there is any error executing required
-// commands to attach the volume, this function returns false. This function
-// only returns true if "/dev/ubi%d_0" becomes available in |timeout| seconds.
-bool TryAttachingUbiVolume(int volume_num, int timeout);
-
 // If |base_filename_template| is neither absolute (starts with "/") nor
 // explicitly relative to the current working directory (starts with "./" or
 // "../"), then it is prepended the system's temporary directory. On success,
@@ -163,14 +158,6 @@
 // Returns empty string when invalid parameters are passed in
 std::string MakePartitionName(const std::string& disk_name, int partition_num);
 
-// Similar to "MakePartitionName" but returns a name that is suitable for
-// mounting. On NAND system we can write to "/dev/ubiX_0", which is what
-// MakePartitionName returns, but we cannot mount that device. To mount, we
-// have to use "/dev/ubiblockX_0" for rootfs. Stateful and OEM partitions are
-// mountable with "/dev/ubiX_0". The input is a partition device such as
-// /dev/sda3. Return empty string on error.
-std::string MakePartitionNameForMount(const std::string& part_name);
-
 // Set the read-only attribute on the block device |device| to the value passed
 // in |read_only|. Return whether the operation succeeded.
 bool SetBlockDeviceReadOnly(const std::string& device, bool read_only);
@@ -332,6 +319,9 @@
 
 // Return a string representation of |utime| for log file names.
 std::string GetTimeAsString(time_t utime);
+// Returns the string format of the hashed |str_to_convert| that can be used
+// with |Excluder| as the exclusion name.
+std::string GetExclusionName(const std::string& str_to_convert);
 
 }  // namespace utils
 
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index b4ac2f5..ebcc548 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -123,10 +123,6 @@
   EXPECT_EQ("/dev/mmcblk0", disk);
   EXPECT_EQ(3, part_num);
 
-  EXPECT_TRUE(utils::SplitPartitionName("/dev/ubiblock3_2", &disk, &part_num));
-  EXPECT_EQ("/dev/ubiblock", disk);
-  EXPECT_EQ(3, part_num);
-
   EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10", &disk, &part_num));
   EXPECT_EQ("/dev/loop", disk);
   EXPECT_EQ(10, part_num);
@@ -135,14 +131,6 @@
   EXPECT_EQ("/dev/loop28", disk);
   EXPECT_EQ(11, part_num);
 
-  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop10_0", &disk, &part_num));
-  EXPECT_EQ("/dev/loop", disk);
-  EXPECT_EQ(10, part_num);
-
-  EXPECT_TRUE(utils::SplitPartitionName("/dev/loop28p11_0", &disk, &part_num));
-  EXPECT_EQ("/dev/loop28", disk);
-  EXPECT_EQ(11, part_num);
-
   EXPECT_FALSE(utils::SplitPartitionName("/dev/mmcblk0p", &disk, &part_num));
   EXPECT_FALSE(utils::SplitPartitionName("/dev/sda", &disk, &part_num));
   EXPECT_FALSE(utils::SplitPartitionName("/dev/foo/bar", &disk, &part_num));
@@ -157,29 +145,6 @@
   EXPECT_EQ("/dev/mmcblk0p2", utils::MakePartitionName("/dev/mmcblk0", 2));
   EXPECT_EQ("/dev/loop8", utils::MakePartitionName("/dev/loop", 8));
   EXPECT_EQ("/dev/loop12p2", utils::MakePartitionName("/dev/loop12", 2));
-  EXPECT_EQ("/dev/ubi5_0", utils::MakePartitionName("/dev/ubiblock", 5));
-  EXPECT_EQ("/dev/mtd4", utils::MakePartitionName("/dev/ubiblock", 4));
-  EXPECT_EQ("/dev/ubi3_0", utils::MakePartitionName("/dev/ubiblock", 3));
-  EXPECT_EQ("/dev/mtd2", utils::MakePartitionName("/dev/ubiblock", 2));
-  EXPECT_EQ("/dev/ubi1_0", utils::MakePartitionName("/dev/ubiblock", 1));
-}
-
-TEST(UtilsTest, MakePartitionNameForMountTest) {
-  EXPECT_EQ("/dev/sda4", utils::MakePartitionNameForMount("/dev/sda4"));
-  EXPECT_EQ("/dev/sda123", utils::MakePartitionNameForMount("/dev/sda123"));
-  EXPECT_EQ("/dev/mmcblk2", utils::MakePartitionNameForMount("/dev/mmcblk2"));
-  EXPECT_EQ("/dev/mmcblk0p2",
-            utils::MakePartitionNameForMount("/dev/mmcblk0p2"));
-  EXPECT_EQ("/dev/loop0", utils::MakePartitionNameForMount("/dev/loop0"));
-  EXPECT_EQ("/dev/loop8", utils::MakePartitionNameForMount("/dev/loop8"));
-  EXPECT_EQ("/dev/loop12p2", utils::MakePartitionNameForMount("/dev/loop12p2"));
-  EXPECT_EQ("/dev/ubiblock5_0",
-            utils::MakePartitionNameForMount("/dev/ubiblock5_0"));
-  EXPECT_EQ("/dev/mtd4", utils::MakePartitionNameForMount("/dev/ubi4_0"));
-  EXPECT_EQ("/dev/ubiblock3_0",
-            utils::MakePartitionNameForMount("/dev/ubiblock3"));
-  EXPECT_EQ("/dev/mtd2", utils::MakePartitionNameForMount("/dev/ubi2"));
-  EXPECT_EQ("/dev/ubi1_0", utils::MakePartitionNameForMount("/dev/ubiblock1"));
 }
 
 TEST(UtilsTest, FuzzIntTest) {