Merge "liblp: Remove last_logical_sector from LpMetadataGeometry."
diff --git a/adb/Android.bp b/adb/Android.bp
index bccc71a..2a88de5 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -174,6 +174,12 @@
         "libdiagnose_usb",
         "libmdnssd",
         "libusb",
+        "libandroidfw",
+        "libziparchive",
+        "libz",
+        "libutils",
+        "liblog",
+        "libcutils",
     ],
 }
 
@@ -256,6 +262,12 @@
         "liblog",
         "libmdnssd",
         "libusb",
+        "libandroidfw",
+        "libziparchive",
+        "libz",
+        "libutils",
+        "liblog",
+        "libcutils",
     ],
 
     stl: "libc++_static",
@@ -474,7 +486,7 @@
     },
 }
 
-python_binary_host {
+python_test_host {
     name: "adb_integration_test_device",
     main: "test_device.py",
     srcs: [
@@ -483,6 +495,8 @@
     libs: [
         "adb_py",
     ],
+    test_config: "adb_integration_test_device.xml",
+    test_suites: ["general-tests"],
     version: {
         py2: {
             enabled: true,
diff --git a/adb/adb_integration_test_device.xml b/adb/adb_integration_test_device.xml
new file mode 100644
index 0000000..b892377
--- /dev/null
+++ b/adb/adb_integration_test_device.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config to run adb integration tests for device">
+    <option name="test-suite-tag" value="adb_tests" />
+    <option name="test-suite-tag" value="adb_integration_device" />
+    <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
+        <option name="disable" value="false" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
+    <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+        <option name="par-file-name" value="adb_integration_test_device" />
+        <option name="inject-android-serial" value="true" />
+        <option name="test-timeout" value="2m" />
+    </test>
+</configuration>
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index f4a92e3..051ab73 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -21,6 +21,7 @@
 
 #include <algorithm>
 #include <list>
+#include <memory>
 
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -29,7 +30,6 @@
 
 #include "socket_spec.h"
 #include "sysdeps.h"
-#include "sysdeps/memory.h"
 #include "transport.h"
 
 // A listener is an entity which binds to a local port and, upon receiving a connection on that
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 4cbc45a..d69dbef 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -14,31 +14,27 @@
  * limitations under the License.
  */
 
-#define TRACE_TAG ADB
+#include "adb_install.h"
 
 #include <stdio.h>
 #include <stdlib.h>
-
-#include "adb.h"
-#include "adb_client.h"
-#include "adb_install.h"
-#include "adb_utils.h"
-#include "client/file_sync_client.h"
-#include "commandline.h"
-#include "fastdeploy.h"
-#include "sysdeps.h"
-
+#include <unistd.h>
 #include <algorithm>
 #include <iostream>
 #include <string>
 #include <vector>
 
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/test_utils.h>
+#include "adb.h"
+#include "adb_client.h"
+#include "adb_utils.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+#include "android-base/test_utils.h"
+#include "client/file_sync_client.h"
+#include "commandline.h"
+#include "fastdeploy.h"
+#include "sysdeps.h"
 
 static constexpr int kFastDeployMinApi = 24;
 
@@ -146,41 +142,16 @@
         TemporaryFile patchTmpFile;
 
         FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
-        int metadata_len = extract_metadata(file, metadataFile);
+        extract_metadata(file, metadataFile);
         fclose(metadataFile);
 
-        int result = -1;
-        if (metadata_len <= 0) {
-            printf("failed to extract metadata %d\n", metadata_len);
-            return 1;
-        } else {
-            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;
-                goto cleanup_streamed_apk;
-            } else {
-                std::vector<const char*> pm_args;
-                // pass all but 1st (command) and last (apk path) parameters through to pm for
-                // session creation
-                for (int i = 1; i < argc - 1; i++) {
-                    pm_args.push_back(argv[i]);
-                }
-                int apply_patch_result =
-                        install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
-                if (apply_patch_result != 0) {
-                    printf("Patch application failure, error code: %d\n", apply_patch_result);
-                    result = apply_patch_result;
-                    goto cleanup_streamed_apk;
-                }
-            }
-        }
-
-    cleanup_streamed_apk:
-        if (use_fastdeploy == true) {
-            delete_device_patch_file(file);
-        }
-        return result;
+        create_patch(file, metadataTmpFile.path, patchTmpFile.path);
+        // pass all but 1st (command) and last (apk path) parameters through to pm for
+        // session creation
+        std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
+        install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
+        delete_device_patch_file(file);
+        return 0;
     } else {
         struct stat sb;
         if (stat(file, &sb) == -1) {
@@ -265,29 +236,11 @@
         TemporaryFile patchTmpFile;
 
         FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
-        int metadata_len = extract_metadata(apk_file[0], metadataFile);
+        extract_metadata(apk_file[0], metadataFile);
         fclose(metadataFile);
 
-        if (metadata_len <= 0) {
-            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);
-            if (create_patch_result != 0) {
-                printf("Patch creation failure, error code: %d\n", create_patch_result);
-                result = create_patch_result;
-                goto cleanup_apk;
-            } else {
-                int apply_patch_result =
-                        apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
-                if (apply_patch_result != 0) {
-                    printf("Patch application failure, error code: %d\n", apply_patch_result);
-                    result = apply_patch_result;
-                    goto cleanup_apk;
-                }
-            }
-        }
+        create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
+        apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
     } else {
         if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
     }
@@ -347,7 +300,6 @@
             use_localagent = true;
 #endif
         }
-        // TODO: --installlog <filename>
     }
 
     if (installMode == INSTALL_DEFAULT) {
diff --git a/adb/client/adb_install.h b/adb/client/adb_install.h
index e9410a9..5b6c4cb 100644
--- a/adb/client/adb_install.h
+++ b/adb/client/adb_install.h
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef ADB_INSTALL_H
-#define ADB_INSTALL_H
+#pragma once
 
-#include "fastdeploy.h"
+#include <string>
 
 int install_app(int argc, const char** argv);
 int install_multiple_app(int argc, const char** argv);
@@ -26,4 +25,3 @@
 int delete_device_file(const std::string& filename);
 int delete_host_file(const std::string& filename);
 
-#endif
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e38e305..07b5747 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -63,7 +63,6 @@
 #include "services.h"
 #include "shell_protocol.h"
 #include "sysdeps/chrono.h"
-#include "sysdeps/memory.h"
 
 extern int gListenAll;
 
@@ -1580,15 +1579,20 @@
         }
         return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
     }
+    // clang-format off
     else if (!strcmp(argv[0], "remount") ||
              !strcmp(argv[0], "reboot") ||
              !strcmp(argv[0], "reboot-bootloader") ||
+             !strcmp(argv[0], "reboot-fastboot") ||
              !strcmp(argv[0], "usb") ||
              !strcmp(argv[0], "disable-verity") ||
              !strcmp(argv[0], "enable-verity")) {
+        // clang-format on
         std::string command;
         if (!strcmp(argv[0], "reboot-bootloader")) {
             command = "reboot:bootloader";
+        } else if (!strcmp(argv[0], "reboot-fastboot")) {
+            command = "reboot:fastboot";
         } else if (argc > 1) {
             command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
         } else {
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index d3f35c8..183a1fa 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-#include <libgen.h>
+#include "fastdeploy.h"
+
 #include <algorithm>
 #include <array>
+#include <memory>
 
 #include "android-base/file.h"
 #include "android-base/strings.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/ZipFileRO.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
-#include "fastdeploy.h"
 #include "fastdeploycallbacks.h"
 #include "utils/String16.h"
 
@@ -138,60 +141,82 @@
     }
 }
 
-static std::string get_aapt2_path() {
-    if (g_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);
+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 {};
     }
-
-    std::string adb_dir = android::base::GetExecutableDirectory();
-    if (adb_dir.empty()) {
-        fatal("Could not locate aapt2");
-    }
-    return adb_dir + "/aapt2";
+    std::string utf8;
+    utf8.resize(utf8_length);
+    utf16_to_utf8(input, input_len, &*utf8.begin(), utf8_length + 1);
+    return utf8;
 }
 
-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 std::string get_packagename_from_apk(const char* apkPath) {
-    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);
-
-    std::string package_name;
-    int exit_code = system_capture(getPackagenameCommand.c_str(), package_name);
-    if (exit_code != 0) {
-        fatal("Error executing '%s' exitcode: %d", getPackagenameCommand.c_str(), exit_code);
+    std::unique_ptr<android::ZipFileRO> zipFile(android::ZipFileRO::open(apkPath));
+    if (zipFile == nullptr) {
+        fatal("Could not open %s", apkPath);
     }
-
-    // strip any line end characters from the output
-    return android::base::Trim(package_name);
+    android::ZipEntryRO entry = zipFile->findEntryByName("AndroidManifest.xml");
+    if (entry == nullptr) {
+        fatal("Could not find AndroidManifest.xml inside %s", apkPath);
+    }
+    uint32_t manifest_len = 0;
+    if (!zipFile->getEntryInfo(entry, NULL, &manifest_len, NULL, NULL, NULL, NULL)) {
+        fatal("Could not read AndroidManifest.xml inside %s", apkPath);
+    }
+    std::vector<char> manifest_data(manifest_len);
+    if (!zipFile->uncompressEntry(entry, manifest_data.data(), manifest_len)) {
+        fatal("Could not uncompress AndroidManifest.xml inside %s", apkPath);
+    }
+    android::ResXMLTree tree;
+    android::status_t setto_status = tree.setTo(manifest_data.data(), manifest_len, true);
+    if (setto_status != android::OK) {
+        fatal("Could not parse AndroidManifest.xml inside %s", apkPath);
+    }
+    android::ResXMLParser::event_code_t code;
+    while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
+           code != android::ResXMLParser::END_DOCUMENT) {
+        switch (code) {
+            case android::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 (size_t i = 0; i < 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;
+                            }
+                            return get_string_from_utf16(attribute_value_text,
+                                                         attribute_value_length);
+                        }
+                    }
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    fatal("Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
 }
 
-int extract_metadata(const char* apkPath, FILE* outputFp) {
+void extract_metadata(const char* apkPath, FILE* outputFp) {
     std::string packageName = get_packagename_from_apk(apkPath);
     const char* kAgentExtractCommandPattern = "/data/local/tmp/deployagent extract %s";
     std::string extractCommand =
@@ -200,13 +225,10 @@
     std::vector<char> extractErrorBuffer;
     int statusCode;
     DeployAgentFileCallback cb(outputFp, &extractErrorBuffer, &statusCode);
-    int ret = send_shell_command(extractCommand, false, &cb);
-
-    if (ret == 0) {
-        return cb.getBytesWritten();
+    int returnCode = send_shell_command(extractCommand, false, &cb);
+    if (returnCode != 0) {
+        fatal("Executing %s returned %d\n", extractCommand.c_str(), returnCode);
     }
-
-    return ret;
 }
 
 static std::string get_patch_generator_command() {
@@ -229,11 +251,14 @@
                                        adb_dir.c_str());
 }
 
-int create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
+void create_patch(const char* apkPath, const char* metadataPath, const char* patchPath) {
     std::string generatePatchCommand = android::base::StringPrintf(
             R"(%s "%s" "%s" > "%s")", get_patch_generator_command().c_str(), apkPath, metadataPath,
             patchPath);
-    return system(generatePatchCommand.c_str());
+    int returnCode = system(generatePatchCommand.c_str());
+    if (returnCode != 0) {
+        fatal("Executing %s returned %d\n", generatePatchCommand.c_str(), returnCode);
+    }
 }
 
 std::string get_patch_path(const char* apkPath) {
@@ -243,36 +268,38 @@
     return patchDevicePath;
 }
 
-int apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
+void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath) {
     const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -o %s";
     std::string packageName = get_packagename_from_apk(apkPath);
     std::string patchDevicePath = get_patch_path(apkPath);
 
     std::vector<const char*> srcs = {patchPath};
     bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
-
     if (!push_ok) {
-        return -1;
+        fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
     }
 
     std::string applyPatchCommand =
             android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
                                         patchDevicePath.c_str(), outputPath);
 
