Merge "lmkd: rate-limit and cleanup failed kill reports"
diff --git a/adb/Android.bp b/adb/Android.bp
index 1469e77..6cff0be 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -174,12 +174,6 @@
         "libdiagnose_usb",
         "libmdnssd",
         "libusb",
-        "libandroidfw",
-        "libziparchive",
-        "libz",
-        "libutils",
-        "liblog",
-        "libcutils",
     ],
 }
 
@@ -262,12 +256,6 @@
         "liblog",
         "libmdnssd",
         "libusb",
-        "libandroidfw",
-        "libziparchive",
-        "libz",
-        "libutils",
-        "liblog",
-        "libcutils",
     ],
 
     stl: "libc++_static",
@@ -277,6 +265,10 @@
     // will violate ODR
     shared_libs: [],
 
+    required: [
+        "deploypatchgenerator",
+    ],
+
     target: {
         darwin: {
             cflags: [
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 95574ed..c0d09fd 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -40,6 +40,8 @@
 #include <android-base/strings.h>
 #include <android-base/test_utils.h>
 
+static constexpr int kFastDeployMinApi = 24;
+
 static bool _use_legacy_install() {
     FeatureSet features;
     std::string error;
@@ -130,7 +132,7 @@
 }
 
 static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy,
-                                bool use_localagent, const char* adb_path) {
+                                bool use_localagent) {
     printf("Performing Streamed Install\n");
 
     // The last argument must be the APK file
@@ -152,8 +154,7 @@
             printf("failed to extract metadata %d\n", metadata_len);
             return 1;
         } else {
-            int create_patch_result = create_patch(file, metadataTmpFile.path, patchTmpFile.path,
-                                                   use_localagent, adb_path);
+            int create_patch_result = create_patch(file, metadataTmpFile.path, patchTmpFile.path);
             if (create_patch_result != 0) {
                 printf("Patch creation failure, error code: %d\n", create_patch_result);
                 result = create_patch_result;
@@ -226,8 +227,8 @@
     }
 }
 
-static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy, bool use_localagent,
-                              const char* adb_path) {
+static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy,
+                              bool use_localagent) {
     static const char* const DATA_DEST = "/data/local/tmp/%s";
     static const char* const SD_DEST = "/sdcard/tmp/%s";
     const char* where = DATA_DEST;
@@ -269,8 +270,8 @@
             printf("failed to extract metadata %d\n", metadata_len);
             return 1;
         } else {
-            int create_patch_result = create_patch(apk_file[0], metadataTmpFile.path,
-                                                   patchTmpFile.path, use_localagent, adb_path);
+            int create_patch_result =
+                    create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
             if (create_patch_result != 0) {
                 printf("Patch creation failure, error code: %d\n", create_patch_result);
                 result = create_patch_result;
@@ -380,14 +381,10 @@
         }
     }
 
-    std::string adb_path = android::base::GetExecutablePath();
-
-    if (adb_path.length() == 0) {
-        return 1;
-    }
     if (use_fastdeploy == true) {
-        bool agent_up_to_date =
-                update_agent(agent_update_strategy, use_localagent, adb_path.c_str());
+        fastdeploy_set_local_agent(use_localagent);
+
+        bool agent_up_to_date = update_agent(agent_update_strategy);
         if (agent_up_to_date == false) {
             printf("Failed to update agent, exiting\n");
             return 1;
@@ -397,10 +394,10 @@
     switch (installMode) {
         case INSTALL_PUSH:
             return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
-                                      use_fastdeploy, use_localagent, adb_path.c_str());
+                                      use_fastdeploy, use_localagent);
         case INSTALL_STREAM:
             return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
-                                        use_fastdeploy, use_localagent, adb_path.c_str());
+                                        use_fastdeploy, use_localagent);
         case INSTALL_DEFAULT:
         default:
             return 1;
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index 3b05661..2914836 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <androidfw/ResourceTypes.h>
-#include <androidfw/ZipFileRO.h>
 #include <libgen.h>
 #include <algorithm>
+#include <array>
 
+#include "android-base/file.h"
+#include "android-base/strings.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
@@ -29,11 +30,13 @@
 
 static constexpr const char* kDeviceAgentPath = "/data/local/tmp/";
 
