Merge "snapshotctl: send snapshot merge report metrics"
diff --git a/adb/Android.bp b/adb/Android.bp
index c71138a..32581a2 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -341,6 +341,8 @@
         "client/line_printer.cpp",
         "client/fastdeploy.cpp",
         "client/fastdeploycallbacks.cpp",
+        "client/incremental.cpp",
+        "client/incremental_server.cpp",
         "shell_service_protocol.cpp",
     ],
 
@@ -360,6 +362,7 @@
         "libfastdeploy_host",
         "libdiagnose_usb",
         "liblog",
+        "liblz4",
         "libmdnssd",
         "libprotobuf-cpp-lite",
         "libusb",
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 80f146c..cea24fe 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -118,22 +118,22 @@
         return;
     }
 
-    std::unordered_map<std::string, int> trace_flags = {
-        {"1", -1},
-        {"all", -1},
-        {"adb", ADB},
-        {"sockets", SOCKETS},
-        {"packets", PACKETS},
-        {"rwx", RWX},
-        {"usb", USB},
-        {"sync", SYNC},
-        {"sysdeps", SYSDEPS},
-        {"transport", TRANSPORT},
-        {"jdwp", JDWP},
-        {"services", SERVICES},
-        {"auth", AUTH},
-        {"fdevent", FDEVENT},
-        {"shell", SHELL}};
+    std::unordered_map<std::string, int> trace_flags = {{"1", -1},
+                                                        {"all", -1},
+                                                        {"adb", ADB},
+                                                        {"sockets", SOCKETS},
+                                                        {"packets", PACKETS},
+                                                        {"rwx", RWX},
+                                                        {"usb", USB},
+                                                        {"sync", SYNC},
+                                                        {"sysdeps", SYSDEPS},
+                                                        {"transport", TRANSPORT},
+                                                        {"jdwp", JDWP},
+                                                        {"services", SERVICES},
+                                                        {"auth", AUTH},
+                                                        {"fdevent", FDEVENT},
+                                                        {"shell", SHELL},
+                                                        {"incremental", INCREMENTAL}};
 
     std::vector<std::string> elements = android::base::Split(trace_setting, " ");
     for (const auto& elem : elements) {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 1d2c8c7..ed4be88 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -25,19 +25,20 @@
  * the adb_trace_init() function implemented in adb_trace.cpp.
  */
 enum AdbTrace {
-    ADB = 0,   /* 0x001 */
+    ADB = 0, /* 0x001 */
     SOCKETS,
     PACKETS,
     TRANSPORT,
-    RWX,       /* 0x010 */
+    RWX, /* 0x010 */
     USB,
     SYNC,
     SYSDEPS,
-    JDWP,      /* 0x100 */
+    JDWP, /* 0x100 */
     SERVICES,
     AUTH,
     FDEVENT,
-    SHELL
+    SHELL,
+    INCREMENTAL,
 };
 
 #define VLOG_IS_ON(TAG) \
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 2bcd0a6..982a96b 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -36,8 +36,10 @@
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
+#include "incremental.h"
 
 static constexpr int kFastDeployMinApi = 24;
+static constexpr int kIncrementalMinApi = 29;
 
 namespace {
 
@@ -45,8 +47,8 @@
     INSTALL_DEFAULT,
     INSTALL_PUSH,
     INSTALL_STREAM,
+    INSTALL_INCREMENTAL,
 };
-
 }
 
 static bool can_use_feature(const char* feature) {
@@ -70,6 +72,10 @@
     return can_use_feature(kFeatureApex);
 }
 