-    return send_shell_command(applyPatchCommand);
+    int returnCode = send_shell_command(applyPatchCommand);
+    if (returnCode != 0) {
+        fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+    }
 }
 
-int install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
+void install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv) {
     const std::string kAgentApplyCommandPattern = "/data/local/tmp/deployagent apply %s %s -pm %s";
     std::string packageName = get_packagename_from_apk(apkPath);
-    std::vector<const char*> srcs;
+
     std::string patchDevicePath =
             android::base::StringPrintf("%s%s.patch", kDeviceAgentPath, packageName.c_str());
-    srcs.push_back(patchPath);
-    bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
 
+    std::vector<const char*> srcs{patchPath};
+    bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
     if (!push_ok) {
-        return -1;
+        fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
     }
 
     std::vector<unsigned char> applyOutputBuffer;
@@ -287,5 +314,8 @@
     std::string applyPatchCommand =
             android::base::StringPrintf(kAgentApplyCommandPattern.c_str(), packageName.c_str(),
                                         patchDevicePath.c_str(), argsString.c_str());
-    return send_shell_command(applyPatchCommand);
+    int returnCode = send_shell_command(applyPatchCommand);
+    if (returnCode != 0) {
+        fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+    }
 }
diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h
index e5e7663..a6b10d3 100644
--- a/adb/client/fastdeploy.h
+++ b/adb/client/fastdeploy.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include "adb.h"
+#include <string>
 
 enum FastDeploy_AgentUpdateStrategy {
     FastDeploy_AgentUpdateAlways,
@@ -27,8 +27,8 @@
 void fastdeploy_set_local_agent(bool use_localagent);
 int get_device_api_level();
 void 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);
-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);
+void extract_metadata(const char* apkPath, FILE* outputFp);
+void create_patch(const char* apkPath, const char* metadataPath, const char* patchPath);
+void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
+void 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/fdevent_test.cpp b/adb/fdevent_test.cpp
index 0cb2439..816134f 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -19,6 +19,7 @@
 #include <gtest/gtest.h>
 
 #include <limits>
+#include <memory>
 #include <queue>
 #include <string>
 #include <thread>
@@ -26,7 +27,6 @@
 
 #include "adb_io.h"
 #include "fdevent_test.h"
-#include "sysdeps/memory.h"
 
 class FdHandler {
   public:
diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp
index 6869947..9a37ea2 100644
--- a/adb/sysdeps/errno.cpp
+++ b/adb/sysdeps/errno.cpp
@@ -24,10 +24,6 @@
 
 #include "adb.h"
 
-#if defined(_WIN32)
-#define ETXTBSY EBUSY
-#endif
-
 // Use the linux asm-generic values for errno (which are used on all android archs but mips).
 #define ERRNO_VALUES()             \
     ERRNO_VALUE(EACCES, 13);       \
diff --git a/adb/sysdeps/memory.h b/adb/sysdeps/memory.h
deleted file mode 100644
index 4108aff..0000000
--- a/adb/sysdeps/memory.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <memory>
-#include <type_traits>
-
-#if defined(_WIN32)
-// We don't have C++14 on Windows yet.
-// Reimplement std::make_unique ourselves until we do.
-
-namespace internal {
-
-template <typename T>
-struct array_known_bounds;
-
-template <typename T>
-struct array_known_bounds<T[]> {
-    constexpr static bool value = false;
-};
-
-template <typename T, size_t N>
-struct array_known_bounds<T[N]> {
-    constexpr static bool value = true;
-};
-
-}  // namespace internal
-
-namespace std {
-
-template <typename T, typename... Args>
-typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(
-    Args&&... args) {
-    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
-template <typename T>
-typename std::enable_if<std::is_array<T>::value && !internal::array_known_bounds<T>::value,
-                        std::unique_ptr<T>>::type
-make_unique(std::size_t size) {
-    return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
-}
-
-template <typename T, typename... Args>
-typename std::enable_if<std::is_array<T>::value && internal::array_known_bounds<T>::value,
-                        std::unique_ptr<T>>::type
-make_unique(Args&&... args) = delete;
-
-}  // namespace std
-
-#endif
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 8784757..0a08fbb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -94,6 +94,10 @@
     _fh_socket_writev,
 };
 
+#if defined(assert)
+#undef assert
+#endif
+
 #define assert(cond)                                                                       \
     do {                                                                                   \
         if (!(cond)) fatal("assertion failed '%s' on %s:%d\n", #cond, __FILE__, __LINE__); \
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 95df490..cabd279 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -17,7 +17,6 @@
 #define TRACE_TAG TRANSPORT
 
 #include "sysdeps.h"
-#include "sysdeps/memory.h"
 
 #include "transport.h"
 
@@ -32,6 +31,7 @@
 #include <algorithm>
 #include <deque>
 #include <list>
+#include <memory>
 #include <mutex>
 #include <set>
 #include <thread>
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
index 85f3c52..ec61279 100644
--- a/adb/transport_fd.cpp
+++ b/adb/transport_fd.cpp
@@ -17,6 +17,7 @@
 #include <stdint.h>
 
 #include <deque>
+#include <memory>
 #include <mutex>
 #include <string>
 #include <thread>
@@ -28,7 +29,6 @@
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "sysdeps.h"
-#include "sysdeps/memory.h"
 #include "transport.h"
 #include "types.h"
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 8353d89..dc87ac7 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 
 #include <condition_variable>
+#include <memory>
 #include <mutex>
 #include <thread>
 #include <unordered_map>
@@ -45,7 +46,6 @@
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "sysdeps/chrono.h"
-#include "sysdeps/memory.h"
 
 #if ADB_HOST
 
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 602970c..c471bf9 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -16,8 +16,9 @@
 
 #define TRACE_TAG TRANSPORT
 
+#include <memory>
+
 #include "sysdeps.h"
-#include "sysdeps/memory.h"
 #include "transport.h"
 
 #include <stdio.h>
diff --git a/adb/types.h b/adb/types.h
index 1f7008e..0c71c3a 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -25,7 +25,6 @@
 
 #include <android-base/logging.h>
 
-#include "sysdeps/memory.h"
 #include "sysdeps/uio.h"
 
 // Essentially std::vector<char>, except without zero initialization or reallocation.
diff --git a/adb/types_test.cpp b/adb/types_test.cpp
index 31ab90a..1fbd2ca 100644
--- a/adb/types_test.cpp
+++ b/adb/types_test.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "sysdeps/memory.h"
+#include <memory>
 #include "types.h"
 
 static std::unique_ptr<IOVector::block_type> create_block(const std::string& string) {
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
index 4b91623..1a414ec 100644
--- a/base/include/android-base/utf8.h
+++ b/base/include/android-base/utf8.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #ifdef _WIN32
+#include <sys/types.h>
 #include <string>
 #else
 // Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index d5ea6db..6e45133 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -237,7 +237,13 @@
     CommandResult ret;
     auto cb = [&ret](CommandResult result) { ret = result; };
     auto result = boot_control_hal->setActiveBootSlot(slot, cb);
-    if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
+    if (result.isOk() && ret.success) {
+        // Save as slot suffix to match the suffix format as returned from
+        // the boot control HAL.
+        auto current_slot = "_" + args[1];
+        device->set_active_slot(current_slot);
+        return device->WriteStatus(FastbootResult::OKAY, "");
+    }
     return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
 }
 
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index b843c05..6cb4892 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -57,7 +57,8 @@
       transport_(std::make_unique<ClientUsbTransport>()),
       boot_control_hal_(IBootControl::getService()),
       health_hal_(get_health_service()),
-      fastboot_hal_(IFastboot::getService()) {}
+      fastboot_hal_(IFastboot::getService()),
+      active_slot_("") {}
 
 FastbootDevice::~FastbootDevice() {
     CloseDevice();
@@ -68,6 +69,11 @@
 }
 
 std::string FastbootDevice::GetCurrentSlot() {
+    // Check if a set_active ccommand was issued earlier since the boot control HAL
+    // returns the slot that is currently booted into.
+    if (!active_slot_.empty()) {
+        return active_slot_;
+    }
     // Non-A/B devices must not have boot control HALs.
     if (!boot_control_hal_) {
         return "";
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 2eb7177..091aadf 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -56,6 +56,8 @@
     }
     android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
 
+    void set_active_slot(const std::string& active_slot) { active_slot_ = active_slot; }
+
   private:
     const std::unordered_map<std::string, CommandHandler> kCommandMap;
 
@@ -64,4 +66,5 @@
     android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
     android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
     std::vector<char> download_data_;
+    std::string active_slot_;
 };
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 4fc3d1d..2347496 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -72,7 +72,7 @@
 }
 
 int FlashSparseData(int fd, std::vector<char>& downloaded_data) {
-    struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, true);
+    struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, false);
     if (!file) {
         return -ENOENT;
     }
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 630e22d..cbd2856 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -288,7 +288,7 @@
     bool is_zero_length;
     if (LogicalPartitionExists(args[0], device->GetCurrentSlot(), &is_zero_length) &&
         is_zero_length) {
-        *message = "0";
+        *message = "0x0";
         return true;
     }
     // Otherwise, open the partition as normal.
@@ -308,7 +308,14 @@
         *message = "Missing argument";
         return false;
     }
+
     std::string partition_name = args[0];
+    if (!FindPhysicalPartition(partition_name) &&
+        !LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
+        *message = "Invalid partition";
+        return false;
+    }
+
     auto fastboot_hal = device->fastboot_hal();
     if (!fastboot_hal) {
         *message = "Fastboot HAL not found";
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5962650..e27a897 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -155,10 +155,10 @@
     { nullptr,    "system_other.img", "system.sig",   "system",   true,  ImageType::Normal },
     { "userdata", "userdata.img",     "userdata.sig", "userdata", true,  ImageType::Extra },
     { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  ImageType::BootCritical },
-    { "vbmeta_mainline",
-                  "vbmeta_mainline.img",
-                                      "vbmeta_mainline.sig",
-                                                      "vbmeta_mainline",
+    { "vbmeta_system",
+                  "vbmeta_system.img",
+                                      "vbmeta_system.sig",
+                                                      "vbmeta_system",
                                                                   true,  ImageType::BootCritical },
     { "vendor",   "vendor.img",       "vendor.sig",   "vendor",   true,  ImageType::Normal },
     { nullptr,    "vendor_other.img", "vendor.sig",   "vendor",   true,  ImageType::Normal },
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index e2076f5..c02ab1c 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -43,6 +43,7 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 #include <sparse/sparse.h>
@@ -331,8 +332,9 @@
                 << cmd + " responded with a string with leading whitespace";
         EXPECT_FALSE(resp.compare(0, 2, "0x"))
                 << cmd + "responded with a string that does not start with 0x...";
-        int64_t size = strtoll(resp.c_str(), nullptr, 16);
-        EXPECT_GT(size, 0) << "'" + resp + "' is not a valid response from " + cmd;
+        uint64_t size;
+        ASSERT_TRUE(android::base::ParseUint(resp, &size))
+                << "'" + resp + "' is not a valid response from " + cmd;
     }
 }
 
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 7f9d9a4..a6ef35b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -851,56 +851,115 @@
     return true;
 }
 
-bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
-    if (fs_mgr_is_checkpoint_fs(rec)) {
-        if (!strcmp(rec->fs_type, "f2fs")) {
-            std::string opts(rec->fs_options);
+class CheckpointManager {
+  public:
+    CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
 
-            opts += ",checkpoint=disable";
-            free(rec->fs_options);
-            rec->fs_options = strdup(opts.c_str());
-        } else {
-            LERROR << rec->fs_type << " does not implement checkpoints.";
+    bool Update(struct fstab_rec* rec) {
+        if (!fs_mgr_is_checkpoint(rec)) {
+            return true;
         }
-    } else if (fs_mgr_is_checkpoint_blk(rec)) {
-        call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
 
-        android::base::unique_fd fd(
-                TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
-        if (!fd) {
-            PERROR << "Cannot open device " << rec->blk_device;
+        if (fs_mgr_is_checkpoint_blk(rec)) {
+            call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+        }
+
+        if (needs_checkpoint_ == UNKNOWN &&
+            !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
+            LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+            needs_checkpoint_ = NO;
+        }
+
+        if (needs_checkpoint_ != YES) {
+            return true;
+        }
+
+        if (!UpdateCheckpointPartition(rec)) {
+            LERROR << "Could not set up checkpoint partition, skipping!";
             return false;
         }
 
-        uint64_t size = get_block_device_size(fd) / 512;
-        if (!size) {
-            PERROR << "Cannot get device size";
-            return false;
+        return true;
+    }
+
+    bool Revert(struct fstab_rec* rec) {
+        if (!fs_mgr_is_checkpoint(rec)) {
+            return true;
         }
 
-        android::dm::DmTable table;
-        if (!table.AddTarget(
-                    std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
-            LERROR << "Failed to add Bow target";
-            return false;
+        if (device_map_.find(rec->blk_device) == device_map_.end()) {
+            return true;
         }
 
+        std::string bow_device = rec->blk_device;
+        free(rec->blk_device);
+        rec->blk_device = strdup(device_map_[bow_device].c_str());
+        device_map_.erase(bow_device);
+
         DeviceMapper& dm = DeviceMapper::Instance();
-        if (!dm.CreateDevice("bow", table)) {
-            PERROR << "Failed to create bow device";
-            return false;
+        if (!dm.DeleteDevice("bow")) {
+            PERROR << "Failed to remove bow device";
         }
 
-        std::string name;
-        if (!dm.GetDmDevicePathByName("bow", &name)) {
-            PERROR << "Failed to get bow device name";
-            return false;
-        }
-
-        rec->blk_device = strdup(name.c_str());
+        return true;
     }
-    return true;
-}
+
+  private:
+    bool UpdateCheckpointPartition(struct fstab_rec* rec) {
+        if (fs_mgr_is_checkpoint_fs(rec)) {
+            if (!strcmp(rec->fs_type, "f2fs")) {
+                std::string opts(rec->fs_options);
+
+                opts += ",checkpoint=disable";
+                free(rec->fs_options);
+                rec->fs_options = strdup(opts.c_str());
+            } else {
+                LERROR << rec->fs_type << " does not implement checkpoints.";
+            }
+        } else if (fs_mgr_is_checkpoint_blk(rec)) {
+            android::base::unique_fd fd(
+                    TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+            if (!fd) {
+                PERROR << "Cannot open device " << rec->blk_device;
+                return false;
+            }
+
+            uint64_t size = get_block_device_size(fd) / 512;
+            if (!size) {
+                PERROR << "Cannot get device size";
+                return false;
+            }
+
+            android::dm::DmTable table;
+            if (!table.AddTarget(
+                        std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+                LERROR << "Failed to add bow target";
+                return false;
+            }
+
+            DeviceMapper& dm = DeviceMapper::Instance();
+            if (!dm.CreateDevice("bow", table)) {
+                PERROR << "Failed to create bow device";
+                return false;
+            }
+
+            std::string name;
+            if (!dm.GetDmDevicePathByName("bow", &name)) {
+                PERROR << "Failed to get bow device name";
+                return false;
+            }
+
+            device_map_[name] = rec->blk_device;
+            free(rec->blk_device);
+            rec->blk_device = strdup(name.c_str());
+        }
+        return true;
+    }
+
+    enum { UNKNOWN = -1, NO = 0, YES = 1 };
+    int needs_checkpoint_;
+    std::map<std::string, std::string> device_map_;
+};
 
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
@@ -914,7 +973,7 @@
     int mret = -1;
     int mount_errno = 0;
     int attempted_idx = -1;
-    int need_checkpoint = -1;
+    CheckpointManager checkpoint_manager;
     FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
@@ -961,16 +1020,8 @@
             }
         }
 
-        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
-            if (need_checkpoint == -1 &&
-                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
-                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
-                need_checkpoint = 0;
-            }
-            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
-                LERROR << "Could not set up checkpoint partition, skipping!";
-                continue;
-            }
+        if (!checkpoint_manager.Update(&fstab->recs[i])) {
+            continue;
         }
 
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1053,6 +1104,9 @@
                    << " is wiped and " << fstab->recs[top_idx].mount_point
                    << " " << fstab->recs[top_idx].fs_type
                    << " is formattable. Format it.";
+
+            checkpoint_manager.Revert(&fstab->recs[top_idx]);
+
             if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
                 strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
                 int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY);
@@ -1173,11 +1227,12 @@
  * in turn, and stop on 1st success, or no more match.
  */
 static int fs_mgr_do_mount_helper(fstab* fstab, const char* n_name, char* n_blk_device,
-                                  char* tmp_mount_point, int need_checkpoint) {
+                                  char* tmp_mount_point, int needs_checkpoint) {
     int i = 0;
     int mount_errors = 0;
     int first_mount_errno = 0;
     char* mount_point;
+    CheckpointManager checkpoint_manager(needs_checkpoint);
     FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
@@ -1206,16 +1261,9 @@
             }
         }
 
-        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
-            if (need_checkpoint == -1 &&
-                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
-                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
-                need_checkpoint = 0;
-            }
-            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
-                LERROR << "Could not set up checkpoint partition, skipping!";
-                continue;
-            }
+        if (!checkpoint_manager.Update(&fstab->recs[i])) {
+            LERROR << "Could not set up checkpoint partition, skipping!";
+            continue;
         }
 
         /* First check the filesystem if requested */
@@ -1292,8 +1340,8 @@
 }
 
 int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
-                    bool needs_cp) {
-    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_cp);
+                    bool needs_checkpoint) {
+    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint);
 }
 
 /*
@@ -1498,8 +1546,6 @@
 
     DeviceMapper& dm = DeviceMapper::Instance();
 
-    bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
-
     for (int i = 0; i < fstab->num_entries; i++) {
         auto fsrec = &fstab->recs[i];
         if (!fs_mgr_is_verified(fsrec) && !fs_mgr_is_avb(fsrec)) {
@@ -1507,7 +1553,7 @@
         }
 
         std::string mount_point;
-        if (system_root && !strcmp(fsrec->mount_point, "/")) {
+        if (!strcmp(fsrec->mount_point, "/")) {
             // In AVB, the dm device name is vroot instead of system.
             mount_point = fs_mgr_is_avb(fsrec) ? "vroot" : "system";
         } else {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 95326d1..4934f5a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -29,6 +29,7 @@
 #include <sys/vfs.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <string>
@@ -40,12 +41,18 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4_utils.h>
+#include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
+#include <libdm/dm.h>
+#include <liblp/builder.h>
+#include <liblp/liblp.h>
 
 #include "fs_mgr_priv.h"
 
 using namespace std::literals;
+using namespace android::dm;
+using namespace android::fs_mgr;
 
 #if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs
 
@@ -71,8 +78,10 @@
 
 namespace {
 
-// acceptable overlayfs backing storage
-const auto kOverlayMountPoint = "/cache"s;
+// list of acceptable overlayfs backing storage
+const auto kScratchMountPoint = "/mnt/scratch"s;
+const auto kCacheMountPoint = "/cache"s;
+const std::vector<const std::string> kOverlayMountPoints = {kScratchMountPoint, kCacheMountPoint};
 
 // Return true if everything is mounted, but before adb is started.  Right
 // after 'trigger load_persist_props_action' is done.
@@ -133,14 +142,17 @@
 
 std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
     if (!fs_mgr_is_dir(mount_point)) return "";
-    auto dir =
-            kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/";
-    auto upper = dir + kUpperName;
-    if (!fs_mgr_is_dir(upper)) return "";
-    auto work = dir + kWorkName;
-    if (!fs_mgr_is_dir(work)) return "";
-    if (!fs_mgr_dir_is_writable(work)) return "";
-    return dir;
+    const auto base = android::base::Basename(mount_point) + "/";
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        auto dir = overlay_mount_point + kOverlayTopDir + "/" + base;
+        auto upper = dir + kUpperName;
+        if (!fs_mgr_is_dir(upper)) continue;
+        auto work = dir + kWorkName;
+        if (!fs_mgr_is_dir(work)) continue;
+        if (!fs_mgr_dir_is_writable(work)) continue;
+        return dir;
+    }
+    return "";
 }
 
 const auto kLowerdirOption = "lowerdir="s;
@@ -155,25 +167,9 @@
            candidate + kUpperName + ",workdir=" + candidate + kWorkName;
 }
 
-bool fs_mgr_system_root_image(const fstab* fstab) {
-    if (!fstab) {  // can not happen?
-        // This will return empty on init first_stage_mount,
-        // hence why we prefer checking the fstab instead.
-        return android::base::GetBoolProperty("ro.build.system_root_image", false);
-    }
-    for (auto i = 0; i < fstab->num_entries; i++) {
-        const auto fsrec = &fstab->recs[i];
-        auto fsrec_mount_point = fsrec->mount_point;
-        if (!fsrec_mount_point) continue;
-        if ("/system"s == fsrec_mount_point) return false;
-    }
-    return true;
-}
-
-const char* fs_mgr_mount_point(const fstab* fstab, const char* mount_point) {
+const char* fs_mgr_mount_point(const char* mount_point) {
     if (!mount_point) return mount_point;
     if ("/"s != mount_point) return mount_point;
-    if (!fs_mgr_system_root_image(fstab)) return mount_point;
     return "/system";
 }
 
@@ -184,6 +180,14 @@
     return ret;
 }
 
+bool fs_mgr_rw_access(const std::string& path) {
+    if (path.empty()) return false;
+    auto save_errno = errno;
+    auto ret = access(path.c_str(), R_OK | W_OK) == 0;
+    errno = save_errno;
+    return ret;
+}
+
 // return true if system supports overlayfs
 bool fs_mgr_wants_overlayfs() {
     // Properties will return empty on init first_stage_mount, so speculative
@@ -197,7 +201,7 @@
     return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
 }
 
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
                                                                fs_mgr_free_fstab);
     if (!fstab) return false;
@@ -206,10 +210,11 @@
         const auto fsrec = &fstab->recs[i];
         const auto fs_type = fsrec->fs_type;
         if (!fs_type) continue;
-        if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
+        if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
         auto fsrec_mount_point = fsrec->mount_point;
         if (!fsrec_mount_point) continue;
         if (mount_point != fsrec_mount_point) continue;
+        if (!overlay_only) return true;
         const auto fs_options = fsrec->fs_options;
         if (!fs_options) continue;
         const auto options = android::base::Split(fs_options, ",");
@@ -222,13 +227,12 @@
     return false;
 }
 
-bool fs_mgr_overlayfs_verity_enabled(const std::string& basename_mount_point) {
-    auto found = false;
-    fs_mgr_update_verity_state(
-            [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
-                if (mount_point && (basename_mount_point == mount_point)) found = true;
-            });
-    return found;
+std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
+    std::vector<std::string> ret;
+    fs_mgr_update_verity_state([&ret](fstab_rec*, const char* mount_point, int, int) {
+        ret.emplace_back(mount_point);
+    });
+    return ret;
 }
 
 bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
@@ -254,7 +258,7 @@
 
     if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
 
-    return !fs_mgr_overlayfs_verity_enabled(android::base::Basename(fsrec_mount_point));
+    return true;
 }
 
 bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
@@ -371,6 +375,67 @@
     return ret;
 }
 
+uint32_t fs_mgr_overlayfs_slot_number() {
+    return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
+}
+
+std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
+    return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number);
+}
+
+bool fs_mgr_overlayfs_has_logical(const fstab* fstab) {
+    if (!fstab) return false;
+    for (auto i = 0; i < fstab->num_entries; i++) {
+        const auto fsrec = &fstab->recs[i];
+        if (fs_mgr_is_logical(fsrec)) return true;
+    }
+    return false;
+}
+
+// reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
+std::string scratch_device_cache;
+
+bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) {
+    // umount and delete kScratchMountPoint storage if we have logical partitions
+    if (overlay != kScratchMountPoint) return true;
+    scratch_device_cache.erase();
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return true;
+
+    auto save_errno = errno;
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
+        // Lazy umount will allow us to move on and possibly later
+        // establish a new fresh mount without requiring a reboot should
+        // the developer wish to restart.  Old references should melt
+        // away or have no data.  Main goal is to shut the door on the
+        // current overrides with an expectation of a subsequent reboot,
+        // thus any errors here are ignored.
+        umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+    }
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) {
+        errno = save_errno;
+        return true;
+    }
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    if (builder->FindPartition(partition_name) == nullptr) {
+        errno = save_errno;
+        return true;
+    }
+    builder->RemovePartition(partition_name);
+    auto metadata = builder->Export();
+    if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+        if (change) *change = true;
+        if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+    } else {
+        PERROR << "delete partition " << overlay;
+        return false;
+    }
+    errno = save_errno;
+    return true;
+}
+
 bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
                                    bool* change) {
     const auto top = overlay + kOverlayTopDir;
@@ -404,13 +469,16 @@
         save_errno = errno;
         if (!rmdir(top.c_str())) {
             if (change) *change = true;
+            cleanup_all = true;
         } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
             ret = false;
             PERROR << "rmdir " << top;
         } else {
             errno = save_errno;
+            cleanup_all = true;
         }
     }
+    if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change);
     return ret;
 }
 
@@ -445,11 +513,16 @@
     std::vector<std::string> mounts;
     if (!fstab) return mounts;
 
+    auto verity = fs_mgr_overlayfs_verity_enabled_list();
     for (auto i = 0; i < fstab->num_entries; i++) {
         const auto fsrec = &fstab->recs[i];
         if (!fs_mgr_wants_overlayfs(fsrec)) continue;
-        std::string new_mount_point(fs_mgr_mount_point(fstab, fsrec->mount_point));
+        std::string new_mount_point(fs_mgr_mount_point(fsrec->mount_point));
         if (mount_point && (new_mount_point != mount_point)) continue;
+        if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
+            verity.end()) {
+            continue;
+        }
         auto duplicate_or_more_specific = false;
         for (auto it = mounts.begin(); it != mounts.end();) {
             if ((*it == new_mount_point) ||
@@ -465,19 +538,164 @@
         }
         if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
     }
-    // if not itemized /system or /, system as root, fake up
-    // fs_mgr_wants_overlayfs evaluation of /system as candidate.
 
-    if ((std::find(mounts.begin(), mounts.end(), "/system") == mounts.end()) &&
-        !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/") &&
-        !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system") &&
-        (!mount_point || ("/system"s == mount_point)) &&
-        !fs_mgr_overlayfs_verity_enabled("system")) {
-        mounts.emplace_back("/system");
+    // if not itemized /system or /, system as root, fake one up?
+
+    // do we want or need to?
+    if (mount_point && ("/system"s != mount_point)) return mounts;
+    if (std::find(mounts.begin(), mounts.end(), "/system") != mounts.end()) return mounts;
+
+    // fs_mgr_overlayfs_verity_enabled_list says not to?
+    if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
+
+    // confirm that fstab is missing system
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/")) {
+        return mounts;
     }
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system")) {
+        return mounts;
+    }
+
+    // We have a stunted fstab (w/o system or / ) passed in by the caller,
+    // verity claims are assumed accurate because they are collected internally
+    // from fs_mgr_fstab_default() from within fs_mgr_update_verity_state(),
+    // Can (re)evaluate /system with impunity since we know it is ever-present.
+    mounts.emplace_back("/system");
     return mounts;
 }
 
+// Mount kScratchMountPoint
+bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) {
+    if (setfscreatecon(kOverlayfsFileContext)) {
+        PERROR << "setfscreatecon " << kOverlayfsFileContext;
+    }
+    if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) {
+        PERROR << "create " << kScratchMountPoint;
+    }
+
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab(
+            static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab);
+    auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec)));
+    local_fstab->num_entries = 1;
+    local_fstab->recs = fsrec;
+    fsrec->blk_device = strdup(device_path.c_str());
+    fsrec->mount_point = strdup(kScratchMountPoint.c_str());
+    fsrec->fs_type = strdup(mnt_type.c_str());
+    fsrec->flags = MS_RELATIME;
+    fsrec->fs_options = strdup("");
+    auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+    auto save_errno = errno;
+    setfscreatecon(nullptr);
+    if (!mounted) rmdir(kScratchMountPoint.c_str());
+    errno = save_errno;
+    return mounted;
+}
+
+const std::string kMkF2fs("/system/bin/make_f2fs");
+const std::string kMkExt4("/system/bin/mke2fs");
+
+std::string fs_mgr_overlayfs_scratch_mount_type() {
+    if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
+    if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+    return "auto";
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+    if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+    auto& dm = DeviceMapper::Instance();
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    std::string path;
+    if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+    return scratch_device_cache = path;
+}
+
+// Create and mount kScratchMountPoint storage if we have logical partitions
+bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) {
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
+    auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
+    auto scratch_device = fs_mgr_overlayfs_scratch_device();
+    auto partition_exists = fs_mgr_rw_access(scratch_device);
+    if (!partition_exists) {
+        auto slot_number = fs_mgr_overlayfs_slot_number();
+        auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+        if (!fs_mgr_rw_access(super_device)) return false;
+        if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+        auto builder = MetadataBuilder::New(super_device, slot_number);
+        if (!builder) {
+            PERROR << "open " << super_device << " metadata";
+            return false;
+        }
+        const auto partition_name = android::base::Basename(kScratchMountPoint);
+        partition_exists = builder->FindPartition(partition_name) != nullptr;
+        if (!partition_exists) {
+            auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+            if (!partition) {
+                PERROR << "create " << partition_name;
+                return false;
+            }
+            auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
+            // 512MB or half the remaining available space, whichever is greater.
+            partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
+            if (!builder->ResizePartition(partition, partition_size)) {
+                PERROR << "resize " << partition_name;
+                return false;
+            }
+
+            auto metadata = builder->Export();
+            if (!metadata) {
+                LERROR << "generate new metadata " << partition_name;
+                return false;
+            }
+            if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+                LERROR << "update " << partition_name;
+                return false;
+            }
+
+            if (change) *change = true;
+        }
+
+        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+                                    &scratch_device))
+            return false;
+    }
+
+    if (partition_exists) {
+        if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
+            if (change) *change = true;
+            return true;
+        }
+        // partition existed, but was not initialized;
+        errno = 0;
+    }
+
+    auto ret = system((mnt_type == "f2fs")
+                              ? ((kMkF2fs + " -d1 " + scratch_device).c_str())
+                              : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint +
+                                  " -O has_journal " + scratch_device)
+                                         .c_str()));
+    if (ret) {
+        LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " error=" << ret;
+        return false;
+    }
+
+    if (change) *change = true;
+
+    return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
+}
+
+bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) {
+    if (scratch_device.empty()) return false;
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return false;
+    if (fs_mgr_rw_access(scratch_device)) return true;
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return false;
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) return false;
+    return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
+}
+
 }  // namespace
 
 bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
@@ -487,14 +705,37 @@
 
     if (!fstab) return ret;
 
+    auto scratch_can_be_mounted = true;
     for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
         if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        if (scratch_can_be_mounted) {
+            scratch_can_be_mounted = false;
+            auto scratch_device = fs_mgr_overlayfs_scratch_device();
+            if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
+                fs_mgr_wait_for_file(scratch_device, 10s) &&
+                fs_mgr_overlayfs_mount_scratch(scratch_device,
+                                               fs_mgr_overlayfs_scratch_mount_type()) &&
+                !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
+                umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+                rmdir(kScratchMountPoint.c_str());
+            }
+        }
         if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
     }
     return ret;
 }
 
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) {
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) {
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+        return {};
+    }
+
+    for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
+        if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        auto device = fs_mgr_overlayfs_scratch_device();
+        if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break;
+        return {device};
+    }
     return {};
 }
 
@@ -503,10 +744,6 @@
 bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
     if (change) *change = false;
     auto ret = false;
-    if (backing && (kOverlayMountPoint != backing)) {
-        errno = EINVAL;
-        return ret;
-    }
     if (!fs_mgr_wants_overlayfs()) return ret;
     if (!fs_mgr_boot_completed()) {
         errno = EBUSY;
@@ -516,16 +753,32 @@
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
                                                                fs_mgr_free_fstab);
-    if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
-    auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point));
-    if (fstab && mounts.empty()) return ret;
+    if (!fstab) return ret;
+    auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(mount_point));
+    if (mounts.empty()) return ret;
+
+    std::string dir;
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        if (backing && backing[0] && (overlay_mount_point != backing)) continue;
+        if (overlay_mount_point == kScratchMountPoint) {
+            if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
+                !fs_mgr_overlayfs_has_logical(fstab.get())) {
+                continue;
+            }
+            if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue;
+        } else {
+            if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue;
+        }
+        dir = overlay_mount_point;
+        break;
+    }
+    if (dir.empty()) {
+        errno = ESRCH;
+        return ret;
+    }
 
     std::string overlay;
-    ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change);
-
-    if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
-        ret = true;
-    }
+    ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change);
     for (const auto& fsrec_mount_point : mounts) {
         ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change);
     }
@@ -536,11 +789,11 @@
 // If something is altered, set *change.
 bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
     if (change) *change = false;
-    mount_point = fs_mgr_mount_point(std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>(
-                                             fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
-                                             .get(),
-                                     mount_point);
-    auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change);
+    mount_point = fs_mgr_mount_point(mount_point);
+    auto ret = true;
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
+    }
     if (!fs_mgr_wants_overlayfs()) {
         // After obligatory teardown to make sure everything is clean, but if
         // we didn't want overlayfs in the the first place, we do not want to
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 506e81d..5e83cfb 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -128,10 +128,10 @@
                           FileWaitMode wait_mode = FileWaitMode::Exists);
 
 int fs_mgr_set_blk_ro(const char* blockdev);
-bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_update_for_slotselect(fstab* fstab);
 bool fs_mgr_is_device_unlocked();
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
-int load_verity_state(struct fstab_rec* fstab, int* mode);
+int load_verity_state(fstab_rec* fstab, int* mode);
 
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a4544b2..5dabe76 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -51,8 +51,8 @@
 };
 
 // Callback function for verity status
-typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point,
-                                          int mode, int status);
+typedef void fs_mgr_verity_state_callback(fstab_rec* fstab, const char* mount_point, int mode,
+                                          int status);
 
 #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
 #define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
@@ -63,32 +63,31 @@
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
 #define FS_MGR_MNTALL_FAIL (-1)
-int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
+int fs_mgr_mount_all(fstab* fstab, int mount_mode);
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
 #define FS_MGR_DOMNT_SUCCESS 0
 
-int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
-                    char *tmp_mount_point);
-int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
-                    char* tmp_mount_point, bool need_cp);
-int fs_mgr_do_mount_one(struct fstab_rec *rec);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+                    bool need_cp);
+int fs_mgr_do_mount_one(fstab_rec* rec);
 int fs_mgr_do_tmpfs_mount(const char *n_name);
-struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
-void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
+fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
+void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback);
 int fs_mgr_swapon_all(struct fstab *fstab);
 bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
 
-int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
+int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer);
 
 #define FS_MGR_SETUP_VERITY_SKIPPED  (-3)
 #define FS_MGR_SETUP_VERITY_DISABLED (-2)
 #define FS_MGR_SETUP_VERITY_FAIL (-1)
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
+int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev);
 
 // Return the name of the super partition if it exists. If a slot number is
 // specified, the super partition for the corresponding metadata slot will be
diff --git a/init/Android.mk b/init/Android.mk
index 5554995..ef08329 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -51,7 +51,8 @@
     uevent_listener.cpp \
     util.cpp \
 
-LOCAL_MODULE := init
+LOCAL_MODULE := init_first_stage
+LOCAL_MODULE_STEM := init
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
@@ -87,8 +88,32 @@
     libselinux \
     libcap \
 
-LOCAL_REQUIRED_MODULES := \
-    init_second_stage \
-
 LOCAL_SANITIZE := signed-integer-overflow
 include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init_system
+ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+LOCAL_REQUIRED_MODULES := \
+   init_first_stage \
+   init_second_stage \
+
+else
+LOCAL_REQUIRED_MODULES := \
+   init_second_stage \
+
+endif
+include $(BUILD_PHONY_PACKAGE)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init_vendor
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+LOCAL_REQUIRED_MODULES := \
+   init_first_stage \
+
+endif
+include $(BUILD_PHONY_PACKAGE)
+
+
diff --git a/init/README.md b/init/README.md
index 02a65d5..f938ccc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -189,7 +189,7 @@
 
 `critical`
 > This is a device-critical service. If it exits more than four times in
-  four minutes, the device will reboot into recovery mode.
+  four minutes, the device will reboot into bootloader.
 
 `disabled`
 > This service will not automatically start with its class.
@@ -213,7 +213,8 @@
 `interface <interface name> <instance name>`
 > Associates this service with a list of the HIDL services that it provides. The interface name
   must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
-  lazily start services.
+  lazily start services. When multiple interfaces are served, this tag should be used multiple
+  times.
   For example: interface vendor.foo.bar@1.0::IBaz default
 
 `ioprio <class> <priority>`
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 17d34e1..7da2526 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1018,7 +1018,11 @@
         if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
             if (e4crypt_is_native()) {
                 LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
-                reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+                if (auto result = reboot_into_recovery(
+                            {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+                    !result) {
+                    LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+                }
             } else {
                 LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
             }
diff --git a/init/keychords.cpp b/init/keychords.cpp
index b8c1cfd..f5ac44f 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -41,7 +41,7 @@
 
 Keychords::~Keychords() noexcept {
     if (inotify_fd_ >= 0) {
-        epoll_->UnregisterHandler(inotify_fd_);
+        epoll_->UnregisterHandler(inotify_fd_).IgnoreError();
         ::close(inotify_fd_);
     }
     while (!registration_.empty()) GeteventCloseDevice(registration_.begin()->first);
@@ -186,7 +186,11 @@
         current_ |= mask & available & set;
         LambdaCheck();
     }
-    epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
+    if (auto result = epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
+        !result) {
+        LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
+        return false;
+    }
     return true;
 }
 
@@ -208,7 +212,7 @@
     auto it = registration_.find(device);
     if (it == registration_.end()) return;
     auto fd = (*it).second;
-    epoll_->UnregisterHandler(fd);
+    epoll_->UnregisterHandler(fd).IgnoreError();
     registration_.erase(it);
     ::close(fd);
 }
@@ -266,7 +270,11 @@
     }
 
     if (inotify_fd_ >= 0) {
-        epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
+        if (auto result =
+                    epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
+            !result) {
+            LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
+        }
     }
 }
 
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index a3baeb1..e5a6fd3 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -213,7 +213,7 @@
 }
 
 void TestFrame::RelaxForMs(std::chrono::milliseconds wait) {
-    epoll_.Wait(wait);
+    epoll_.Wait(wait).IgnoreError();
 }
 
 void TestFrame::SetChord(int key, bool value) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 866f40e..a145797 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -142,7 +142,9 @@
         LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
         return;
     }
-    service->Start();
+    if (auto result = service->Start(); !result) {
+        LOG(WARNING) << "Could not start blank_screen service: " << result.error();
+    }
 }
 
 static void ShutdownVold() {
@@ -307,15 +309,14 @@
 
     auto shutdown_timeout = 0ms;
     if (!SHUTDOWN_ZERO_TIMEOUT) {
-        if (is_thermal_shutdown) {
-            constexpr unsigned int thermal_shutdown_timeout = 1;
-            shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
-        } else {
-            constexpr unsigned int shutdown_timeout_default = 6;
-            auto shutdown_timeout_property = android::base::GetUintProperty(
-                "ro.build.shutdown_timeout", shutdown_timeout_default);
-            shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+        constexpr unsigned int shutdown_timeout_default = 6;
+        constexpr unsigned int max_thermal_shutdown_timeout = 3;
+        auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
+                                                                     shutdown_timeout_default);
+        if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
+            shutdown_timeout_final = max_thermal_shutdown_timeout;
         }
+        shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
     }
     LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
 
diff --git a/init/result.h b/init/result.h
index fc03962..0e3fd3d 100644
--- a/init/result.h
+++ b/init/result.h
@@ -151,7 +151,7 @@
 }
 
 template <typename T>
-class Result {
+class [[nodiscard]] Result {
   public:
     Result() {}
 
@@ -170,6 +170,8 @@
         : contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
                     result_error.error_errno) {}
 
+    void IgnoreError() const {}
+
     bool has_value() const { return contents_.index() == 0; }
 
     T& value() & { return std::get<0>(contents_); }
diff --git a/init/service.cpp b/init/service.cpp
index a3e5953..0b1425d 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -369,7 +369,7 @@
         return;
     }
 
-    // If we crash > 4 times in 4 minutes, reboot into recovery.
+    // If we crash > 4 times in 4 minutes, reboot into bootloader.
     boot_clock::time_point now = boot_clock::now();
     if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
diff --git a/init/service.h b/init/service.h
index e8d5ead..ee53adf 100644
--- a/init/service.h
+++ b/init/service.h
@@ -43,7 +43,7 @@
 #define SVC_RUNNING 0x004         // currently active
 #define SVC_RESTARTING 0x008      // waiting to restart
 #define SVC_CONSOLE 0x010         // requires console
-#define SVC_CRITICAL 0x020        // will reboot into recovery if keeps crashing
+#define SVC_CRITICAL 0x020        // will reboot into bootloader if keeps crashing
 #define SVC_RESET 0x040           // Use when stopping a process,
                                   // but not disabling so it can be restarted with its class.
 #define SVC_RC_DISABLED 0x080     // Remember if the disabled flag was set in the rc script.
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 4972d10..baef833 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -31,6 +31,7 @@
 static const std::set<std::string> kExportedActionableProperties = {
     "dev.bootcomplete",
     "init.svc.console",
+    "init.svc.dumpstatez",
     "init.svc.mediadrm",
     "init.svc.surfaceflinger",
     "init.svc.zygote",
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index 6307993..eae03e3 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -39,7 +39,7 @@
     free(context);
 
     while (state.KeepRunning()) {
-        subcontext.Execute(std::vector<std::string>{"return_success"});
+        subcontext.Execute(std::vector<std::string>{"return_success"}).IgnoreError();
     }
 
     if (subcontext.pid() > 0) {
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 95be6af..66491dd 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -175,7 +175,7 @@
     //
     // When a subprocess crashes, we fatally abort from ueventd.  init will restart ueventd when
     // init reaps it, and the cold boot process will start again.  If this continues to fail, then
-    // since ueventd is marked as a critical service, init will reboot to recovery.
+    // since ueventd is marked as a critical service, init will reboot to bootloader.
     //
     // When a subprocess gets stuck, keep ueventd spinning waiting for it.  init has a timeout for
     // cold boot and will reboot to the bootloader if ueventd does not complete in time.
diff --git a/libcutils/partition_utils.cpp b/libcutils/partition_utils.cpp
index 6735d6c..2211ff6 100644
--- a/libcutils/partition_utils.cpp
+++ b/libcutils/partition_utils.cpp
@@ -25,7 +25,7 @@
 
 #include <cutils/properties.h>
 
-static int only_one_char(char *buf, int len, char c)
+static int only_one_char(uint8_t *buf, int len, uint8_t c)
 {
     int i, ret;
 
@@ -41,7 +41,7 @@
 
 int partition_wiped(char *source)
 {
-    char buf[4096];
+    uint8_t buf[4096];
     int fd, ret;
 
     if ((fd = open(source, O_RDONLY)) < 0) {
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index 735088a..8eedc60 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -125,6 +125,7 @@
 
 void stats_log_close() {
     statsd_writer_init_lock();
+    write_to_statsd = __write_to_statsd_init;
     if (statsdLoggerWrite.close) {
         (*statsdLoggerWrite.close)();
     }
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 24ea7aa..9dc2699 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -374,6 +374,7 @@
                     continue;
                 if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
                     return false;
+                continue;
             default:
                 continue;
         }
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 430f6c5..17e2526 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -126,7 +126,7 @@
 
   const std::string dex_debug_name("__dex_debug_descriptor");
   for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+    if (!(info->flags & PROT_READ) || info->offset != 0) {
       continue;
     }
 
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 4723606..56a0679 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -194,26 +194,26 @@
   return true;
 }
 
-void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
+bool Elf::GetInfo(Memory* memory, uint64_t* size) {
   if (!IsValidElf(memory)) {
-    *valid = false;
-    return;
+    return false;
   }
   *size = 0;
-  *valid = true;
 
-  // Now read the section header information.
   uint8_t class_type;
   if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
-    return;
+    return false;
   }
+
+  // Get the maximum size of the elf data from the header.
   if (class_type == ELFCLASS32) {
     ElfInterface32::GetMaxSize(memory, size);
   } else if (class_type == ELFCLASS64) {
     ElfInterface64::GetMaxSize(memory, size);
   } else {
-    *valid = false;
+    return false;
   }
+  return true;
 }
 
 bool Elf::IsValidPc(uint64_t pc) {
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 0c319ec..821aacf 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -174,7 +174,7 @@
 
   const std::string descriptor_name("__jit_debug_descriptor");
   for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+    if (!(info->flags & PROT_READ) || info->offset != 0) {
       continue;
     }
 
@@ -194,10 +194,9 @@
 
     Elf* elf = info->GetElf(memory_, true);
     uint64_t descriptor_addr;
-    if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr)) {
-      // Search for the first non-zero entry.
-      descriptor_addr += info->start;
-      entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr);
+    // Find first non-empty entry (libart might be loaded multiple times).
+    if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
+      entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
       if (entry_addr_ != 0) {
         break;
       }
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 64005ae..52b7535 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -53,10 +53,8 @@
     return nullptr;
   }
 
-  bool valid;
   uint64_t max_size;
-  Elf::GetInfo(memory.get(), &valid, &max_size);
-  if (!valid) {
+  if (!Elf::GetInfo(memory.get(), &max_size)) {
     // Init as if the whole file is an elf.
     if (memory->Init(name, 0)) {
       elf_offset = offset;
@@ -109,11 +107,7 @@
   // first part of the elf file. This is done if the linker rosegment
   // option is used.
   std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
-  bool valid;
-  uint64_t max_size;
-  Elf::GetInfo(memory.get(), &valid, &max_size);
-  if (valid) {
-    // Valid elf, we are done.
+  if (Elf::IsValidElf(memory.get())) {
     return memory.release();
   }
 
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 099cc9e..ee1cd1a 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -190,6 +190,12 @@
         FillInDexFrame();
         // Clear the dex pc so that we don't repeat this frame later.
         regs_->set_dex_pc(0);
+
+        // Make sure there is enough room for the real frame.
+        if (frames_.size() == max_frames_) {
+          last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
+          break;
+        }
       }
 
       FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f4cdbda..9af859d 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -94,7 +94,7 @@
 
   static bool IsValidElf(Memory* memory);
 
-  static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
+  static bool GetInfo(Memory* memory, uint64_t* size);
 
   static uint64_t GetLoadBias(Memory* memory);
 
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index d029bb0..c6d7f33 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -46,17 +46,17 @@
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
                        "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -w-s 00000000 00:00 0\n"
-                       "a000-c000 r-xp 00000000 00:00 0\n"
-                       "c000-f000 rwxp 00000000 00:00 0\n"
-                       "f000-11000 r-xp 00000000 00:00 0\n"
+                       "6000-8000 -wxs 00000000 00:00 0\n"
+                       "a000-c000 r--p 00000000 00:00 0\n"
+                       "c000-f000 rw-p 00000000 00:00 0\n"
+                       "f000-11000 r--p 00000000 00:00 0\n"
                        "100000-110000 rw-p 0000000 00:00 0\n"
                        "200000-210000 rw-p 0000000 00:00 0\n"
                        "300000-400000 rw-p 0000000 00:00 0\n"));
     ASSERT_TRUE(maps_->Parse());
 
-    // Global variable in a section that is not readable/executable.
-    MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+    // Global variable in a section that is not readable.
+    MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
     ASSERT_TRUE(map_info != nullptr);
     MemoryFake* memory = new MemoryFake;
     ElfFake* elf = new ElfFake(memory);
@@ -95,7 +95,7 @@
   void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
   void WriteDex(uint64_t dex_file);
 
-  static constexpr size_t kMapGlobalNonReadableExectable = 3;
+  static constexpr size_t kMapGlobalNonReadable = 2;
   static constexpr size_t kMapGlobalSetToZero = 4;
   static constexpr size_t kMapGlobal = 5;
   static constexpr size_t kMapDexFileEntries = 7;
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index c1c45f8..66f0859 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -45,11 +45,11 @@
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
                        "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -w-s 00000000 00:00 0\n"
+                       "6000-8000 -wxs 00000000 00:00 0\n"
                        "a000-c000 --xp 00000000 00:00 0\n"
-                       "c000-f000 rwxp 00000000 00:00 0\n"
-                       "f000-11000 r-xp 00000000 00:00 0\n"
-                       "12000-14000 r-xp 00000000 00:00 0\n"
+                       "c000-f000 rw-p 00000000 00:00 0\n"
+                       "f000-11000 r--p 00000000 00:00 0\n"
+                       "12000-14000 r--p 00000000 00:00 0\n"
                        "100000-110000 rw-p 0000000 00:00 0\n"
                        "200000-210000 rw-p 0000000 00:00 0\n"));
     ASSERT_TRUE(maps_->Parse());
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 4369030..831d3b5 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -946,6 +946,33 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, dex_pc_max_frames) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
+  regs_.FakeSetDexPc(0xa3400);
+
+  Unwinder unwinder(1, &maps_, &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x400U, frame->rel_pc);
+  EXPECT_EQ(0xa3400U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0xa3000U, frame->map_start);
+  EXPECT_EQ(0xa4000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame_static) {
   FrameData frame;
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index fd3f602..3308adf 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -23,11 +23,21 @@
         "-D_FILE_OFFSET_BITS=64",
     ],
     cppflags: [
-        "-Wold-style-cast",
         // Incorrectly warns when C++11 empty brace {} initializer is used.
         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
         "-Wno-missing-field-initializers",
     ],
+
+    // Enable -Wold-style-cast only for non-Windows targets.  _islower_l,
+    // _isupper_l etc. in MinGW locale_win32.h (included from
+    // libcxx/include/__locale) has an old-style-cast.
+    target: {
+        not_windows: {
+            cppflags: [
+                "-Wold-style-cast",
+            ],
+        },
+    },
 }
 
 cc_defaults {
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 018b1a9..32d7901 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -103,7 +103,8 @@
   off64_t offset;
 };
 
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
 
 /*
  * Open a Zip archive, and sets handle to the value of the opaque
@@ -144,7 +145,7 @@
  * this handle for any further operations without an intervening
  * call to one of the OpenArchive variants.
  */