+static bool use_localagent = false;
+
 long get_agent_version() {
     std::vector<char> versionOutputBuffer;
     std::vector<char> versionErrorBuffer;
 
-    int statusCode = capture_shell_command("/data/local/tmp/deployagent.sh version",
+    int statusCode = capture_shell_command("/data/local/tmp/deployagent version",
                                            &versionOutputBuffer, &versionErrorBuffer);
     long version = -1;
 
@@ -58,13 +61,15 @@
     return api_level;
 }
 
+void fastdeploy_set_local_agent(bool set_use_localagent) {
+    use_localagent = set_use_localagent;
+}
+
 // local_path - must start with a '/' and be relative to $ANDROID_PRODUCT_OUT
-static bool get_agent_component_host_path(bool use_localagent, const char* adb_path,
-                                          const char* local_path, const char* sdk_path,
+static bool get_agent_component_host_path(const char* local_path, const char* sdk_path,
                                           std::string* output_path) {
-    std::string mutable_adb_path = adb_path;
-    const char* adb_dir = dirname(&mutable_adb_path[0]);
-    if (adb_dir == nullptr) {
+    std::string adb_dir = android::base::GetExecutableDirectory();
+    if (adb_dir.empty()) {
         return false;
     }
 
@@ -76,26 +81,24 @@
         *output_path = android::base::StringPrintf("%s%s", product_out, local_path);
         return true;
     } else {
-        *output_path = android::base::StringPrintf("%s%s", adb_dir, sdk_path);
+        *output_path = adb_dir + sdk_path;
         return true;
     }
     return false;
 }
 
-static bool deploy_agent(bool checkTimeStamps, bool use_localagent, const char* adb_path) {
+static bool deploy_agent(bool checkTimeStamps) {
     std::vector<const char*> srcs;
-
     std::string agent_jar_path;
-    if (get_agent_component_host_path(use_localagent, adb_path, "/system/framework/deployagent.jar",
-                                      "/deployagent.jar", &agent_jar_path)) {
+    if (get_agent_component_host_path("/system/framework/deployagent.jar", "/deployagent.jar",
+                                      &agent_jar_path)) {
         srcs.push_back(agent_jar_path.c_str());
     } else {
         return false;
     }
 
     std::string agent_sh_path;
-    if (get_agent_component_host_path(use_localagent, adb_path, "/system/bin/deployagent.sh",
-                                      "/deployagent.sh", &agent_sh_path)) {
+    if (get_agent_component_host_path("/system/bin/deployagent", "/deployagent", &agent_sh_path)) {
         srcs.push_back(agent_sh_path.c_str());
     } else {
         return false;
@@ -104,7 +107,7 @@
     if (do_sync_push(srcs, kDeviceAgentPath, checkTimeStamps)) {
         // on windows the shell script might have lost execute permission
         // so need to set this explicitly
-        const char* kChmodCommandPattern = "chmod 777 %sdeployagent.sh";
+        const char* kChmodCommandPattern = "chmod 777 %sdeployagent";
         std::string chmodCommand =
                 android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentPath);
         int ret = send_shell_command(chmodCommand);
@@ -114,17 +117,16 @@
     }
 }
 
-bool update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy, bool use_localagent,
-                  const char* adb_path) {
+bool update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy) {
     long agent_version = get_agent_version();
     switch (agentUpdateStrategy) {
         case FastDeploy_AgentUpdateAlways:
-            if (deploy_agent(false, use_localagent, adb_path) == false) {
+            if (deploy_agent(false) == false) {
                 return false;
             }
             break;
         case FastDeploy_AgentUpdateNewerTimeStamp:
-            if (deploy_agent(true, use_localagent, adb_path) == false) {
+            if (deploy_agent(true) == false) {
                 return false;
             }
             break;
@@ -136,7 +138,7 @@
                     printf("Device agent version is (%ld), (%ld) is required, re-deploying\n",
                            agent_version, kRequiredAgentVersion);
                 }
-                if (deploy_agent(false, use_localagent, adb_path) == false) {
+                if (deploy_agent(false) == false) {
                     return false;
                 }
             }
@@ -147,91 +149,54 @@
     return (agent_version == kRequiredAgentVersion);
 }
 
-static std::string get_string_from_utf16(const char16_t* input, int input_len) {
-    ssize_t utf8_length = utf16_to_utf8_length(input, input_len);
-    if (utf8_length <= 0) {
-        return {};
+static std::string get_aapt2_path() {
+    if (use_localagent) {
+        // This should never happen on a Windows machine
+        const char* host_out = getenv("ANDROID_HOST_OUT");
+        if (host_out == nullptr) {
+            fatal("Could not locate aapt2 because $ANDROID_HOST_OUT is not defined");
+        }
+        return android::base::StringPrintf("%s/bin/aapt2", host_out);
     }
 
-    std::string utf8;
-    utf8.resize(utf8_length);
-    utf16_to_utf8(input, input_len, &*utf8.begin(), utf8_length + 1);
-    return utf8;
+    std::string adb_dir = android::base::GetExecutableDirectory();
+    if (adb_dir.empty()) {
+        fatal("Could not locate aapt2");
+    }
+    return adb_dir + "/aapt2";
+}
+
+static int system_capture(const char* cmd, std::string& output) {
+    FILE* pipe = popen(cmd, "re");
+    int fd = -1;
+
+    if (pipe != nullptr) {
+        fd = fileno(pipe);
+    }
+
+    if (fd == -1) {
+        fatal_errno("Could not create pipe for process '%s'", cmd);
+    }
+
+    if (!android::base::ReadFdToString(fd, &output)) {
+        fatal_errno("Error reading from process '%s'", cmd);
+    }
+
+    return pclose(pipe);
 }
 
 // output is required to point to a valid output string (non-null)
 static bool get_packagename_from_apk(const char* apkPath, std::string* output) {
-    using namespace android;
+    const char* kAapt2DumpNameCommandPattern = R"(%s dump packagename "%s")";
+    std::string aapt2_path_string = get_aapt2_path();
+    std::string getPackagenameCommand = android::base::StringPrintf(
+            kAapt2DumpNameCommandPattern, aapt2_path_string.c_str(), apkPath);
 
-    ZipFileRO* zipFile = ZipFileRO::open(apkPath);
-    if (zipFile == nullptr) {
-        return false;
+    if (system_capture(getPackagenameCommand.c_str(), *output) == 0) {
+        // strip any line end characters from the output
+        *output = android::base::Trim(*output);
+        return true;
     }
-
-    ZipEntryRO entry = zipFile->findEntryByName("AndroidManifest.xml");
-    if (entry == nullptr) {
-        return false;
-    }
-
-    uint32_t manifest_len = 0;
-    if (!zipFile->getEntryInfo(entry, NULL, &manifest_len, NULL, NULL, NULL, NULL)) {
-        return false;
-    }
-
-    std::vector<char> manifest_data(manifest_len);
-    if (!zipFile->uncompressEntry(entry, manifest_data.data(), manifest_len)) {
-        return false;
-    }
-
-    ResXMLTree tree;
-    status_t setto_status = tree.setTo(manifest_data.data(), manifest_len, true);
-    if (setto_status != NO_ERROR) {
-        return false;
-    }
-
-    ResXMLParser::event_code_t code;
-    while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
-           code != ResXMLParser::END_DOCUMENT) {
-        switch (code) {
-            case ResXMLParser::START_TAG: {
-                size_t element_name_length;
-                const char16_t* element_name = tree.getElementName(&element_name_length);
-                if (element_name == nullptr) {
-                    continue;
-                }
-
-                std::u16string element_name_string(element_name, element_name_length);
-                if (element_name_string == u"manifest") {
-                    for (int i = 0; i < (int)tree.getAttributeCount(); i++) {
-                        size_t attribute_name_length;
-                        const char16_t* attribute_name_text =
-                                tree.getAttributeName(i, &attribute_name_length);
-                        if (attribute_name_text == nullptr) {
-                            continue;
-                        }
-                        std::u16string attribute_name_string(attribute_name_text,
-                                                             attribute_name_length);
-
-                        if (attribute_name_string == u"package") {
-                            size_t attribute_value_length;
-                            const char16_t* attribute_value_text =
-                                    tree.getAttributeStringValue(i, &attribute_value_length);
-                            if (attribute_value_text == nullptr) {
-                                continue;
-                            }
-                            *output = get_string_from_utf16(attribute_value_text,
-                                                            attribute_value_length);
-                            return true;
-                        }
-                    }
-                }
-                break;
-            }
-            default:
-                break;
-        }
-    }
-
     return false;
 }
 
@@ -241,7 +206,7 @@
         return -1;
     }
 
-    const char* kAgentExtractCommandPattern = "/data/local/tmp/deployagent.sh extract %s";
+    const char* kAgentExtractCommandPattern = "/data/local/tmp/deployagent extract %s";
     std::string extractCommand =
             android::base::StringPrintf(kAgentExtractCommandPattern, packageName.c_str());
 
@@ -257,43 +222,30 @@
     return ret;
 }
 
-// output is required to point to a valid output string (non-null)
-static bool patch_generator_command(bool use_localagent, const char* adb_path,
-                                    std::string* output) {
+static std::string get_patch_generator_command() {
     if (use_localagent) {
         // This should never happen on a Windows machine
-        const char* kGeneratorCommandPattern = "java -jar %s/framework/deploypatchgenerator.jar";
         const char* host_out = getenv("ANDROID_HOST_OUT");
         if (host_out == nullptr) {
-            return false;
+            fatal("Could not locate deploypatchgenerator.jar because $ANDROID_HOST_OUT is not "
+                  "defined");
         }
-        *output = android::base::StringPrintf(kGeneratorCommandPattern, host_out, host_out);
-        return true;
-    } else {
-        const char* kGeneratorCommandPattern = R"(java -jar "%s/deploypatchgenerator.jar")";
-        std::string mutable_adb_path = adb_path;
-        const char* adb_dir = dirname(&mutable_adb_path[0]);
-        if (adb_dir == nullptr) {
-            return false;
-        }
-
-        *output = android::base::StringPrintf(kGeneratorCommandPattern, adb_dir, adb_dir);
-        return true;
+        return android::base::StringPrintf("java -jar %s/framework/deploypatchgenerator.jar",
+                                           host_out);
     }
-    return false;
+
+    std::string adb_dir = android::base::GetExecutableDirectory();
+    if (adb_dir.empty()) {
+        fatal("Could not locate deploypatchgenerator.jar");
+    }
+    return android::base::StringPrintf(R"(java -jar "%s/deploypatchgenerator.jar")",
+                                       adb_dir.c_str());
 }
 
-int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath,
-                 bool use_localagent, const char* adb_path) {
-    const char* kGeneratePatchCommandPattern = R"(%s "%s" "%s" > "%s")";
-    std::string patch_generator_command_string;
-    if (patch_generator_command(use_localagent, adb_path, &patch_generator_command_string) ==
-        false) {
-        return 1;
-    }
+int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
     std::string generatePatchCommand = android::base::StringPrintf(
-            kGeneratePatchCommandPattern, patch_generator_command_string.c_str(), apkPath,
-            metadataPath, patchPath);
+            R"(%s "%s" "%s" > "%s")", get_patch_generator_command().c_str(), apkPath, metadataPath,
+            patchPath);
     return system(generatePatchCommand.c_str());
 }
 
@@ -302,19 +254,20 @@
     if (get_packagename_from_apk(apkPath, &packageName) == false) {
         return "";
     }
+
     std::string patchDevicePath =
             android::base::StringPrintf("%s%s.patch", kDeviceAgentPath, packageName.c_str());
     return patchDevicePath;
 }
 
 int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
-    const std::string kAgentApplyCommandPattern =
-            "/data/local/tmp/deployagent.sh apply %s %s -o %s";
+    const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -o %s";
 
     std::string packageName;
     if (get_packagename_from_apk(apkPath, &packageName) == false) {
         return -1;
     }
+
     std::string patchDevicePath = get_patch_path(apkPath);
 
     std::vector<const char*> srcs = {patchPath};
@@ -327,12 +280,12 @@
     std::string applyPatchCommand =
             android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
                                         patchDevicePath.c_str(), outputPath);
+
     return send_shell_command(applyPatchCommand);
 }
 
 int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
-    const std::string kAgentApplyCommandPattern =
-            "/data/local/tmp/deployagent.sh apply %s %s -pm %s";
+    const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -pm %s";
 
     std::string packageName;
     if (get_packagename_from_apk(apkPath, &packageName) == false) {
diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h
index d8acd30..80f3875 100644
--- a/adb/client/fastdeploy.h
+++ b/adb/client/fastdeploy.h
@@ -18,20 +18,17 @@
 
 #include "adb.h"
 
-typedef enum EFastDeploy_AgentUpdateStrategy {
+enum FastDeploy_AgentUpdateStrategy {
     FastDeploy_AgentUpdateAlways,
     FastDeploy_AgentUpdateNewerTimeStamp,
     FastDeploy_AgentUpdateDifferentVersion
-} FastDeploy_AgentUpdateStrategy;
+};
 
-static constexpr int kFastDeployMinApi = 24;
-
+void fastdeploy_set_local_agent(bool use_localagent);
 int get_device_api_level();
-bool update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy, bool use_localagent,
-                  const char* adb_path);
+bool update_agent(FastDeploy_AgentUpdateStrategy agentUpdateStrategy);
 int extract_metadata(const char* apkPath, FILE* outputFp);
-int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath,
-                 bool use_localagent, const char* adb_path);
+int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath);
 int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
 int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv);
 std::string get_patch_path(const char* apkPath);
