Merge "Add fastboot mode to recovery"
diff --git a/Android.bp b/Android.bp
index 5677b6c..e97f71d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -127,19 +127,20 @@
     ],
 
     shared_libs: [
+        "android.hardware.health@2.0",
         "libbase",
         "libbootloader_message",
         "libcrypto",
-        "libcrypto_utils",
         "libcutils",
         "libext4_utils",
         "libfs_mgr",
         "libfusesideload",
         "libhidl-gen-utils",
+        "libhidlbase",
+        "libhidltransport",
         "liblog",
         "libpng",
         "libselinux",
-        "libsparse",
         "libtinyxml2",
         "libutils",
         "libz",
@@ -151,20 +152,11 @@
         "libminui",
         "libverifier",
         "libotautil",
+
+        // external dependencies
+        "libhealthhalutils",
         "libvintf_recovery",
         "libvintf",
-
-        // TODO(b/80132328): Remove the dependency on static health HAL.
-        "libhealthd.default",
-        "android.hardware.health@2.0-impl",
-        "android.hardware.health@2.0",
-        "android.hardware.health@1.0",
-        "android.hardware.health@1.0-convert",
-        "libhealthstoragedefault",
-        "libhidltransport",
-        "libhidlbase",
-        "libhwbinder_noltopgo",
-        "libbatterymonitor",
     ],
 }
 
diff --git a/Android.mk b/Android.mk
index 9888f86..7d13f4c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,7 +14,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# Needed by build/make/core/Makefile.
+# Needed by build/make/core/Makefile. Must be consistent with the value in Android.bp.
 RECOVERY_API_VERSION := 3
 RECOVERY_FSTAB_VERSION := 2
 
diff --git a/recovery.cpp b/recovery.cpp
index 24f105d..01bd83b 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -49,7 +49,7 @@
 #include <android-base/unique_fd.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/properties.h> /* for property_list */
-#include <health2/Health.h>
+#include <healthhalutils/HealthHalUtils.h>
 #include <ziparchive/zip_archive.h>
 
 #include "adb_install.h"
@@ -879,42 +879,29 @@
 
 static bool is_battery_ok(int* required_battery_level) {
   using android::hardware::health::V1_0::BatteryStatus;
+  using android::hardware::health::V2_0::get_health_service;
+  using android::hardware::health::V2_0::IHealth;
   using android::hardware::health::V2_0::Result;
   using android::hardware::health::V2_0::toString;
-  using android::hardware::health::V2_0::implementation::Health;
 
-  struct healthd_config healthd_config = {
-    .batteryStatusPath = android::String8(android::String8::kEmptyString),
-    .batteryHealthPath = android::String8(android::String8::kEmptyString),
-    .batteryPresentPath = android::String8(android::String8::kEmptyString),
-    .batteryCapacityPath = android::String8(android::String8::kEmptyString),
-    .batteryVoltagePath = android::String8(android::String8::kEmptyString),
-    .batteryTemperaturePath = android::String8(android::String8::kEmptyString),
-    .batteryTechnologyPath = android::String8(android::String8::kEmptyString),
-    .batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
-    .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
-    .batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
-    .batteryFullChargePath = android::String8(android::String8::kEmptyString),
-    .batteryCycleCountPath = android::String8(android::String8::kEmptyString),
-    .energyCounter = nullptr,
-    .boot_min_cap = 0,
-    .screen_on = nullptr
-  };
-
-  auto health =
-      android::hardware::health::V2_0::implementation::Health::initInstance(&healthd_config);
+  android::sp<IHealth> health = get_health_service();
 
   static constexpr int BATTERY_READ_TIMEOUT_IN_SEC = 10;
   int wait_second = 0;
   while (true) {
     auto charge_status = BatteryStatus::UNKNOWN;
-    health
-        ->getChargeStatus([&charge_status](auto res, auto out_status) {
-          if (res == Result::SUCCESS) {
-            charge_status = out_status;
-          }
-        })
-        .isOk();  // should not have transport error
+
+    if (health == nullptr) {
+      LOG(WARNING) << "no health implementation is found, assuming defaults";
+    } else {
+      health
+          ->getChargeStatus([&charge_status](auto res, auto out_status) {
+            if (res == Result::SUCCESS) {
+              charge_status = out_status;
+            }
+          })
+          .isOk();  // should not have transport error
+    }
 
     // Treat unknown status as charged.
     bool charged = (charge_status != BatteryStatus::DISCHARGING &&
@@ -922,15 +909,17 @@
 
     Result res = Result::UNKNOWN;
     int32_t capacity = INT32_MIN;
-    health
-        ->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
-          res = out_res;
-          capacity = out_capacity;
-        })
-        .isOk();  // should not have transport error
+    if (health != nullptr) {
+      health
+          ->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
+            res = out_res;
+            capacity = out_capacity;
+          })
+          .isOk();  // should not have transport error
+    }
 