-void CloseArchive(ZipArchiveHandle handle);
+void CloseArchive(ZipArchiveHandle archive);
 
 /*
  * Find an entry in the Zip archive, by name. |entryName| must be a null
@@ -162,7 +163,7 @@
  * On non-Windows platforms this method does not modify internal state and
  * can be called concurrently.
  */
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data);
 
 /*
  * Start iterating over all entries of a zip file. The order of iteration
@@ -177,8 +178,8 @@
  *
  * Returns 0 on success and negative values on failure.
  */
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
-                       const ZipString* optional_suffix);
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       const ZipString* optional_prefix, const ZipString* optional_suffix);
 
 /*
  * Advance to the next element in the zipfile in iteration order.
@@ -203,7 +204,7 @@
  *
  * Returns 0 on success and negative values on failure.
  */
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd);
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
 
 /**
  * Uncompress a given zip entry to the memory region at |begin| and of
@@ -213,9 +214,9 @@
  *
  * Returns 0 on success and negative values on failure.
  */
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size);
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size);
 
-int GetFileDescriptor(const ZipArchiveHandle handle);
+int GetFileDescriptor(const ZipArchiveHandle archive);
 
 const char* ErrorCodeString(int32_t error_code);
 
@@ -226,7 +227,7 @@
  * Stream the uncompressed data through the supplied function,
  * passing cookie to it each time it gets called.
  */
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
                                 ProcessZipEntryFunction func, void* cookie);
 #endif
 
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6a3db6b..4221ee7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -517,8 +517,7 @@
 /*
  * Close a ZipArchive, closing the file and freeing the contents.
  */