diff --git a/adb/fastdeploy/Android.bp b/adb/fastdeploy/Android.bp
index 30f4730..400b12f 100644
--- a/adb/fastdeploy/Android.bp
+++ b/adb/fastdeploy/Android.bp
@@ -14,24 +14,17 @@
 // limitations under the License.
 //
 
-java_library {
+java_binary {
     name: "deployagent",
     sdk_version: "24",
     srcs: ["deployagent/src/**/*.java", "deploylib/src/**/*.java", "proto/**/*.proto"],
     static_libs: ["apkzlib_zip"],
+    wrapper: "deployagent/deployagent.sh",
     proto: {
         type: "lite",
     }
 }
 
-cc_prebuilt_binary {
-    name: "deployagent.sh",
-
-    srcs: ["deployagent/deployagent.sh"],
-    required: ["deployagent"],
-    device_supported: true,
-}
-
 java_binary_host {
     name: "deploypatchgenerator",
     srcs: ["deploypatchgenerator/src/**/*.java", "deploylib/src/**/*.java", "proto/**/*.proto"],
diff --git a/adb/test_adb.py b/adb/test_adb.py
index cde2b22..7e73818 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -490,6 +490,58 @@
                 self.assertEqual(_devices(server_port), [])
 
 
+@unittest.skipUnless(sys.platform == "win32", "requires Windows")
+class PowerTest(unittest.TestCase):
+    def test_resume_usb_kick(self):
+        """Resuming from sleep/hibernate should kick USB devices."""
+        try:
+            usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip()
+        except subprocess.CalledProcessError:
+            # If there are multiple USB devices, we don't have a way to check whether the selected
+            # device is USB.
+            raise unittest.SkipTest('requires single USB device')
+
+        try:
+            serial = subprocess.check_output(["adb", "get-serialno"]).strip()
+        except subprocess.CalledProcessError:
+            # Did you forget to select a device with $ANDROID_SERIAL?
+            raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device')
+
+        # Test only works with USB devices because adb _power_notification_thread does not kick
+        # non-USB devices on resume event.
+        if serial != usb_serial:
+            raise unittest.SkipTest('requires USB device')
+
+        # Run an adb shell command in the background that takes a while to complete.
+        proc = subprocess.Popen(['adb', 'shell', 'sleep', '5'])
+
+        # Wait for startup of adb server's _power_notification_thread.
+        time.sleep(0.1)
+
+        # Simulate resuming from sleep/hibernation by sending Windows message.
+        import ctypes
+        from ctypes import wintypes
+        HWND_BROADCAST = 0xffff
+        WM_POWERBROADCAST = 0x218
+        PBT_APMRESUMEAUTOMATIC = 0x12
+
+        PostMessageW = ctypes.windll.user32.PostMessageW
+        PostMessageW.restype = wintypes.BOOL
+        PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
+        result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0)
+        if not result:
+            raise ctypes.WinError()
+
+        # Wait for connection to adb shell to be broken by _power_notification_thread detecting the
+        # Windows message.
+        start = time.time()
+        proc.wait()
+        end = time.time()
+
+        # If the power event was detected, the adb shell command should be broken very quickly.
+        self.assertLess(end - start, 2)
+
+
 def main():
     """Main entrypoint."""
     random.seed(0)
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index d80e986..0ac57af 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -44,43 +44,10 @@
 #include "constants.h"
 #include "transport.h"
 
-enum Op {
-    OP_DOWNLOAD,
-    OP_COMMAND,
-    OP_QUERY,
-    OP_NOTICE,
-    OP_DOWNLOAD_SPARSE,
-    OP_WAIT_FOR_DISCONNECT,
-    OP_DOWNLOAD_FD,
-    OP_UPLOAD,
-};
+using android::base::StringPrintf;
 
-struct Action {
-    Action(Op op, const std::string& cmd) : op(op), cmd(cmd) {}
-
-    Op op;
-    std::string cmd;
-    std::string msg;
-
-    std::string product;
-
-    void* data = nullptr;
-    // The protocol only supports 32-bit sizes, so you'll have to break
-    // anything larger into multiple chunks.
-    uint32_t size = 0;
-
-    int fd = -1;
-
-    int (*func)(Action& a, int status, const char* resp) = nullptr;
-
-    double start = -1;
-};
-
-static std::vector<std::unique_ptr<Action>> action_list;
 static fastboot::FastBootDriver* fb = nullptr;
 
-static constexpr char kStatusFormat[] = "%-50s ";
-
 void fb_init(fastboot::FastBootDriver& fbi) {
     fb = &fbi;
     auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
@@ -101,81 +68,72 @@
     return !fb->GetVar(key, value);
 }
 
-static int cb_default(Action& a, int status, const char* resp) {
+static void HandleResult(double start, int status) {
     if (status) {
-        fprintf(stderr,"FAILED (%s)\n", resp);
+        fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+        die("Command failed");
     } else {
         double split = now();
-        fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
-        a.start = split;
+        fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
     }
-    return status;
 }
 
-static Action& queue_action(Op op, const std::string& cmd) {
-    std::unique_ptr<Action> a{new Action(op, cmd)};
-    a->func = cb_default;
-
-    action_list.push_back(std::move(a));
-    return *action_list.back();
-}
+#define RUN_COMMAND(command)         \
+    {                                \
+        double start = now();        \
+        auto status = (command);     \
+        HandleResult(start, status); \
+    }
 
 void fb_set_active(const std::string& slot) {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_SET_ACTIVE ":" + slot);
-    a.msg = "Setting current slot to '" + slot + "'";
+    Status("Setting current slot to '" + slot + "'");
+    RUN_COMMAND(fb->SetActive(slot));
 }
 
-void fb_queue_erase(const std::string& partition) {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_ERASE ":" + partition);
-    a.msg = "Erasing '" + partition + "'";
+void fb_erase(const std::string& partition) {
+    Status("Erasing '" + partition + "'");
+    RUN_COMMAND(fb->Erase(partition));
 }
 
-void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
-    Action& a = queue_action(OP_DOWNLOAD_FD, "");
-    a.fd = fd;
-    a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
+void fb_flash_fd(const std::string& partition, int fd, uint32_t sz) {
+    Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
+    RUN_COMMAND(fb->Download(fd, sz));
 
-    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
-    b.msg = "Writing '" + partition + "'";
+    Status("Writing '" + partition + "'");
+    RUN_COMMAND(fb->Flash(partition));
 }
 
-void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
-    Action& a = queue_action(OP_DOWNLOAD, "");
-    a.data = data;
-    a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
+void fb_flash(const std::string& partition, void* data, uint32_t sz) {
+    Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
+    RUN_COMMAND(fb->Download(static_cast<char*>(data), sz));
 
-    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
-    b.msg = "Writing '" + partition + "'";
+    Status("Writing '" + partition + "'");
+    RUN_COMMAND(fb->Flash(partition));
 }
 
-void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
-                           size_t current, size_t total) {
-    Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
-    a.data = s;
-    a.size = 0;
-    a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(),
-                                        current, total, sz / 1024);
+void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
+                     size_t current, size_t total) {
+    Status(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
+                        sz / 1024));
+    RUN_COMMAND(fb->Download(s));
 