+static bool is_abb_exec_supported() {
+    return can_use_feature(kFeatureAbbExec);
+}
+
 static int pm_command(int argc, const char** argv) {
     std::string cmd = "pm";
 
@@ -193,14 +199,14 @@
     posix_fadvise(local_fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
 #endif
 
-    const bool use_abb = can_use_feature(kFeatureAbbExec);
+    const bool use_abb_exec = is_abb_exec_supported();
     std::string error;
-    std::vector<std::string> cmd_args = {use_abb ? "package" : "exec:cmd package"};
+    std::vector<std::string> cmd_args = {use_abb_exec ? "package" : "exec:cmd package"};
     cmd_args.reserve(argc + 3);
 
     // don't copy the APK name, but, copy the rest of the arguments as-is
     while (argc-- > 1) {
-        if (use_abb) {
+        if (use_abb_exec) {
             cmd_args.push_back(*argv++);
         } else {
             cmd_args.push_back(escape_arg(*argv++));
@@ -217,7 +223,7 @@
     }
 
     unique_fd remote_fd;
-    if (use_abb) {
+    if (use_abb_exec) {
         remote_fd = send_abb_exec_command(cmd_args, &error);
     } else {
         remote_fd.reset(adb_connect(android::base::Join(cmd_args, " "), &error));
@@ -287,8 +293,60 @@
     return result;
 }
 
+template <class TimePoint>
+static int msBetween(TimePoint start, TimePoint end) {
+    return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+}
+
+static int install_app_incremental(int argc, const char** argv) {
+    printf("Performing Incremental Install\n");
+    using clock = std::chrono::high_resolution_clock;
+    const auto start = clock::now();
+    int first_apk = -1;
+    int last_apk = -1;
+    std::string cert_path;
+    bool wait = false;
+    std::vector<std::string_view> args = {"package"};
+    for (int i = 0; i < argc; ++i) {
+        const auto arg = std::string_view(argv[i]);
+        if (android::base::EndsWithIgnoreCase(arg, ".apk")) {
+            last_apk = i;
+            if (first_apk == -1) {
+                first_apk = i;
+            }
+        } else if (arg == "--wait") {
+            wait = true;
+        } else if (arg.starts_with("install-")) {
+            // incremental installation command on the device is the same for all its variations in
+            // the adb, e.g. install-multiple or install-multi-package
+            args.push_back("install");
+        } else {
+            args.push_back(arg);
+        }
+    }
+
+    if (first_apk == -1) error_exit("Need at least one APK file on command line");
+
+    const auto afterApk = clock::now();
+
+    auto server_process = incremental::install({argv + first_apk, argv + last_apk + 1});
+    if (!server_process) {
+        return -1;
+    }
+
+    const auto end = clock::now();
+    printf("Install command complete (ms: %d total, %d apk prep, %d install)\n",
+           msBetween(start, end), msBetween(start, afterApk), msBetween(afterApk, end));
+
+    if (wait) {
+        (*server_process).wait();
+    }
+
+    return 0;
+}
+
 int install_app(int argc, const char** argv) {
-    std::vector<int> processedArgIndicies;
+    std::vector<int> processedArgIndices;
     InstallMode installMode = INSTALL_DEFAULT;
     bool use_fastdeploy = false;
     bool is_reinstall = false;
@@ -296,30 +354,42 @@
 
     for (int i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "--streaming")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             installMode = INSTALL_STREAM;
         } else if (!strcmp(argv[i], "--no-streaming")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             installMode = INSTALL_PUSH;
         } else if (!strcmp(argv[i], "-r")) {
-            // Note that this argument is not added to processedArgIndicies because it
+            // Note that this argument is not added to processedArgIndices because it
             // must be passed through to pm
             is_reinstall = true;
         } else if (!strcmp(argv[i], "--fastdeploy")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             use_fastdeploy = true;
         } else if (!strcmp(argv[i], "--no-fastdeploy")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             use_fastdeploy = false;
         } else if (!strcmp(argv[i], "--force-agent")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             agent_update_strategy = FastDeploy_AgentUpdateAlways;
         } else if (!strcmp(argv[i], "--date-check-agent")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
         } else if (!strcmp(argv[i], "--version-check-agent")) {
-            processedArgIndicies.push_back(i);
+            processedArgIndices.push_back(i);
             agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+        } else if (!strcmp(argv[i], "--incremental")) {
+            processedArgIndices.push_back(i);
+            installMode = INSTALL_INCREMENTAL;
+        } else if (!strcmp(argv[i], "--no-incremental")) {
+            processedArgIndices.push_back(i);
+            installMode = INSTALL_DEFAULT;
+        }
+    }
+
+    if (installMode == INSTALL_INCREMENTAL) {
+        if (get_device_api_level() < kIncrementalMinApi || !is_abb_exec_supported()) {
+            error_exit("Attempting to use incremental install on unsupported device");
         }
     }
 
@@ -341,8 +411,8 @@
 
     std::vector<const char*> passthrough_argv;
     for (int i = 0; i < argc; i++) {
-        if (std::find(processedArgIndicies.begin(), processedArgIndicies.end(), i) ==
-            processedArgIndicies.end()) {
+        if (std::find(processedArgIndices.begin(), processedArgIndices.end(), i) ==
+            processedArgIndices.end()) {
             passthrough_argv.push_back(argv[i]);
         }
     }
@@ -357,6 +427,8 @@
         case INSTALL_STREAM:
             return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
                                         use_fastdeploy);
+        case INSTALL_INCREMENTAL:
+            return install_app_incremental(passthrough_argv.size(), passthrough_argv.data());
         case INSTALL_DEFAULT:
         default:
             return 1;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index c302965..84c0e01 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -60,6 +60,7 @@
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
+#include "incremental_server.h"
 #include "services.h"
 #include "shell_protocol.h"
 #include "sysdeps/chrono.h"
@@ -1959,6 +1960,18 @@
                 error_exit("usage: adb reconnect [device|offline]");
             }
         }
+    } else if (!strcmp(argv[0], "inc-server")) {
+        if (argc < 3) {
+            error_exit("usage: adb inc-server FD FILE1 FILE2 ...");
+        }
+        int fd = atoi(argv[1]);
+        if (fd < 3) {
+            // Disallow invalid FDs and stdin/out/err as well.
+            error_exit("Invalid fd number given: %d", fd);
+        }
+        fd = adb_register_socket(fd);
+        close_on_exec(fd);
+        return incremental::serve(fd, argc - 2, argv + 2);
     }
 
     error_exit("unknown command %s", argv[0]);
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index 5fa0edb..c5fc12f 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -81,17 +81,21 @@
 }  // namespace
 
 int get_device_api_level() {
-    REPORT_FUNC_TIME();
-    std::vector<char> sdk_version_output_buffer;
-    std::vector<char> sdk_version_error_buffer;
-    int api_level = -1;
+    static const int api_level = [] {
+        REPORT_FUNC_TIME();
+        std::vector<char> sdk_version_output_buffer;
+        std::vector<char> sdk_version_error_buffer;
+        int api_level = -1;
 
-    int statusCode = capture_shell_command("getprop ro.build.version.sdk",
-                                           &sdk_version_output_buffer, &sdk_version_error_buffer);
-    if (statusCode == 0 && sdk_version_output_buffer.size() > 0) {
-        api_level = strtol((char*)sdk_version_output_buffer.data(), NULL, 10);
-    }
+        int status_code =
+                capture_shell_command("getprop ro.build.version.sdk", &sdk_version_output_buffer,
+                                      &sdk_version_error_buffer);
+        if (status_code == 0 && sdk_version_output_buffer.size() > 0) {
+            api_level = strtol((char*)sdk_version_output_buffer.data(), nullptr, 10);
+        }
 
+        return api_level;
+    }();
     return api_level;
 }
 
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
new file mode 100644
index 0000000..cffd4bd
--- /dev/null
+++ b/adb/client/incremental.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "incremental.h"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <openssl/base64.h>
+
+#include "adb_client.h"
+#include "adb_io.h"
+#include "adb_utils.h"
+#include "commandline.h"
+#include "sysdeps.h"
+
+#ifndef _WIN32
+#include <endian.h>
+#else
+#define be32toh(x) _byteswap_ulong(x)
+#endif
+
+using namespace std::literals;
+
+namespace incremental {
+
+namespace {
+
+static constexpr auto IDSIG = ".idsig"sv;
+
+using android::base::StringPrintf;
+
+using Size = int64_t;
+
+static inline int32_t read_int32(borrowed_fd fd) {
+    int32_t result;
+    ReadFully(fd, &result, sizeof(result));
+    return result;
+}
+
+static inline int32_t read_be_int32(borrowed_fd fd) {
+    return int32_t(be32toh(read_int32(fd)));
+}
+
+static inline void append_bytes_with_size(borrowed_fd fd, std::vector<char>* bytes) {
+    int32_t be_size = read_int32(fd);
+    int32_t size = int32_t(be32toh(be_size));
+    auto old_size = bytes->size();
+    bytes->resize(old_size + sizeof(be_size) + size);
+    memcpy(bytes->data() + old_size, &be_size, sizeof(be_size));
+    ReadFully(fd, bytes->data() + old_size + sizeof(be_size), size);
+}
+
+static inline std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
+    std::vector<char> result;
+    append_bytes_with_size(fd, &result);  // verityRootHash
+    append_bytes_with_size(fd, &result);  // v3Digest
+    append_bytes_with_size(fd, &result);  // pkcs7SignatureBlock
+    auto tree_size = read_be_int32(fd);   // size of the verity tree
+    return {std::move(result), tree_size};
+}
+
+static inline Size verity_tree_size_for_file(Size fileSize) {
+    constexpr int INCFS_DATA_FILE_BLOCK_SIZE = 4096;
+    constexpr int SHA256_DIGEST_SIZE = 32;
+    constexpr int digest_size = SHA256_DIGEST_SIZE;
+    constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
+
+    Size total_tree_block_count = 0;
+
+    auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
+    auto hash_block_count = block_count;
+    for (auto i = 0; hash_block_count > 1; i++) {
+        hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
+        total_tree_block_count += hash_block_count;
+    }
+    return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
+}
+
+// Base64-encode signature bytes. Keeping fd at the position of start of verity tree.
+static std::pair<unique_fd, std::string> read_and_encode_signature(Size file_size,
+                                                                   std::string signature_file) {
+    signature_file += IDSIG;
+
+    struct stat st;
+    if (stat(signature_file.c_str(), &st)) {
+        fprintf(stderr, "Failed to stat signature file %s. Abort.\n", signature_file.c_str());
+        return {};
+    }
+
+    unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) {
+        fprintf(stderr, "Failed to open signature file: %s. Abort.\n", signature_file.c_str());
+        return {};
+    }
+
+    auto [signature, tree_size] = read_id_sig_headers(fd);
+    if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) {
+        fprintf(stderr,
+                "Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n",
+                signature_file.c_str(), (long long)tree_size, (long long)expected);
+        return {};
+    }
+
+    size_t base64_len = 0;
+    if (!EVP_EncodedLength(&base64_len, signature.size())) {
+        fprintf(stderr, "Fail to estimate base64 encoded length. Abort.\n");
+        return {};
+    }
+    std::string encoded_signature;
+    encoded_signature.resize(base64_len);
+    encoded_signature.resize(EVP_EncodeBlock((uint8_t*)encoded_signature.data(),
+                                             (const uint8_t*)signature.data(), signature.size()));
+
+    return {std::move(fd), std::move(encoded_signature)};
+}
+
+// Send install-incremental to the device along with properly configured file descriptors in
+// streaming format. Once connection established, send all fs-verity tree bytes.
+static unique_fd start_install(const std::vector<std::string>& files) {
+    std::vector<std::string> command_args{"package", "install-incremental"};
+
+    // fd's with positions at the beginning of fs-verity
+    std::vector<unique_fd> signature_fds;
+    signature_fds.reserve(files.size());
+    for (int i = 0, size = files.size(); i < size; ++i) {
+        const auto& file = files[i];
+
+        struct stat st;
+        if (stat(file.c_str(), &st)) {
+            fprintf(stderr, "Failed to stat input file %s. Abort.\n", file.c_str());
+            return {};
+        }
+
+        auto [signature_fd, signature] = read_and_encode_signature(st.st_size, file);
+        if (!signature_fd.ok()) {
+            return {};
+        }
+
+        auto file_desc =
+                StringPrintf("%s:%lld:%s:%s", android::base::Basename(file).c_str(),
+                             (long long)st.st_size, std::to_string(i).c_str(), signature.c_str());
+        command_args.push_back(std::move(file_desc));
+
+        signature_fds.push_back(std::move(signature_fd));
+    }
+
+    std::string error;
+    auto connection_fd = unique_fd(send_abb_exec_command(command_args, &error));
+    if (connection_fd < 0) {
+        fprintf(stderr, "Failed to run: %s, error: %s\n",
+                android::base::Join(command_args, " ").c_str(), error.c_str());
+        return {};
+    }
+
+    // Pushing verity trees for all installation files.
+    for (auto&& local_fd : signature_fds) {
+        if (!copy_to_file(local_fd.get(), connection_fd.get())) {
+            fprintf(stderr, "Failed to stream tree bytes: %s. Abort.\n", strerror(errno));
+            return {};
+        }
+    }
+
+    return connection_fd;
+}
+
+}  // namespace
+
+std::optional<Process> install(std::vector<std::string> files) {
+    auto connection_fd = start_install(files);
+    if (connection_fd < 0) {
+        fprintf(stderr, "adb: failed to initiate installation on device.\n");
+        return {};
+    }
+
+    std::string adb_path = android::base::GetExecutablePath();
+
+    auto osh = adb_get_os_handle(connection_fd.get());
+#ifdef _WIN32
+    auto fd_param = std::to_string(reinterpret_cast<intptr_t>(osh));
+#else /* !_WIN32 a.k.a. Unix */
+    auto fd_param = std::to_string(osh);
+#endif
+
+    std::vector<std::string> args(std::move(files));
+    args.insert(args.begin(), {"inc-server", fd_param});
+    auto child = adb_launch_process(adb_path, std::move(args), {connection_fd.get()});
+    if (!child) {
+        fprintf(stderr, "adb: failed to fork: %s\n", strerror(errno));
+        return {};
+    }
+
+    auto killOnExit = [](Process* p) { p->kill(); };
+    std::unique_ptr<Process, decltype(killOnExit)> serverKiller(&child, killOnExit);
+    // TODO: Terminate server process if installation fails.
+    serverKiller.release();
+
+    return child;
+}
+
+}  // namespace incremental
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
new file mode 100644
index 0000000..4b9f6bd
--- /dev/null
+++ b/adb/client/incremental.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "adb_unique_fd.h"
+
+#include <optional>
+#include <string>
+
+#include "sysdeps.h"
+
+namespace incremental {
+
+std::optional<Process> install(std::vector<std::string> files);
+
+}  // namespace incremental
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
new file mode 100644
index 0000000..d9fd77a
--- /dev/null
+++ b/adb/client/incremental_server.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG INCREMENTAL
+
+#include "incremental_server.h"
+
+#include "adb.h"
+#include "adb_io.h"
+#include "adb_trace.h"
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+
+#ifndef _WIN32
+#include <endian.h>
+#else
+#define be64toh(x) _byteswap_uint64(x)
+#define be32toh(x) _byteswap_ulong(x)
+#define be16toh(x) _byteswap_ushort(x)
+#define htobe64(x) _byteswap_uint64(x)
+#define htobe32(x) _byteswap_ulong(x)
+#define htobe16(x) _byteswap_ushort(x)
+#endif
+
+#include <android-base/strings.h>
+#include <lz4.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <array>
+#include <deque>
+#include <fstream>
+#include <thread>
+#include <type_traits>
+#include <unordered_set>
+
+namespace incremental {
+
+static constexpr int kBlockSize = 4096;
+static constexpr int kCompressedSizeMax = kBlockSize * 0.95;
+static constexpr short kCompressionNone = 0;
+static constexpr short kCompressionLZ4 = 1;
+static constexpr int kCompressBound = std::max(kBlockSize, LZ4_COMPRESSBOUND(kBlockSize));
+static constexpr auto kReadBufferSize = 128 * 1024;
+
+using BlockSize = int16_t;
+using FileId = int16_t;
+using BlockIdx = int32_t;
+using NumBlocks = int32_t;
+using CompressionType = int16_t;
+using RequestType = int16_t;
+using ChunkHeader = int32_t;
+using MagicType = uint32_t;
+
+static constexpr MagicType INCR = 0x494e4352;  // LE INCR
+
+static constexpr RequestType EXIT = 0;
+static constexpr RequestType BLOCK_MISSING = 1;
+static constexpr RequestType PREFETCH = 2;
+
+static constexpr inline int64_t roundDownToBlockOffset(int64_t val) {
+    return val & ~(kBlockSize - 1);
+}
+
+static constexpr inline int64_t roundUpToBlockOffset(int64_t val) {
+    return roundDownToBlockOffset(val + kBlockSize - 1);
+}
+
+static constexpr inline NumBlocks numBytesToNumBlocks(int64_t bytes) {
+    return roundUpToBlockOffset(bytes) / kBlockSize;
+}
+
+static constexpr inline off64_t blockIndexToOffset(BlockIdx blockIdx) {
+    return static_cast<off64_t>(blockIdx) * kBlockSize;
+}
+
+template <typename T>
+static inline constexpr T toBigEndian(T t) {
+    using unsigned_type = std::make_unsigned_t<T>;
+    if constexpr (std::is_same_v<T, int16_t>) {
+        return htobe16(static_cast<unsigned_type>(t));
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        return htobe32(static_cast<unsigned_type>(t));
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        return htobe64(static_cast<unsigned_type>(t));
+    } else {
+        return t;
+    }
+}
+
+template <typename T>
+static inline constexpr T readBigEndian(void* data) {
+    using unsigned_type = std::make_unsigned_t<T>;
+    if constexpr (std::is_same_v<T, int16_t>) {
+        return static_cast<T>(be16toh(*reinterpret_cast<unsigned_type*>(data)));
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        return static_cast<T>(be32toh(*reinterpret_cast<unsigned_type*>(data)));
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        return static_cast<T>(be64toh(*reinterpret_cast<unsigned_type*>(data)));
+    } else {
+        return T();
+    }
+}
+
+// Received from device
+// !Does not include magic!
+struct RequestCommand {
+    RequestType request_type;  // 2 bytes
+    FileId file_id;            // 2 bytes
+    union {
+        BlockIdx block_idx;
+        NumBlocks num_blocks;
+    };  // 4 bytes
+} __attribute__((packed));
+
+// Placed before actual data bytes of each block
+struct ResponseHeader {
+    FileId file_id;                    // 2 bytes
+    CompressionType compression_type;  // 2 bytes
+    BlockIdx block_idx;                // 4 bytes
+    BlockSize block_size;              // 2 bytes
+} __attribute__((packed));
+
+// Holds streaming state for a file
+class File {
+  public:
+    // Plain file
+    File(const char* filepath, FileId id, int64_t size, unique_fd fd) : File(filepath, id, size) {
+        this->fd_ = std::move(fd);
+    }
+    int64_t ReadBlock(BlockIdx block_idx, void* buf, bool* is_zip_compressed,
+                      std::string* error) const {
+        char* buf_ptr = static_cast<char*>(buf);
+        int64_t bytes_read = -1;
+        const off64_t offsetStart = blockIndexToOffset(block_idx);
+        bytes_read = adb_pread(fd_, &buf_ptr[sizeof(ResponseHeader)], kBlockSize, offsetStart);
+        return bytes_read;
+    }
+
+    const unique_fd& RawFd() const { return fd_; }
+
+    std::vector<bool> sentBlocks;
+    NumBlocks sentBlocksCount;
+
+    const char* const filepath;
+    const FileId id;
+    const int64_t size;
+
+  private:
+    File(const char* filepath, FileId id, int64_t size) : filepath(filepath), id(id), size(size) {
+        sentBlocks.resize(numBytesToNumBlocks(size));
+    }
+    unique_fd fd_;
+};
+
+class IncrementalServer {
+  public:
+    IncrementalServer(unique_fd fd, std::vector<File> files)
+        : adb_fd_(std::move(fd)), files_(std::move(files)) {
+        buffer_.reserve(kReadBufferSize);
+    }
+
+    bool Serve();
+
+  private:
+    struct PrefetchState {
+        const File* file;
+        BlockIdx overallIndex = 0;
+        BlockIdx overallEnd = 0;
+
+        PrefetchState(const File& f) : file(&f), overallEnd((BlockIdx)f.sentBlocks.size()) {}
+        PrefetchState(const File& f, BlockIdx start, int count)
+            : file(&f),
+              overallIndex(start),
+              overallEnd(std::min<BlockIdx>(start + count, f.sentBlocks.size())) {}
+
+        bool done() const { return overallIndex >= overallEnd; }
+    };
+
+    bool SkipToRequest(void* buffer, size_t* size, bool blocking);
+    std::optional<RequestCommand> ReadRequest(bool blocking);
+
+    void erase_buffer_head(int count) { buffer_.erase(buffer_.begin(), buffer_.begin() + count); }
+
+    enum class SendResult { Sent, Skipped, Error };
+    SendResult SendBlock(FileId fileId, BlockIdx blockIdx, bool flush = false);
+    bool SendDone();
+    void RunPrefetching();
+
+    void Send(const void* data, size_t size, bool flush);
+    void Flush();
+    using TimePoint = decltype(std::chrono::high_resolution_clock::now());
+    bool Exit(std::optional<TimePoint> startTime, int missesCount, int missesSent);
+
+    unique_fd const adb_fd_;
+    std::vector<File> files_;
+
+    // Incoming data buffer.
+    std::vector<char> buffer_;
+
+    std::deque<PrefetchState> prefetches_;
+    int compressed_ = 0, uncompressed_ = 0;
+    long long sentSize_ = 0;
+
+    std::vector<char> pendingBlocks_;
+};
+
+bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) {
+    while (true) {
+        // Looking for INCR magic.
+        bool magic_found = false;
+        int bcur = 0;
+        for (int bsize = buffer_.size(); bcur + 4 < bsize; ++bcur) {
+            uint32_t magic = be32toh(*(uint32_t*)(buffer_.data() + bcur));
+            if (magic == INCR) {
+                magic_found = true;
+                break;
+            }
+        }
+
+        if (bcur > 0) {
+            // Stream the rest to stderr.
+            fprintf(stderr, "%.*s", bcur, buffer_.data());
+            erase_buffer_head(bcur);
+        }
+
+        if (magic_found && buffer_.size() >= *size + sizeof(INCR)) {
+            // fine, return
+            memcpy(buffer, buffer_.data() + sizeof(INCR), *size);
+            erase_buffer_head(*size + sizeof(INCR));
+            return true;
+        }
+
+        adb_pollfd pfd = {adb_fd_.get(), POLLIN, 0};
+        auto res = adb_poll(&pfd, 1, blocking ? -1 : 0);
+        if (res != 1) {
+            if (res < 0) {
+                fprintf(stderr, "Failed to poll: %s\n", strerror(errno));
+                return false;
+            }
+            *size = 0;
+            return true;
+        }
+
+        auto bsize = buffer_.size();
+        buffer_.resize(kReadBufferSize);
+        int r = adb_read(adb_fd_, buffer_.data() + bsize, kReadBufferSize - bsize);
+        if (r > 0) {
+            buffer_.resize(bsize + r);
+            continue;
+        }
+
+        if (r == -1) {
+            fprintf(stderr, "Failed to read from fd %d: %d. Exit\n", adb_fd_.get(), errno);
+            return true;
+        }
+
+        // socket is closed
+        return false;
+    }
+}
+
+std::optional<RequestCommand> IncrementalServer::ReadRequest(bool blocking) {
+    uint8_t commandBuf[sizeof(RequestCommand)];
+    auto size = sizeof(commandBuf);
+    if (!SkipToRequest(&commandBuf, &size, blocking)) {
+        return {{EXIT}};
+    }
+    if (size < sizeof(RequestCommand)) {
+        return {};
+    }
+    RequestCommand request;
+    request.request_type = readBigEndian<RequestType>(&commandBuf[0]);
+    request.file_id = readBigEndian<FileId>(&commandBuf[2]);
+    request.block_idx = readBigEndian<BlockIdx>(&commandBuf[4]);
+    return request;
+}
+
+auto IncrementalServer::SendBlock(FileId fileId, BlockIdx blockIdx, bool flush) -> SendResult {
+    auto& file = files_[fileId];
+    if (blockIdx >= static_cast<long>(file.sentBlocks.size())) {
+        fprintf(stderr, "Failed to read file %s at block %" PRId32 " (past end).\n", file.filepath,
+                blockIdx);
+        return SendResult::Error;
+    }
+    if (file.sentBlocks[blockIdx]) {
+        return SendResult::Skipped;
+    }
+    std::string error;
+    char raw[sizeof(ResponseHeader) + kBlockSize];
+    bool isZipCompressed = false;
+    const int64_t bytesRead = file.ReadBlock(blockIdx, &raw, &isZipCompressed, &error);
+    if (bytesRead < 0) {
+        fprintf(stderr, "Failed to get data for %s at blockIdx=%d (%s).\n", file.filepath, blockIdx,
+                error.c_str());
+        return SendResult::Error;
+    }
+
+    ResponseHeader* header = nullptr;
+    char data[sizeof(ResponseHeader) + kCompressBound];
+    char* compressed = data + sizeof(*header);
+    int16_t compressedSize = 0;
+    if (!isZipCompressed) {
+        compressedSize =
+                LZ4_compress_default(raw + sizeof(*header), compressed, bytesRead, kCompressBound);
+    }
+    int16_t blockSize;
+    if (compressedSize > 0 && compressedSize < kCompressedSizeMax) {
+        ++compressed_;
+        blockSize = compressedSize;
+        header = reinterpret_cast<ResponseHeader*>(data);
+        header->compression_type = toBigEndian(kCompressionLZ4);
+    } else {
+        ++uncompressed_;
+        blockSize = bytesRead;
+        header = reinterpret_cast<ResponseHeader*>(raw);
+        header->compression_type = toBigEndian(kCompressionNone);
+    }
+
+    header->file_id = toBigEndian(fileId);
+    header->block_size = toBigEndian(blockSize);
+    header->block_idx = toBigEndian(blockIdx);
+
+    file.sentBlocks[blockIdx] = true;
+    file.sentBlocksCount += 1;
+    Send(header, sizeof(*header) + blockSize, flush);
+    return SendResult::Sent;
+}
+
+bool IncrementalServer::SendDone() {
+    ResponseHeader header;
+    header.file_id = -1;
+    header.compression_type = 0;
+    header.block_idx = 0;
+    header.block_size = 0;
+    Send(&header, sizeof(header), true);
+    return true;
+}
+
+void IncrementalServer::RunPrefetching() {
+    constexpr auto kPrefetchBlocksPerIteration = 128;
+
+    int blocksToSend = kPrefetchBlocksPerIteration;
+    while (!prefetches_.empty() && blocksToSend > 0) {
+        auto& prefetch = prefetches_.front();
+        const auto& file = *prefetch.file;
+        for (auto& i = prefetch.overallIndex; blocksToSend > 0 && i < prefetch.overallEnd; ++i) {
+            if (auto res = SendBlock(file.id, i); res == SendResult::Sent) {
+                --blocksToSend;
+            } else if (res == SendResult::Error) {
+                fprintf(stderr, "Failed to send block %" PRId32 "\n", i);
+            }
+        }
+        if (prefetch.done()) {
+            prefetches_.pop_front();
+        }
+    }
+}
+
+void IncrementalServer::Send(const void* data, size_t size, bool flush) {
+    constexpr auto kChunkFlushSize = 31 * kBlockSize;
+
+    if (pendingBlocks_.empty()) {
+        pendingBlocks_.resize(sizeof(ChunkHeader));
+    }
+    pendingBlocks_.insert(pendingBlocks_.end(), static_cast<const char*>(data),
+                          static_cast<const char*>(data) + size);
+    if (flush || pendingBlocks_.size() > kChunkFlushSize) {
+        Flush();
+    }
+}
+
+void IncrementalServer::Flush() {
+    if (pendingBlocks_.empty()) {
+        return;
+    }
+
+    *(ChunkHeader*)pendingBlocks_.data() =
+            toBigEndian<int32_t>(pendingBlocks_.size() - sizeof(ChunkHeader));
+    if (!WriteFdExactly(adb_fd_, pendingBlocks_.data(), pendingBlocks_.size())) {
+        fprintf(stderr, "Failed to write %d bytes\n", int(pendingBlocks_.size()));
+    }
+    sentSize_ += pendingBlocks_.size();
+    pendingBlocks_.clear();
+}
+
+bool IncrementalServer::Exit(std::optional<TimePoint> startTime, int missesCount, int missesSent) {
+    using namespace std::chrono;
+    auto endTime = high_resolution_clock::now();
+    fprintf(stderr,
+            "Connection failed or received exit command. Exit.\n"
+            "Misses: %d, of those unique: %d; sent compressed: %d, uncompressed: "
+            "%d, mb: %.3f\n"
+            "Total time taken: %.3fms\n",
+            missesCount, missesSent, compressed_, uncompressed_, sentSize_ / 1024.0 / 1024.0,
+            duration_cast<microseconds>(endTime - (startTime ? *startTime : endTime)).count() /
+                    1000.0);
+    return true;
+}
+
+bool IncrementalServer::Serve() {
+    // Initial handshake to verify connection is still alive
+    if (!SendOkay(adb_fd_)) {
+        fprintf(stderr, "Connection is dead. Abort.\n");
+        return false;
+    }
+
+    std::unordered_set<FileId> prefetchedFiles;
+    bool doneSent = false;
+    int missesCount = 0;
+    int missesSent = 0;
+
+    using namespace std::chrono;
+    std::optional<TimePoint> startTime;
+
+    while (true) {
+        if (!doneSent && prefetches_.empty() &&
+            std::all_of(files_.begin(), files_.end(), [](const File& f) {
+                return f.sentBlocksCount == NumBlocks(f.sentBlocks.size());
+            })) {
+            fprintf(stdout, "All files should be loaded. Notifying the device.\n");
+            SendDone();
+            doneSent = true;
+        }
+
+        const bool blocking = prefetches_.empty();
+        if (blocking) {
+            // We've no idea how long the blocking call is, so let's flush whatever is still unsent.
+            Flush();
+        }
+        auto request = ReadRequest(blocking);
+
+        if (!startTime) {
+            startTime = high_resolution_clock::now();
+        }
+
+        if (request) {
+            FileId fileId = request->file_id;
+            BlockIdx blockIdx = request->block_idx;
+
+            switch (request->request_type) {
+                case EXIT: {
+                    // Stop everything.
+                    return Exit(startTime, missesCount, missesSent);
+                }
+                case BLOCK_MISSING: {
+                    ++missesCount;
+                    // Sends one single block ASAP.
+                    if (fileId < 0 || fileId >= (FileId)files_.size() || blockIdx < 0 ||
+                        blockIdx >= (BlockIdx)files_[fileId].sentBlocks.size()) {
+                        fprintf(stderr,
+                                "Received invalid data request for file_id %" PRId16
+                                " block_idx %" PRId32 ".\n",
+                                fileId, blockIdx);
+                        break;
+                    }
+                    // fprintf(stderr, "\treading file %d block %04d\n", (int)fileId,
+                    // (int)blockIdx);
+                    if (auto res = SendBlock(fileId, blockIdx, true); res == SendResult::Error) {
+                        fprintf(stderr, "Failed to send block %" PRId32 ".\n", blockIdx);
+                    } else if (res == SendResult::Sent) {
+                        ++missesSent;
+                        // Make sure we send more pages from this place onward, in case if the OS is
+                        // reading a bigger block.
+                        prefetches_.emplace_front(files_[fileId], blockIdx + 1, 7);
+                    }
+                    break;
+                }
+                case PREFETCH: {
+                    // Start prefetching for a file
+                    if (fileId < 0) {
+                        fprintf(stderr,
+                                "Received invalid prefetch request for file_id %" PRId16 "\n",
+                                fileId);
+                        break;
+                    }
+                    if (!prefetchedFiles.insert(fileId).second) {
+                        fprintf(stderr,
+                                "Received duplicate prefetch request for file_id %" PRId16 "\n",
+                                fileId);
+                        break;
+                    }
+                    D("Received prefetch request for file_id %" PRId16 ".\n", fileId);
+                    prefetches_.emplace_back(files_[fileId]);
+                    break;
+                }
+                default:
+                    fprintf(stderr, "Invalid request %" PRId16 ",%" PRId16 ",%" PRId32 ".\n",
+                            request->request_type, fileId, blockIdx);
+                    break;
+            }
+        }
+
+        RunPrefetching();
+    }
+}
+
+bool serve(int adb_fd, int argc, const char** argv) {
+    auto connection_fd = unique_fd(adb_fd);
+    if (argc <= 0) {
+        error_exit("inc-server: must specify at least one file.");
+    }
+
+    std::vector<File> files;
+    files.reserve(argc);
+    for (int i = 0; i < argc; ++i) {
+        auto filepath = argv[i];
+
+        struct stat st;
+        if (stat(filepath, &st)) {
+            fprintf(stderr, "Failed to stat input file %s. Abort.\n", filepath);
+            return {};
+        }
+
+        unique_fd fd(adb_open(filepath, O_RDONLY));
+        if (fd < 0) {
+            error_exit("inc-server: failed to open file '%s'.", filepath);
+        }
+        files.emplace_back(filepath, i, st.st_size, std::move(fd));
+    }
+
+    IncrementalServer server(std::move(connection_fd), std::move(files));
+    printf("Serving...\n");
+    fclose(stdin);
+    fclose(stdout);
+    return server.Serve();
+}
+
+}  // namespace incremental
diff --git a/adb/client/incremental_server.h b/adb/client/incremental_server.h
new file mode 100644
index 0000000..53f011e
--- /dev/null
+++ b/adb/client/incremental_server.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace incremental {
+
+// Expecting arguments like:
+// {FILE1 FILE2 ...}
+// Where FILE* are files to serve.
+bool serve(int adbFd, int argc, const char** argv);
+
+}  // namespace incremental
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0c5a6b4..2318395 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -267,6 +267,39 @@
 
 #define getcwd adb_getcwd
 