-void CloseArchive(ZipArchiveHandle handle) {
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+void CloseArchive(ZipArchiveHandle archive) {
   ALOGV("Closing archive %p", archive);
   delete archive;
 }
@@ -745,10 +744,8 @@
   }
 };
 
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
-                       const ZipString* optional_suffix) {
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
-
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       const ZipString* optional_prefix, const ZipString* optional_suffix) {
   if (archive == NULL || archive->hash_table == NULL) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
     return kInvalidHandle;
@@ -766,8 +763,7 @@
   delete reinterpret_cast<IterationHandle*>(cookie);
 }
 
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data) {
-  const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data) {
   if (entryName.name_length == 0) {
     ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
     return kInvalidEntryName;
@@ -1116,8 +1112,7 @@
   return 0;
 }
 
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t ExtractToWriter(ZipArchiveHandle archive, ZipEntry* entry, zip_archive::Writer* writer) {
   const uint16_t method = entry->method;
 
   // this should default to kUnknownCompressionMethod.
@@ -1145,18 +1140,18 @@
   return return_value;
 }
 
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size) {
   MemoryWriter writer(begin, size);
-  return ExtractToWriter(handle, entry, &writer);
+  return ExtractToWriter(archive, entry, &writer);
 }
 
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd) {
   auto writer = FileWriter::Create(fd, entry);
   if (!writer.IsValid()) {
     return kIoError;
   }
 
-  return ExtractToWriter(handle, entry, &writer);
+  return ExtractToWriter(archive, entry, &writer);
 }
 
 const char* ErrorCodeString(int32_t error_code) {
@@ -1173,8 +1168,8 @@
   return "Unknown return code";
 }
 