-    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
-    b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
-                                        total);
+    Status(StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current, total));
+    RUN_COMMAND(fb->Flash(partition));
 }
 
-void fb_queue_create_partition(const std::string& partition, const std::string& size) {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_CREATE_PARTITION ":" + partition + ":" + size);
-    a.msg = "Creating '" + partition + "'";
+void fb_create_partition(const std::string& partition, const std::string& size) {
+    Status("Creating '" + partition + "'");
+    RUN_COMMAND(fb->RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size));
 }
 
-void fb_queue_delete_partition(const std::string& partition) {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_DELETE_PARTITION ":" + partition);
-    a.msg = "Deleting '" + partition + "'";
+void fb_delete_partition(const std::string& partition) {
+    Status("Deleting '" + partition + "'");
+    RUN_COMMAND(fb->RawCommand(FB_CMD_DELETE_PARTITION ":" + partition));
 }
 
-void fb_queue_resize_partition(const std::string& partition, const std::string& size) {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size);
-    a.msg = "Resizing '" + partition + "'";
+void fb_resize_partition(const std::string& partition, const std::string& size) {
+    Status("Resizing '" + partition + "'");
+    RUN_COMMAND(fb->RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size));
 }
 
 static int match(const char* str, const char** value, unsigned count) {
@@ -199,193 +157,108 @@
     return 0;
 }
 