+// A very simple wrapper over a launched child process
+class Process {
+  public:
+    constexpr explicit Process(HANDLE h = nullptr) : h_(h) {}
+    ~Process() { close(); }
+    constexpr explicit operator bool() const { return h_ != nullptr; }
+
+    void wait() {
+        if (*this) {
+            ::WaitForSingleObject(h_, INFINITE);
+            close();
+        }
+    }
+    void kill() {
+        if (*this) {
+            ::TerminateProcess(h_, -1);
+        }
+    }
+
+  private:
+    void close() {
+        if (*this) {
+            ::CloseHandle(h_);
+            h_ = nullptr;
+        }
+    }
+
+    HANDLE h_;
+};
+
+Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
+                           std::initializer_list<int> fds_to_inherit = {});
+
 // Helper class to convert UTF-16 argv from wmain() to UTF-8 args that can be
 // passed to main().
 class NarrowArgs {
@@ -432,11 +465,11 @@
     return TEMP_FAILURE_RETRY(read(fd.get(), buf, len));
 }
 
-static __inline__ int adb_pread(int fd, void* buf, size_t len, off64_t offset) {
+static __inline__ int adb_pread(borrowed_fd fd, void* buf, size_t len, off64_t offset) {
 #if defined(__APPLE__)
-    return TEMP_FAILURE_RETRY(pread(fd, buf, len, offset));
+    return TEMP_FAILURE_RETRY(pread(fd.get(), buf, len, offset));
 #else
-    return TEMP_FAILURE_RETRY(pread64(fd, buf, len, offset));
+    return TEMP_FAILURE_RETRY(pread64(fd.get(), buf, len, offset));
 #endif
 }
 
@@ -612,6 +645,32 @@
     return fd.get();
 }
 