-int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
+int GetFileDescriptor(const ZipArchiveHandle archive) {
+  return archive->mapped_zip.GetFileDescriptor();
 }
 
 ZipString::ZipString(const char* entry_name) : name(reinterpret_cast<const uint8_t*>(entry_name)) {
@@ -1198,10 +1193,10 @@
   void* cookie_;
 };
 
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
                                 ProcessZipEntryFunction func, void* cookie) {
   ProcessWriter writer(func, cookie);
-  return ExtractToWriter(handle, entry, &writer);
+  return ExtractToWriter(archive, entry, &writer);
 }
 
 #endif  //! defined(_WIN32)
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index 1e2df2f..4d39dd9 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -57,7 +57,7 @@
 #define LLK_BLACKLIST_UID_PROPERTY     "ro.llk.blacklist.uid"
 #define LLK_BLACKLIST_UID_DEFAULT      ""
 #define LLK_BLACKLIST_STACK_PROPERTY   "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT    "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd"
+#define LLK_BLACKLIST_STACK_DEFAULT    "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd,apexd"
 /* clang-format on */
 
 __END_DECLS
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index fe6364d..e8f51da 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -30,6 +30,7 @@
     LMK_TARGET = 0,  /* Associate minfree with oom_adj_score */
     LMK_PROCPRIO,    /* Register a process and set its oom_adj_score */
     LMK_PROCREMOVE,  /* Unregister a process */