-static int cb_check(Action& a, int status, const char* resp, int invert) {
-    const char** value = reinterpret_cast<const char**>(a.data);
-    unsigned count = a.size;
-    unsigned n;
+void fb_require(const std::string& product, const std::string& var, bool invert, size_t count,
+                const char** values) {
+    Status("Checking '" + var + "'");
+
+    double start = now();
+
+    std::string var_value;
+    auto status = fb->GetVar(var, &var_value);
 
     if (status) {
-        fprintf(stderr,"FAILED (%s)\n", resp);
-        return status;
+        fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
+        die("requirements not met!");
     }
 
-    if (!a.product.empty()) {
-        if (a.product != cur_product) {
+    if (!product.empty()) {
+        if (product != cur_product) {
             double split = now();
             fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product,
-                    a.product.c_str(), (split - a.start));
-            a.start = split;
-            return 0;
+                    product.c_str(), (split - start));
+            return;
         }
     }
 
-    int yes = match(resp, value, count);
+    int yes = match(var_value.c_str(), values, count);
     if (invert) yes = !yes;
 
     if (yes) {
         double split = now();
-        fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
-        a.start = split;
-        return 0;
+        fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
+        return;
     }
 
     fprintf(stderr, "FAILED\n\n");
-    fprintf(stderr, "Device %s is '%s'.\n", a.cmd.c_str() + 7, resp);
-    fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", value[0]);
-    for (n = 1; n < count; n++) {
-        fprintf(stderr, " or '%s'", value[n]);
+    fprintf(stderr, "Device %s is '%s'.\n", var.c_str(), var_value.c_str());
+    fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", values[0]);
+    for (size_t n = 1; n < count; n++) {
+        fprintf(stderr, " or '%s'", values[n]);
     }
     fprintf(stderr, ".\n\n");
-    return -1;
+    die("requirements not met!");
 }
 
-static int cb_require(Action& a, int status, const char* resp) {
-    return cb_check(a, status, resp, 0);
-}
+void fb_display(const std::string& label, const std::string& var) {
+    std::string value;
+    auto status = fb->GetVar(var, &value);
 
-static int cb_reject(Action& a, int status, const char* resp) {
-    return cb_check(a, status, resp, 1);
-}
-
-void fb_queue_require(const std::string& product, const std::string& var, bool invert,
-                      size_t nvalues, const char** values) {
-    Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
-    a.product = product;
-    a.data = values;
-    a.size = nvalues;
-    a.msg = "Checking " + var;
-    a.func = invert ? cb_reject : cb_require;
-    if (a.data == nullptr) die("out of memory");
-}
-
-static int cb_display(Action& a, int status, const char* resp) {
     if (status) {
-        fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
-        return status;
+        fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
+        return;
     }
-    fprintf(stderr, "%s: %s\n", static_cast<const char*>(a.data), resp);
-    free(static_cast<char*>(a.data));
-    return 0;
+    fprintf(stderr, "%s: %s\n", label.c_str(), value.c_str());
 }
 
-void fb_queue_display(const std::string& label, const std::string& var) {
-    Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
-    a.data = xstrdup(label.c_str());
-    a.func = cb_display;
-}
+void fb_query_save(const std::string& var, char* dest, uint32_t dest_size) {
+    std::string value;
+    auto status = fb->GetVar(var, &value);
 
-static int cb_save(Action& a, int status, const char* resp) {
     if (status) {
-        fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
-        return status;
+        fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
+        return;
     }
-    strncpy(reinterpret_cast<char*>(a.data), resp, a.size);
-    return 0;
+
+    strncpy(dest, value.c_str(), dest_size);
 }
 
-void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
-    Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
-    a.data = dest;
-    a.size = dest_size;
-    a.func = cb_save;
-}
-
-static int cb_do_nothing(Action&, int, const char*) {
+void fb_reboot() {
+    fprintf(stderr, "Rebooting");
+    fb->Reboot();
     fprintf(stderr, "\n");
-    return 0;
 }
 
-void fb_queue_reboot() {
-    Action& a = queue_action(OP_COMMAND, FB_CMD_REBOOT);
-    a.func = cb_do_nothing;
-    a.msg = "Rebooting";
+void fb_command(const std::string& cmd, const std::string& msg) {
+    Status(msg);
+    RUN_COMMAND(fb->RawCommand(cmd));
 }
 
-void fb_queue_command(const std::string& cmd, const std::string& msg) {
-    Action& a = queue_action(OP_COMMAND, cmd);
-    a.msg = msg;
+void fb_download(const std::string& name, void* data, uint32_t size) {
+    Status("Downloading '" + name + "'");
+    RUN_COMMAND(fb->Download(static_cast<char*>(data), size));
 }
 
-void fb_queue_download(const std::string& name, void* data, uint32_t size) {
-    Action& a = queue_action(OP_DOWNLOAD, "");
-    a.data = data;
-    a.size = size;
-    a.msg = "Downloading '" + name + "'";
+void fb_download_fd(const std::string& name, int fd, uint32_t sz) {
+    Status(StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024));
+    RUN_COMMAND(fb->Download(fd, sz));
 }
 
-void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz) {
-    Action& a = queue_action(OP_DOWNLOAD_FD, "");
-    a.fd = fd;
-    a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024);
+void fb_upload(const std::string& outfile) {
+    Status("Uploading '" + outfile + "'");
+    RUN_COMMAND(fb->Upload(outfile));
 }
 
-void fb_queue_upload(const std::string& outfile) {
-    Action& a = queue_action(OP_UPLOAD, "");
-    a.data = xstrdup(outfile.c_str());
-    a.msg = "Uploading '" + outfile + "'";
+void fb_notice(const std::string& notice) {
+    Status(notice);
+    fprintf(stderr, "\n");
 }
 
-void fb_queue_notice(const std::string& notice) {
-    Action& a = queue_action(OP_NOTICE, "");
-    a.msg = notice;
-}
-
-void fb_queue_wait_for_disconnect() {
-    queue_action(OP_WAIT_FOR_DISCONNECT, "");
-}
-
-int64_t fb_execute_queue() {
-    int64_t status = 0;
-    for (auto& a : action_list) {
-        a->start = now();
-        if (!a->msg.empty()) {
-            fprintf(stderr, kStatusFormat, a->msg.c_str());
-            verbose("\n");
-        }
-        if (a->op == OP_DOWNLOAD) {
-            char* cbuf = static_cast<char*>(a->data);
-            status = fb->Download(cbuf, a->size);
-            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
-            if (status) break;
-        } else if (a->op == OP_DOWNLOAD_FD) {
-            status = fb->Download(a->fd, a->size);
-            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
-            if (status) break;
-        } else if (a->op == OP_COMMAND) {
-            status = fb->RawCommand(a->cmd);
-            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
-            if (status) break;
-        } else if (a->op == OP_QUERY) {
-            std::string resp;
-            status = fb->RawCommand(a->cmd, &resp);
-            status = a->func(*a, status, status ? fb_get_error().c_str() : resp.c_str());
-            if (status) break;
-        } else if (a->op == OP_NOTICE) {
-            // We already showed the notice because it's in `Action::msg`.
-            fprintf(stderr, "\n");
-        } else if (a->op == OP_DOWNLOAD_SPARSE) {
-            status = fb->Download(reinterpret_cast<sparse_file*>(a->data));
-            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
-            if (status) break;
-        } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
-            fb->WaitForDisconnect();
-        } else if (a->op == OP_UPLOAD) {
-            status = fb->Upload(reinterpret_cast<const char*>(a->data));
-            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
-        } else {
-            die("unknown action: %d", a->op);
-        }
-    }
-    action_list.clear();
-    return status;
+void fb_wait_for_disconnect() {
+    fb->WaitForDisconnect();
 }
 
 bool fb_reboot_to_userspace() {
-    // First ensure that the queue is flushed.
-    fb_execute_queue();
-
-    fprintf(stderr, kStatusFormat, "Rebooting to userspace fastboot");
+    Status("Rebooting to userspace fastboot");
     verbose("\n");
 
     if (fb->RebootTo("fastboot") != fastboot::RetCode::SUCCESS) {
diff --git a/fastboot/engine.h b/fastboot/engine.h
index f098ca7..d78cb13 100644
--- a/fastboot/engine.h
+++ b/fastboot/engine.h
@@ -44,36 +44,29 @@
 
 const std::string fb_get_error();
 
-//#define FB_COMMAND_SZ (fastboot::FB_COMMAND_SZ)
-//#define FB_RESPONSE_SZ (fastboot::FB_RESPONSE_SZ)
-
-/* engine.c - high level command queue engine */
-
 void fb_init(fastboot::FastBootDriver& fbi);
 void fb_reinit(Transport* transport);
 
 bool fb_getvar(const std::string& key, std::string* value);
-void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
-void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz);
-void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
-                           size_t current, size_t total);
-void fb_queue_erase(const std::string& partition);
-void fb_queue_format(const std::string& partition, int skip_if_not_supported, int32_t max_chunk_sz);
-void fb_queue_require(const std::string& prod, const std::string& var, bool invert, size_t nvalues,
-                      const char** values);
-void fb_queue_display(const std::string& label, const std::string& var);
-void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size);
-void fb_queue_reboot(void);
-void fb_queue_command(const std::string& cmd, const std::string& msg);
-void fb_queue_download(const std::string& name, void* data, uint32_t size);
-void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz);
-void fb_queue_upload(const std::string& outfile);
-void fb_queue_notice(const std::string& notice);
-void fb_queue_wait_for_disconnect(void);
-void fb_queue_create_partition(const std::string& partition, const std::string& size);
-void fb_queue_delete_partition(const std::string& partition);
-void fb_queue_resize_partition(const std::string& partition, const std::string& size);
-int64_t fb_execute_queue();
+void fb_flash(const std::string& partition, void* data, uint32_t sz);
+void fb_flash_fd(const std::string& partition, int fd, uint32_t sz);
+void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
+                     size_t current, size_t total);
+void fb_erase(const std::string& partition);
+void fb_require(const std::string& prod, const std::string& var, bool invert, size_t nvalues,
+                const char** values);
+void fb_display(const std::string& label, const std::string& var);
+void fb_query_save(const std::string& var, char* dest, uint32_t dest_size);
+void fb_reboot();
+void fb_command(const std::string& cmd, const std::string& msg);
+void fb_download(const std::string& name, void* data, uint32_t size);
+void fb_download_fd(const std::string& name, int fd, uint32_t sz);
+void fb_upload(const std::string& outfile);
+void fb_notice(const std::string& notice);
+void fb_wait_for_disconnect(void);
+void fb_create_partition(const std::string& partition, const std::string& size);
+void fb_delete_partition(const std::string& partition);
+void fb_resize_partition(const std::string& partition, const std::string& size);
 void fb_set_active(const std::string& slot);
 bool fb_reboot_to_userspace();
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 1aef567..817afd0 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -688,7 +688,7 @@
         out[i] = xstrdup(strip(val[i]));
     }
 
-    fb_queue_require(product, var, invert, count, out);
+    fb_require(product, var, invert, count, out);
 }
 
 static void check_requirements(char* data, int64_t sz) {
@@ -702,15 +702,14 @@
             s++;
         }
     }