-    ui_print("charge_status %d, charged %d, status %s, capacity %" PRId32 "\n", charge_status,
-             charged, toString(res).c_str(), capacity);
+    LOG(INFO) << "charge_status " << toString(charge_status) << ", charged " << charged
+              << ", status " << toString(res) << ", capacity " << capacity;
     // At startup, the battery drivers in devices like N5X/N6P take some time to load
     // the battery profile. Before the load finishes, it reports value 50 as a fake
     // capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
diff --git a/tests/Android.mk b/tests/Android.mk
index b6f5b45..b59da80 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -127,13 +127,11 @@
 libupdater_static_libraries := \
     libupdater \
     libapplypatch \
+    libbootloader_message \
     libbspatch \
     libedify \
-    libziparchive \
-    libotautil \
-    libbootloader_message \
-    libutils \
     libotafault \
+    libotautil \
     libext4_utils \
     libfec \
     libfec_rs \
@@ -144,28 +142,18 @@
     libselinux \
     libsparse \
     libsquashfs_utils \
+    libbrotli \
     libbz \
+    libziparchive \
     libz \
     libbase \
     libcrypto \
     libcrypto_utils \
     libcutils \
+    libutils \
     libtune2fs \
-    libbrotli \
     $(tune2fs_static_libraries)
 
-health_hal_static_libraries := \
-    android.hardware.health@2.0-impl \
-    android.hardware.health@2.0 \
-    android.hardware.health@1.0 \
-    android.hardware.health@1.0-convert \
-    libhealthstoragedefault \
-    libhidltransport \
-    libhidlbase \
-    libhwbinder_noltopgo \
-    libvndksupport \
-    libbatterymonitor
-
 librecovery_static_libraries := \
     librecovery \
     libbootloader_message \
@@ -175,7 +163,6 @@
     libminui \
     libverifier \
     libotautil \
-    $(health_hal_static_libraries) \
     libcrypto_utils \
     libcrypto \
     libext4_utils \
diff --git a/tests/unit/commands_test.cpp b/tests/unit/commands_test.cpp
index 9679a9e..19841d6 100644
--- a/tests/unit/commands_test.cpp
+++ b/tests/unit/commands_test.cpp
@@ -333,6 +333,25 @@
   ASSERT_EQ(PatchInfo(), command.patch());
 }
 