+    LMK_PROCPURGE,   /* Purge all registered processes */
 };
 
 /*
@@ -142,6 +143,15 @@
     return 2 * sizeof(int);
 }
 
+/*
+ * Prepare LMK_PROCPURGE packet and return packet size in bytes.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
+    packet[0] = htonl(LMK_PROCPURGE);
+    return sizeof(int);
+}
+
 __END_DECLS
 
 #endif /* _LMKD_H_ */
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 1980dc6..0a469e8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -559,7 +559,7 @@
         } else if (params.oomadj >= 300) {
             soft_limit_mult = 1;
         } else if (params.oomadj >= 200) {
-            soft_limit_mult = 2;
+            soft_limit_mult = 8;
         } else if (params.oomadj >= 100) {
             soft_limit_mult = 10;
         } else if (params.oomadj >=   0) {
@@ -612,9 +612,38 @@
     }
 
     lmkd_pack_get_procremove(packet, &params);
+    /*
+     * WARNING: After pid_remove() procp is freed and can't be used!
+     * Therefore placed at the end of the function.
+     */
     pid_remove(params.pid);
 }
 
+static void cmd_procpurge() {
+    int i;
+    struct proc *procp;
+    struct proc *next;
+
+    if (use_inkernel_interface) {
+        return;
+    }
+
+    for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
+        procadjslot_list[i].next = &procadjslot_list[i];
+        procadjslot_list[i].prev = &procadjslot_list[i];
+    }
+
+    for (i = 0; i < PIDHASH_SZ; i++) {
+        procp = pidhash[i];
+        while (procp) {
+            next = procp->pidhash_next;
+            free(procp);
+            procp = next;
+        }
+    }
+    memset(&pidhash[0], 0, sizeof(pidhash));
+}
+
 static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
     int i;
     struct lmk_target target;
@@ -757,6 +786,11 @@
             goto wronglen;
         cmd_procremove(packet);
         break;
+    case LMK_PROCPURGE:
+        if (nargs != 0)
+            goto wronglen;
+        cmd_procpurge();
+        break;
     default:
         ALOGE("Received unknown command code %d", cmd);
         return;
@@ -822,7 +856,7 @@
 }
 
 #ifdef LMKD_LOG_STATS
-static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
+static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) {
     char key[LINE_MAX + 1];
     int64_t value;
 
@@ -844,17 +878,10 @@
         mem_st->swap_in_bytes = value;
 }
 
-static int memory_stat_parse(struct memory_stat *mem_st,  int pid, uid_t uid) {
+static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) {
     FILE *fp;
     char buf[PATH_MAX];
 
-    /*
-     * Per-application memory.stat files are available only when
-     * per-application memcgs are enabled.
-     */
-    if (!per_app_memcg)
-        return -1;
-
     snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
 
     fp = fopen(buf, "r");
@@ -864,13 +891,50 @@
         return -1;
     }
 
-    while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
+    while (fgets(buf, PAGE_SIZE, fp) != NULL) {
         memory_stat_parse_line(buf, mem_st);
     }
     fclose(fp);
 
     return 0;
 }
+
+static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
+    char path[PATH_MAX];
+    char buffer[PROC_STAT_BUFFER_SIZE];
+    int fd, ret;
+
+    snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
+    if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
+        ALOGE("%s open failed: %s", path, strerror(errno));
+        return -1;
+    }
+
+    ret = read(fd, buffer, sizeof(buffer));
+    if (ret < 0) {
+        ALOGE("%s read failed: %s", path, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    // field 10 is pgfault
+    // field 12 is pgmajfault
+    // field 24 is rss_in_pages
+    int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0;
+    if (sscanf(buffer,
+               "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
+               "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
+               "%*d %*d %" SCNd64 "",
+               &pgfault, &pgmajfault, &rss_in_pages) != 3) {
+        return -1;
+    }
+    mem_st->pgfault = pgfault;
+    mem_st->pgmajfault = pgmajfault;
+    mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE);
+
+    return 0;
+}
 #endif
 
 /* /prop/zoneinfo parsing routines */
@@ -1105,6 +1169,7 @@
     char *taskname;
     int tasksize;
     int r;
+    int result = -1;
 
 #ifdef LMKD_LOG_STATS
     struct memory_stat mem_st = {};
@@ -1113,19 +1178,21 @@
 
     taskname = proc_get_name(pid);
     if (!taskname) {
-        pid_remove(pid);
-        return -1;
+        goto out;
     }
 
     tasksize = proc_get_size(pid);
     if (tasksize <= 0) {
-        pid_remove(pid);
-        return -1;
+        goto out;
     }
 
 #ifdef LMKD_LOG_STATS
     if (enable_stats_log) {
-        memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid);
+        if (per_app_memcg) {
+            memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid);
+        } else {
+            memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid);
+        }
     }
 #endif
 
@@ -1135,25 +1202,33 @@
     r = kill(pid, SIGKILL);
     ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
         taskname, pid, uid, procp->oomadj, tasksize * page_k);
-    pid_remove(pid);
 
     TRACE_KILL_END();
 
     if (r) {
         ALOGE("kill(%d): errno=%d", pid, errno);
-        return -1;
+        goto out;
     } else {
 #ifdef LMKD_LOG_STATS
         if (memory_stat_parse_result == 0) {
             stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
                     procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
                     mem_st.cache_in_bytes, mem_st.swap_in_bytes);
+        } else if (enable_stats_log) {
+            stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
+                                          -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1);
         }
 #endif
-        return tasksize;
+        result = tasksize;
     }
 