-    if (fb_execute_queue()) die("requirements not met!");
 }
 
-static void queue_info_dump() {
-    fb_queue_notice("--------------------------------------------");
-    fb_queue_display("Bootloader Version...", "version-bootloader");
-    fb_queue_display("Baseband Version.....", "version-baseband");
-    fb_queue_display("Serial Number........", "serialno");
-    fb_queue_notice("--------------------------------------------");
+static void dump_info() {
+    fb_notice("--------------------------------------------");
+    fb_display("Bootloader Version...", "version-bootloader");
+    fb_display("Baseband Version.....", "version-baseband");
+    fb_display("Serial Number........", "serialno");
+    fb_notice("--------------------------------------------");
 }
 
 static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
@@ -883,12 +882,12 @@
 
             for (size_t i = 0; i < sparse_files.size(); ++i) {
                 const auto& pair = sparse_files[i];
-                fb_queue_flash_sparse(partition, pair.first, pair.second, i + 1, sparse_files.size());
+                fb_flash_sparse(partition, pair.first, pair.second, i + 1, sparse_files.size());
             }
             break;
         }
         case FB_BUFFER_FD:
-            fb_queue_flash_fd(partition, buf->fd, buf->sz);
+            fb_flash_fd(partition, buf->fd, buf->sz);
             break;
         default:
             die("unknown buffer type: %d", buf->type);