+TEST(CommandsTest, Parse_COMPUTE_HASH_TREE) {
+  const std::string input{ "compute_hash_tree 2,0,1 2,3,4 sha1 unknown-salt unknown-root-hash" };
+  std::string err;
+  Command command = Command::Parse(input, 9, &err);
+  ASSERT_TRUE(command);
+
+  ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, command.type());
+  ASSERT_EQ(9, command.index());
+  ASSERT_EQ(input, command.cmdline());
+
+  HashTreeInfo expected_info(RangeSet({ { 0, 1 } }), RangeSet({ { 3, 4 } }), "sha1", "unknown-salt",
+                             "unknown-root-hash");
+  ASSERT_EQ(expected_info, command.hash_tree_info());
+  ASSERT_EQ(TargetInfo(), command.target());
+  ASSERT_EQ(SourceInfo(), command.source());
+  ASSERT_EQ(StashInfo(), command.stash());
+  ASSERT_EQ(PatchInfo(), command.patch());
+}
+
 TEST(CommandsTest, Parse_InvalidNumberOfArgs) {
   Command::abort_allowed_ = true;
 
@@ -341,6 +360,7 @@
   std::vector<std::string> inputs{
     "abort foo",
     "bsdiff",
+    "compute_hash_tree, 2,0,1 2,0,1 unknown-algorithm unknown-salt",
     "erase",
     "erase 4,3,5,10,12 hash1",
     "free",
diff --git a/updater/Android.bp b/updater/Android.bp
new file mode 100644
index 0000000..9a36ebb
--- /dev/null
+++ b/updater/Android.bp
@@ -0,0 +1,71 @@
+// 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.
+
+cc_library_static {
+    name: "libupdater",
+
+    defaults: [
+        "recovery_defaults",
+    ],
+
+    srcs: [
+        "blockimg.cpp",
+        "commands.cpp",
+        "install.cpp",
+    ],
+
+    include_dirs: [
+        "external/e2fsprogs/misc",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    static_libs: [
+        "libapplypatch",
+        "libbootloader_message",
+        "libbspatch",
+        "libedify",
+        "libotafault",
+        "libotautil",
+        "libext4_utils",
+        "libfec",
+        "libfec_rs",
+        "libverity_tree",
+        "libfs_mgr",
+        "libgtest_prod",
+        "liblog",
+        "libselinux",
+        "libsparse",
+        "libsquashfs_utils",
+        "libbrotli",
+        "libbz",
+        "libziparchive",
+        "libz",
+        "libbase",
+        "libcrypto",
+        "libcrypto_utils",
+        "libcutils",
+        "libutils",
+        "libtune2fs",
+
+        "libext2_com_err",
+        "libext2_blkid",
+        "libext2_quota",
+        "libext2_uuid",
+        "libext2_e2p",
+        "libext2fs",
+    ],
+}
diff --git a/updater/Android.mk b/updater/Android.mk
index 78d0bd4..5478a7d 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -25,12 +25,10 @@
 updater_common_static_libraries := \
     libapplypatch \
     libbootloader_message \
+    libbspatch \
     libedify \
     libotafault \
     libotautil \
-    libbspatch \
-    libziparchive \
-    libutils \
     libext4_utils \
     libfec \
     libfec_rs \
@@ -41,43 +39,18 @@
     libselinux \
     libsparse \
     libsquashfs_utils \
+    libbrotli \
     libbz \
+    libziparchive \
     libz \
     libbase \
     libcrypto \
     libcrypto_utils \
     libcutils \
+    libutils \
     libtune2fs \
-    libbrotli \
     $(tune2fs_static_libraries)
 
-# libupdater (static library)
-# ===============================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libupdater
-
-LOCAL_SRC_FILES := \
-    commands.cpp \
-    install.cpp \
-    blockimg.cpp
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH)/include \
-    external/e2fsprogs/misc
-
-LOCAL_CFLAGS := \
-    -Wall \
-    -Werror
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
-    $(updater_common_static_libraries)
-
-include $(BUILD_STATIC_LIBRARY)
-
 # updater (static executable)
 # ===============================
 include $(CLEAR_VARS)
diff --git a/updater/commands.cpp b/updater/commands.cpp
index 15a787c..4a90ea8 100644
--- a/updater/commands.cpp
+++ b/updater/commands.cpp
@@ -31,6 +31,14 @@
 
 bool Command::abort_allowed_ = false;
 
+Command::Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info)
+    : type_(type),
+      index_(index),
+      cmdline_(std::move(cmdline)),
+      hash_tree_info_(std::move(hash_tree_info)) {
+  CHECK(type == Type::COMPUTE_HASH_TREE);
+}
+
 Command::Type Command::ParseType(const std::string& type_str) {
   if (type_str == "abort") {
     if (!abort_allowed_) {
@@ -177,7 +185,6 @@
   SourceInfo source_info;
   StashInfo stash_info;
 
-  // TODO(xunchang) add the parse code of compute_hash_tree
   if (op == Type::ZERO || op == Type::NEW || op == Type::ERASE) {
     // zero/new/erase <rangeset>
     if (pos + 1 != tokens.size()) {
@@ -255,6 +262,39 @@
                                          tokens.size() - pos);
       return {};
     }
+  } else if (op == Type::COMPUTE_HASH_TREE) {
+    // <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash>
+    if (pos + 5 != tokens.size()) {
+      *err = android::base::StringPrintf("invalid number of args: %zu (expected 5)",
+                                         tokens.size() - pos);
+      return {};
+    }
+
+    // Expects the hash_tree data to be contiguous.
+    RangeSet hash_tree_ranges = RangeSet::Parse(tokens[pos++]);
+    if (!hash_tree_ranges || hash_tree_ranges.size() != 1) {
+      *err = "invalid hash tree ranges in: " + line;
+      return {};
+    }
+
+    RangeSet source_ranges = RangeSet::Parse(tokens[pos++]);
+    if (!source_ranges) {
+      *err = "invalid source ranges in: " + line;
+      return {};
+    }
+
+    std::string hash_algorithm = tokens[pos++];
+    std::string salt_hex = tokens[pos++];
+    std::string root_hash = tokens[pos++];
+    if (hash_algorithm.empty() || salt_hex.empty() || root_hash.empty()) {
+      *err = "invalid hash tree arguments in " + line;
+      return {};
+    }
+
+    HashTreeInfo hash_tree_info(std::move(hash_tree_ranges), std::move(source_ranges),
+                                std::move(hash_algorithm), std::move(salt_hex),
+                                std::move(root_hash));
+    return Command(op, index, line, std::move(hash_tree_info));
   } else {
     *err = "invalid op";
     return {};
diff --git a/updater/include/private/commands.h b/updater/include/private/commands.h
index 7f9dc79..85b5288 100644
--- a/updater/include/private/commands.h
+++ b/updater/include/private/commands.h
@@ -166,6 +166,50 @@
   size_t length_{ 0 };
 };
 
+// The arguments to build a hash tree from blocks on the block device.
+class HashTreeInfo {
+ public:
+  HashTreeInfo() = default;
+
+  HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm,
+               std::string salt_hex, std::string root_hash)
+      : hash_tree_ranges_(std::move(hash_tree_ranges)),
+        source_ranges_(std::move(source_ranges)),
+        hash_algorithm_(std::move(hash_algorithm)),
+        salt_hex_(std::move(salt_hex)),
+        root_hash_(std::move(root_hash)) {}
+
+  const RangeSet& hash_tree_ranges() const {
+    return hash_tree_ranges_;
+  }
+  const RangeSet& source_ranges() const {
+    return source_ranges_;
+  }
+
+  const std::string& hash_algorithm() const {
+    return hash_algorithm_;
+  }
+  const std::string& salt_hex() const {
+    return salt_hex_;
+  }
+  const std::string& root_hash() const {
+    return root_hash_;
+  }
+
+  bool operator==(const HashTreeInfo& other) const {
+    return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ &&
+           hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ &&
+           root_hash_ == other.root_hash_;
+  }
+
+ private:
+  RangeSet hash_tree_ranges_;
+  RangeSet source_ranges_;
+  std::string hash_algorithm_;
+  std::string salt_hex_;
+  std::string root_hash_;
+};
+
 // Command class holds the info for an update command that performs block-based OTA (BBOTA). Each
 // command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo.
 // The currently used BBOTA version is v4.
@@ -248,6 +292,8 @@
         source_(std::move(source)),
         stash_(std::move(stash)) {}
 
+  Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info);
+
   // Parses the given command 'line' into a Command object and returns it. The 'index' is specified
   // by the caller to index the object. On parsing error, it returns an empty Command object that
   // evaluates to false, and the specific error message will be set in 'err'.
@@ -284,6 +330,10 @@
     return stash_;
   }
 
+  const HashTreeInfo& hash_tree_info() const {
+    return hash_tree_info_;
+  }
+
   constexpr explicit operator bool() const {
     return type_ != Type::LAST;
   }
@@ -325,6 +375,8 @@
   // The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may
   // also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_).
   StashInfo stash_;
+  // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE.
+  HashTreeInfo hash_tree_info_;
 };
 
 std::ostream& operator<<(std::ostream& os, const Command& command);