Merge "emmc_optimized means stable_inodes" into rvc-dev
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 610e985..f2de0d2 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -302,7 +302,7 @@
 }
 
 template <class TimePoint>
-static int msBetween(TimePoint start, TimePoint end) {
+static int ms_between(TimePoint start, TimePoint end) {
     return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
 }
 
@@ -350,7 +350,7 @@
     }
 
     const auto end = clock::now();
-    printf("Install command complete in %d ms\n", msBetween(start, end));
+    printf("Install command complete in %d ms\n", ms_between(start, end));
 
     if (wait) {
         (*server_process).wait();
@@ -359,9 +359,9 @@
     return 0;
 }
 
-static std::pair<InstallMode, std::optional<InstallMode>> calculateInstallMode(
-        InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incrementalRequest) {
-    if (incrementalRequest == CmdlineOption::Enable) {
+static std::pair<InstallMode, std::optional<InstallMode>> calculate_install_mode(
+        InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) {
+    if (incremental_request == CmdlineOption::Enable) {
         if (fastdeploy) {
             error_exit(
                     "--incremental and --fast-deploy options are incompatible. "
@@ -370,30 +370,30 @@
     }
 
     if (modeFromArgs != INSTALL_DEFAULT) {
-        if (incrementalRequest == CmdlineOption::Enable) {
+        if (incremental_request == CmdlineOption::Enable) {
             error_exit("--incremental is not compatible with other installation modes");
         }
         return {modeFromArgs, std::nullopt};
     }
 
-    if (incrementalRequest != CmdlineOption::Disable && !is_abb_exec_supported()) {
-        if (incrementalRequest == CmdlineOption::None) {
-            incrementalRequest = CmdlineOption::Disable;
+    if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) {
+        if (incremental_request == CmdlineOption::None) {
+            incremental_request = CmdlineOption::Disable;
         } else {
             error_exit("Device doesn't support incremental installations");
         }
     }
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // check if the host is ok with incremental by default
         if (const char* incrementalFromEnv = getenv("ADB_INSTALL_DEFAULT_INCREMENTAL")) {
             using namespace android::base;
             auto val = ParseBool(incrementalFromEnv);
             if (val == ParseBoolResult::kFalse) {
-                incrementalRequest = CmdlineOption::Disable;
+                incremental_request = CmdlineOption::Disable;
             }
         }
     }
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // still ok: let's see if the device allows using incremental by default
         // it starts feeling like we're looking for an excuse to not to use incremental...
         std::string error;
@@ -409,17 +409,17 @@
             using namespace android::base;
             auto val = ParseBool(buf);
             if (val == ParseBoolResult::kFalse) {
-                incrementalRequest = CmdlineOption::Disable;
+                incremental_request = CmdlineOption::Disable;
             }
         }
     }
 
-    if (incrementalRequest == CmdlineOption::Enable) {
+    if (incremental_request == CmdlineOption::Enable) {
         // explicitly requested - no fallback
         return {INSTALL_INCREMENTAL, std::nullopt};
     }
     const auto bestMode = best_install_mode();
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // no opinion - use incremental, fallback to regular on a failure.
         return {INSTALL_INCREMENTAL, bestMode};
     }
@@ -427,57 +427,75 @@
     return {bestMode, std::nullopt};
 }
 
-int install_app(int argc, const char** argv) {
-    std::vector<int> processedArgIndices;
-    InstallMode installMode = INSTALL_DEFAULT;
-    bool use_fastdeploy = false;
-    bool is_reinstall = false;
-    bool wait = false;
-    auto incremental_request = CmdlineOption::None;
-    FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+static std::vector<const char*> parse_install_mode(std::vector<const char*> argv,
+                                                   InstallMode* install_mode,
+                                                   CmdlineOption* incremental_request,
+                                                   bool* incremental_wait) {
+    *install_mode = INSTALL_DEFAULT;
+    *incremental_request = CmdlineOption::None;
+    *incremental_wait = false;
 
-    for (int i = 1; i < argc; i++) {
-        if (argv[i] == "--streaming"sv) {
-            processedArgIndices.push_back(i);
-            installMode = INSTALL_STREAM;
-        } else if (argv[i] == "--no-streaming"sv) {
-            processedArgIndices.push_back(i);
-            installMode = INSTALL_PUSH;
-        } else if (argv[i] == "-r"sv) {
-            // Note that this argument is not added to processedArgIndices because it
-            // must be passed through to pm
-            is_reinstall = true;
-        } else if (argv[i] == "--fastdeploy"sv) {
-            processedArgIndices.push_back(i);
-            use_fastdeploy = true;
-        } else if (argv[i] == "--no-fastdeploy"sv) {
-            processedArgIndices.push_back(i);
-            use_fastdeploy = false;
-        } else if (argv[i] == "--force-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateAlways;
-        } else if (argv[i] == "--date-check-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
-        } else if (argv[i] == "--version-check-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
-        } else if (strlen(argv[i]) >= "--incr"sv.size() && "--incremental"sv.starts_with(argv[i])) {
-            processedArgIndices.push_back(i);
-            incremental_request = CmdlineOption::Enable;
-        } else if (strlen(argv[i]) >= "--no-incr"sv.size() &&
-                   "--no-incremental"sv.starts_with(argv[i])) {
-            processedArgIndices.push_back(i);
-            incremental_request = CmdlineOption::Disable;
-        } else if (argv[i] == "--wait"sv) {
-            processedArgIndices.push_back(i);
-            wait = true;
+    std::vector<const char*> passthrough;
+    for (auto&& arg : argv) {
+        if (arg == "--streaming"sv) {
+            *install_mode = INSTALL_STREAM;
+        } else if (arg == "--no-streaming"sv) {
+            *install_mode = INSTALL_PUSH;
+        } else if (strlen(arg) >= "--incr"sv.size() && "--incremental"sv.starts_with(arg)) {
+            *incremental_request = CmdlineOption::Enable;
+        } else if (strlen(arg) >= "--no-incr"sv.size() && "--no-incremental"sv.starts_with(arg)) {
+            *incremental_request = CmdlineOption::Disable;
+        } else if (arg == "--wait"sv) {
+            *incremental_wait = true;
+        } else {
+            passthrough.push_back(arg);
         }
     }
+    return passthrough;
+}
 
-    auto [primaryMode, fallbackMode] =
-            calculateInstallMode(installMode, use_fastdeploy, incremental_request);
-    if ((primaryMode == INSTALL_STREAM || fallbackMode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+static std::vector<const char*> parse_fast_deploy_mode(
+        std::vector<const char*> argv, bool* use_fastdeploy,
+        FastDeploy_AgentUpdateStrategy* agent_update_strategy) {
+    *use_fastdeploy = false;
+    *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+    std::vector<const char*> passthrough;
+    for (auto&& arg : argv) {
+        if (arg == "--fastdeploy"sv) {
+            *use_fastdeploy = true;
+        } else if (arg == "--no-fastdeploy"sv) {
+            *use_fastdeploy = false;
+        } else if (arg == "--force-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateAlways;
+        } else if (arg == "--date-check-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
+        } else if (arg == "--version-check-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+        } else {
+            passthrough.push_back(arg);
+        }
+    }
+    return passthrough;
+}
+
+int install_app(int argc, const char** argv) {
+    InstallMode install_mode = INSTALL_DEFAULT;
+    auto incremental_request = CmdlineOption::None;
+    bool incremental_wait = false;
+
+    bool use_fastdeploy = false;
+    FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+    auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request,
+                                          &incremental_wait);
+    auto passthrough_argv =
+            parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy);
+
+    auto [primary_mode, fallback_mode] =
+            calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+    if ((primary_mode == INSTALL_STREAM ||
+         fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
         best_install_mode() == INSTALL_PUSH) {
         error_exit("Attempting to use streaming install on unsupported device");
     }
@@ -491,19 +509,12 @@
     }
     fastdeploy_set_agent_update_strategy(agent_update_strategy);
 
-    std::vector<const char*> passthrough_argv;
-    for (int i = 0; i < argc; i++) {
-        if (std::find(processedArgIndices.begin(), processedArgIndices.end(), i) ==
-            processedArgIndices.end()) {
-            passthrough_argv.push_back(argv[i]);
-        }
-    }
     if (passthrough_argv.size() < 2) {
         error_exit("install requires an apk argument");
     }
 
-    auto runInstallMode = [&](InstallMode installMode, bool silent) {
-        switch (installMode) {
+    auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+        switch (install_mode) {
             case INSTALL_PUSH:
                 return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
                                           use_fastdeploy);
@@ -512,20 +523,20 @@
                                             use_fastdeploy);
             case INSTALL_INCREMENTAL:
                 return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
-                                               wait, silent);
+                                               incremental_wait, silent);
             case INSTALL_DEFAULT:
             default:
-                return 1;
+                error_exit("invalid install mode");
         }
     };
-    auto res = runInstallMode(primaryMode, fallbackMode.has_value());
-    if (res && fallbackMode.value_or(primaryMode) != primaryMode) {
-        res = runInstallMode(*fallbackMode, false);
+    auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+    if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+        res = run_install_mode(*fallback_mode, false);
     }
     return res;
 }
 
-int install_multiple_app(int argc, const char** argv) {
+static int install_multiple_app_streamed(int argc, const char** argv) {
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
@@ -551,7 +562,6 @@
     if (first_apk == -1) error_exit("need APK file on command line");
 
     const bool use_abb_exec = is_abb_exec_supported();
-
     const std::string install_cmd =
             use_abb_exec ? "package"
                          : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package";
@@ -674,6 +684,44 @@
     return EXIT_SUCCESS;
 }
 
+int install_multiple_app(int argc, const char** argv) {
+    InstallMode install_mode = INSTALL_DEFAULT;
+    auto incremental_request = CmdlineOption::None;
+    bool incremental_wait = false;
+    bool use_fastdeploy = false;
+
+    auto passthrough_argv = parse_install_mode({argv + 1, argv + argc}, &install_mode,
+                                               &incremental_request, &incremental_wait);
+
+    auto [primary_mode, fallback_mode] =
+            calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+    if ((primary_mode == INSTALL_STREAM ||
+         fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+        best_install_mode() == INSTALL_PUSH) {
+        error_exit("Attempting to use streaming install on unsupported device");
+    }
+
+    auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+        switch (install_mode) {
+            case INSTALL_PUSH:
+            case INSTALL_STREAM:
+                return install_multiple_app_streamed(passthrough_argv.size(),
+                                                     passthrough_argv.data());
+            case INSTALL_INCREMENTAL:
+                return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
+                                               incremental_wait, silent);
+            case INSTALL_DEFAULT:
+            default:
+                error_exit("invalid install mode");
+        }
+    };
+    auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+    if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+        res = run_install_mode(*fallback_mode, false);
+    }
+    return res;
+}
+
 int install_multi_package(int argc, const char** argv) {
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
@@ -698,23 +746,31 @@
         fprintf(stderr, "adb: multi-package install is not supported on this device\n");
         return EXIT_FAILURE;
     }
-    std::string install_cmd = "exec:cmd package";
 
-    std::string multi_package_cmd =
-            android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
+    const bool use_abb_exec = is_abb_exec_supported();
+    const std::string install_cmd = use_abb_exec ? "package" : "exec:cmd package";
+
+    std::vector<std::string> multi_package_cmd_args = {install_cmd, "install-create",
+                                                       "--multi-package"};
+
+    multi_package_cmd_args.reserve(first_package + 4);
     for (int i = 1; i < first_package; i++) {
-        multi_package_cmd += " " + escape_arg(argv[i]);
+        if (use_abb_exec) {
+            multi_package_cmd_args.push_back(argv[i]);
+        } else {
+            multi_package_cmd_args.push_back(escape_arg(argv[i]));
+        }
     }
 
     if (apex_found) {
-        multi_package_cmd += " --staged";
+        multi_package_cmd_args.emplace_back("--staged");
     }
 
     // Create multi-package install session
     std::string error;
     char buf[BUFSIZ];
     {
-        unique_fd fd(adb_connect(multi_package_cmd, &error));
+        unique_fd fd = send_command(multi_package_cmd_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
             return EXIT_FAILURE;
@@ -736,6 +792,7 @@
         fputs(buf, stderr);
         return EXIT_FAILURE;
     }
+    const auto parent_session_id_str = std::to_string(parent_session_id);
 
     fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
 
@@ -743,17 +800,30 @@
 
     // Valid session, now create the individual sessions and stream the APKs
     int success = EXIT_FAILURE;
-    std::string individual_cmd =
-            android::base::StringPrintf("%s install-create", install_cmd.c_str());
-    std::string all_session_ids = "";
+    std::vector<std::string> individual_cmd_args = {install_cmd, "install-create"};
     for (int i = 1; i < first_package; i++) {
-        individual_cmd += " " + escape_arg(argv[i]);
+        if (use_abb_exec) {
+            individual_cmd_args.push_back(argv[i]);
+        } else {
+            individual_cmd_args.push_back(escape_arg(argv[i]));
+        }
     }
     if (apex_found) {
-        individual_cmd += " --staged";
+        individual_cmd_args.emplace_back("--staged");
     }
-    std::string individual_apex_cmd = individual_cmd + " --apex";
-    std::string cmd = "";
+
+    std::vector<std::string> individual_apex_cmd_args;
+    if (apex_found) {
+        individual_apex_cmd_args = individual_cmd_args;
+        individual_apex_cmd_args.emplace_back("--apex");
+    }
+
+    std::vector<std::string> add_session_cmd_args = {
+            install_cmd,
+            "install-add-session",
+            parent_session_id_str,
+    };
+
     for (int i = first_package; i < argc; i++) {
         const char* file = argv[i];
         char buf[BUFSIZ];
@@ -761,9 +831,9 @@
             unique_fd fd;
             // Create individual install session
             if (android::base::EndsWithIgnoreCase(file, ".apex")) {
-                fd.reset(adb_connect(individual_apex_cmd, &error));
+                fd = send_command(individual_apex_cmd_args, &error);
             } else {
-                fd.reset(adb_connect(individual_cmd, &error));
+                fd = send_command(individual_cmd_args, &error);
             }
             if (fd < 0) {
                 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
@@ -786,6 +856,7 @@
             fputs(buf, stderr);
             goto finalize_multi_package_session;
         }
+        const auto session_id_str = std::to_string(session_id);
 
         fprintf(stdout, "Created child session ID %d.\n", session_id);
         session_ids.push_back(session_id);
@@ -800,10 +871,15 @@
                 goto finalize_multi_package_session;
             }
 
-            std::string cmd = android::base::StringPrintf(
-                    "%s install-write -S %" PRIu64 " %d %d_%s -", install_cmd.c_str(),
-                    static_cast<uint64_t>(sb.st_size), session_id, i,
-                    android::base::Basename(split).c_str());
+            std::vector<std::string> cmd_args = {
+                    install_cmd,
+                    "install-write",
+                    "-S",
+                    std::to_string(sb.st_size),
+                    session_id_str,
+                    android::base::StringPrintf("%d_%s", i, android::base::Basename(file).c_str()),
+                    "-",
+            };
 
             unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC));
             if (local_fd < 0) {
@@ -812,7 +888,7 @@
             }
 
             std::string error;
-            unique_fd remote_fd(adb_connect(cmd, &error));
+            unique_fd remote_fd = send_command(cmd_args, &error);
             if (remote_fd < 0) {
                 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
                 goto finalize_multi_package_session;
@@ -831,13 +907,11 @@
                 goto finalize_multi_package_session;
             }
         }