@@ -1145,7 +1144,7 @@
     for (const auto& [image, slot] : os_images_) {
         auto resize_partition = [](const std::string& partition) -> void {
             if (is_logical(partition)) {
-                fb_queue_resize_partition(partition, "0");
+                fb_resize_partition(partition, "0");
             }
         };
         do_for_partitions(image->part_name, slot, resize_partition, false);
@@ -1223,12 +1222,12 @@
         int64_t sz;
         void* data = source_.ReadFile(image.sig_name, &sz);
         if (data) {
-            fb_queue_download("signature", data, sz);
-            fb_queue_command("signature", "installing signature");
+            fb_download("signature", data, sz);
+            fb_command("signature", "installing signature");
         }
 
         if (is_logical(partition_name)) {
-            fb_queue_resize_partition(partition_name, std::to_string(buf->image_size));
+            fb_resize_partition(partition_name, std::to_string(buf->image_size));
         }
         flash_buf(partition_name.c_str(), buf);
     };
@@ -1247,17 +1246,13 @@
     if (!is_userspace_fastboot()) {
         reboot_to_userspace_fastboot();
     }
-    fb_queue_download_fd("super", fd, get_file_size(fd));
+    fb_download_fd("super", fd, get_file_size(fd));
 
     std::string command = "update-super:super";
     if (wipe_) {
         command += ":wipe";
     }
-    fb_queue_command(command, "Updating super partition");
-
-    // We need these commands to have finished before proceeding, since
-    // otherwise "getvar is-logical" may not return a correct answer below.
-    fb_execute_queue();
+    fb_command(command, "Updating super partition");
 }
 
 class ZipImageSource final : public ImageSource {
@@ -1279,9 +1274,9 @@
 }
 
 static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
-    queue_info_dump();
+    dump_info();
 
-    fb_queue_query_save("product", cur_product, sizeof(cur_product));
+    fb_query_save("product", cur_product, sizeof(cur_product));
 
     ZipArchiveHandle zip;
     int error = OpenArchive(filename, &zip);
@@ -1316,9 +1311,9 @@
 
 static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
     std::string fname;
-    queue_info_dump();
+    dump_info();
 
-    fb_queue_query_save("product", cur_product, sizeof(cur_product));
+    fb_query_save("product", cur_product, sizeof(cur_product));
 
     FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
     tool.Flash();
@@ -1338,7 +1333,7 @@
     while (!args->empty()) {
         command += " " + next_arg(args);
     }
-    fb_queue_command(command, "");
+    fb_command(command, "");
 }
 
 static std::string fb_fix_numeric_var(std::string var) {
@@ -1641,7 +1636,7 @@
 
         if (command == "getvar") {
             std::string variable = next_arg(&args);
-            fb_queue_display(variable, variable);
+            fb_display(variable, variable);
         } else if (command == "erase") {
             std::string partition = next_arg(&args);
             auto erase = [&](const std::string& partition) {
@@ -1653,7 +1648,7 @@
                             partition_type.c_str());
                 }
 
-                fb_queue_erase(partition);
+                fb_erase(partition);
             };
             do_for_partitions(partition, slot_override, erase, true);
         } else if (android::base::StartsWith(command, "format")) {
@@ -1681,8 +1676,8 @@
             data = load_file(filename.c_str(), &sz);
             if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
             if (sz != 256) die("signature must be 256 bytes (got %" PRId64 ")", sz);
-            fb_queue_download("signature", data, sz);
-            fb_queue_command("signature", "installing signature");
+            fb_download("signature", data, sz);
+            fb_command("signature", "installing signature");
         } else if (command == "reboot") {
             wants_reboot = true;
 
@@ -1710,7 +1705,7 @@
         } else if (command == "reboot-fastboot") {
             wants_reboot_fastboot = true;
         } else if (command == "continue") {
-            fb_queue_command("continue", "resuming boot");
+            fb_command("continue", "resuming boot");
         } else if (command == "boot") {
             std::string kernel = next_arg(&args);
             std::string ramdisk;
@@ -1719,8 +1714,8 @@
             if (!args.empty()) second_stage = next_arg(&args);
 
             data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
-            fb_queue_download("boot.img", data, sz);
-            fb_queue_command("boot", "booting");
+            fb_download("boot.img", data, sz);
+            fb_command("boot", "booting");
         } else if (command == "flash") {
             std::string pname = next_arg(&args);
 
@@ -1746,7 +1741,7 @@
 
             data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
             auto flashraw = [&](const std::string& partition) {
-                fb_queue_flash(partition, data, sz);
+                fb_flash(partition, data, sz);
             };
             do_for_partitions(partition, slot_override, flashraw, true);
         } else if (command == "flashall") {
@@ -1778,10 +1773,10 @@
             if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
                 die("cannot load '%s'", filename.c_str());
             }