+// A very simple wrapper over a launched child process
+class Process {
+  public:
+    constexpr explicit Process(pid_t pid) : pid_(pid) {}
+    constexpr explicit operator bool() const { return pid_ >= 0; }
+
+    void wait() {
+        if (*this) {
+            int status;
+            ::waitpid(pid_, &status, 0);
+            pid_ = -1;
+        }
+    }
+    void kill() {
+        if (*this) {
+            ::kill(pid_, SIGTERM);
+        }
+    }
+
+  private:
+    pid_t pid_;
+};
+
+Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
+                           std::initializer_list<int> fds_to_inherit = {});
+
 #endif /* !_WIN32 */
 
 static inline void disable_tcp_nagle(borrowed_fd fd) {
diff --git a/adb/sysdeps_unix.cpp b/adb/sysdeps_unix.cpp
index 3fdc917..e565706 100644
--- a/adb/sysdeps_unix.cpp
+++ b/adb/sysdeps_unix.cpp
@@ -56,3 +56,37 @@
 
     return true;
 }
+
+static __inline__ void disable_close_on_exec(borrowed_fd fd) {
+    const auto oldFlags = fcntl(fd.get(), F_GETFD);
+    const auto newFlags = (oldFlags & ~FD_CLOEXEC);
+    if (newFlags != oldFlags) {
+        fcntl(fd.get(), F_SETFD, newFlags);
+    }
+}
+
+Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
+                           std::initializer_list<int> fds_to_inherit) {
+    const auto pid = fork();
+    if (pid != 0) {
+        // parent, includes the case when failed to fork()
+        return Process(pid);
+    }
+    // child
+    std::vector<std::string> copies;
+    copies.reserve(args.size() + 1);
+    copies.emplace_back(executable);
+    copies.insert(copies.end(), std::make_move_iterator(args.begin()),
+                  std::make_move_iterator(args.end()));
+
+    std::vector<char*> rawArgs;
+    rawArgs.reserve(copies.size() + 1);
+    for (auto&& str : copies) {
+        rawArgs.push_back(str.data());
+    }
+    rawArgs.push_back(nullptr);
+    for (auto fd : fds_to_inherit) {
+        disable_close_on_exec(fd);
+    }
+    exit(execv(copies.front().data(), rawArgs.data()));
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index d9cc36f..e33d51c 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -2771,6 +2771,66 @@
     return buf;
 }
 
+void enable_inherit(borrowed_fd fd) {
+    auto osh = adb_get_os_handle(fd);
+    const auto h = reinterpret_cast<HANDLE>(osh);
+    ::SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+}
+
+void disable_inherit(borrowed_fd fd) {
+    auto osh = adb_get_os_handle(fd);
+    const auto h = reinterpret_cast<HANDLE>(osh);
+    ::SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0);
+}
+
+Process adb_launch_process(std::string_view executable, std::vector<std::string> args,
+                           std::initializer_list<int> fds_to_inherit) {
+    std::wstring wexe;
+    if (!android::base::UTF8ToWide(executable.data(), executable.size(), &wexe)) {
+        return Process();
+    }
+
+    std::wstring wargs = L"\"" + wexe + L"\"";
+    std::wstring warg;
+    for (auto arg : args) {
+        warg.clear();
+        if (!android::base::UTF8ToWide(arg.data(), arg.size(), &warg)) {
+            return Process();
+        }
+        wargs += L" \"";
+        wargs += warg;
+        wargs += L'\"';
+    }
+
+    STARTUPINFOW sinfo = {sizeof(sinfo)};
+    PROCESS_INFORMATION pinfo = {};
+
+    // TODO: use the Vista+ API to pass the list of inherited handles explicitly;
+    // see http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx
+    for (auto fd : fds_to_inherit) {
+        enable_inherit(fd);
+    }
+    const auto created = CreateProcessW(wexe.c_str(), wargs.data(),
+                                        nullptr,                    // process attributes
+                                        nullptr,                    // thread attributes
+                                        fds_to_inherit.size() > 0,  // inherit any handles?
+                                        0,                          // flags
+                                        nullptr,                    // environment
+                                        nullptr,                    // current directory
+                                        &sinfo,                     // startup info
+                                        &pinfo);
+    for (auto fd : fds_to_inherit) {
+        disable_inherit(fd);
+    }
+
+    if (!created) {
+        return Process();
+    }
+
+    ::CloseHandle(pinfo.hThread);
+    return Process(pinfo.hProcess);
+}
+
 // The SetThreadDescription API was brought in version 1607 of Windows 10.
 typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
 
diff --git a/adb/tls/adb_ca_list.cpp b/adb/tls/adb_ca_list.cpp
index 8d37bbe..36afe42 100644
--- a/adb/tls/adb_ca_list.cpp
+++ b/adb/tls/adb_ca_list.cpp
@@ -32,13 +32,13 @@
 // CA issuer identifier to distinguished embedded keys. Also has version
 // information appended to the end of the string (e.g. "AdbKey-0").
 static constexpr int kAdbKeyIdentifierNid = NID_organizationName;
-static constexpr char kAdbKeyIdentifierPrefix[] = "AdbKey-";
-static constexpr int kAdbKeyVersion = 0;
+static constexpr char kAdbKeyIdentifierV0[] = "AdbKey-0";
 
 // Where we store the actual data
 static constexpr int kAdbKeyValueNid = NID_commonName;
 
 // TODO: Remove this once X509_NAME_add_entry_by_NID is fixed to use const unsigned char*
+// https://boringssl-review.googlesource.com/c/boringssl/+/39764
 int X509_NAME_add_entry_by_NID_const(X509_NAME* name, int nid, int type, const unsigned char* bytes,
                                      int len, int loc, int set) {
     return X509_NAME_add_entry_by_NID(name, nid, type, const_cast<unsigned char*>(bytes), len, loc,
@@ -55,13 +55,13 @@
     // |len| is the len of the text excluding the final null
     int len = X509_NAME_get_text_by_NID(name, nid, nullptr, -1);
     if (len <= 0) {
-        return {};
+        return std::nullopt;
     }
 
     // Include the space for the final null byte
     std::vector<char> buf(len + 1, '\0');
     CHECK(X509_NAME_get_text_by_NID(name, nid, buf.data(), buf.size()));
-    return buf.data();
+    return std::make_optional(std::string(buf.data()));
 }
 
 }  // namespace
@@ -73,8 +73,7 @@
     // "O=AdbKey-0;CN=<key>;"
     CHECK(!key.empty());
 
-    std::string identifier = kAdbKeyIdentifierPrefix;
-    identifier += std::to_string(kAdbKeyVersion);
+    std::string identifier = kAdbKeyIdentifierV0;
     bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
     CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC,
                                            reinterpret_cast<const uint8_t*>(identifier.data()),
@@ -91,27 +90,34 @@
     CHECK(issuer);
 
     auto buf = GetX509NameTextByNid(issuer, kAdbKeyIdentifierNid);
-    if (!buf || !android::base::StartsWith(*buf, kAdbKeyIdentifierPrefix)) {
-        return {};
+    if (!buf) {
+        return std::nullopt;
     }
 
-    return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
+    // Check for supported versions
+    if (*buf == kAdbKeyIdentifierV0) {
+        return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
+    }
+    return std::nullopt;
 }
 
 std::string SHA256BitsToHexString(std::string_view sha256) {
     CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
     std::stringstream ss;
+    auto* u8 = reinterpret_cast<const uint8_t*>(sha256.data());
     ss << std::uppercase << std::setfill('0') << std::hex;
     // Convert to hex-string representation
     for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
-        ss << std::setw(2) << (0x00FF & sha256[i]);
+        // Need to cast to something bigger than one byte, or
+        // stringstream will interpret it as a char value.
+        ss << std::setw(2) << static_cast<uint16_t>(u8[i]);
     }
     return ss.str();
 }
 
 std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
     if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
-        return {};
+        return std::nullopt;
     }
 
     std::string result;
@@ -119,7 +125,7 @@
         auto bytestr = std::string(sha256_str.substr(i * 2, 2));
         if (!IsHexDigit(bytestr[0]) || !IsHexDigit(bytestr[1])) {
             LOG(ERROR) << "SHA256 string has invalid non-hex chars";
-            return {};
+            return std::nullopt;
         }
         result += static_cast<char>(std::stol(bytestr, nullptr, 16));
     }
diff --git a/adb/tls/include/adb/tls/tls_connection.h b/adb/tls/include/adb/tls/tls_connection.h
index ae70857..bc5b98a 100644
--- a/adb/tls/include/adb/tls/tls_connection.h
+++ b/adb/tls/include/adb/tls/tls_connection.h
@@ -55,16 +55,15 @@
 
     // Adds a trusted certificate to the list for the SSL connection.
     // During the handshake phase, it will check the list of trusted certificates.
-    // The connection will fail if the peer's certificate is not in the list. Use
-    // |EnableCertificateVerification(false)| to disable certificate
-    // verification.
+    // The connection will fail if the peer's certificate is not in the list. If
+    // you would like to accept any certificate, use #SetCertVerifyCallback and
+    // set your callback to always return 1.
     //
     // Returns true if |cert| was successfully added, false otherwise.
     virtual bool AddTrustedCertificate(std::string_view cert) = 0;
 
     // Sets a custom certificate verify callback. |cb| must return 1 if the
-    // certificate is trusted. Otherwise, return 0 if not. Note that |cb| is
-    // only used if EnableCertificateVerification(false).
+    // certificate is trusted. Otherwise, return 0 if not.
     virtual void SetCertVerifyCallback(CertVerifyCb cb) = 0;
 
     // Configures a client |ca_list| that the server sends to the client in the
diff --git a/adb/tls/tests/tls_connection_test.cpp b/adb/tls/tests/tls_connection_test.cpp
index 880904b..27bc1c9 100644
--- a/adb/tls/tests/tls_connection_test.cpp
+++ b/adb/tls/tests/tls_connection_test.cpp
@@ -199,24 +199,10 @@
 static std::vector<CAIssuer> kCAIssuers = {
         {
                 {NID_commonName, {'a', 'b', 'c', 'd', 'e'}},
-                {NID_organizationName,
-                 {
-                         'd',
-                         'e',
-                         'f',
-                         'g',
-                 }},
+                {NID_organizationName, {'d', 'e', 'f', 'g'}},
         },
         {
-                {NID_commonName,
-                 {
-                         'h',
-                         'i',
-                         'j',
-                         'k',
-                         'l',
-                         'm',
-                 }},
+                {NID_commonName, {'h', 'i', 'j', 'k', 'l', 'm'}},
                 {NID_countryName, {'n', 'o'}},
         },
 };
@@ -224,8 +210,6 @@
 class AdbWifiTlsConnectionTest : public testing::Test {
   protected:
     virtual void SetUp() override {
-        // TODO: move client code in each test into its own thread, as the
-        // socket pair buffer is limited.
         android::base::Socketpair(SOCK_STREAM, &server_fd_, &client_fd_);
         server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert,
                                         kTestRsa2048ServerPrivKey, server_fd_);
@@ -257,14 +241,8 @@
         return ret;
     }
 