-    return tasksize;
+out:
+    /*
+     * WARNING: After pid_remove() procp is freed and can't be used!
+     * Therefore placed at the end of the function.
+     */
+    pid_remove(pid);
+    return result;
 }
 
 /*
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
index edebb19..8458480 100644
--- a/lmkd/statslog.h
+++ b/lmkd/statslog.h
@@ -67,6 +67,9 @@
 };
 
 #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
+#define PROC_STAT_FILE_PATH "/proc/%d/stat"
+#define PROC_STAT_BUFFER_SIZE 1024
+#define BYTES_IN_KILOBYTE 1024
 
 /**
  * Logs the change in LMKD state which is used as start/stop boundaries for logging
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 658e079..bd17555 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -42,7 +42,7 @@
     LogTimeEntry::wrlock();
     LastLogTimes::iterator it = times.begin();
     while (it != times.end()) {
-        entry = (*it);
+        entry = it->get();
         if (entry->mClient == client) {
             if (!entry->isWatchingMultiple(mLogMask)) {
                 LogTimeEntry::unlock();
@@ -63,31 +63,12 @@
                 }
             }
             entry->triggerReader_Locked();
-            if (entry->runningReader_Locked()) {
-                LogTimeEntry::unlock();
-                return;
-            }
-            entry->incRef_Locked();
-            break;
+            LogTimeEntry::unlock();
+            return;
         }
         it++;
     }
 
-    if (it == times.end()) {
-        // Create LogTimeEntry in notifyNewLog() ?
-        if (mTail == (unsigned long)-1) {
-            LogTimeEntry::unlock();
-            return;
-        }
-        entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask,
-                                 mPid, mStart, mTimeout);
-        times.push_front(entry);
-    }
-
-    client->incRef();
-
-    // release client and entry reference counts once done
-    entry->startReader_Locked();
     LogTimeEntry::unlock();
 }
 
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 543dfc3..ceaf393 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -27,36 +27,11 @@
 
 class FlushCommand : public SocketClientCommand {
     LogReader& mReader;
-    bool mNonBlock;
-    unsigned long mTail;
     log_mask_t mLogMask;
-    pid_t mPid;
-    log_time mStart;
-    uint64_t mTimeout;
 
    public:
-    // for opening a reader
-    explicit FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
-                          log_mask_t logMask, pid_t pid, log_time start,
-                          uint64_t timeout)
-        : mReader(reader),
-          mNonBlock(nonBlock),
-          mTail(tail),
-          mLogMask(logMask),
-          mPid(pid),
-          mStart(start),
-          mTimeout((start != log_time::EPOCH) ? timeout : 0) {
-    }
-
-    // for notification of an update
     explicit FlushCommand(LogReader& reader, log_mask_t logMask)
-        : mReader(reader),
-          mNonBlock(false),
-          mTail(-1),
-          mLogMask(logMask),
-          mPid(0),
-          mStart(log_time::EPOCH),
-          mTimeout(0) {
+        : mReader(reader), mLogMask(logMask) {
     }
 
     virtual void runSocketCommand(SocketClient* client);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index fd1b8b2..fbdbf79 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -105,10 +105,8 @@
 
     LastLogTimes::iterator times = mTimes.begin();
     while (times != mTimes.end()) {
-        LogTimeEntry* entry = (*times);
-        if (entry->owned_Locked()) {
-            entry->triggerReader_Locked();
-        }
+        LogTimeEntry* entry = times->get();
+        entry->triggerReader_Locked();
         times++;
     }
 
@@ -409,17 +407,15 @@
 
         LastLogTimes::iterator times = mTimes.begin();
         while (times != mTimes.end()) {
-            LogTimeEntry* entry = (*times);
-            if (entry->owned_Locked()) {
-                if (!entry->mNonBlock) {
-                    end_always = true;
-                    break;
-                }
-                // it passing mEnd is blocked by the following checks.
-                if (!end_set || (end <= entry->mEnd)) {
-                    end = entry->mEnd;
-                    end_set = true;
-                }
+            LogTimeEntry* entry = times->get();
+            if (!entry->mNonBlock) {
+                end_always = true;
+                break;
+            }
+            // it passing mEnd is blocked by the following checks.
+            if (!end_set || (end <= entry->mEnd)) {
+                end = entry->mEnd;
+                end_set = true;
             }
             times++;
         }
@@ -710,8 +706,8 @@
     // Region locked?
     LastLogTimes::iterator times = mTimes.begin();
     while (times != mTimes.end()) {
-        LogTimeEntry* entry = (*times);
-        if (entry->owned_Locked() && entry->isWatching(id) &&
+        LogTimeEntry* entry = times->get();
+        if (entry->isWatching(id) &&
             (!oldest || (oldest->mStart > entry->mStart) ||
              ((oldest->mStart == entry->mStart) &&
               (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
@@ -1052,9 +1048,9 @@
                 LogTimeEntry::wrlock();
                 LastLogTimes::iterator times = mTimes.begin();
                 while (times != mTimes.end()) {
-                    LogTimeEntry* entry = (*times);
+                    LogTimeEntry* entry = times->get();
                     // Killer punch
-                    if (entry->owned_Locked() && entry->isWatching(id)) {
+                    if (entry->isWatching(id)) {
                         entry->release_Locked();
                     }
                     times++;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2b6556d..13c7af3 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -41,6 +41,7 @@
     runOnEachSocket(&command);
 }
 
+// Note returning false will release the SocketClient instance.
 bool LogReader::onDataAvailable(SocketClient* cli) {
     static bool name_set;
     if (!name_set) {
@@ -57,6 +58,18 @@
     }
     buffer[len] = '\0';
 
+    // Clients are only allowed to send one command, disconnect them if they
+    // send another.
+    LogTimeEntry::wrlock();
+    for (const auto& entry : mLogbuf.mTimes) {
+        if (entry->mClient == cli) {
+            entry->release_Locked();
+            LogTimeEntry::unlock();
+            return false;
+        }
+    }
+    LogTimeEntry::unlock();
+
     unsigned long tail = 0;
     static const char _tail[] = " tail=";
     char* cp = strstr(buffer, _tail);
@@ -199,14 +212,25 @@
         cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
         logMask, (int)pid, sequence.nsec(), timeout);
 
-    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
+    LogTimeEntry::wrlock();
+    auto entry = std::make_unique<LogTimeEntry>(
+        *this, cli, nonBlock, tail, logMask, pid, sequence, timeout);
+    if (!entry->startReader_Locked()) {
+        LogTimeEntry::unlock();
+        return false;
+    }
+
+    // release client and entry reference counts once done
+    cli->incRef();
+    mLogbuf.mTimes.emplace_front(std::move(entry));
 
     // Set acceptable upper limit to wait for slow reader processing b/27242723
     struct timeval t = { LOGD_SNDTIMEO, 0 };
     setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
                sizeof(t));
 
-    command.runSocketCommand(cli);
+    LogTimeEntry::unlock();
+
     return true;
 }
 
@@ -215,9 +239,8 @@
     LogTimeEntry::wrlock();
     LastLogTimes::iterator it = times.begin();
     while (it != times.end()) {
-        LogTimeEntry* entry = (*it);
+        LogTimeEntry* entry = it->get();
         if (entry->mClient == cli) {
-            times.erase(it);
             entry->release_Locked();
             break;
         }
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 7a6f84b..1715501 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -30,11 +30,7 @@
 LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
                            bool nonBlock, unsigned long tail, log_mask_t logMask,
                            pid_t pid, log_time start, uint64_t timeout)
-    : mRefCount(1),
-      mRelease(false),
-      mError(false),
-      threadRunning(false),
-      leadingDropped(false),
+    : leadingDropped(false),
       mReader(reader),
       mLogMask(logMask),
       mPid(pid),
@@ -52,65 +48,21 @@
     cleanSkip_Locked();
 }
 
-void LogTimeEntry::startReader_Locked(void) {
+bool LogTimeEntry::startReader_Locked() {
     pthread_attr_t attr;
 
-    threadRunning = true;
-
     if (!pthread_attr_init(&attr)) {
         if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
             if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
                                 this)) {
                 pthread_attr_destroy(&attr);
-                return;
+                return true;
             }
         }
         pthread_attr_destroy(&attr);
     }
-    threadRunning = false;
-    if (mClient) {
-        mClient->decRef();
-    }
-    decRef_Locked();
-}
 
-void LogTimeEntry::threadStop(void* obj) {
-    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
-    wrlock();
-
-    if (me->mNonBlock) {
-        me->error_Locked();
-    }
-
-    SocketClient* client = me->mClient;
-
-    if (me->isError_Locked()) {
-        LogReader& reader = me->mReader;
-        LastLogTimes& times = reader.logbuf().mTimes;
-
-        LastLogTimes::iterator it = times.begin();
-        while (it != times.end()) {
-            if (*it == me) {
-                times.erase(it);
-                me->release_nodelete_Locked();
-                break;
-            }
-            it++;
-        }
-
-        me->mClient = nullptr;
-        reader.release(client);
-    }
-
-    if (client) {
-        client->decRef();
-    }
-
-    me->threadRunning = false;
-    me->decRef_Locked();
-
-    unlock();
+    return false;
 }
 
 void* LogTimeEntry::threadStart(void* obj) {
@@ -118,13 +70,7 @@
 
     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
 
-    pthread_cleanup_push(threadStop, obj);
-
     SocketClient* client = me->mClient;
-    if (!client) {
-        me->error();
-        return nullptr;
-    }
 
     LogBuffer& logbuf = me->mReader.logbuf();
 
@@ -137,14 +83,14 @@
 
     log_time start = me->mStart;
 
-    while (me->threadRunning && !me->isError_Locked()) {
+    while (!me->mRelease) {
         if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
             if (pthread_cond_timedwait(&me->threadTriggeredCondition,
                                        &timesLock, &me->mTimeout) == ETIMEDOUT) {
                 me->mTimeout.tv_sec = 0;
                 me->mTimeout.tv_nsec = 0;
             }
-            if (!me->threadRunning || me->isError_Locked()) {
+            if (me->mRelease) {
                 break;
             }
         }
@@ -162,13 +108,12 @@
         wrlock();
 
         if (start == LogBufferElement::FLUSH_ERROR) {
-            me->error_Locked();
             break;
         }
 
         me->mStart = start + log_time(0, 1);
 
-        if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
+        if (me->mNonBlock || me->mRelease) {
             break;
         }
 
@@ -179,9 +124,21 @@
         }
     }
 
-    unlock();
+    LogReader& reader = me->mReader;
+    reader.release(client);
 
-    pthread_cleanup_pop(true);
+    client->decRef();
+
+    LastLogTimes& times = reader.logbuf().mTimes;
+    auto it =
+        std::find_if(times.begin(), times.end(),
+                     [&me](const auto& other) { return other.get() == me; });
+
+    if (it != times.end()) {
+        times.erase(it);
+    }
+
+    unlock();
 
     return nullptr;
 }
@@ -247,10 +204,6 @@
         goto skip;
     }
 
-    if (me->isError_Locked()) {
-        goto stop;
-    }
-
     if (!me->mTail) {
         goto ok;
     }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 76d016c..f4e165f 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -22,6 +22,7 @@
 #include <time.h>
 
 #include <list>
+#include <memory>
 
 #include <log/log.h>
 #include <sysutils/SocketClient.h>
@@ -33,16 +34,12 @@
 
 class LogTimeEntry {
     static pthread_mutex_t timesLock;
-    unsigned int mRefCount;
-    bool mRelease;
-    bool mError;
-    bool threadRunning;
+    bool mRelease = false;
     bool leadingDropped;
     pthread_cond_t threadTriggeredCondition;
     pthread_t mThread;
     LogReader& mReader;
     static void* threadStart(void* me);
-    static void threadStop(void* me);
     const log_mask_t mLogMask;
     const pid_t mPid;
     unsigned int skipAhead[LOG_ID_MAX];
@@ -73,11 +70,8 @@
         pthread_mutex_unlock(&timesLock);
     }
 
-    void startReader_Locked(void);
+    bool startReader_Locked();
 
-    bool runningReader_Locked(void) const {
-        return threadRunning || mRelease || mError || mNonBlock;
-    }
     void triggerReader_Locked(void) {
         pthread_cond_signal(&threadTriggeredCondition);
     }
@@ -87,54 +81,11 @@
     }
     void cleanSkip_Locked(void);
 
-    // These called after LogTimeEntry removed from list, lock implicitly held
-    void release_nodelete_Locked(void) {
-        mRelease = true;
-        pthread_cond_signal(&threadTriggeredCondition);
-        // assumes caller code path will call decRef_Locked()
-    }
-
     void release_Locked(void) {
         mRelease = true;
         pthread_cond_signal(&threadTriggeredCondition);
-        if (mRefCount || threadRunning) {
-            return;
-        }
-        // No one else is holding a reference to this
-        delete this;
     }
 
-    // Called to mark socket in jeopardy
-    void error_Locked(void) {
-        mError = true;
-    }
-    void error(void) {
-        wrlock();
-        error_Locked();
-        unlock();
-    }
-
-    bool isError_Locked(void) const {
-        return mRelease || mError;
-    }
-
-    // Mark Used
-    //  Locking implied, grabbed when protection around loop iteration
-    void incRef_Locked(void) {
-        ++mRefCount;
-    }
-
-    bool owned_Locked(void) const {
-        return mRefCount != 0;
-    }
-
-    void decRef_Locked(void) {
-        if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
-            return;
-        }
-        // No one else is holding a reference to this
-        delete this;
-    }
     bool isWatching(log_id_t id) const {
         return mLogMask & (1 << id);
     }
@@ -146,6 +97,6 @@
     static int FilterSecondPass(const LogBufferElement* element, void* me);
 };
 
-typedef std::list<LogTimeEntry*> LastLogTimes;
+typedef std::list<std::unique_ptr<LogTimeEntry>> LastLogTimes;
 
 #endif  // _LOGD_LOG_TIMES_H__
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index a4c3955..e4e1650 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -67,6 +67,13 @@
   LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
 endif
 
+EXPORT_GLOBAL_HWASAN_OPTIONS :=
+ifneq ($(filter hwaddress,$(SANITIZE_TARGET)),)
+  ifneq ($(HWADDRESS_SANITIZER_GLOBAL_OPTIONS),)
+    EXPORT_GLOBAL_HWASAN_OPTIONS := export HWASAN_OPTIONS $(HWADDRESS_SANITIZER_GLOBAL_OPTIONS)
+  endif
+endif
+
 EXPORT_GLOBAL_GCOV_OPTIONS :=
 ifeq ($(NATIVE_COVERAGE),true)
   EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
@@ -151,6 +158,7 @@
 	$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
 	$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
 	$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
+	$(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
 
 bcp_md5 :=
 bcp_dep :=
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
index 6029ae7..ca22eb8 100644
--- a/rootdir/OWNERS
+++ b/rootdir/OWNERS
@@ -1,3 +1,4 @@
+ccross@google.com
 jeffv@google.com
 jiyong@google.com
 smoreland@google.com
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 2e2ab74..4576776 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -11,3 +11,4 @@
     export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
     %EXPORT_GLOBAL_ASAN_OPTIONS%
     %EXPORT_GLOBAL_GCOV_OPTIONS%
+    %EXPORT_GLOBAL_HWASAN_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6a6a8f9..21d234f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -336,6 +336,8 @@
     start servicemanager
     start hwservicemanager
     start vndservicemanager
+    start vold
+    exec - system system -- /system/bin/vdc checkpoint markBootAttempt
 
     # Once everything is setup, no need to modify /.
     # The bind+remount combination allows this to work in containers.
@@ -398,6 +400,10 @@
     class_start early_hal
 
 on post-fs-data
+    # Start checkpoint before we touch data
+    start vold
+    exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
+
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
     chmod 0771 /data
@@ -405,8 +411,6 @@
     restorecon /data
 
     # Make sure we have the device encryption key.
-    start vold
-    exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
     installkey /data
 
     # Start bootcharting as soon as possible after the data partition is