-            fb_queue_download_fd(filename, buf.fd, buf.sz);
+            fb_download_fd(filename, buf.fd, buf.sz);
         } else if (command == "get_staged") {
             std::string filename = next_arg(&args);
-            fb_queue_upload(filename);
+            fb_upload(filename);
         } else if (command == "oem") {
             do_oem_command("oem", &args);
         } else if (command == "flashing") {
@@ -1798,14 +1793,14 @@
         } else if (command == "create-logical-partition") {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
-            fb_queue_create_partition(partition, size);
+            fb_create_partition(partition, size);
         } else if (command == "delete-logical-partition") {
             std::string partition = next_arg(&args);
-            fb_queue_delete_partition(partition);
+            fb_delete_partition(partition);
         } else if (command == "resize-logical-partition") {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
-            fb_queue_resize_partition(partition, size);
+            fb_resize_partition(partition, size);
         } else {
             syntax_error("unknown command %s", command.c_str());
         }
@@ -1817,7 +1812,7 @@
             std::string partition_type;
             if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue;
             if (partition_type.empty()) continue;
-            fb_queue_erase(partition);
+            fb_erase(partition);
             if (partition == "userdata" && set_fbe_marker) {
                 fprintf(stderr, "setting FBE marker on initial userdata...\n");
                 std::string initial_userdata_dir = create_fbemarker_tmpdir();
@@ -1832,26 +1827,25 @@
         fb_set_active(next_active);
     }
     if (wants_reboot && !skip_reboot) {
-        fb_queue_reboot();
-        fb_queue_wait_for_disconnect();
+        fb_reboot();
+        fb_wait_for_disconnect();
     } else if (wants_reboot_bootloader) {
-        fb_queue_command("reboot-bootloader", "rebooting into bootloader");
-        fb_queue_wait_for_disconnect();
+        fb_command("reboot-bootloader", "rebooting into bootloader");
+        fb_wait_for_disconnect();
     } else if (wants_reboot_recovery) {
-        fb_queue_command("reboot-recovery", "rebooting into recovery");
-        fb_queue_wait_for_disconnect();
+        fb_command("reboot-recovery", "rebooting into recovery");
+        fb_wait_for_disconnect();
     } else if (wants_reboot_fastboot) {
-        fb_queue_command("reboot-fastboot", "rebooting into fastboot");
-        fb_queue_wait_for_disconnect();
+        fb_command("reboot-fastboot", "rebooting into fastboot");
+        fb_wait_for_disconnect();
     }
 
-    int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
     fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
 
     if (Transport* old_transport = fb.set_transport(nullptr)) {
         delete old_transport;
     }
-    return status;
+    return 0;
 }
 
 void FastBootTool::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) {
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index f9e640a..4a14131 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -97,9 +97,9 @@
     return RawCommand("reboot-" + target, response, info);
 }
 
-RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
+RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
                                   std::vector<std::string>* info) {
-    return RawCommand(Commands::SET_ACTIVE + part, response, info);
+    return RawCommand(Commands::SET_ACTIVE + slot, response, info);
 }
 
 RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index ca9003a..4d85ba0 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -89,7 +89,7 @@
     RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
     RetCode RebootTo(std::string target, std::string* response = nullptr,
                      std::vector<std::string>* info = nullptr);
-    RetCode SetActive(const std::string& part, std::string* response = nullptr,
+    RetCode SetActive(const std::string& slot, std::string* response = nullptr,
                       std::vector<std::string>* info = nullptr);
     RetCode Upload(const std::string& outfile, std::string* response = nullptr,
                    std::vector<std::string>* info = nullptr);
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h b/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
index 89cc009..8119aea 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
+++ b/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
@@ -72,7 +72,7 @@
 
     virtual ssize_t Read(void* data, size_t len) override;
     virtual ssize_t Write(const void* data, size_t len) override;
-    virtual int Close() override;
+    virtual int Close() override final;  // note usage in destructor
     virtual int Reset() override;
 
     const std::vector<Event> Transfers();
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index 8f6e52a..125182d 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -70,6 +70,11 @@
     fprintf(stderr, "\n");
 }
 
+void Status(const std::string& message) {
+    static constexpr char kStatusFormat[] = "%-50s ";
+    fprintf(stderr, kStatusFormat, message.c_str());
+}
+
 char* xstrdup(const char* s) {
     char* result = strdup(s);
     if (!result) die("out of memory");
diff --git a/fastboot/util.h b/fastboot/util.h
index 9033f93..20be461 100644
--- a/fastboot/util.h
+++ b/fastboot/util.h
@@ -12,6 +12,8 @@
 char* xstrdup(const char*);
 void set_verbose();
 
+void Status(const std::string& message);
+
 // These printf-like functions are implemented in terms of vsnprintf, so they
 // use the same attribute for compile-time format string checking.
 void die(const char* fmt, ...) __attribute__((__noreturn__))
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index c44e441..bebcc71 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -1230,7 +1230,7 @@
         }
 
         int size, consumed, max, payload;
-        char size_mult[3], consumed_mult[3];
+        char size_mult[4], consumed_mult[4];
         size = consumed = max = payload = 0;
         if (6 == sscanf(buffer,
                         "events: ring buffer is %d %3s (%d %3s consumed),"
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1c2ef64..915540e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -306,12 +306,12 @@
     # /data, which in turn can only be loaded when system properties are present.
     trigger post-fs-data
 
-    # Now we can start zygote for devices with file based encryption
-    trigger zygote-start
-
     # Load persist properties and override properties (if enabled) from /data.
     trigger load_persist_props_action
 
+    # Now we can start zygote for devices with file based encryption
+    trigger zygote-start
+
     # Remove a file to wake up anything waiting for firmware.
     trigger firmware_mounts_complete