-    void StartClientHandshakeAsync(bool expect_success) {
-        client_thread_ = std::thread([=]() {
-            if (expect_success) {
-                EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
-            } else {
-                EXPECT_NE(client_->DoHandshake(), TlsError::Success);
-            }
-        });
+    void StartClientHandshakeAsync(TlsError expected) {
+        client_thread_ = std::thread([=]() { EXPECT_EQ(client_->DoHandshake(), expected); });
     }
 
     void WaitForClientConnection() {
@@ -313,45 +291,52 @@
     // Allow any certificate
     server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
     client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
-    StartClientHandshakeAsync(true);
+    StartClientHandshakeAsync(TlsError::Success);
 
     // Handshake should succeed
-    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
     WaitForClientConnection();
 
-    // Client write, server read
-    EXPECT_TRUE(client_->WriteFully(
-            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // Test client/server read and writes
+    client_thread_ = std::thread([&]() {
+        EXPECT_TRUE(client_->WriteFully(
+                std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+        // Try with overloaded ReadFully
+        std::vector<uint8_t> buf(msg_.size());
+        ASSERT_TRUE(client_->ReadFully(buf.data(), msg_.size()));
+        EXPECT_EQ(buf, msg_);
+    });
+
     auto data = server_->ReadFully(msg_.size());
     EXPECT_EQ(data, msg_);
-
-    // Client read, server write
     EXPECT_TRUE(server_->WriteFully(
             std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
-    // Try with overloaded ReadFully
-    std::vector<uint8_t> buf(msg_.size());
-    ASSERT_TRUE(client_->ReadFully(buf.data(), msg_.size()));
-    EXPECT_EQ(buf, msg_);
+
+    WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, NoTrustedCertificates) {
-    StartClientHandshakeAsync(false);
+    StartClientHandshakeAsync(TlsError::CertificateRejected);
 
     // Handshake should not succeed
-    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
     WaitForClientConnection();
 
-    // Client write, server read should fail
-    EXPECT_FALSE(client_->WriteFully(
-            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // All writes and reads should fail
+    client_thread_ = std::thread([&]() {
+        // Client write, server read should fail
+        EXPECT_FALSE(client_->WriteFully(
+                std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+        auto data = client_->ReadFully(msg_.size());
+        EXPECT_EQ(data.size(), 0);
+    });
+
     auto data = server_->ReadFully(msg_.size());
     EXPECT_EQ(data.size(), 0);
-
-    // Client read, server write should fail
     EXPECT_FALSE(server_->WriteFully(
             std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
-    data = client_->ReadFully(msg_.size());
-    EXPECT_EQ(data.size(), 0);
+
+    WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates) {
@@ -359,23 +344,26 @@
     EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
     EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
 
-    StartClientHandshakeAsync(true);
+    StartClientHandshakeAsync(TlsError::Success);
 
     // Handshake should succeed
-    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
     WaitForClientConnection();
 
-    // Client write, server read
-    EXPECT_TRUE(client_->WriteFully(
-            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // All read writes should succeed
+    client_thread_ = std::thread([&]() {
+        EXPECT_TRUE(client_->WriteFully(
+                std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+        auto data = client_->ReadFully(msg_.size());
+        EXPECT_EQ(data, msg_);
+    });
+
     auto data = server_->ReadFully(msg_.size());
     EXPECT_EQ(data, msg_);
-
-    // Client read, server write
     EXPECT_TRUE(server_->WriteFully(
             std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
-    data = client_->ReadFully(msg_.size());
-    EXPECT_EQ(data, msg_);
+
+    WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates_ClientWrongCert) {
@@ -387,23 +375,26 @@
     // Without enabling EnableClientPostHandshakeCheck(), DoHandshake() will
     // succeed, because in TLS 1.3, the client doesn't get notified if the
     // server rejected the certificate until a read operation is called.
-    StartClientHandshakeAsync(true);
+    StartClientHandshakeAsync(TlsError::Success);
 
     // Handshake should fail for server, succeed for client
-    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
     WaitForClientConnection();
 
-    // Client write succeeds, server read should fail
-    EXPECT_TRUE(client_->WriteFully(
-            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // Client writes will succeed, everything else will fail.
+    client_thread_ = std::thread([&]() {
+        EXPECT_TRUE(client_->WriteFully(
+                std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+        auto data = client_->ReadFully(msg_.size());
+        EXPECT_EQ(data.size(), 0);
+    });
+
     auto data = server_->ReadFully(msg_.size());
     EXPECT_EQ(data.size(), 0);
-
-    // Client read, server write should fail
     EXPECT_FALSE(server_->WriteFully(
             std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
-    data = client_->ReadFully(msg_.size());
-    EXPECT_EQ(data.size(), 0);
+
+    WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, ExportKeyingMaterial) {
@@ -415,10 +406,10 @@
     EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
     EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
 
-    StartClientHandshakeAsync(true);
+    StartClientHandshakeAsync(TlsError::Success);
 
     // Handshake should succeed
-    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
     WaitForClientConnection();
 
     // Verify the client and server's exported key material match.
@@ -439,10 +430,10 @@
     // Client handshake should succeed, because in TLS 1.3, client does not
     // realize that the peer rejected the certificate until after a read
     // operation.
-    client_thread_ = std::thread([&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::Success); });
+    StartClientHandshakeAsync(TlsError::Success);
 
     // Server handshake should fail
-    EXPECT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
     WaitForClientConnection();
 }
 
@@ -455,11 +446,10 @@
     server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
 
     // Client handshake should fail because server rejects everything
-    client_thread_ = std::thread(
-            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::PeerRejectedCertificate); });
+    StartClientHandshakeAsync(TlsError::PeerRejectedCertificate);
 
     // Server handshake should fail
-    EXPECT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
     WaitForClientConnection();
 }
 
@@ -469,11 +459,10 @@
     // Server accepts all
     server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
     // Client handshake should fail
-    client_thread_ = std::thread(
-            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+    StartClientHandshakeAsync(TlsError::CertificateRejected);
 
     // Server handshake should fail
-    EXPECT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
     WaitForClientConnection();
 }
 
@@ -488,15 +477,15 @@
     server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
 
     // Client handshake should fail
-    client_thread_ = std::thread(
-            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+    StartClientHandshakeAsync(TlsError::CertificateRejected);
 
     // Server handshake should fail
-    EXPECT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
     WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, EnableClientPostHandshakeCheck_ClientWrongCert) {
+    client_->AddTrustedCertificate(kTestRsa2048ServerCert);
     // client's DoHandshake() will fail if the server rejected the certificate
     client_->EnableClientPostHandshakeCheck(true);
 
@@ -504,23 +493,26 @@
     EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
 
     // Handshake should fail for client
-    StartClientHandshakeAsync(false);
+    StartClientHandshakeAsync(TlsError::PeerRejectedCertificate);
 
     // Handshake should fail for server
-    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
     WaitForClientConnection();
 
-    // Client write fails, server read should fail
-    EXPECT_FALSE(client_->WriteFully(
-            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // All read writes should fail
+    client_thread_ = std::thread([&]() {
+        EXPECT_FALSE(client_->WriteFully(
+                std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+        auto data = client_->ReadFully(msg_.size());
+        EXPECT_EQ(data.size(), 0);
+    });
+
     auto data = server_->ReadFully(msg_.size());
     EXPECT_EQ(data.size(), 0);
-
-    // Client read, server write should fail
     EXPECT_FALSE(server_->WriteFully(
             std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
-    data = client_->ReadFully(msg_.size());
-    EXPECT_EQ(data.size(), 0);
+
+    WaitForClientConnection();
 }
 
 TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Empty) {
@@ -569,12 +561,12 @@
             return 1;
         });
         // Client handshake should succeed
-        EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+        ASSERT_EQ(client_->DoHandshake(), TlsError::Success);
     });
 
     EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
     // Server handshake should succeed
-    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
     client_thread_.join();
 }
 
@@ -604,12 +596,12 @@
             return 1;
         });
         // Client handshake should succeed
-        EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+        ASSERT_EQ(client_->DoHandshake(), TlsError::Success);
     });
 
     server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
     // Server handshake should succeed
-    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
     client_thread_.join();
 }
 }  // namespace tls
diff --git a/adb/tls/tls_connection.cpp b/adb/tls/tls_connection.cpp
index 7df6ef4..853cdac 100644
--- a/adb/tls/tls_connection.cpp
+++ b/adb/tls/tls_connection.cpp
@@ -61,6 +61,7 @@
     static const char* SSLErrorString();
     void Invalidate();
     TlsError GetFailureReason(int err);
+    const char* RoleToString() { return role_ == Role::Server ? kServerRoleStr : kClientRoleStr; }
 
     Role role_;
     bssl::UniquePtr<EVP_PKEY> priv_key_;
@@ -75,15 +76,19 @@
     CertVerifyCb cert_verify_cb_;
     SetCertCb set_cert_cb_;
     borrowed_fd fd_;
+    static constexpr char kClientRoleStr[] = "[client]: ";
+    static constexpr char kServerRoleStr[] = "[server]: ";
 };  // TlsConnectionImpl
 
 TlsConnectionImpl::TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key,
                                      borrowed_fd fd)
     : role_(role), fd_(fd) {
     CHECK(!cert.empty() && !priv_key.empty());
-    LOG(INFO) << "Initializing adbwifi TlsConnection";
+    LOG(INFO) << RoleToString() << "Initializing adbwifi TlsConnection";
     cert_ = BufferFromPEM(cert);
+    CHECK(cert_);
     priv_key_ = EvpPkeyFromPEM(priv_key);
+    CHECK(priv_key_);
 }
 
 TlsConnectionImpl::~TlsConnectionImpl() {
@@ -149,7 +154,7 @@
     // Create X509 buffer from the certificate string
     auto buf = X509FromBuffer(BufferFromPEM(cert));
     if (buf == nullptr) {
-        LOG(ERROR) << "Failed to create a X509 buffer for the certificate.";
+        LOG(ERROR) << RoleToString() << "Failed to create a X509 buffer for the certificate.";
         return false;
     }
     known_certificates_.push_back(std::move(buf));
@@ -205,8 +210,7 @@
 }
 
 TlsConnection::TlsError TlsConnectionImpl::DoHandshake() {
-    int err = -1;
-    LOG(INFO) << "Starting adbwifi tls handshake";
+    LOG(INFO) << RoleToString() << "Starting adbwifi tls handshake";
     ssl_ctx_.reset(SSL_CTX_new(TLS_method()));
     // TODO: Remove set_max_proto_version() once external/boringssl is updated
     // past
@@ -214,14 +218,14 @@
     if (ssl_ctx_.get() == nullptr ||
         !SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION) ||
         !SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION)) {
-        LOG(ERROR) << "Failed to create SSL context";
+        LOG(ERROR) << RoleToString() << "Failed to create SSL context";
         return TlsError::UnknownFailure;
     }
 
     // Register user-supplied known certificates
     for (auto const& cert : known_certificates_) {
         if (X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx_.get()), cert.get()) == 0) {
-            LOG(ERROR) << "Unable to add certificates into the X509_STORE";
+            LOG(ERROR) << RoleToString() << "Unable to add certificates into the X509_STORE";
             return TlsError::UnknownFailure;
         }
     }
@@ -248,7 +252,8 @@
     };
     if (!SSL_CTX_set_chain_and_key(ssl_ctx_.get(), cert_chain.data(), cert_chain.size(),
                                    priv_key_.get(), nullptr)) {
-        LOG(ERROR) << "Unable to register the certificate chain file and private key ["
+        LOG(ERROR) << RoleToString()
+                   << "Unable to register the certificate chain file and private key ["
                    << SSLErrorString() << "]";
         Invalidate();
         return TlsError::UnknownFailure;
@@ -259,19 +264,21 @@
     // Okay! Let's try to do the handshake!
     ssl_.reset(SSL_new(ssl_ctx_.get()));
     if (!SSL_set_fd(ssl_.get(), fd_.get())) {
-        LOG(ERROR) << "SSL_set_fd failed. [" << SSLErrorString() << "]";
+        LOG(ERROR) << RoleToString() << "SSL_set_fd failed. [" << SSLErrorString() << "]";
         return TlsError::UnknownFailure;
     }
+
     switch (role_) {
         case Role::Server:
-            err = SSL_accept(ssl_.get());
+            SSL_set_accept_state(ssl_.get());
             break;
         case Role::Client:
-            err = SSL_connect(ssl_.get());
+            SSL_set_connect_state(ssl_.get());
             break;
     }
-    if (err != 1) {
-        LOG(ERROR) << "Handshake failed in SSL_accept/SSL_connect [" << SSLErrorString() << "]";
+    if (SSL_do_handshake(ssl_.get()) != 1) {
+        LOG(ERROR) << RoleToString() << "Handshake failed in SSL_accept/SSL_connect ["
+                   << SSLErrorString() << "]";
         auto sslerr = ERR_get_error();
         Invalidate();
         return GetFailureReason(sslerr);
@@ -281,16 +288,16 @@
         uint8_t check;
         // Try to peek one byte for any failures. This assumes on success that
         // the server actually sends something.
-        err = SSL_peek(ssl_.get(), &check, 1);
-        if (err <= 0) {
-            LOG(ERROR) << "Post-handshake SSL_peek failed [" << SSLErrorString() << "]";
+        if (SSL_peek(ssl_.get(), &check, 1) <= 0) {
+            LOG(ERROR) << RoleToString() << "Post-handshake SSL_peek failed [" << SSLErrorString()
+                       << "]";
             auto sslerr = ERR_get_error();
             Invalidate();
             return GetFailureReason(sslerr);
         }
     }
 
-    LOG(INFO) << "Handshake succeeded.";
+    LOG(INFO) << RoleToString() << "Handshake succeeded.";
     return TlsError::Success;
 }
 
@@ -311,7 +318,7 @@
 bool TlsConnectionImpl::ReadFully(void* buf, size_t size) {
     CHECK_GT(size, 0U);
     if (!ssl_) {
-        LOG(ERROR) << "Tried to read on a null SSL connection";
+        LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection";
         return false;
     }
 
@@ -321,7 +328,7 @@
         int bytes_read =
                 SSL_read(ssl_.get(), p8 + offset, std::min(static_cast<size_t>(INT_MAX), size));
         if (bytes_read <= 0) {
-            LOG(WARNING) << "SSL_read failed [" << SSLErrorString() << "]";
+            LOG(ERROR) << RoleToString() << "SSL_read failed [" << SSLErrorString() << "]";
             return false;
         }
         size -= bytes_read;
@@ -333,7 +340,7 @@
 bool TlsConnectionImpl::WriteFully(std::string_view data) {
     CHECK(!data.empty());
     if (!ssl_) {
-        LOG(ERROR) << "Tried to read on a null SSL connection";
+        LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection";
         return false;
     }
 
@@ -341,7 +348,7 @@
         int bytes_out = SSL_write(ssl_.get(), data.data(),
                                   std::min(static_cast<size_t>(INT_MAX), data.size()));
         if (bytes_out <= 0) {
-            LOG(WARNING) << "SSL_write failed [" << SSLErrorString() << "]";
+            LOG(ERROR) << RoleToString() << "SSL_write failed [" << SSLErrorString() << "]";
             return false;
         }
         data = data.substr(bytes_out);
diff --git a/base/Android.bp b/base/Android.bp
index a32959b..25c74f2 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -128,6 +128,10 @@
     static_libs: ["fmtlib"],
     whole_static_libs: ["fmtlib"],
     export_static_lib_headers: ["fmtlib"],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_library_static {
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index e3ce531..f28c778 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -171,6 +171,7 @@
 
     srcs: [
         "libdebuggerd/backtrace.cpp",
+        "libdebuggerd/gwp_asan.cpp",
         "libdebuggerd/open_files_list.cpp",
         "libdebuggerd/tombstone.cpp",
         "libdebuggerd/utility.cpp",
@@ -181,7 +182,10 @@
 
     // Needed for private/bionic_fdsan.h
     include_dirs: ["bionic/libc"],
-    header_libs: ["bionic_libc_platform_headers"],
+    header_libs: [
+        "bionic_libc_platform_headers",
+        "gwp_asan_headers",
+    ],
 
     static_libs: [
         "libdexfile_support_static",  // libunwindstack dependency
@@ -192,6 +196,8 @@
         "liblog",
     ],
 
+    whole_static_libs: ["gwp_asan_crash_handler"],
+
     target: {
         recovery: {
             exclude_static_libs: [
@@ -246,10 +252,12 @@
 
     static_libs: [
         "libdebuggerd",
+        "libgmock",
     ],
 
     header_libs: [
         "bionic_libc_platform_headers",
+        "gwp_asan_headers",
     ],
 
     local_include_dirs: [
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
index 2545cd6..ebb8d86 100644
--- a/debuggerd/client/debuggerd_client_test.cpp
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -73,8 +73,8 @@
   unique_fd pipe_read, pipe_write;
   ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));
 
-  // 64 MiB should be enough for everyone.
-  constexpr int PIPE_SIZE = 64 * 1024 * 1024;
+  // 16 MiB should be enough for everyone.
+  constexpr int PIPE_SIZE = 16 * 1024 * 1024;
   ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));
 
   // Wait for a bit to let the child spawn all of its threads.
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index e8f366f..3e99880 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -255,7 +255,8 @@
 
 static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
                           std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address,
-                          uintptr_t* fdsan_table_address) {
+                          uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state,
+                          uintptr_t* gwp_asan_metadata) {
   std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
   CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
   ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
@@ -272,6 +273,10 @@
         expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
         break;
 
+      case 3:
+        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);
+        break;
+
       default:
         LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version;
         break;
@@ -284,7 +289,13 @@
   }
 
   *fdsan_table_address = 0;
+  *gwp_asan_state = 0;
+  *gwp_asan_metadata = 0;
   switch (crash_info->header.version) {
+    case 3:
+      *gwp_asan_state = crash_info->data.v3.gwp_asan_state;
+      *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
+      FALLTHROUGH_INTENDED;
     case 2:
       *fdsan_table_address = crash_info->data.v2.fdsan_table_address;
       FALLTHROUGH_INTENDED;
@@ -416,6 +427,8 @@
   DebuggerdDumpType dump_type;
   uintptr_t abort_msg_address = 0;
   uintptr_t fdsan_table_address = 0;
+  uintptr_t gwp_asan_state = 0;
+  uintptr_t gwp_asan_metadata = 0;
 
   Initialize(argv);
   ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
@@ -477,7 +490,7 @@
       if (thread == g_target_thread) {
         // Read the thread's registers along with the rest of the crash info out of the pipe.
         ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address,
-                      &fdsan_table_address);
+                      &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata);
         info.siginfo = &siginfo;
         info.signo = info.siginfo->si_signo;
       } else {
@@ -592,7 +605,8 @@
     {
       ATRACE_NAME("engrave_tombstone");
       engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
-                        abort_msg_address, &open_files, &amfd_data);
+                        abort_msg_address, &open_files, &amfd_data, gwp_asan_state,
+                        gwp_asan_metadata);
     }
   }
 
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index f8192b5..8b4b630 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -49,6 +49,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
 #include <bionic/reserved_signals.h>
@@ -298,6 +299,8 @@
   void* ucontext;
   uintptr_t abort_msg;
   uintptr_t fdsan_table;
+  uintptr_t gwp_asan_state;
+  uintptr_t gwp_asan_metadata;
 };
 
 // Logging and contacting debuggerd requires free file descriptors, which we might not have.
@@ -342,23 +345,25 @@
   }
 
   // ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
-  uint32_t version = 2;
-  constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
+  uint32_t version = 3;
+  constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);
 
   errno = 0;
   if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) {
     fatal_errno("failed to set pipe buffer size");
   }
 
-  struct iovec iovs[5] = {
+  struct iovec iovs[] = {
       {.iov_base = &version, .iov_len = sizeof(version)},
       {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
       {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
       {.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)},
       {.iov_base = &thread_info->fdsan_table, .iov_len = sizeof(uintptr_t)},
+      {.iov_base = &thread_info->gwp_asan_state, .iov_len = sizeof(uintptr_t)},
+      {.iov_base = &thread_info->gwp_asan_metadata, .iov_len = sizeof(uintptr_t)},
   };
 
-  ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, 5));
+  ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs)));
   if (rc == -1) {
     fatal_errno("failed to write crash info");
   } else if (rc != expected) {
@@ -485,6 +490,8 @@
   }
 
   void* abort_message = nullptr;
+  const gwp_asan::AllocatorState* gwp_asan_state = nullptr;
+  const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr;
   uintptr_t si_val = reinterpret_cast<uintptr_t>(info->si_ptr);
   if (signal_number == BIONIC_SIGNAL_DEBUGGER) {
     if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) {
@@ -499,6 +506,12 @@
     if (g_callbacks.get_abort_message) {
       abort_message = g_callbacks.get_abort_message();
     }
+    if (g_callbacks.get_gwp_asan_state) {
+      gwp_asan_state = g_callbacks.get_gwp_asan_state();
+    }
+    if (g_callbacks.get_gwp_asan_metadata) {
+      gwp_asan_metadata = g_callbacks.get_gwp_asan_metadata();
+    }
   }
 
   // If sival_int is ~0, it means that the fallback handler has been called
@@ -532,6 +545,8 @@
       .ucontext = context,
       .abort_msg = reinterpret_cast<uintptr_t>(abort_message),
       .fdsan_table = reinterpret_cast<uintptr_t>(android_fdsan_get_fd_table()),
+      .gwp_asan_state = reinterpret_cast<uintptr_t>(gwp_asan_state),
+      .gwp_asan_metadata = reinterpret_cast<uintptr_t>(gwp_asan_metadata),
   };
 
   // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index cd6fc05..4f24360 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -24,11 +24,20 @@
 
 __BEGIN_DECLS
 
+// Forward declare these classes so not everyone has to include GWP-ASan
+// headers.
+namespace gwp_asan {
+struct AllocatorState;
+struct AllocationMetadata;
+};  // namespace gwp_asan
+
 // These callbacks are called in a signal handler, and thus must be async signal safe.
 // If null, the callbacks will not be called.
 typedef struct {
   struct abort_msg_t* (*get_abort_message)();
   void (*post_dump)();
+  const struct gwp_asan::AllocatorState* (*get_gwp_asan_state)();
+  const struct gwp_asan::AllocationMetadata* (*get_gwp_asan_metadata)();
 } debuggerd_callbacks_t;
 
 void debuggerd_init(debuggerd_callbacks_t* callbacks);
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
new file mode 100644
index 0000000..53df783
--- /dev/null
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libdebuggerd/gwp_asan.h"
+#include "libdebuggerd/utility.h"
+
+#include "gwp_asan/common.h"
+#include "gwp_asan/crash_handler.h"
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
+
+// Retrieve GWP-ASan state from `state_addr` inside the process at
+// `process_memory`. Place the state into `*state`.
+static bool retrieve_gwp_asan_state(unwindstack::Memory* process_memory, uintptr_t state_addr,
+                                    gwp_asan::AllocatorState* state) {
+  return process_memory->ReadFully(state_addr, state, sizeof(*state));
+}
+
+// Retrieve the GWP-ASan metadata pool from `metadata_addr` inside the process
+// at `process_memory`. The number of metadata slots is retrieved from the
+// allocator state provided. This function returns a heap-allocated copy of the
+// metadata pool whose ownership should be managed by the caller. Returns
+// nullptr on failure.
+static const gwp_asan::AllocationMetadata* retrieve_gwp_asan_metadata(
+    unwindstack::Memory* process_memory, const gwp_asan::AllocatorState& state,
+    uintptr_t metadata_addr) {
+  if (state.MaxSimultaneousAllocations > 1024) {
+    ALOGE(
+        "Error when retrieving GWP-ASan metadata, MSA from state (%zu) "
+        "exceeds maximum allowed (1024).",
+        state.MaxSimultaneousAllocations);
+    return nullptr;
+  }
+
+  gwp_asan::AllocationMetadata* meta =
+      new gwp_asan::AllocationMetadata[state.MaxSimultaneousAllocations];
+  if (!process_memory->ReadFully(metadata_addr, meta,
+                                 sizeof(*meta) * state.MaxSimultaneousAllocations)) {
+    ALOGE(
+        "Error when retrieving GWP-ASan metadata, could not retrieve %zu "
+        "pieces of metadata.",
+        state.MaxSimultaneousAllocations);
+    delete[] meta;
+    meta = nullptr;
+  }
+  return meta;
+}
+
+GwpAsanCrashData::GwpAsanCrashData(unwindstack::Memory* process_memory,
+                                   uintptr_t gwp_asan_state_ptr, uintptr_t gwp_asan_metadata_ptr,
+                                   const ThreadInfo& thread_info) {
+  if (!process_memory || !gwp_asan_metadata_ptr || !gwp_asan_state_ptr) return;
+  // Extract the GWP-ASan regions from the dead process.
+  if (!retrieve_gwp_asan_state(process_memory, gwp_asan_state_ptr, &state_)) return;
+  metadata_.reset(retrieve_gwp_asan_metadata(process_memory, state_, gwp_asan_metadata_ptr));
+  if (!metadata_.get()) return;
+
+  // Get the external crash address from the thread info.
+  crash_address_ = 0u;
+  if (signal_has_si_addr(thread_info.siginfo)) {
+    crash_address_ = reinterpret_cast<uintptr_t>(thread_info.siginfo->si_addr);
+  }
+
+  // Ensure the error belongs to GWP-ASan.
+  if (!__gwp_asan_error_is_mine(&state_, crash_address_)) return;
+
+  is_gwp_asan_responsible_ = true;
+  thread_id_ = thread_info.tid;
+
+  // Grab the internal error address, if it exists.
+  uintptr_t internal_crash_address = __gwp_asan_get_internal_crash_address(&state_);
+  if (internal_crash_address) {
+    crash_address_ = internal_crash_address;
+  }
+
+  // Get other information from the internal state.
+  error_ = __gwp_asan_diagnose_error(&state_, metadata_.get(), crash_address_);
+  error_string_ = gwp_asan::ErrorToString(error_);
+  responsible_allocation_ = __gwp_asan_get_metadata(&state_, metadata_.get(), crash_address_);
+}
+
+bool GwpAsanCrashData::CrashIsMine() const {
+  return is_gwp_asan_responsible_;
+}
+
+void GwpAsanCrashData::DumpCause(log_t* log) const {
+  if (!CrashIsMine()) {
+    ALOGE("Internal Error: DumpCause() on a non-GWP-ASan crash.");
+    return;
+  }
+
+  if (error_ == gwp_asan::Error::UNKNOWN) {
+    _LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: Unknown error occurred at 0x%" PRIxPTR ".\n",
+         crash_address_);
+    return;
+  }
+
+  if (!responsible_allocation_) {
+    _LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: %s at 0x%" PRIxPTR ".\n", error_string_,
+         crash_address_);
+    return;
+  }
+
+  uintptr_t alloc_address = __gwp_asan_get_allocation_address(responsible_allocation_);
+  size_t alloc_size = __gwp_asan_get_allocation_size(responsible_allocation_);
+
+  if (crash_address_ == alloc_address) {
+    // Use After Free on a 41-byte allocation at 0xdeadbeef.
+    _LOG(log, logtype::HEADER, "Cause: [GWP-ASan]: %s on a %zu-byte allocation at 0x%" PRIxPTR "\n",
+         error_string_, alloc_size, alloc_address);
+    return;
+  }
+
+  uintptr_t diff;
+  const char* location_str;
+
+  if (crash_address_ < alloc_address) {
+    // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
+    location_str = "left of";
+    diff = alloc_address - crash_address_;
+  } else if (crash_address_ - alloc_address < alloc_size) {
+    // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
+    location_str = "into";
+    diff = crash_address_ - alloc_address;
+  } else {
+    // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef, or
+    // Invalid Free, 47 bytes right of a 41-byte allocation at 0xdeadbeef.
+    location_str = "right of";
+    diff = crash_address_ - alloc_address;
+    if (error_ == gwp_asan::Error::BUFFER_OVERFLOW) {
+      diff -= alloc_size;
+    }
+  }
+
+  // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
+  const char* byte_suffix = "s";
+  if (diff == 1) {
+    byte_suffix = "";
+  }
+  _LOG(log, logtype::HEADER,
+       "Cause: [GWP-ASan]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
+       error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
+}
+
+// Build a frame for symbolization using the maps from the provided unwinder.
+// The constructed frame contains just enough information to be used to
+// symbolize a GWP-ASan stack trace.
+static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintptr_t pc,
+                                         size_t frame_num) {
+  unwindstack::FrameData frame;
+  frame.num = frame_num;
+
+  unwindstack::Maps* maps = unwinder->GetMaps();
+  unwindstack::MapInfo* map_info = maps->Find(pc);
+  if (!map_info) {
+    frame.rel_pc = pc;
+    return frame;
+  }
+
+  unwindstack::Elf* elf =
+      map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
+
+  uint64_t relative_pc = elf->GetRelPc(pc, map_info);
+
+  // Create registers just to get PC adjustment. Doesn't matter what they point
+  // to.
+  unwindstack::Regs* regs = unwindstack::Regs::CreateFromLocal();
+  uint64_t pc_adjustment = regs->GetPcAdjustment(relative_pc, elf);
+  relative_pc -= pc_adjustment;
+  // The debug PC may be different if the PC comes from the JIT.
+  uint64_t debug_pc = relative_pc;
+
+  // If we don't have a valid ELF file, check the JIT.
+  if (!elf->valid()) {
+    unwindstack::JitDebug jit_debug(unwinder->GetProcessMemory());
+    uint64_t jit_pc = pc - pc_adjustment;
+    unwindstack::Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
+    if (jit_elf != nullptr) {
+      debug_pc = jit_pc;
+      elf = jit_elf;
+    }
+  }
+
+  // Copy all the things we need into the frame for symbolization.
+  frame.rel_pc = relative_pc;
+  frame.pc = pc - pc_adjustment;
+  frame.map_name = map_info->name;
+  frame.map_elf_start_offset = map_info->elf_start_offset;
+  frame.map_exact_offset = map_info->offset;
+  frame.map_start = map_info->start;
+  frame.map_end = map_info->end;
+  frame.map_flags = map_info->flags;
+  frame.map_load_bias = elf->GetLoadBias();
+
+  if (!elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
+    frame.function_name = "";
+    frame.function_offset = 0;
+  }
+  return frame;
+}
+
+constexpr size_t kMaxTraceLength = gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect;
+
+bool GwpAsanCrashData::HasDeallocationTrace() const {
+  assert(CrashIsMine() && "HasDeallocationTrace(): Crash is not mine!");
+  if (!responsible_allocation_ || !__gwp_asan_is_deallocated(responsible_allocation_)) {
+    return false;
+  }
+  return true;
+}
+
+void GwpAsanCrashData::DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
+  assert(HasDeallocationTrace() && "DumpDeallocationTrace(): No dealloc trace!");
+  uint64_t thread_id = __gwp_asan_get_deallocation_thread_id(responsible_allocation_);
+
+  std::unique_ptr<uintptr_t> frames(new uintptr_t[kMaxTraceLength]);
+  size_t num_frames =
+      __gwp_asan_get_deallocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
+
+  if (thread_id == gwp_asan::kInvalidThreadID) {
+    _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread <unknown>:\n");
+  } else {
+    _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %" PRIu64 ":\n", thread_id);
+  }
+
+  unwinder->SetDisplayBuildID(true);
+  for (size_t i = 0; i < num_frames; ++i) {
+    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
+    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
+  }
+}
+
+bool GwpAsanCrashData::HasAllocationTrace() const {
+  assert(CrashIsMine() && "HasAllocationTrace(): Crash is not mine!");
+  return responsible_allocation_ != nullptr;
+}
+
+void GwpAsanCrashData::DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const {
+  assert(HasAllocationTrace() && "DumpAllocationTrace(): No dealloc trace!");
+  uint64_t thread_id = __gwp_asan_get_allocation_thread_id(responsible_allocation_);
+
+  std::unique_ptr<uintptr_t> frames(new uintptr_t[kMaxTraceLength]);
+  size_t num_frames =
+      __gwp_asan_get_allocation_trace(responsible_allocation_, frames.get(), kMaxTraceLength);
+
+  if (thread_id == gwp_asan::kInvalidThreadID) {
+    _LOG(log, logtype::BACKTRACE, "\nallocated by thread <unknown>:\n");
+  } else {
+    _LOG(log, logtype::BACKTRACE, "\nallocated by thread %" PRIu64 ":\n", thread_id);
+  }
+
+  unwinder->SetDisplayBuildID(true);
+  for (size_t i = 0; i < num_frames; ++i) {
+    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
+    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
+  }
+}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
new file mode 100644
index 0000000..aef4c62
--- /dev/null
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <log/log.h>
+#include <unwindstack/Memory.h>
+
+#include "gwp_asan/common.h"
+#include "types.h"
+#include "utility.h"
+
+class GwpAsanCrashData {
+ public:
+  GwpAsanCrashData() = delete;
+  ~GwpAsanCrashData() = default;
+
+  // Construct the crash data object. Takes a handle to the object that can
+  // supply the memory of the dead process, and pointers to the GWP-ASan state
+  // and metadata regions within that process. Also takes the thread information
+  // of the crashed process. If the process didn't crash via SEGV, GWP-ASan may
+  // still be responsible, as it terminates when it detects an internal error
+  // (double free, invalid free). In these cases, we will retrieve the fault
+  // address from the GWP-ASan allocator's state.
+  GwpAsanCrashData(unwindstack::Memory* process_memory, uintptr_t gwp_asan_state_ptr,
+                   uintptr_t gwp_asan_metadata_ptr, const ThreadInfo& thread_info);
+
+  // Is GWP-ASan responsible for this crash.
+  bool CrashIsMine() const;
+
+  // Returns the fault address. The fault address may be the same as provided
+  // during construction, or it may have been retrieved from GWP-ASan's internal
+  // allocator crash state.
+  uintptr_t GetFaultAddress() const;
+
+  // Dump the GWP-ASan stringified cause of this crash. May only be called if
+  // CrashIsMine() returns true.
+  void DumpCause(log_t* log) const;
+
+  // Returns whether this crash has a deallocation trace. May only be called if
+  // CrashIsMine() returns true.
+  bool HasDeallocationTrace() const;
+
+  // Dump the GWP-ASan deallocation trace for this crash. May only be called if
+  // HasDeallocationTrace() returns true.
+  void DumpDeallocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
+
+  // Returns whether this crash has a allocation trace. May only be called if
+  // CrashIsMine() returns true.
+  bool HasAllocationTrace() const;
+
+  // Dump the GWP-ASan allocation trace for this crash. May only be called if
+  // HasAllocationTrace() returns true.
+  void DumpAllocationTrace(log_t* log, unwindstack::Unwinder* unwinder) const;
+
+ protected:
+  // Is GWP-ASan responsible for this crash.
+  bool is_gwp_asan_responsible_ = false;
+
+  // Thread ID of the crash.
+  size_t thread_id_;
+
+  // The type of error that GWP-ASan caused (and the stringified version),
+  // Undefined if GWP-ASan isn't responsible for the crash.
+  gwp_asan::Error error_;
+  const char* error_string_;
+
+  // Pointer to the crash address. Holds the internal crash address if it
+  // exists, otherwise the address provided at construction.
+  uintptr_t crash_address_ = 0u;
+
+  // Pointer to the metadata for the responsible allocation, nullptr if it
+  // doesn't exist.
+  const gwp_asan::AllocationMetadata* responsible_allocation_ = nullptr;
+
+  // Internal state.
+  gwp_asan::AllocatorState state_;
+  std::unique_ptr<const gwp_asan::AllocationMetadata> metadata_;
+};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 7133f77..291d994 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -55,6 +55,7 @@
 void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