-        all_session_ids += android::base::StringPrintf(" %d", session_id);
+        add_session_cmd_args.push_back(std::to_string(session_id));
     }
 
-    cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
-                                      parent_session_id, all_session_ids.c_str());
     {
-        unique_fd fd(adb_connect(cmd, &error));
+        unique_fd fd = send_command(add_session_cmd_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
             goto finalize_multi_package_session;
@@ -846,7 +920,8 @@
     }
 
     if (strncmp("Success", buf, 7)) {
-        fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
+        fprintf(stderr, "adb: failed to link sessions (%s)\n",
+                android::base::Join(add_session_cmd_args, " ").c_str());
         fputs(buf, stderr);
         goto finalize_multi_package_session;
     }
@@ -856,11 +931,14 @@
 
 finalize_multi_package_session:
     // Commit session if we streamed everything okay; otherwise abandon
-    std::string service =
-            android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
-                                        success == 0 ? "commit" : "abandon", parent_session_id);
+    std::vector<std::string> service_args = {
+            install_cmd,
+            success == 0 ? "install-commit" : "install-abandon",
+            parent_session_id_str,
+    };
+
     {
-        unique_fd fd(adb_connect(service, &error));
+        unique_fd fd = send_command(service_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             return EXIT_FAILURE;
@@ -881,10 +959,13 @@
     session_ids.push_back(parent_session_id);
     // try to abandon all remaining sessions
     for (std::size_t i = 0; i < session_ids.size(); i++) {
-        service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
-                                              session_ids[i]);
+        std::vector<std::string> service_args = {
+                install_cmd,
+                "install-abandon",
+                std::to_string(session_ids[i]),
+        };
         fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
-        unique_fd fd(adb_connect(service, &error));
+        unique_fd fd = send_command(service_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             continue;
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index a7cde68..cf0f1ac 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -117,8 +117,10 @@
         "device/main.cpp",
         "device/usb.cpp",
         "device/usb_client.cpp",
+        "device/tcp_client.cpp",
         "device/utility.cpp",
         "device/variables.cpp",
+        "socket.cpp",
     ],
 
     shared_libs: [
@@ -143,6 +145,7 @@
     ],
 
     static_libs: [
+        "libgtest_prod",
         "libhealthhalutils",
         "libsnapshot_nobinder",
     ],
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index bb085c5..1b0859f 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -19,6 +19,7 @@
 #include <algorithm>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android/hardware/boot/1.0/IBootControl.h>
 #include <android/hardware/fastboot/1.0/IFastboot.h>
@@ -28,6 +29,7 @@
 
 #include "constants.h"
 #include "flashing.h"
+#include "tcp_client.h"
 #include "usb_client.h"
 
 using android::fs_mgr::EnsurePathUnmounted;
@@ -60,11 +62,16 @@
               {FB_CMD_GSI, GsiHandler},
               {FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
       }),
-      transport_(std::make_unique<ClientUsbTransport>()),
       boot_control_hal_(IBootControl::getService()),
       health_hal_(get_health_service()),
       fastboot_hal_(IFastboot::getService()),
       active_slot_("") {
+    if (android::base::GetProperty("fastbootd.protocol", "usb") == "tcp") {
+        transport_ = std::make_unique<ClientTcpTransport>();
+    } else {
+        transport_ = std::make_unique<ClientUsbTransport>();
+    }
+
     if (boot_control_hal_) {
         boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
     }
diff --git a/fastboot/device/tcp_client.cpp b/fastboot/device/tcp_client.cpp
new file mode 100644
index 0000000..ec5e1e3
--- /dev/null
+++ b/fastboot/device/tcp_client.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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 "tcp_client.h"
+#include "constants.h"
+
+#include <android-base/errors.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+static constexpr int kDefaultPort = 5554;
+static constexpr int kProtocolVersion = 1;
+static constexpr int kHandshakeTimeoutMs = 2000;
+static constexpr size_t kHandshakeLength = 4;
+
+// Extract the big-endian 8-byte message length into a 64-bit number.
+static uint64_t ExtractMessageLength(const void* buffer) {
+    uint64_t ret = 0;
+    for (int i = 0; i < 8; ++i) {
+        ret |= uint64_t{reinterpret_cast<const uint8_t*>(buffer)[i]} << (56 - i * 8);
+    }
+    return ret;
+}
+
+// Encode the 64-bit number into a big-endian 8-byte message length.
+static void EncodeMessageLength(uint64_t length, void* buffer) {
+    for (int i = 0; i < 8; ++i) {
+        reinterpret_cast<uint8_t*>(buffer)[i] = length >> (56 - i * 8);
+    }
+}
+
+ClientTcpTransport::ClientTcpTransport() {
+    service_ = Socket::NewServer(Socket::Protocol::kTcp, kDefaultPort);
+
+    // A workaround to notify recovery to continue its work.
+    android::base::SetProperty("sys.usb.ffs.ready", "1");
+}
+
+ssize_t ClientTcpTransport::Read(void* data, size_t len) {
+    if (len > SSIZE_MAX) {
+        return -1;
+    }
+
+    size_t total_read = 0;
+    do {
+        // Read a new message
+        while (message_bytes_left_ == 0) {
+            if (socket_ == nullptr) {
+                ListenFastbootSocket();
+            }
+
+            char buffer[8];
+            if (socket_->ReceiveAll(buffer, 8, 0) == 8) {
+                message_bytes_left_ = ExtractMessageLength(buffer);
+            } else {
+                // If connection is closed by host, Receive will return 0 immediately.
+                socket_.reset(nullptr);
+                // In DATA phase, return error.
+                if (downloading_) {
+                    return -1;
+                }
+            }
+        }
+
+        size_t read_length = len - total_read;
+        if (read_length > message_bytes_left_) {
+            read_length = message_bytes_left_;
+        }
+        ssize_t bytes_read =
+                socket_->ReceiveAll(reinterpret_cast<char*>(data) + total_read, read_length, 0);
+        if (bytes_read == -1) {
+            socket_.reset(nullptr);
+            return -1;
+        } else {
+            message_bytes_left_ -= bytes_read;
+            total_read += bytes_read;
+        }
+    // There are more than one DATA phases if the downloading buffer is too
+    // large, like a very big system image. All of data phases should be
+    // received until the whole buffer is filled in that case.
+    } while (downloading_ && total_read < len);
+
+    return total_read;
+}
+
+ssize_t ClientTcpTransport::Write(const void* data, size_t len) {
+    if (socket_ == nullptr || len > SSIZE_MAX) {
+        return -1;
+    }
+
+    // Use multi-buffer writes for better performance.
+    char header[8];
+    EncodeMessageLength(len, header);
+
+    if (!socket_->Send(std::vector<cutils_socket_buffer_t>{{header, 8}, {data, len}})) {
+        socket_.reset(nullptr);
+        return -1;
+    }
+
+    // In DATA phase
+    if (android::base::StartsWith(reinterpret_cast<const char*>(data), RESPONSE_DATA)) {
+        downloading_ = true;
+    } else {
+        downloading_ = false;
+    }
+
+    return len;
+}
+
+int ClientTcpTransport::Close() {
+    if (socket_ == nullptr) {
+        return -1;
+    }
+    socket_.reset(nullptr);
+
+    return 0;
+}
+
+int ClientTcpTransport::Reset() {
+    return Close();
+}
+
+void ClientTcpTransport::ListenFastbootSocket() {
+    while (true) {
+        socket_ = service_->Accept();
+
+        // Handshake
+        char buffer[kHandshakeLength + 1];
+        buffer[kHandshakeLength] = '\0';
+        if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) !=
+            kHandshakeLength) {
+            PLOG(ERROR) << "No Handshake message received";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        if (memcmp(buffer, "FB", 2) != 0) {
+            PLOG(ERROR) << "Unrecognized initialization message";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        int version = 0;
+        if (!android::base::ParseInt(buffer + 2, &version) || version < kProtocolVersion) {
+            LOG(ERROR) << "Unknown TCP protocol version " << buffer + 2
+                       << ", our version: " << kProtocolVersion;
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        std::string handshake_message(android::base::StringPrintf("FB%02d", kProtocolVersion));
+        if (!socket_->Send(handshake_message.c_str(), kHandshakeLength)) {
+            PLOG(ERROR) << "Failed to send initialization message";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        break;
+    }
+}
diff --git a/fastboot/device/tcp_client.h b/fastboot/device/tcp_client.h
new file mode 100644
index 0000000..32e9834
--- /dev/null
+++ b/fastboot/device/tcp_client.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "socket.h"
+#include "transport.h"
+
+class ClientTcpTransport : public Transport {
+  public:
+    ClientTcpTransport();
+    ~ClientTcpTransport() override = default;
+
+    ssize_t Read(void* data, size_t len) override;
+    ssize_t Write(const void* data, size_t len) override;
+    int Close() override;
+    int Reset() override;
+
+  private:
+    void ListenFastbootSocket();
+
+    std::unique_ptr<Socket> service_;
+    std::unique_ptr<Socket> socket_;
+    uint64_t message_bytes_left_ = 0;
+    bool downloading_ = false;
+
+    DISALLOW_COPY_AND_ASSIGN(ClientTcpTransport);
+};
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index e56ffcf..5a14b63 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -54,7 +54,9 @@
     while (total < length) {
         ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
 
-        if (bytes == -1) {
+        // Returns 0 only when the peer has disconnected because our requested length is not 0. So
+        // we return immediately to avoid dead loop here.
+        if (bytes <= 0) {
             if (total == 0) {
                 return -1;
             }
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index ea9c957..9046132 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -52,17 +52,27 @@
 using DmTargetZero = android::dm::DmTargetZero;
 using DmTargetLinear = android::dm::DmTargetLinear;
 
-static bool GetPhysicalPartitionDevicePath(const IPartitionOpener& opener,
-                                           const LpMetadata& metadata,
+static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params,
                                            const LpMetadataBlockDevice& block_device,
                                            const std::string& super_device, std::string* result) {
     // If the super device is the source of this block device's metadata,
     // make sure we use the correct super device (and not just "super",
     // which might not exist.)
     std::string name = GetBlockDevicePartitionName(block_device);
-    std::string dev_string = opener.GetDeviceString(name);
-    if (GetMetadataSuperBlockDevice(metadata) == &block_device) {
-        dev_string = opener.GetDeviceString(super_device);
+    if (android::base::StartsWith(name, "dm-")) {
+        // Device-mapper nodes are not normally allowed in LpMetadata, since
+        // they are not consistent across reboots. However for the purposes of
+        // testing it's useful to handle them. For example when running DSUs,
+        // userdata is a device-mapper device, and some stacking will result
+        // when using libfiemap.
+        *result = "/dev/block/" + name;
+        return true;
+    }
+
+    auto opener = params.partition_opener;
+    std::string dev_string = opener->GetDeviceString(name);
+    if (GetMetadataSuperBlockDevice(*params.metadata) == &block_device) {
+        dev_string = opener->GetDeviceString(super_device);
     }
 
     // Note: device-mapper will not accept symlinks, so we must use realpath
@@ -93,8 +103,8 @@
             case LP_TARGET_TYPE_LINEAR: {
                 const auto& block_device = params.metadata->block_devices[extent.target_source];
                 std::string dev_string;
-                if (!GetPhysicalPartitionDevicePath(*params.partition_opener, *params.metadata,
-                                                    block_device, super_device, &dev_string)) {
+                if (!GetPhysicalPartitionDevicePath(params, block_device, super_device,
+                                                    &dev_string)) {
                     LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
                     return false;
                 }
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 6717922..3ee742f 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -51,6 +51,7 @@
 using android::fs_mgr::GetPartitionName;
 
 static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
+static constexpr char kOtaTestImageMetadataDir[] = "/metadata/gsi/ota/test";
 
 std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
     auto metadata_dir = "/metadata/gsi/" + dir_prefix;
@@ -135,10 +136,13 @@
     return !!FindPartition(*metadata.get(), name);
 }
 
+static bool IsTestDir(const std::string& path) {
+    return android::base::StartsWith(path, kTestImageMetadataDir) ||
+           android::base::StartsWith(path, kOtaTestImageMetadataDir);
+}
+
 static bool IsUnreliablePinningAllowed(const std::string& path) {
-    return android::base::StartsWith(path, "/data/gsi/dsu/") ||
-           android::base::StartsWith(path, "/data/gsi/test/") ||
-           android::base::StartsWith(path, "/data/gsi/ota/test/");
+    return android::base::StartsWith(path, "/data/gsi/dsu/") || IsTestDir(path);
 }
 
 FiemapStatus ImageManager::CreateBackingImage(
@@ -174,8 +178,7 @@
     // if device-mapper is stacked in some complex way not supported by
     // FiemapWriter.
     auto device_path = GetDevicePathForFile(fw.get());
-    if (android::base::StartsWith(device_path, "/dev/block/dm-") &&
-        !android::base::StartsWith(metadata_dir_, kTestImageMetadataDir)) {
+    if (android::base::StartsWith(device_path, "/dev/block/dm-") && !IsTestDir(metadata_dir_)) {
         LOG(ERROR) << "Cannot persist images against device-mapper device: " << device_path;
 
         fw = {};
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 4505382..2288674 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -124,6 +124,64 @@
     return true;
 }
 
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
+    bool found = false;
+    const uint8_t* desc_partition_name;
+    auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
+
+    for (const auto& vbmeta : vbmeta_images) {
+        size_t num_descriptors;
+        std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
+                avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+        if (!descriptors || num_descriptors < 1) {
+            continue;
+        }
+
+        for (size_t n = 0; n < num_descriptors && !found; n++) {
+            AvbDescriptor desc;
+            if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+                LWARNING << "Descriptor[" << n << "] is invalid";
+                continue;
+            }
+            if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
+                desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
+                if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
+                                                               hash_desc.get())) {
+                    continue;
+                }
+                if (hash_desc->partition_name_len != partition_name.length()) {
+                    continue;
+                }
+                // Notes that desc_partition_name is not NUL-terminated.
+                std::string hash_partition_name((const char*)desc_partition_name,
+                                                hash_desc->partition_name_len);
+                if (hash_partition_name == partition_name) {
+                    found = true;
+                }
+            }
+        }
+
+        if (found) break;
+    }
+
+    if (!found) {
+        LERROR << "Hash descriptor not found: " << partition_name;
+        return nullptr;
+    }
+
+    hash_desc->partition_name = partition_name;
+
+    const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
+    hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
+
+    const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
+    hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
+
+    return hash_desc;
+}
+
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
     bool found = false;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 09c786a..e8f7c39 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -40,6 +40,9 @@
 std::string GetAvbPropertyDescriptor(const std::string& key,
                                      const std::vector<VBMetaData>& vbmeta_images);
 
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
+
 // AvbHashtreeDescriptor to dm-verity table setup.
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
index f82f83d..1c14cc0 100644
--- a/fs_mgr/libfs_avb/fs_avb_util.cpp
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -74,5 +74,15 @@
     return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
 }
 
+// Given a path, loads and verifies the vbmeta, to extract the Avb Hash descriptor.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+                                                       VBMetaData&& vbmeta) {
+    if (!vbmeta.size()) return nullptr;
+
+    std::vector<VBMetaData> vbmeta_images;
+    vbmeta_images.emplace_back(std::move(vbmeta));
+    return GetHashDescriptor(avb_partition_name, vbmeta_images);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
index ec8badb..3f37bd7 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -32,9 +32,20 @@
                                                 std::string* out_avb_partition_name,
                                                 VBMetaVerifyResult* out_verify_result);
 
+// Loads the single vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+        const std::string& image_path, const std::string& partition_name,
+        const std::string& expected_public_key_blob, bool allow_verification_error,
+        bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
+        bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result);
+
 // Gets the hashtree descriptor for avb_partition_name from the vbmeta.
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& avb_partition_name, VBMetaData&& vbmeta);
 
+// Gets the hash descriptor for avb_partition_name from the vbmeta.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+                                                       VBMetaData&& vbmeta);
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/types.h b/fs_mgr/libfs_avb/include/fs_avb/types.h
index bd638e6..f2aa7cc 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/types.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/types.h
@@ -55,6 +55,12 @@
 
 std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
 
+struct FsAvbHashDescriptor : AvbHashDescriptor {
+    std::string partition_name;
+    std::string salt;
+    std::string digest;
+};
+
 struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
     std::string partition_name;
     std::string salt;
diff --git a/init/README.md b/init/README.md
index 726c0cc..b70366b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -644,7 +644,8 @@
 `wait <path> [ <timeout> ]`
 > Poll for the existence of the given file and return when found,
   or the timeout has been reached. If timeout is not specified it
-  currently defaults to five seconds.
+  currently defaults to five seconds. The timeout value can be
+  fractional seconds, specified in floating point notation.
 
 `wait_for_prop <name> <value>`
 > Wait for system property _name_ to be _value_. Properties are expanded
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..149a766 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -49,6 +49,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -1065,11 +1066,12 @@
 static Result<void> do_wait(const BuiltinArguments& args) {
     auto timeout = kCommandRetryTimeout;
     if (args.size() == 3) {
-        int timeout_int;
-        if (!android::base::ParseInt(args[2], &timeout_int)) {
+        double timeout_double;
+        if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
             return Error() << "failed to parse timeout";
         }
-        timeout = std::chrono::seconds(timeout_int);
+        timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                std::chrono::duration<double>(timeout_double));
     }
 
     if (wait_for_file(args[1].c_str(), timeout) != 0) {
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index d62ecb0..d1a84f3 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 
 #include <android-base/logging.h>
+#include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 
@@ -205,8 +206,8 @@
 
 Result<void> check_wait(const BuiltinArguments& args) {
     if (args.size() == 3 && !args[2].empty()) {
-        int timeout_int;
-        if (!android::base::ParseInt(args[2], &timeout_int)) {
+        double timeout_double;
+        if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
             return Error() << "failed to parse timeout";
         }
     }
diff --git a/init/init.cpp b/init/init.cpp
index 6465df1..29859c5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -509,7 +509,9 @@
 // Set the UDC controller for the ConfigFS USB Gadgets.
 // Read the UDC controller in use from "/sys/class/udc".
 // In case of multiple UDC controllers select the first one.
-static void set_usb_controller() {
+static void SetUsbController() {
+    static auto controller_set = false;
+    if (controller_set) return;
     std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
     if (!dir) return;
 
@@ -518,6 +520,7 @@
         if (dp->d_name[0] == '.') continue;
 
         SetProperty("sys.usb.controller", dp->d_name);
+        controller_set = true;
         break;
     }
 }
@@ -772,7 +775,7 @@
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
     MountHandler mount_handler(&epoll);
-    set_usb_controller();
+    SetUsbController();
 
     const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
     Action::set_function_map(&function_map);
@@ -879,6 +882,7 @@
         }
         if (!IsShuttingDown()) {
             HandleControlMessages();
+            SetUsbController();
         }
     }
 
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
index 74acb20..549acdc 100644
--- a/libstats/socket/stats_buffer_writer.c
+++ b/libstats/socket/stats_buffer_writer.c
@@ -50,24 +50,16 @@
 int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
     int ret = 1;
 
-#ifdef __ANDROID__
-    bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
-#else
-    bool statsdEnabled = false;
-#endif
+    struct iovec vecs[2];
+    vecs[0].iov_base = (void*)&kStatsEventTag;
+    vecs[0].iov_len = sizeof(kStatsEventTag);
+    vecs[1].iov_base = buffer;
+    vecs[1].iov_len = size;
 
-    if (statsdEnabled) {
-        struct iovec vecs[2];
-        vecs[0].iov_base = (void*)&kStatsEventTag;
-        vecs[0].iov_len = sizeof(kStatsEventTag);
-        vecs[1].iov_base = buffer;
-        vecs[1].iov_len = size;
+    ret = __write_to_statsd(vecs, 2);
 
-        ret = __write_to_statsd(vecs, 2);
-
-        if (ret < 0) {
-            note_log_drop(ret, atomId);
-        }
+    if (ret < 0) {
+        note_log_drop(ret, atomId);
     }
 
     return ret;