-                       std::string* amfd_data);
+                       std::string* amfd_data, uintptr_t gwp_asan_state,
+                       uintptr_t gwp_asan_metadata);
 
 #endif  // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index b33adf3..eed95bc 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "libdebuggerd/utility.h"
@@ -31,8 +32,13 @@
 #include "host_signal_fixup.h"
 #include "log_fake.h"
 
+// Include tombstone.cpp to define log_tag before GWP-ASan includes log.
 #include "tombstone.cpp"
 
+#include "gwp_asan.cpp"
+
+using ::testing::MatchesRegex;
+
 class TombstoneTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
@@ -359,3 +365,131 @@
   dump_timestamp(&log_, 0);
   ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
 }
+
+class GwpAsanCrashDataTest : public GwpAsanCrashData {
+public:
+  GwpAsanCrashDataTest(
+      gwp_asan::Error error,
+      const gwp_asan::AllocationMetadata *responsible_allocation) :
+      GwpAsanCrashData(nullptr, 0u, 0u, ThreadInfo{}) {
+    is_gwp_asan_responsible_ = true;
+    error_ = error;
+    responsible_allocation_ = responsible_allocation;
+    error_string_ = gwp_asan::ErrorToString(error_);
+  }
+
+  void SetCrashAddress(uintptr_t crash_address) {
+    crash_address_ = crash_address;
+  }
+};
+
+TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
+  crash_data.SetCrashAddress(0x1000);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(tombstone_contents,
+              MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free on a 32-byte "
+                           "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
+  crash_data.SetCrashAddress(0x1000);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(tombstone_contents,
+              MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free on a 32-byte "
+                           "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
+  crash_data.SetCrashAddress(0x1025);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(
+      tombstone_contents,
+      MatchesRegex(
+          "Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
+          "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
+  crash_data.SetCrashAddress(0xffe);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(
+      tombstone_contents,
+      MatchesRegex(
+          "Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
+          "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
+  crash_data.SetCrashAddress(0x1001);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(
+      tombstone_contents,
+      MatchesRegex(
+          "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
+          "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
+TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
+  gwp_asan::AllocationMetadata meta;
+  meta.Addr = 0x1000;
+  meta.Size = 32;
+
+  GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
+  crash_data.SetCrashAddress(0x1021);
+
+  crash_data.DumpCause(&log_);
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  std::string tombstone_contents;
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_THAT(
+      tombstone_contents,
+      MatchesRegex(
+          "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
+          "allocation at 0x[a-fA-F0-9]+\n"));
+}
+
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 4e7f35c..fd52e81 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -53,9 +53,13 @@
 #include <unwindstack/Unwinder.h>
 
 #include "libdebuggerd/backtrace.h"
+#include "libdebuggerd/gwp_asan.h"
 #include "libdebuggerd/open_files_list.h"
 #include "libdebuggerd/utility.h"
 
+#include "gwp_asan/common.h"
+#include "gwp_asan/crash_handler.h"
+
 using android::base::GetBoolProperty;
 using android::base::GetProperty;
 using android::base::StringPrintf;
@@ -372,7 +376,8 @@
 }
 
 static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
-                        uint64_t abort_msg_address, bool primary_thread) {
+                        uint64_t abort_msg_address, bool primary_thread,
+                        const GwpAsanCrashData& gwp_asan_crash_data) {
   log->current_tid = thread_info.tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -381,7 +386,13 @@
 
   if (thread_info.siginfo) {
     dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
-    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(), thread_info.registers.get());
+  }
+
+  if (primary_thread && gwp_asan_crash_data.CrashIsMine()) {
+    gwp_asan_crash_data.DumpCause(log);
+  } else if (thread_info.siginfo) {
+    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
+                        thread_info.registers.get());
   }
 
   if (primary_thread) {
@@ -402,6 +413,14 @@
   }
 
   if (primary_thread) {
+    if (gwp_asan_crash_data.HasDeallocationTrace()) {
+      gwp_asan_crash_data.DumpDeallocationTrace(log, unwinder);
+    }
+
+    if (gwp_asan_crash_data.HasAllocationTrace()) {
+      gwp_asan_crash_data.DumpAllocationTrace(log, unwinder);
+    }
+
     unwindstack::Maps* maps = unwinder->GetMaps();
     dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
                          thread_info.registers.get());
@@ -583,13 +602,14 @@
   }
 
   engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
-                    nullptr, nullptr);
+                    nullptr, nullptr, 0u, 0u);
 }
 
 void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
-                       std::string* amfd_data) {
+                       std::string* amfd_data, uintptr_t gwp_asan_state_ptr,
+                       uintptr_t gwp_asan_metadata_ptr) {
   // don't copy log messages to tombstone unless this is a dev device
   bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
 
@@ -607,7 +627,13 @@
   if (it == threads.end()) {
     LOG(FATAL) << "failed to find target thread";
   }
-  dump_thread(&log, unwinder, it->second, abort_msg_address, true);
+
+  GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(),
+                                       gwp_asan_state_ptr,
+                                       gwp_asan_metadata_ptr, it->second);
+
+  dump_thread(&log, unwinder, it->second, abort_msg_address, true,
+              gwp_asan_crash_data);
 
   if (want_logs) {
     dump_logs(&log, it->second.pid, 50);
@@ -618,7 +644,7 @@
       continue;
     }
 
-    dump_thread(&log, unwinder, thread_info, 0, false);
+    dump_thread(&log, unwinder, thread_info, 0, false, gwp_asan_crash_data);
   }
 
   if (open_files) {
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index bfd0fbb..bf53864 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -95,10 +95,16 @@
   uintptr_t fdsan_table_address;
 };
 
+struct __attribute__((__packed__)) CrashInfoDataV3 : public CrashInfoDataV2 {
+  uintptr_t gwp_asan_state;
+  uintptr_t gwp_asan_metadata;
+};
+
 struct __attribute__((__packed__)) CrashInfo {
   CrashInfoHeader header;
   union {
     CrashInfoDataV1 v1;
     CrashInfoDataV2 v2;
+    CrashInfoDataV3 v3;
   } data;
 };
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 2099170..c845b6b 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -277,9 +277,9 @@
         } else if (StartsWith(flag, "keydirectory=")) {
             // The metadata flag is followed by an = and the directory for the keys.
             entry->metadata_key_dir = arg;
-        } else if (StartsWith(flag, "metadata_cipher=")) {
-            // Specify the cipher to use for metadata encryption
-            entry->metadata_cipher = arg;
+        } else if (StartsWith(flag, "metadata_encryption=")) {
+            // Specify the cipher and flags to use for metadata encryption
+            entry->metadata_encryption = arg;
         } else if (StartsWith(flag, "sysfs_path=")) {
             // The path to trigger device gc by idle-maint of vold.
             entry->sysfs_path = arg;
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index c769f07..f0e1f83 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,7 +38,7 @@
     std::string fs_options;
     std::string key_loc;
     std::string metadata_key_dir;
-    std::string metadata_cipher;
+    std::string metadata_encryption;
     off64_t length = 0;
     std::string label;
     int partnum = -1;
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index d7b689e..6461788 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -280,6 +280,7 @@
         extra_argv.emplace_back("allow_discards");
         extra_argv.emplace_back("sector_size:4096");
         extra_argv.emplace_back("iv_large_sectors");
+        if (is_hw_wrapped_) extra_argv.emplace_back("wrappedkey_v0");
     }
     if (!extra_argv.empty()) {
         argv.emplace_back(std::to_string(extra_argv.size()));
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index affdd29..67af59a 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -526,13 +526,18 @@
     bool is_legacy;
     ASSERT_TRUE(DmTargetDefaultKey::IsLegacy(&is_legacy));
     // set_dun only in the non-is_legacy case
-    DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0,
-                              is_legacy, !is_legacy);
+    DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
+    if (is_legacy) {
+        target.SetIsLegacy();
+    } else {
+        target.SetSetDun();
+    }
     ASSERT_EQ(target.name(), "default-key");
     ASSERT_TRUE(target.Valid());
     if (is_legacy) {
         ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
     } else {
+        // TODO: Add case for wrapped key enabled
         ASSERT_EQ(target.GetParameterString(),
                   "AES-256-XTS abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
                   "iv_large_sectors");
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index e3dd92b..d2e50d3 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -280,20 +280,20 @@
 class DmTargetDefaultKey final : public DmTarget {
   public:
     DmTargetDefaultKey(uint64_t start, uint64_t length, const std::string& cipher,
-                       const std::string& key, const std::string& blockdev, uint64_t start_sector,
-                       bool is_legacy, bool set_dun)
+                       const std::string& key, const std::string& blockdev, uint64_t start_sector)
         : DmTarget(start, length),
           cipher_(cipher),
           key_(key),
           blockdev_(blockdev),
-          start_sector_(start_sector),
-          is_legacy_(is_legacy),
-          set_dun_(set_dun) {}
+          start_sector_(start_sector) {}
 
     std::string name() const override { return name_; }
     bool Valid() const override;
     std::string GetParameterString() const override;
     static bool IsLegacy(bool* result);
+    void SetIsLegacy() { is_legacy_ = true; }
+    void SetSetDun() { set_dun_ = true; }
+    void SetWrappedKeyV0() { is_hw_wrapped_ = true; }
 
   private:
     static const std::string name_;
@@ -301,8 +301,9 @@
     std::string key_;
     std::string blockdev_;
     uint64_t start_sector_;
-    bool is_legacy_;
-    bool set_dun_;
+    bool is_legacy_ = false;
+    bool set_dun_ = false;
+    bool is_hw_wrapped_ = false;
 };
 
 }  // namespace dm
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index d87274d..5d2840f 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1767,6 +1767,7 @@
   protected:
     void SetUp() override {
         if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
+        GTEST_SKIP() << "WIP failure b/149738928";
 
         SnapshotTest::SetUp();
         userdata_ = std::make_unique<LowSpaceUserdata>();
@@ -1774,6 +1775,7 @@
     }
     void TearDown() override {
         if (!is_virtual_ab_) return;
+        return;  // BUG(149738928)
 
         EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
                     image_manager_->DeleteBackingImage(kImageName));
@@ -1808,10 +1810,6 @@
     std::vector<uint64_t> ret;
     for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) {
         ret.push_back(size);
-#ifdef SKIP_TEST_IN_PRESUBMIT
-        // BUG(148889015);
-        break;
-#endif
     }
     return ret;
 }
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 64fb157..9caae35 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -891,11 +891,11 @@
     EXPECT_EQ("/dir/key", entry->metadata_key_dir);
 }
 
-TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataCipher) {
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption) {
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
     std::string fstab_contents = R"fs(
-source none0       swap   defaults      keydirectory=/dir/key,metadata_cipher=adiantum
+source none0       swap   defaults      keydirectory=/dir/key,metadata_encryption=adiantum
 )fs";
 
     ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
@@ -905,7 +905,28 @@
     ASSERT_EQ(1U, fstab.size());
 
     auto entry = fstab.begin();
-    EXPECT_EQ("adiantum", entry->metadata_cipher);
+    EXPECT_EQ("adiantum", entry->metadata_encryption);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption_WrappedKey) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      keydirectory=/dir/key,metadata_encryption=aes-256-xts:wrappedkey_v0
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption);
+    auto parts = android::base::Split(entry->metadata_encryption, ":");
+    EXPECT_EQ(2U, parts.size());
+    EXPECT_EQ("aes-256-xts", parts[0]);
+    EXPECT_EQ("wrappedkey_v0", parts[1]);
 }
 
 TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_SysfsPath) {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index b85f23f..8e9e074 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -55,6 +55,7 @@
 using android::hardware::health::V1_0::BatteryHealth;
 using android::hardware::health::V1_0::BatteryStatus;
 using android::hardware::health::V2_1::BatteryCapacityLevel;
+using android::hardware::health::V2_1::Constants;
 
 namespace android {
 
@@ -79,6 +80,8 @@
     // HIDL enum values are zero initialized, so they need to be initialized
     // properly.
     health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+    health_info_2_1->batteryChargeTimeToFullNowSeconds =
+            (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
     auto* props = &health_info_2_1->legacy.legacy;
     props->batteryStatus = BatteryStatus::UNKNOWN;
     props->batteryHealth = BatteryHealth::UNKNOWN;
@@ -134,13 +137,13 @@
             {"Normal", BatteryCapacityLevel::NORMAL},
             {"High", BatteryCapacityLevel::HIGH},
             {"Full", BatteryCapacityLevel::FULL},
-            {NULL, BatteryCapacityLevel::UNKNOWN},
+            {NULL, BatteryCapacityLevel::UNSUPPORTED},
     };
 
     auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
     if (!ret) {
-        KLOG_WARNING(LOG_TAG, "Unknown battery capacity level '%s'\n", capacityLevel);
-        *ret = BatteryCapacityLevel::UNKNOWN;
+        KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
+        *ret = BatteryCapacityLevel::UNSUPPORTED;
     }
 
     return *ret;
diff --git a/libcutils/include/private/android_projectid_config.h b/libcutils/include/private/android_projectid_config.h
new file mode 100644
index 0000000..7ef3854
--- /dev/null
+++ b/libcutils/include/private/android_projectid_config.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/*
+ * This file describes the project ID values we use for filesystem quota
+ * tracking.  It is used on devices that don't have the sdcardfs kernel module,
+ * which requires us to use filesystem project IDs for efficient quota
+ * calculation.
+ *
+ * These values are typically set on files and directories using extended
+ * attributes; see vold for examples.
+ */
+
+/* Default project ID for files on external storage. */
+#define PROJECT_ID_EXT_DEFAULT 1000
+/* Project ID for audio files on external storage. */
+#define PROJECT_ID_EXT_MEDIA_AUDIO 1001
+/* Project ID for video files on external storage. */
+#define PROJECT_ID_EXT_MEDIA_VIDEO 1002
+/* Project ID for image files on external storage. */
+#define PROJECT_ID_EXT_MEDIA_IMAGE 1003
+
+/* Start of project IDs for apps to mark external app data. */
+#define PROJECT_ID_EXT_DATA_START 20000
+/* End of project IDs for apps to mark external app data. */
+#define PROJECT_ID_EXT_DATA_END 29999
+
+/* Start of project IDs for apps to mark external cached data. */
+#define PROJECT_ID_EXT_CACHE_START 30000
+/* End of project IDs for apps to mark external cached data. */
+#define PROJECT_ID_EXT_CACHE_END 39999
+
+/* Start of project IDs for apps to mark external OBB data. */
+#define PROJECT_ID_EXT_OBB_START 40000
+/* End of project IDs for apps to mark external OBB data. */
+#define PROJECT_ID_EXT_OBB_END 49999
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index c84ddf7..c98455d 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -274,7 +274,7 @@
  * Gets the minimum priority that will be logged for this process.  If none has been set by a
  * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
  */
-int __android_log_get_minimum_priority();
+int __android_log_get_minimum_priority(void);
 
 /**
  * Sets the default tag if no tag is provided when writing a log message.  Defaults to
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index f30058a..abd48fc 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -405,7 +405,7 @@
   static struct cache2_char security = {
       PTHREAD_MUTEX_INITIALIZER, 0,
       "persist.logd.security",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
-      "ro.device_owner",         {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
+      "ro.organization_owned",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
       evaluate_security};
 
   return do_cache2_char(&security);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 75a26bf..a60d2df 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1637,7 +1637,7 @@
 TEST(liblog, __security) {
 #ifdef __ANDROID__
   static const char persist_key[] = "persist.logd.security";
-  static const char readonly_key[] = "ro.device_owner";
+  static const char readonly_key[] = "ro.organization_owned";
   // A silly default value that can never be in readonly_key so
   // that it can be determined the property is not set.
   static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
@@ -1657,7 +1657,7 @@
   if (!strcmp(readonly, nothing_val)) {
     // Lets check if we can set the value (we should not be allowed to do so)
     EXPECT_FALSE(__android_log_security());
-    fprintf(stderr, "WARNING: setting ro.device_owner to a domain\n");
+    fprintf(stderr, "WARNING: setting ro.organization_owned to a domain\n");
     static const char domain[] = "com.google.android.SecOps.DeviceOwner";
     EXPECT_NE(0, property_set(readonly_key, domain));
     useconds_t total_time = 0;
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index f8b38ad..437879b 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -43,10 +43,10 @@
         ],
     },
     apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
         //TODO(b/149340100): Remove this once libstatssocket is only linked as shared.
         "//apex_available:platform",
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
     ],
 }
 
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index ccda5d1..627f0d4 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -39,6 +39,10 @@
         "clang-analyzer-security*",
         "android-*",
     ],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_test {
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 08e3d22..76a970f 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1129,7 +1129,7 @@
         if (!ret) {
             error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
 
-This means that either logd crashed, or more likely, this instance of logcat was unable to read log
+This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
 messages as quickly as they were being produced.
 
 If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
diff --git a/logd/README.property b/logd/README.property
index d2a2cbb..1b7e165 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -6,7 +6,7 @@
 ro.logd.auditd.main        bool   true   selinux audit messages sent to main.
 ro.logd.auditd.events      bool   true   selinux audit messages sent to events.
 persist.logd.security      bool   false  Enable security buffer.
-ro.device_owner            bool   false  Override persist.logd.security to false
+ro.organization_owned      bool   false  Override persist.logd.security to false
 ro.logd.kernel             bool+ svelte+ Enable klogd daemon
 ro.logd.statistics         bool+ svelte+ Enable logcat -S statistics.
 ro.debuggable              number        if not "1", logd.statistics &
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
index f4a846f..a643062 100644
--- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -317,7 +317,7 @@
       {"ro.boot.bootreason", "u:object_r:bootloader_boot_reason_prop:s0", "string", false},
       {"persist.sys.boot.reason", "u:object_r:last_boot_reason_prop:s0", "string", false},
       {"sys.boot.reason", "u:object_r:system_boot_reason_prop:s0", "string", false},
-      {"ro.device_owner", "u:object_r:device_logging_prop:s0", "string", false},
+      {"ro.organization_owned", "u:object_r:device_logging_prop:s0", "string", false},
 
       {"selinux.restorecon_recursive", "u:object_r:restorecon_prop:s0", "string", false},
 
@@ -669,7 +669,7 @@
       {"ro.crypto.type", "u:object_r:vold_prop:s0"},
       {"ro.dalvik.vm.native.bridge", "u:object_r:dalvik_prop:s0"},
       {"ro.debuggable", "u:object_r:default_prop:s0"},
-      {"ro.device_owner", "u:object_r:device_logging_prop:s0"},
+      {"ro.organization_owned", "u:object_r:device_logging_prop:s0"},
       {"ro.expect.recovery_id", "u:object_r:default_prop:s0"},
       {"ro.frp.pst", "u:object_r:default_prop:s0"},
       {"ro.hardware", "u:object_r:default_prop:s0"},