Merge "Add a few leak check tests."
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 7c57258..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-LOCAL_PATH := $(my-dir)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f9c3b4a..bc5685b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,6 +7,9 @@
       "name": "debuggerd_test"
     },
     {
+      "name": "fs_mgr_unit_test"
+    },
+    {
       "name": "init_tests"
     },
     {
diff --git a/adb/Android.bp b/adb/Android.bp
index 36bfad4..8199fff 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -22,35 +22,16 @@
         "-Wexit-time-destructors",
         "-Wno-unused-parameter",
         "-Wno-missing-field-initializers",
+        "-Wthread-safety",
         "-Wvla",
+        "-DADB_HOST=1", // overridden by adbd_defaults
     ],
     cpp_std: "experimental",
 
     use_version_lib: true,
-
     compile_multilib: "first",
-    product_variables: {
-        debuggable: {
-            cflags: [
-                "-DALLOW_ADBD_ROOT",
-                "-DALLOW_ADBD_DISABLE_VERITY",
-                "-DALLOW_ADBD_NO_AUTH",
-            ],
-        },
-    },
 
     target: {
-        android: {
-            cflags: [
-                "-DADB_HOST=0",
-                "-Wthread-safety",
-            ],
-        },
-
-        host: {
-            cflags: ["-DADB_HOST=1"],
-        },
-
         darwin: {
             host_ldlibs: [
                 "-lpthread",
@@ -76,6 +57,9 @@
 
                 // MinGW hides some things behind _POSIX_SOURCE.
                 "-D_POSIX_SOURCE",
+
+                // Not supported yet.
+                "-Wno-thread-safety",
             ],
 
             host_ldlibs: [
@@ -84,15 +68,46 @@
                 "-luserenv",
             ],
         },
+    },
+}
 
-        not_windows: {
+cc_defaults {
+    name: "adbd_defaults",
+    defaults: ["adb_defaults"],
+
+    cflags: ["-UADB_HOST", "-DADB_HOST=0"],
+    product_variables: {
+        debuggable: {
             cflags: [
-                "-Wthread-safety",
+                "-DALLOW_ADBD_ROOT",
+                "-DALLOW_ADBD_DISABLE_VERITY",
+                "-DALLOW_ADBD_NO_AUTH",
             ],
         },
     },
 }
 
+cc_defaults {
+    name: "host_adbd_supported",
+
+    host_supported: true,
+    target: {
+        linux: {
+            enabled: true,
+            host_ldlibs: [
+                "-lresolv", // b64_pton
+                "-lutil", // forkpty
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+}
+
 // libadb
 // =========================================================
 // These files are compiled for both the host and the device.
@@ -313,7 +328,7 @@
 // libadbd_core contains the common sources to build libadbd and libadbd_services.
 cc_library_static {
     name: "libadbd_core",
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
 
     // libminadbd wants both, as it's used to build native tests.
@@ -322,9 +337,6 @@
     srcs: libadb_srcs + libadb_posix_srcs + [
         "daemon/auth.cpp",
         "daemon/jdwp_service.cpp",
-        "daemon/usb.cpp",
-        "daemon/usb_ffs.cpp",
-        "daemon/usb_legacy.cpp",
     ],
 
     local_include_dirs: [
@@ -335,7 +347,6 @@
 
     static_libs: [
         "libdiagnose_usb",
-        "libqemu_pipe",
     ],
 
     shared_libs: [
@@ -346,22 +357,36 @@
         "libcutils",
         "liblog",
     ],
+
+    target: {
+        android: {
+            whole_static_libs: [
+                "libqemu_pipe",
+            ],
+            srcs: [
+                "daemon/transport_qemu.cpp",
+                "daemon/usb.cpp",
+                "daemon/usb_ffs.cpp",
+                "daemon/usb_legacy.cpp",
+            ]
+        },
+        linux_glibc: {
+            srcs: [
+                "daemon/usb_dummy.cpp",
+            ]
+        }
+    },
 }
 
 cc_library {
     name: "libadbd_services",
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
     compile_multilib: "both",
 
     srcs: [
-        "daemon/abb_service.cpp",
         "daemon/file_sync_service.cpp",
-        "daemon/framebuffer_service.cpp",
-        "daemon/mdns.cpp",
-        "daemon/remount_service.cpp",
         "daemon/services.cpp",
-        "daemon/set_verity_enable_state_service.cpp",
         "daemon/shell_service.cpp",
         "shell_service_protocol.cpp",
     ],
@@ -373,27 +398,41 @@
 
     static_libs: [
         "libadbd_core",
-        "libavb_user",
         "libdiagnose_usb",
-        "libqemu_pipe",
     ],
 
     shared_libs: [
         "libasyncio",
         "libbase",
-        "libbootloader_message",
         "libcrypto",
         "libcrypto_utils",
         "libcutils",
-        "libext4_utils",
-        "libfec",
-        "libfs_mgr",
         "liblog",
-        "libmdnssd",
-        "libselinux",
     ],
 
     target: {
+        android: {
+            srcs: [
+                "daemon/abb_service.cpp",
+                "daemon/framebuffer_service.cpp",
+                "daemon/mdns.cpp",
+                "daemon/reboot_service.cpp",
+                "daemon/remount_service.cpp",
+                "daemon/restart_service.cpp",
+                "daemon/set_verity_enable_state_service.cpp",
+            ],
+            static_libs: [
+                "libavb_user",
+            ],
+            shared_libs: [
+                "libbootloader_message",
+                "libmdnssd",
+                "libext4_utils",
+                "libfec",
+                "libfs_mgr",
+                "libselinux",
+            ],
+        },
         recovery: {
             exclude_srcs: [
                 "daemon/abb_service.cpp",
@@ -404,7 +443,7 @@
 
 cc_library {
     name: "libadbd",
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
 
     // Avoid getting duplicate symbol of android::build::GetBuildNumber().
@@ -435,7 +474,7 @@
 
 cc_binary {
     name: "adbd",
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
 
     srcs: [
@@ -467,7 +506,7 @@
 cc_binary {
     name: "abb",
 
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults"],
     recovery_available: false,
 
     srcs: [
@@ -500,7 +539,7 @@
 
 cc_test {
     name: "adbd_test",
-    defaults: ["adb_defaults"],
+    defaults: ["adbd_defaults"],
     srcs: libadb_test_srcs + [
         "daemon/services.cpp",
         "daemon/shell_service.cpp",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 06e4c50..a5b2f7b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1134,7 +1134,9 @@
         std::string host;
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
         std::string error;
-        if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
+        if (address.starts_with("vsock:")) {
+            serial = address;
+        } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
             SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
                                                            address.c_str(), error.c_str()));
             return true;
diff --git a/adb/adb.h b/adb/adb.h
index d79cd2d..9209997 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -139,7 +139,7 @@
 atransport* find_emulator_transport_by_console_port(int console_port);
 #endif
 
-int service_to_fd(std::string_view name, atransport* transport);
+unique_fd service_to_fd(std::string_view name, atransport* transport);
 #if !ADB_HOST
 unique_fd daemon_service_to_fd(std::string_view name, atransport* transport);
 #endif
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index be457a6..29909a5 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -75,41 +75,36 @@
 
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
-        int fd = adb_socket_accept(_fd, nullptr, nullptr);
+        unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
         if (fd < 0) return;
 
         int rcv_buf_size = CHUNK_SIZE;
-        adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
+        adb_setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
 
-        asocket* s = create_local_socket(fd);
+        asocket* s = create_local_socket(std::move(fd));
         if (s) {
             connect_to_smartsocket(s);
             return;
         }
-
-        adb_close(fd);
     }
 }
 
 static void listener_event_func(int _fd, unsigned ev, void* _l)
 {
     alistener* listener = reinterpret_cast<alistener*>(_l);
-    asocket *s;
 
     if (ev & FDE_READ) {
-        int fd = adb_socket_accept(_fd, nullptr, nullptr);
+        unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
         if (fd < 0) {
             return;
         }
 
-        s = create_local_socket(fd);
+        asocket* s = create_local_socket(std::move(fd));
         if (s) {
             s->transport = listener->transport;
             connect_to_remote(s, listener->connect_to);
             return;
         }
-
-        adb_close(fd);
     }
 }
 
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 2bd6a3e..80f146c 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -32,7 +32,9 @@
 
 #if !ADB_HOST
 const char* adb_device_banner = "device";
+#if defined(__ANDROID__)
 static android::base::LogdLogger gLogdLogger;
+#endif
 #else
 const char* adb_device_banner = "host";
 #endif
@@ -46,7 +48,7 @@
     fflush(stderr);
 #endif
 
-#if !ADB_HOST
+#if !ADB_HOST && defined(__ANDROID__)
     // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
     // doesn't result in exponential logging.
     if (severity >= android::base::INFO) {
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 8253487..a85ca8c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -53,8 +53,6 @@
 
 bool set_file_block_mode(int fd, bool block);
 
-int adb_close(int fd);
-
 // Given forward/reverse targets, returns true if they look sane. If an error is found, fills
 // |error| and returns false.
 // Currently this only checks "tcp:" targets. Additional checking could be added for other targets
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index bb09425..8518e17 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -147,17 +147,16 @@
 
 #if !defined(_WIN32)
 TEST(adb_utils, set_file_block_mode) {
-  int fd = adb_open("/dev/null", O_RDWR | O_APPEND);
-  ASSERT_GE(fd, 0);
-  int flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND)));
-  ASSERT_TRUE(set_file_block_mode(fd, false));
-  int new_flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(flags | O_NONBLOCK, new_flags);
-  ASSERT_TRUE(set_file_block_mode(fd, true));
-  new_flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(flags, new_flags);
-  ASSERT_EQ(0, adb_close(fd));
+    unique_fd fd(adb_open("/dev/null", O_RDWR | O_APPEND));
+    ASSERT_GE(fd, 0);
+    int flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND)));
+    ASSERT_TRUE(set_file_block_mode(fd, false));
+    int new_flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(flags | O_NONBLOCK, new_flags);
+    ASSERT_TRUE(set_file_block_mode(fd, true));
+    new_flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(flags, new_flags);
 }
 #endif
 
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 9a25d10..0a09d1e 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -100,13 +100,11 @@
 
     if (!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
-        adb_close(fd);
         return -1;
     }
     D("Switch transport in progress");
 
     if (!adb_status(fd, error)) {
-        adb_close(fd);
         D("Switch transport failed: %s", error->c_str());
         return -1;
     }
@@ -194,7 +192,7 @@
 
 int adb_connect(const std::string& service, std::string* error) {
     // first query the adb server's version
-    int fd = _adb_connect("host:version", error);
+    unique_fd fd(_adb_connect("host:version", error));
 
     D("adb_connect: service %s", service.c_str());
     if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
@@ -224,12 +222,10 @@
         if (fd >= 0) {
             std::string version_string;
             if (!ReadProtocolString(fd, &version_string, error)) {
-                adb_close(fd);
                 return -1;
             }
 
             ReadOrderlyShutdown(fd);
-            adb_close(fd);
 
             if (sscanf(&version_string[0], "%04x", &version) != 1) {
                 *error = android::base::StringPrintf("cannot parse version string: %s",
@@ -258,52 +254,48 @@
         return 0;
     }
 
-    fd = _adb_connect(service, error);
+    fd.reset(_adb_connect(service, error));
     if (fd == -1) {
         D("_adb_connect error: %s", error->c_str());
     } else if(fd == -2) {
         fprintf(stderr, "* daemon still not running\n");
     }
-    D("adb_connect: return fd %d", fd);
+    D("adb_connect: return fd %d", fd.get());
 
-    return fd;
+    return fd.release();
 }
 
 
 bool adb_command(const std::string& service) {
     std::string error;
-    int fd = adb_connect(service, &error);
+    unique_fd fd(adb_connect(service, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return false;
     }
 
-    if (!adb_status(fd, &error)) {
+    if (!adb_status(fd.get(), &error)) {
         fprintf(stderr, "error: %s\n", error.c_str());
-        adb_close(fd);
         return false;
     }
 
-    ReadOrderlyShutdown(fd);
-    adb_close(fd);
+    ReadOrderlyShutdown(fd.get());
     return true;
 }
 
 bool adb_query(const std::string& service, std::string* result, std::string* error) {
     D("adb_query: %s", service.c_str());
-    int fd = adb_connect(service, error);
+    unique_fd fd(adb_connect(service, error));
     if (fd < 0) {
         return false;
     }
 
     result->clear();
-    if (!ReadProtocolString(fd, result, error)) {
-        adb_close(fd);
+    if (!ReadProtocolString(fd.get(), result, error)) {
         return false;
     }
 
-    ReadOrderlyShutdown(fd);
-    adb_close(fd);
+    ReadOrderlyShutdown(fd.get());
     return true;
 }
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e963e3d..f70b480 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -794,7 +794,7 @@
 
 static int adb_sideload_legacy(const char* filename, int in_fd, int size) {
     std::string error;
-    int out_fd = adb_connect(android::base::StringPrintf("sideload:%d", size), &error);
+    unique_fd out_fd(adb_connect(android::base::StringPrintf("sideload:%d", size), &error));
     if (out_fd < 0) {
         fprintf(stderr, "adb: pre-KitKat sideload connection failed: %s\n", error.c_str());
         return -1;
@@ -809,14 +809,12 @@
         unsigned xfer = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
         if (!ReadFdExactly(in_fd, buf, xfer)) {
             fprintf(stderr, "adb: failed to read data from %s: %s\n", filename, strerror(errno));
-            adb_close(out_fd);
             return -1;
         }
         if (!WriteFdExactly(out_fd, buf, xfer)) {
             std::string error;
             adb_status(out_fd, &error);
             fprintf(stderr, "adb: failed to write data: %s\n", error.c_str());
-            adb_close(out_fd);
             return -1;
         }
         size -= xfer;
@@ -827,11 +825,9 @@
 
     if (!adb_status(out_fd, &error)) {
         fprintf(stderr, "adb: error response: %s\n", error.c_str());
-        adb_close(out_fd);
         return -1;
     }
 
-    adb_close(out_fd);
     return 0;
 }
 
@@ -1091,7 +1087,7 @@
 
 int send_shell_command(const std::string& command, bool disable_shell_protocol,
                        StandardStreamsCallbackInterface* callback) {
-    int fd;
+    unique_fd fd;
     bool use_shell_protocol = false;
 
     while (true) {
@@ -1114,7 +1110,7 @@
             std::string error;
             std::string service_string = ShellServiceString(use_shell_protocol, "", command);
 
-            fd = adb_connect(service_string, &error);
+            fd.reset(adb_connect(service_string, &error));
             if (fd >= 0) {
                 break;
             }
@@ -1126,13 +1122,7 @@
         }
     }
 
-    int exit_code = read_and_dump(fd, use_shell_protocol, callback);
-
-    if (adb_close(fd) < 0) {
-        PLOG(ERROR) << "failure closing FD " << fd;
-    }
-
-    return exit_code;
+    return read_and_dump(fd.get(), use_shell_protocol, callback);
 }
 
 static int logcat(int argc, const char** argv) {
@@ -1196,7 +1186,7 @@
     if (argc < 2) error_exit("backup either needs a list of packages or -all/-shared");
 
     adb_unlink(filename);
-    int outFd = adb_creat(filename, 0640);
+    unique_fd outFd(adb_creat(filename, 0640));
     if (outFd < 0) {
         fprintf(stderr, "adb: backup unable to create file '%s': %s\n", filename, strerror(errno));
         return EXIT_FAILURE;
@@ -1211,20 +1201,16 @@
 
     D("backup. filename=%s cmd=%s", filename, cmd.c_str());
     std::string error;
-    int fd = adb_connect(cmd, &error);
+    unique_fd fd(adb_connect(cmd, &error));
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
-        adb_close(outFd);
         return EXIT_FAILURE;
     }
 
     fprintf(stdout, "Now unlock your device and confirm the backup operation...\n");
     fflush(stdout);
 
-    copy_to_file(fd, outFd);
-
-    adb_close(fd);
-    adb_close(outFd);
+    copy_to_file(fd.get(), outFd.get());
     return EXIT_SUCCESS;
 }
 
@@ -1232,33 +1218,29 @@
     if (argc != 2) error_exit("restore requires an argument");
 
     const char* filename = argv[1];
-    int tarFd = adb_open(filename, O_RDONLY);
+    unique_fd tarFd(adb_open(filename, O_RDONLY));
     if (tarFd < 0) {
         fprintf(stderr, "adb: unable to open file %s: %s\n", filename, strerror(errno));
         return -1;
     }
 
     std::string error;
-    int fd = adb_connect("restore:", &error);
+    unique_fd fd(adb_connect("restore:", &error));
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for restore: %s\n", error.c_str());
-        adb_close(tarFd);
         return -1;
     }
 
     fprintf(stdout, "Now unlock your device and confirm the restore operation.\n");
     fflush(stdout);
 
-    copy_to_file(tarFd, fd);
+    copy_to_file(tarFd.get(), fd.get());
 
     // Provide an in-band EOD marker in case the archive file is malformed
-    write_zeros(512*2, fd);
+    write_zeros(512 * 2, fd);
 
     // Wait until the other side finishes, or it'll get sent SIGHUP.
-    copy_to_file(fd, STDOUT_FILENO);
-
-    adb_close(fd);
-    adb_close(tarFd);
+    copy_to_file(fd.get(), STDOUT_FILENO);
     return 0;
 }
 
@@ -1298,19 +1280,18 @@
 
 static int adb_connect_command(const std::string& command) {
     std::string error;
-    int fd = adb_connect(command, &error);
+    unique_fd fd(adb_connect(command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
     read_and_dump(fd);
-    adb_close(fd);
     return 0;
 }
 
 static int adb_connect_command_bidirectional(const std::string& command) {
     std::string error;
-    int fd = adb_connect(command, &error);
+    unique_fd fd(adb_connect(command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
@@ -1336,11 +1317,10 @@
         }
     };
 
-    std::thread read(forward, fd, STDOUT_FILENO, true);
-    std::thread write(forward, STDIN_FILENO, fd, false);
+    std::thread read(forward, fd.get(), STDOUT_FILENO, true);
+    std::thread write(forward, STDIN_FILENO, fd.get(), false);
     read.join();
     write.join();
-    adb_close(fd);
     return 0;
 }
 
@@ -1599,19 +1579,17 @@
         }
 
         std::string error;
-        int fd = adb_connect(cmd, &error);
+        unique_fd fd(adb_connect(cmd, &error));
         if (fd < 0) {
             fprintf(stderr, "error: %s\n", error.c_str());
             return -1;
         }
 
         if (exec_in) {
-            copy_to_file(STDIN_FILENO, fd);
+            copy_to_file(STDIN_FILENO, fd.get());
         } else {
-            copy_to_file(fd, STDOUT_FILENO);
+            copy_to_file(fd.get(), STDOUT_FILENO);
         }
-
-        adb_close(fd);
         return 0;
     } else if (!strcmp(argv[0], "kill-server")) {
         return adb_kill_server() ? 0 : 1;
@@ -1706,9 +1684,8 @@
             error_exit("error: %s", error_message.c_str());
         }
 
-        int fd = adb_connect(cmd, &error_message);
-        if (fd < 0 || !adb_status(fd, &error_message)) {
-            adb_close(fd);
+        unique_fd fd(adb_connect(cmd, &error_message));
+        if (fd < 0 || !adb_status(fd.get(), &error_message)) {
             error_exit("error: %s", error_message.c_str());
         }
 
diff --git a/adb/client/console.cpp b/adb/client/console.cpp
index 4e8a3f8..1dbb6e2 100644
--- a/adb/client/console.cpp
+++ b/adb/client/console.cpp
@@ -108,7 +108,7 @@
 }
 
 int adb_send_emulator_command(int argc, const char** argv, const char* serial) {
-    int fd = connect_to_console(serial);
+    unique_fd fd(connect_to_console(serial));
     if (fd == -1) {
         return 1;
     }
@@ -125,7 +125,6 @@
     if (!WriteFdExactly(fd, commands)) {
         fprintf(stderr, "error: cannot write to emulator: %s\n",
                 strerror(errno));
-        adb_close(fd);
         return 1;
     }
 
@@ -178,7 +177,5 @@
     }
 
     printf("%s", emulator_output.c_str() + found);
-    adb_close(fd);
-
     return 0;
 }
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index f0f9a80..b8827ef 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -207,11 +207,10 @@
 
         std::string error;
         if (!adb_get_feature_set(&features_, &error)) {
-            fd = -1;
             Error("failed to get feature set: %s", error.c_str());
         } else {
             have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
-            fd = adb_connect("sync:", &error);
+            fd.reset(adb_connect("sync:", &error));
             if (fd < 0) {
                 Error("connect failed: %s", error.c_str());
             }
@@ -230,7 +229,6 @@
             // case, this will wait for the server to do orderly shutdown.
             ReadOrderlyShutdown(fd);
         }
-        adb_close(fd);
 
         line_printer_.KeepInfoLine();
     }
@@ -240,7 +238,7 @@
     bool IsValid() { return fd >= 0; }
 
     bool ReceivedError(const char* from, const char* to) {
-        adb_pollfd pfd = {.fd = fd, .events = POLLIN};
+        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
         int rc = adb_poll(&pfd, 1, 0);
         if (rc < 0) {
             Error("failed to poll: %s", strerror(errno));
@@ -324,7 +322,7 @@
 
         memset(st, 0, sizeof(*st));
         if (have_stat_v2_) {
-            if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
+            if (!ReadFdExactly(fd.get(), &msg.stat_v2, sizeof(msg.stat_v2))) {
                 PLOG(FATAL) << "protocol fault: failed to read stat response";
             }
 
@@ -350,7 +348,7 @@
             st->st_ctime = msg.stat_v2.ctime;
             return true;
         } else {
-            if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
+            if (!ReadFdExactly(fd.get(), &msg.stat_v1, sizeof(msg.stat_v1))) {
                 PLOG(FATAL) << "protocol fault: failed to read stat response";
             }
 
@@ -437,7 +435,7 @@
         uint64_t total_size = st.st_size;
         uint64_t bytes_copied = 0;
 
-        int lfd = adb_open(lpath, O_RDONLY);
+        unique_fd lfd(adb_open(lpath, O_RDONLY));
         if (lfd < 0) {
             Error("opening '%s' locally failed: %s", lpath, strerror(errno));
             return false;
@@ -449,7 +447,6 @@
             int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
             if (bytes_read == -1) {
                 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
-                adb_close(lfd);
                 return false;
             } else if (bytes_read == 0) {
                 break;
@@ -469,8 +466,6 @@
             ReportProgress(rpath, bytes_copied, total_size);
         }
 
-        adb_close(lfd);
-
         syncmsg msg;
         msg.data.id = ID_DONE;
         msg.data.size = mtime;
@@ -576,7 +571,7 @@
     }
 
     // TODO: add a char[max] buffer here, to replace syncsendbuf...
-    int fd;
+    unique_fd fd;
     size_t max;
 
   private:
@@ -740,7 +735,7 @@
     if (!sc.SendRequest(ID_RECV, rpath)) return false;
 
     adb_unlink(lpath);
-    int lfd = adb_creat(lpath, 0644);
+    unique_fd lfd(adb_creat(lpath, 0644));
     if (lfd < 0) {
         sc.Error("cannot create '%s': %s", lpath, strerror(errno));
         return false;
@@ -750,7 +745,6 @@
     while (true) {
         syncmsg msg;
         if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
@@ -758,7 +752,6 @@
         if (msg.data.id == ID_DONE) break;
 
         if (msg.data.id != ID_DATA) {
-            adb_close(lfd);
             adb_unlink(lpath);
             sc.ReportCopyFailure(rpath, lpath, msg);
             return false;
@@ -766,21 +759,18 @@
 
         if (msg.data.size > sc.max) {
             sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
 
         char buffer[SYNC_DATA_MAX];
         if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
 
         if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
             sc.Error("cannot write '%s': %s", lpath, strerror(errno));
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
@@ -792,7 +782,6 @@
     }
 
     sc.RecordFilesTransferred(1);
-    adb_close(lfd);
     return true;
 }
 
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 180df8f..1800f84 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -67,7 +67,7 @@
                 // b64_pton requires one additional byte in the target buffer for
                 // decoding to succeed. See http://b/28035006 for details.
                 uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
-                if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+                if (b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
                     LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
                     continue;
                 }
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index d55096a..56b5cd8 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -22,13 +22,11 @@
 
 #include <dirent.h>
 #include <errno.h>
-#include <linux/xattr.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/xattr.h>
 #include <unistd.h>
 #include <utime.h>
 
@@ -37,11 +35,17 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
+
+#if defined(__ANDROID__)
 #include <selinux/android.h>
+#include <sys/xattr.h>
+#endif
 
 #include "adb.h"
 #include "adb_io.h"
@@ -55,11 +59,17 @@
 using android::base::StringPrintf;
 
 static bool should_use_fs_config(const std::string& path) {
+#if defined(__ANDROID__)
     // TODO: use fs_config to configure permissions on /data too.
     return !android::base::StartsWith(path, "/data/");
+#else
+    UNUSED(path);
+    return false;
+#endif
 }
 
 static bool update_capabilities(const char* path, uint64_t capabilities) {
+#if defined(__ANDROID__)
     if (capabilities == 0) {
         // Ensure we clean up in case the capabilities weren't 0 in the past.
         removexattr(path, XATTR_NAME_CAPS);
@@ -73,6 +83,10 @@
     cap_data.data[1].permitted = (capabilities >> 32);
     cap_data.data[1].inheritable = 0;
     return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
+#else
+    UNUSED(path, capabilities);
+    return true;
+#endif
 }
 
 static bool secure_mkdirs(const std::string& path) {
@@ -105,8 +119,10 @@
         } else {
             if (chown(partial_path.c_str(), uid, gid) == -1) return false;
 
+#if defined(__ANDROID__)
             // Not all filesystems support setting SELinux labels. http://b/23530370.
             selinux_android_restorecon(partial_path.c_str(), 0);
+#endif
 
             if (!update_capabilities(partial_path.c_str(), capabilities)) return false;
         }
@@ -216,7 +232,7 @@
 
     __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
 
-    int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+    unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
 
     if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) <
         0) {
@@ -228,27 +244,29 @@
             SendSyncFailErrno(s, "secure_mkdirs failed");
             goto fail;
         }
-        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+        fd.reset(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
     }
     if (fd < 0 && errno == EEXIST) {
-        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
+        fd.reset(adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode));
     }
     if (fd < 0) {
         SendSyncFailErrno(s, "couldn't create file");
         goto fail;
     } else {
-        if (fchown(fd, uid, gid) == -1) {
+        if (fchown(fd.get(), uid, gid) == -1) {
             SendSyncFailErrno(s, "fchown failed");
             goto fail;
         }
 
+#if defined(__ANDROID__)
         // Not all filesystems support setting SELinux labels. http://b/23530370.
         selinux_android_restorecon(path, 0);
+#endif
 
         // fchown clears the setuid bit - restore it if present.
         // Ignore the result of calling fchmod. It's not supported
         // by all filesystems, so we don't check for success. b/12441485
-        fchmod(fd, mode);
+        fchmod(fd.get(), mode);
     }
 
     while (true) {
@@ -270,14 +288,12 @@
 
         if (!ReadFdExactly(s, &buffer[0], msg.data.size)) goto abort;
 
-        if (!WriteFdExactly(fd, &buffer[0], msg.data.size)) {
+        if (!WriteFdExactly(fd.get(), &buffer[0], msg.data.size)) {
             SendSyncFailErrno(s, "write failed");
             goto fail;
         }
     }
 
-    adb_close(fd);
-
     if (!update_capabilities(path, capabilities)) {
         SendSyncFailErrno(s, "update_capabilities failed");
         goto fail;
@@ -322,7 +338,6 @@
     }
 
 abort:
-    if (fd >= 0) adb_close(fd);
     if (do_unlink) adb_unlink(path);
     return false;
 }
@@ -427,35 +442,31 @@
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
     __android_log_security_bswrite(SEC_TAG_ADB_RECV_FILE, path);
 
-    int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
+    unique_fd fd(adb_open(path, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         SendSyncFailErrno(s, "open failed");
         return false;
     }
 
-    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
+    if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
         D("[ Failed to fadvise: %d ]", errno);
     }
 
     syncmsg msg;
     msg.data.id = ID_DATA;
     while (true) {
-        int r = adb_read(fd, &buffer[0], buffer.size() - sizeof(msg.data));
+        int r = adb_read(fd.get(), &buffer[0], buffer.size() - sizeof(msg.data));
         if (r <= 0) {
             if (r == 0) break;
             SendSyncFailErrno(s, "read failed");
-            adb_close(fd);
             return false;
         }
         msg.data.size = r;
         if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
-            adb_close(fd);
             return false;
         }
     }
 
-    adb_close(fd);
-
     msg.data.id = ID_DONE;
     msg.data.size = 0;
     return WriteFdExactly(s, &msg.data, sizeof(msg.data));
diff --git a/adb/daemon/framebuffer_service.h b/adb/daemon/framebuffer_service.h
index 264da59..bab44be 100644
--- a/adb/daemon/framebuffer_service.h
+++ b/adb/daemon/framebuffer_service.h
@@ -18,4 +18,6 @@
 
 #include "adb_unique_fd.h"
 
+#if defined(__ANDROID__)
 void framebuffer_service(unique_fd fd);
+#endif
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index f02cc13..032ee42 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -303,7 +303,6 @@
 static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
     sockaddr_un addr;
     socklen_t addrlen;
-    int s;
     int maxpath = sizeof(addr.sun_path);
     int pathlen = socknamelen;
 
@@ -316,7 +315,7 @@
     addr.sun_family = AF_UNIX;
     memcpy(addr.sun_path, sockname, socknamelen);
 
-    s = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+    unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
     if (s < 0) {
         D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
         return -1;
@@ -326,22 +325,18 @@
 
     if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
         D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
-        adb_close(s);
         return -1;
     }
 
     if (listen(s, 4) < 0) {
         D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
-        adb_close(s);
         return -1;
     }
 
-    control->listen_socket = s;
-
-    control->fde = fdevent_create(s, jdwp_control_event, control);
+    control->listen_socket = s.release();
+    control->fde = fdevent_create(control->listen_socket, jdwp_control_event, control);
     if (control->fde == nullptr) {
         D("could not create fdevent for jdwp control socket");
-        adb_close(s);
         return -1;
     }
 
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index f6f1acc..fce3a4f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -18,7 +18,10 @@
 
 #include "sysdeps.h"
 
+#if defined(__BIONIC__)
 #include <android/fdsan.h>
+#endif
+
 #include <errno.h>
 #include <getopt.h>
 #include <malloc.h>
@@ -34,12 +37,15 @@
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+
+#if defined(__ANDROID__)
 #include <libminijail.h>
 #include <log/log_properties.h>
 #include <scoped_minijail.h>
 
 #include <private/android_filesystem_config.h>
 #include "selinux/android.h"
+#endif
 
 #include "adb.h"
 #include "adb_auth.h"
@@ -49,6 +55,7 @@
 
 #include "mdns.h"
 
+#if defined(__ANDROID__)
 static const char* root_seclabel = nullptr;
 
 static bool should_drop_capabilities_bounding_set() {
@@ -167,10 +174,14 @@
         }
     }
 }
+#endif
 
 static void setup_port(int port) {
+    LOG(INFO) << "adbd listening on port " << port;
     local_init(port);
+#if defined(__ANDROID__)
     setup_mdns(port);
+#endif
 }
 
 int adbd_main(int server_port) {
@@ -178,10 +189,12 @@
 
     signal(SIGPIPE, SIG_IGN);
 
+#if defined(__BIONIC__)
     auto fdsan_level = android_fdsan_get_error_level();
     if (fdsan_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) {
         android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
     }
+#endif
 
     init_transport_registration();
 
@@ -206,14 +219,19 @@
           " unchanged.\n");
     }
 
+#if defined(__ANDROID__)
     drop_privileges(server_port);
+#endif
 
     bool is_usb = false;
+
+#if defined(__ANDROID__)
     if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
         // Listen on USB.
         usb_init();
         is_usb = true;
     }
+#endif
 
     // If one of these properties is set, also listen on that port.
     // If one of the properties isn't set and we couldn't listen on usb, listen
@@ -244,8 +262,10 @@
 }
 
 int main(int argc, char** argv) {
+#if defined(__BIONIC__)
     // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
     mallopt(M_DECAY_TIME, 1);
+#endif
 
     while (true) {
         static struct option opts[] = {
@@ -261,19 +281,21 @@
         }
 
         switch (c) {
-        case 's':
-            root_seclabel = optarg;
-            break;
-        case 'b':
-            adb_device_banner = optarg;
-            break;
-        case 'v':
-            printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
-                   ADB_VERSION_MINOR, ADB_SERVER_VERSION);
-            return 0;
-        default:
-            // getopt already prints "adbd: invalid option -- %c" for us.
-            return 1;
+#if defined(__ANDROID__)
+            case 's':
+                root_seclabel = optarg;
+                break;
+#endif
+            case 'b':
+                adb_device_banner = optarg;
+                break;
+            case 'v':
+                printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
+                       ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+                return 0;
+            default:
+                // getopt already prints "adbd: invalid option -- %c" for us.
+                return 1;
         }
     }
 
diff --git a/adb/daemon/reboot_service.cpp b/adb/daemon/reboot_service.cpp
new file mode 100644
index 0000000..a5a11b8
--- /dev/null
+++ b/adb/daemon/reboot_service.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG SERVICES
+
+#include "sysdeps.h"
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <bootloader_message/bootloader_message.h>
+#include <cutils/android_reboot.h>
+
+#include "adb_io.h"
+#include "adb_unique_fd.h"
+
+void reboot_service(unique_fd fd, const std::string& arg) {
+    std::string reboot_arg = arg;
+    sync();
+
+    if (reboot_arg.empty()) reboot_arg = "adb";
+    std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
+
+    if (reboot_arg == "fastboot" &&
+        android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
+        access("/dev/socket/recovery", F_OK) == 0) {
+        LOG(INFO) << "Recovery specific reboot fastboot";
+        /*
+         * The socket is created to allow switching between recovery and
+         * fastboot.
+         */
+        android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+        if (sock < 0) {
+            WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
+            PLOG(ERROR) << "Creating recovery socket failed";
+            return;
+        }
+
+        sockaddr_un addr = {.sun_family = AF_UNIX};
+        strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+        if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+            WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't connect to recovery socket";
+            return;
+        }
+        const char msg_switch_to_fastboot = 'f';
+        auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
+        if (ret != sizeof(msg_switch_to_fastboot)) {
+            WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
+            PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
+            return;
+        }
+    } else {
+        if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
+            WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
+            return;
+        }
+    }
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+    while (true) {
+        pause();
+    }
+}
diff --git a/adb/daemon/reboot_service.h b/adb/daemon/reboot_service.h
new file mode 100644
index 0000000..f68913e
--- /dev/null
+++ b/adb/daemon/reboot_service.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "adb_unique_fd.h"
+
+#if defined(__ANDROID__)
+void reboot_service(unique_fd fd, const std::string& arg);
+#endif
diff --git a/adb/daemon/remount_service.h b/adb/daemon/remount_service.h
index e4e2550..c847403 100644
--- a/adb/daemon/remount_service.h
+++ b/adb/daemon/remount_service.h
@@ -20,5 +20,7 @@
 
 #include "adb_unique_fd.h"
 
+#if defined(__ANDROID__)
 bool make_block_device_writable(const std::string&);
 void remount_service(unique_fd, const std::string&);
+#endif
diff --git a/adb/daemon/restart_service.cpp b/adb/daemon/restart_service.cpp
new file mode 100644
index 0000000..6803d93
--- /dev/null
+++ b/adb/daemon/restart_service.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 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 SERVICES
+
+#include "sysdeps.h"
+
+#include <unistd.h>
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <log/log_properties.h>
+
+#include "adb_io.h"
+#include "adb_unique_fd.h"
+
+void restart_root_service(unique_fd fd) {
+    if (getuid() == 0) {
+        WriteFdExactly(fd.get(), "adbd is already running as root\n");
+        return;
+    }
+    if (!__android_log_is_debuggable()) {
+        WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
+        return;
+    }
+
+    android::base::SetProperty("service.adb.root", "1");
+    WriteFdExactly(fd.get(), "restarting adbd as root\n");
+}
+
+void restart_unroot_service(unique_fd fd) {
+    if (getuid() != 0) {
+        WriteFdExactly(fd.get(), "adbd not running as root\n");
+        return;
+    }
+    android::base::SetProperty("service.adb.root", "0");
+    WriteFdExactly(fd.get(), "restarting adbd as non root\n");
+}
+
+void restart_tcp_service(unique_fd fd, int port) {
+    if (port <= 0) {
+        WriteFdFmt(fd.get(), "invalid port %d\n", port);
+        return;
+    }
+
+    android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
+    WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
+}
+
+void restart_usb_service(unique_fd fd) {
+    android::base::SetProperty("service.adb.tcp.port", "0");
+    WriteFdExactly(fd.get(), "restarting in USB mode\n");
+}
diff --git a/adb/daemon/restart_service.h b/adb/daemon/restart_service.h
new file mode 100644
index 0000000..19840bd
--- /dev/null
+++ b/adb/daemon/restart_service.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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"
+
+#if defined(__ANDROID__)
+void restart_root_service(unique_fd fd);
+void restart_unroot_service(unique_fd fd);
+void restart_tcp_service(unique_fd fd, int port);
+void restart_usb_service(unique_fd fd);
+#endif
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 5ae210f..d1f0345 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -39,8 +39,6 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <bootloader_message/bootloader_message.h>
-#include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <log/log_properties.h>
 
@@ -55,96 +53,12 @@
 
 #include "daemon/file_sync_service.h"
 #include "daemon/framebuffer_service.h"
+#include "daemon/reboot_service.h"
 #include "daemon/remount_service.h"
+#include "daemon/restart_service.h"
 #include "daemon/set_verity_enable_state_service.h"
 #include "daemon/shell_service.h"
 
-void restart_root_service(unique_fd fd) {
-    if (getuid() == 0) {
-        WriteFdExactly(fd.get(), "adbd is already running as root\n");
-        return;
-    }
-    if (!__android_log_is_debuggable()) {
-        WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
-        return;
-    }
-
-    android::base::SetProperty("service.adb.root", "1");
-    WriteFdExactly(fd.get(), "restarting adbd as root\n");
-}
-
-void restart_unroot_service(unique_fd fd) {
-    if (getuid() != 0) {
-        WriteFdExactly(fd.get(), "adbd not running as root\n");
-        return;
-    }
-    android::base::SetProperty("service.adb.root", "0");
-    WriteFdExactly(fd.get(), "restarting adbd as non root\n");
-}
-
-void restart_tcp_service(unique_fd fd, int port) {
-    if (port <= 0) {
-        WriteFdFmt(fd.get(), "invalid port %d\n", port);
-        return;
-    }
-
-    android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
-    WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
-}
-
-void restart_usb_service(unique_fd fd) {
-    android::base::SetProperty("service.adb.tcp.port", "0");
-    WriteFdExactly(fd.get(), "restarting in USB mode\n");
-}
-
-void reboot_service(unique_fd fd, const std::string& arg) {
-    std::string reboot_arg = arg;
-    sync();
-
-    if (reboot_arg.empty()) reboot_arg = "adb";
-    std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
-
-    if (reboot_arg == "fastboot" &&
-        android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
-        access("/dev/socket/recovery", F_OK) == 0) {
-        LOG(INFO) << "Recovery specific reboot fastboot";
-        /*
-         * The socket is created to allow switching between recovery and
-         * fastboot.
-         */
-        android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
-        if (sock < 0) {
-            WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
-            PLOG(ERROR) << "Creating recovery socket failed";
-            return;
-        }
-
-        sockaddr_un addr = {.sun_family = AF_UNIX};
-        strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
-        if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
-            WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
-            PLOG(ERROR) << "Couldn't connect to recovery socket";
-            return;
-        }
-        const char msg_switch_to_fastboot = 'f';
-        auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
-        if (ret != sizeof(msg_switch_to_fastboot)) {
-            WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
-            PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
-            return;
-        }
-    } else {
-        if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
-            WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
-            return;
-        }
-    }
-    // Don't return early. Give the reboot command time to take effect
-    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-    while (true) {
-        pause();
-    }
-}
 
 void reconnect_service(unique_fd fd, atransport* t) {
     WriteFdExactly(fd.get(), "done");
@@ -221,7 +135,8 @@
     }
 
     fdevent_run_on_main_thread([fd = pipe_read.release()]() {
-        fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr);
+        fdevent* fde = fdevent_create(
+                fd, [](int, unsigned, void*) {}, nullptr);
         fdevent_add(fde, FDE_READ);
     });
 
@@ -328,31 +243,16 @@
 }
 
 unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
-#ifndef __ANDROID_RECOVERY__
+#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
     if (name.starts_with("abb:")) {
         name.remove_prefix(strlen("abb:"));
         return execute_binder_command(name);
     }
 #endif
 
-    if (name.starts_with("dev:")) {
-        name.remove_prefix(strlen("dev:"));
-        return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
-    } else if (name.starts_with("framebuffer:")) {
+#if defined(__ANDROID__)
+    if (name.starts_with("framebuffer:")) {
         return create_service_thread("fb", framebuffer_service);
-    } else if (name.starts_with("jdwp:")) {
-        name.remove_prefix(strlen("jdwp:"));
-        std::string str(name);
-        return create_jdwp_connection_fd(atoi(str.c_str()));
-    } else if (name.starts_with("shell")) {
-        name.remove_prefix(strlen("shell"));
-        return ShellService(name, transport);
-    } else if (name.starts_with("exec:")) {
-        name.remove_prefix(strlen("exec:"));
-        return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
-                               SubprocessProtocol::kNone);
-    } else if (name.starts_with("sync:")) {
-        return create_service_thread("sync", file_sync_service);
     } else if (name.starts_with("remount:")) {
         std::string arg(name.begin() + strlen("remount:"), name.end());
         return create_service_thread("remount",
@@ -373,6 +273,12 @@
     } else if (name.starts_with("restore:")) {
         return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
                                SubprocessProtocol::kNone);
+    } else if (name.starts_with("disable-verity:")) {
+        return create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
+                                                            std::placeholders::_1, false));
+    } else if (name.starts_with("enable-verity:")) {
+        return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
+                                                             std::placeholders::_1, true));
     } else if (name.starts_with("tcpip:")) {
         name.remove_prefix(strlen("tcpip:"));
         std::string str(name);
@@ -385,15 +291,28 @@
                                      std::bind(restart_tcp_service, std::placeholders::_1, port));
     } else if (name.starts_with("usb:")) {
         return create_service_thread("usb", restart_usb_service);
+    }
+#endif
+
+    if (name.starts_with("dev:")) {
+        name.remove_prefix(strlen("dev:"));
+        return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
+    } else if (name.starts_with("jdwp:")) {
+        name.remove_prefix(strlen("jdwp:"));
+        std::string str(name);
+        return create_jdwp_connection_fd(atoi(str.c_str()));
+    } else if (name.starts_with("shell")) {
+        name.remove_prefix(strlen("shell"));
+        return ShellService(name, transport);
+    } else if (name.starts_with("exec:")) {
+        name.remove_prefix(strlen("exec:"));
+        return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
+                               SubprocessProtocol::kNone);
+    } else if (name.starts_with("sync:")) {
+        return create_service_thread("sync", file_sync_service);
     } else if (name.starts_with("reverse:")) {
         name.remove_prefix(strlen("reverse:"));
         return reverse_service(name, transport);
-    } else if (name.starts_with("disable-verity:")) {
-        return create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
-                                                            std::placeholders::_1, false));
-    } else if (name.starts_with("enable-verity:")) {
-        return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
-                                                             std::placeholders::_1, true));
     } else if (name == "reconnect") {
         return create_service_thread(
                 "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport));
diff --git a/adb/daemon/set_verity_enable_state_service.h b/adb/daemon/set_verity_enable_state_service.h
index c1413c8..c0ed98e 100644
--- a/adb/daemon/set_verity_enable_state_service.h
+++ b/adb/daemon/set_verity_enable_state_service.h
@@ -18,4 +18,6 @@
 
 #include "adb_unique_fd.h"
 
+#if defined(__ANDROID__)
 void set_verity_enabled_state_service(unique_fd fd, bool enable);
+#endif
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 455595f..0794bcd 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -98,7 +98,10 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <private/android_logger.h>
+
+#if defined(__ANDROID__)
 #include <selinux/android.h>
+#endif
 
 #include "adb.h"
 #include "adb_io.h"
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
new file mode 100644
index 0000000..e996c17
--- /dev/null
+++ b/adb/daemon/transport_qemu.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 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 qemu_pipe.h before sysdeps, since it has inlined references to open, read, write.
+#include <qemu_pipe.h>
+
+#define TRACE_TAG TRANSPORT
+#include "sysdeps.h"
+#include "transport.h"
+
+#include <android-base/properties.h>
+
+#include "adb_io.h"
+#include "adb_trace.h"
+#include "adb_unique_fd.h"
+
+/* A worker thread that monitors host connections, and registers a transport for
+ * every new host connection. This thread replaces server_socket_thread on
+ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
+ * pipe to communicate with adbd daemon inside the guest. This is done in order
+ * to provide more robust communication channel between ADB host and guest. The
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
+ * and thus is sensitive to network disruptions. For instance, the
+ * ConnectionManager may decide to reset all network connections, in which case
+ * the connection between ADB host and guest will be lost. To make ADB traffic
+ * independent from the network, we use here 'adb' QEMUD service to transfer data
+ * between the host, and the guest. See external/qemu/android/adb-*.* that
+ * implements the emulator's side of the protocol. Another advantage of using
+ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
+ * anymore on network being set up.
+ * The guest side of the protocol contains the following phases:
+ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
+ *   is opened, and it becomes clear whether or not emulator supports that
+ *   protocol.
+ * - Wait for the ADB host to create connection with the guest. This is done by
+ *   sending an 'accept' request to the adb QEMUD service, and waiting on
+ *   response.
+ * - When new ADB host connection is accepted, the connection with adb QEMUD
+ *   service is registered as the transport, and a 'start' request is sent to the
+ *   adb QEMUD service, indicating that the guest is ready to receive messages.
+ *   Note that the guest will ignore messages sent down from the emulator before
+ *   the transport registration is completed. That's why we need to send the
+ *   'start' request after the transport is registered.
+ */
+void qemu_socket_thread(int port) {
+    /* 'accept' request to the adb QEMUD service. */
+    static const char _accept_req[] = "accept";
+    /* 'start' request to the adb QEMUD service. */
+    static const char _start_req[] = "start";
+    /* 'ok' reply from the adb QEMUD service. */
+    static const char _ok_resp[] = "ok";
+
+    char tmp[256];
+    char con_name[32];
+
+    adb_thread_setname("qemu socket");
+    D("transport: qemu_socket_thread() starting");
+
+    /* adb QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
+
+    /* Connect to the adb QEMUD service. */
+    unique_fd fd(qemu_pipe_open(con_name));
+    if (fd < 0) {
+        /* This could be an older version of the emulator, that doesn't
+         * implement adb QEMUD service. Fall back to the old TCP way. */
+        D("adb service is not available. Falling back to TCP socket.");
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+        return;
+    }
+
+    while (true) {
+        /*
+         * Wait till the host creates a new connection.
+         */
+
+        /* Send the 'accept' request. */
+        if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) {
+            /* Wait for the response. In the response we expect 'ok' on success,
+             * or 'ko' on failure. */
+            if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
+                D("Accepting ADB host connection has failed.");
+            } else {
+                /* Host is connected. Register the transport, and start the
+                 * exchange. */
+                std::string serial = android::base::StringPrintf("host-%d", fd.get());
+                WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
+                register_socket_transport(std::move(fd), std::move(serial), port, 1,
+                                          [](atransport*) { return ReconnectResult::Abort; });
+            }
+
+            /* Prepare for accepting of the next ADB host connection. */
+            fd.reset(qemu_pipe_open(con_name));
+            if (fd < 0) {
+                D("adb service become unavailable.");
+                return;
+            }
+        } else {
+            D("Unable to send the '%s' request to ADB service.", _accept_req);
+            return;
+        }
+    }
+    D("transport: qemu_socket_thread() exiting");
+    return;
+}
+
+// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
+// goldfish) as the transport. This can either be explicitly set by the
+// service.adb.transport property, or be inferred from ro.kernel.qemu that is
+// set to "1" for ranchu/goldfish.
+bool use_qemu_goldfish() {
+    // Legacy way to detect if adbd should use the goldfish pipe is to check for
+    // ro.kernel.qemu, keep that behaviour for backward compatibility.
+    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+        return true;
+    }
+    // If service.adb.transport is present and is set to "goldfish", use the
+    // QEMUD pipe.
+    if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
+        return true;
+    }
+    return false;
+}
diff --git a/adb/daemon/usb_dummy.cpp b/adb/daemon/usb_dummy.cpp
new file mode 100644
index 0000000..984bc25
--- /dev/null
+++ b/adb/daemon/usb_dummy.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 <adbd/usb.h>
+
+#include <android-base/logging.h>
+
+int usb_write(usb_handle*, const void*, int) {
+    LOG(FATAL) << "unimplemented";
+    return -1;
+}
+
+int usb_read(usb_handle*, void*, int) {
+    LOG(FATAL) << "unimplemented";
+    return -1;
+}
+
+int usb_close(usb_handle*) {
+    LOG(FATAL) << "unimplemented";
+    return -1;
+}
+
+void usb_kick(usb_handle*) {
+    LOG(FATAL) << "unimplemented";
+}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index 8d853c3..24bce59 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -21,6 +21,7 @@
 #include <thread>
 
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "socket.h"
 #include "sysdeps.h"
 #include "sysdeps/chrono.h"
@@ -45,7 +46,7 @@
 
 class FdeventTest : public ::testing::Test {
   protected:
-    int dummy = -1;
+    unique_fd dummy;
 
     static void SetUpTestCase() {
 #if !defined(_WIN32)
@@ -65,12 +66,12 @@
             FAIL() << "failed to create socketpair: " << strerror(errno);
         }
 
-        asocket* dummy_socket = create_local_socket(dummy_fds[1]);
+        asocket* dummy_socket = create_local_socket(unique_fd(dummy_fds[1]));
         if (!dummy_socket) {
             FAIL() << "failed to create local socket: " << strerror(errno);
         }
         dummy_socket->ready(dummy_socket);
-        dummy = dummy_fds[0];
+        dummy.reset(dummy_fds[0]);
 
         thread_ = std::thread([]() { fdevent_loop(); });
         WaitForFdeventLoop();
@@ -85,7 +86,7 @@
         fdevent_terminate_loop();
         ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
         thread_.join();
-        ASSERT_EQ(0, adb_close(dummy));
+        dummy.reset();
     }
 
     std::thread thread_;
diff --git a/adb/services.cpp b/adb/services.cpp
index 73fed09..0061f0e 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -71,7 +71,7 @@
     return unique_fd(s[0]);
 }
 
-int service_to_fd(std::string_view name, atransport* transport) {
+unique_fd service_to_fd(std::string_view name, atransport* transport) {
     unique_fd ret;
 
     if (is_socket_spec(name)) {
@@ -86,9 +86,9 @@
     }
 
     if (ret >= 0) {
-        close_on_exec(ret);
+        close_on_exec(ret.get());
     }
-    return ret.release();
+    return ret;
 }
 
 #if ADB_HOST
@@ -99,9 +99,7 @@
     ConnectionState state;
 };
 
-static void wait_for_state(int fd, void* data) {
-    std::unique_ptr<state_info> sinfo(reinterpret_cast<state_info*>(data));
-
+static void wait_for_state(int fd, state_info* sinfo) {
     D("wait_for_state %d", sinfo->state);
 
     while (true) {
@@ -197,7 +195,7 @@
     } else if (android::base::StartsWith(name, "wait-for-")) {
         name += strlen("wait-for-");
 
-        std::unique_ptr<state_info> sinfo = std::make_unique<state_info>();
+        std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
         if (sinfo == nullptr) {
             fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
             return nullptr;
@@ -233,19 +231,15 @@
             return nullptr;
         }
 
-        int fd = create_service_thread(
-                         "wait", std::bind(wait_for_state, std::placeholders::_1, sinfo.get()))
-                         .release();
-        if (fd != -1) {
-            sinfo.release();
-        }
-        return create_local_socket(fd);
+        unique_fd fd = create_service_thread("wait", [sinfo](int fd) {
+            wait_for_state(fd, sinfo.get());
+        });
+        return create_local_socket(std::move(fd));
     } else if (!strncmp(name, "connect:", 8)) {
         std::string host(name + strlen("connect:"));
-        int fd = create_service_thread("connect",
-                                       std::bind(connect_service, std::placeholders::_1, host))
-                         .release();
-        return create_local_socket(fd);
+        unique_fd fd = create_service_thread(
+                "connect", std::bind(connect_service, std::placeholders::_1, host));
+        return create_local_socket(std::move(fd));
     }
     return nullptr;
 }
diff --git a/adb/socket.h b/adb/socket.h
index e7df991..b8c559a 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -23,6 +23,7 @@
 #include <memory>
 #include <string>
 
+#include "adb_unique_fd.h"
 #include "fdevent.h"
 #include "types.h"
 
@@ -102,7 +103,7 @@
 void remove_socket(asocket *s);
 void close_all_sockets(atransport *t);
 
-asocket *create_local_socket(int fd);
+asocket* create_local_socket(unique_fd fd);
 asocket* create_local_service_socket(std::string_view destination, atransport* transport);
 
 asocket *create_remote_socket(unsigned id, atransport *t);
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index cc67b6b..de4fff9 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -46,6 +46,11 @@
 #define ADB_WINDOWS 0
 #endif
 
+#if ADB_LINUX
+#include <sys/socket.h>
+#include "sysdeps/vm_sockets.h"
+#endif
+
 // Not static because it is used in commandline.c.
 int gListenAll = 0;
 
@@ -174,6 +179,62 @@
             return true;
         }
         return false;
+    } else if (address.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(address);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        unsigned int port_value = port ? *port : 0;
+        if (fragments.size() != 2 && fragments.size() != 3) {
+            *error = android::base::StringPrintf("expected vsock:cid or vsock:port:cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        unsigned int cid = 0;
+        if (!android::base::ParseUint(fragments[1], &cid)) {
+            *error = android::base::StringPrintf("could not parse vsock cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (fragments.size() == 3 && !android::base::ParseUint(fragments[2], &port_value)) {
+            *error = android::base::StringPrintf("could not parse vsock port in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (port_value == 0) {
+            *error = android::base::StringPrintf("vsock port was not provided.");
+            errno = EINVAL;
+            return false;
+        }
+        fd->reset(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (fd->get() == -1) {
+            *error = "could not open vsock socket";
+            return false;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port_value;
+        addr.svm_cid = cid;
+        if (serial) {
+            *serial = android::base::StringPrintf("vsock:%u:%d", cid, port_value);
+        }
+        if (connect(fd->get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not connect to vsock address '%s'",
+                                                 spec_str.c_str());
+            errno = error_num;
+            return false;
+        }
+        if (port) {
+            *port = port_value;
+        }
+        return true;
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return false;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
@@ -187,6 +248,9 @@
 
             fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
                                            SOCK_STREAM, error));
+            if (serial) {
+                *serial = address;
+            }
             return true;
         }
     }
@@ -196,7 +260,7 @@
     return false;
 }
 
-int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) {
+int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_port) {
     if (spec.starts_with("tcp:")) {
         std::string hostname;
         int port;
@@ -215,10 +279,59 @@
             return -1;
         }
 
-        if (result >= 0 && port == 0 && resolved_tcp_port) {
-            *resolved_tcp_port = adb_socket_get_local_port(result);
+        if (result >= 0 && resolved_port) {
+            *resolved_port = adb_socket_get_local_port(result);
         }
         return result;
+    } else if (spec.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(spec);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        if (fragments.size() != 2) {
+            *error = "given vsock server socket string was invalid";
+            return -1;
+        }
+        int port;
+        if (!android::base::ParseInt(fragments[1], &port)) {
+            *error = "could not parse vsock port";
+            errno = EINVAL;
+            return -1;
+        } else if (port < 0) {
+            *error = "vsock port was negative.";
+            errno = EINVAL;
+            return -1;
+        }
+        unique_fd serverfd(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (serverfd == -1) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not create vsock server: '%s'",
+                                                 strerror(error_num));
+            errno = error_num;
+            return -1;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port;
+        addr.svm_cid = VMADDR_CID_ANY;
+        socklen_t addr_len = sizeof(addr);
+        if (bind(serverfd, reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
+            return -1;
+        }
+        if (listen(serverfd, 4)) {
+            return -1;
+        }
+        if (serverfd >= 0 && resolved_port) {
+            if (getsockname(serverfd, reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
+                *resolved_port = addr.svm_port;
+            } else {
+                return -1;
+            }
+        }
+        return serverfd.release();
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return -1;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 80f9430..7908f82 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -58,7 +58,7 @@
     intermediates.resize(INTERMEDIATE_COUNT);
     ASSERT_EQ(0, adb_socketpair(first)) << strerror(errno);
     ASSERT_EQ(0, adb_socketpair(last)) << strerror(errno);
-    asocket* prev_tail = create_local_socket(first[1]);
+    asocket* prev_tail = create_local_socket(unique_fd(first[1]));
     ASSERT_NE(nullptr, prev_tail);
 
     auto connect = [](asocket* tail, asocket* head) {
@@ -70,17 +70,17 @@
     for (auto& intermediate : intermediates) {
         ASSERT_EQ(0, adb_socketpair(intermediate.data())) << strerror(errno);
 
-        asocket* head = create_local_socket(intermediate[0]);
+        asocket* head = create_local_socket(unique_fd(intermediate[0]));
         ASSERT_NE(nullptr, head);
 
-        asocket* tail = create_local_socket(intermediate[1]);
+        asocket* tail = create_local_socket(unique_fd(intermediate[1]));
         ASSERT_NE(nullptr, tail);
 
         connect(prev_tail, head);
         prev_tail = tail;
     }
 
-    asocket* end = create_local_socket(last[0]);
+    asocket* end = create_local_socket(unique_fd(last[0]));
     ASSERT_NE(nullptr, end);
     connect(prev_tail, end);
 
@@ -104,14 +104,14 @@
 }
 
 struct CloseWithPacketArg {
-    int socket_fd;
+    unique_fd socket_fd;
     size_t bytes_written;
-    int cause_close_fd;
+    unique_fd cause_close_fd;
 };
 
 static void CreateCloser(CloseWithPacketArg* arg) {
     fdevent_run_on_main_thread([arg]() {
-        asocket* s = create_local_socket(arg->socket_fd);
+        asocket* s = create_local_socket(std::move(arg->socket_fd));
         ASSERT_TRUE(s != nullptr);
         arg->bytes_written = 0;
 
@@ -135,7 +135,7 @@
         }
         ASSERT_TRUE(socket_filled);
 
-        asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
+        asocket* cause_close_s = create_local_socket(std::move(arg->cause_close_fd));
         ASSERT_TRUE(cause_close_s != nullptr);
         cause_close_s->peer = s;
         s->peer = cause_close_s;
@@ -154,8 +154,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -178,8 +178,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -211,8 +211,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -233,8 +233,8 @@
     ASSERT_EQ(0, adb_socketpair(head_fd));
     ASSERT_EQ(0, adb_socketpair(tail_fd));
 
-    asocket* head = create_local_socket(head_fd[1]);
-    asocket* tail = create_local_socket(tail_fd[1]);
+    asocket* head = create_local_socket(unique_fd(head_fd[1]));
+    asocket* tail = create_local_socket(unique_fd(tail_fd[1]));
 
     head->peer = tail;
     head->ready(head);
@@ -287,7 +287,7 @@
     PrepareThread();
 
     fdevent_run_on_main_thread([accept_fd]() {
-        asocket* s = create_local_socket(accept_fd);
+        asocket* s = create_local_socket(unique_fd(accept_fd));
         ASSERT_TRUE(s != nullptr);
     });
 
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 47ae883..5b4c51e 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -333,7 +333,8 @@
     }
 }
 
-asocket* create_local_socket(int fd) {
+asocket* create_local_socket(unique_fd ufd) {
+    int fd = ufd.release();
     asocket* s = new asocket();
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
@@ -353,13 +354,13 @@
         return s;
     }
 #endif
-    int fd = service_to_fd(name, transport);
+    unique_fd fd = service_to_fd(name, transport);
     if (fd < 0) {
         return nullptr;
     }
 
-    asocket* s = create_local_socket(fd);
-    LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd;
+    asocket* s = create_local_socket(std::move(fd));
+    LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd.get();
 
 #if !ADB_HOST
     if ((name.starts_with("root:") && getuid() != 0 && __android_log_is_debuggable()) ||
@@ -608,6 +609,14 @@
             return false;
         }
     }
+    if (command.starts_with("vsock:")) {
+        // vsock serials are vsock:cid:port, which have an extra colon compared to tcp.
+        size_t next_colon = command.find(':');
+        if (next_colon == std::string::npos) {
+            return false;
+        }
+        consume(next_colon + 1);
+    }
 
     bool found_address = false;
     if (command[0] == '[') {
diff --git a/adb/sysdeps/vm_sockets.h b/adb/sysdeps/vm_sockets.h
new file mode 100644
index 0000000..75c5f44
--- /dev/null
+++ b/adb/sysdeps/vm_sockets.h
@@ -0,0 +1,49 @@
+#if __BIONIC__
+#include <linux/vm_sockets.h>
+#else
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_VM_SOCKETS_H
+#define _UAPI_VM_SOCKETS_H
+#include <linux/socket.h>
+#define SO_VM_SOCKETS_BUFFER_SIZE 0
+#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1
+#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2
+#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3
+#define SO_VM_SOCKETS_TRUSTED 5
+#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6
+#define SO_VM_SOCKETS_NONBLOCK_TXRX 7
+#define VMADDR_CID_ANY -1U
+#define VMADDR_PORT_ANY -1U
+#define VMADDR_CID_HYPERVISOR 0
+#define VMADDR_CID_RESERVED 1
+#define VMADDR_CID_HOST 2
+#define VM_SOCKETS_INVALID_VERSION -1U
+#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24)
+#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16)
+#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF))
+struct sockaddr_vm {
+    __kernel_sa_family_t svm_family;
+    unsigned short svm_reserved1;
+    unsigned int svm_port;
+    unsigned int svm_cid;
+    unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) -
+                           sizeof(unsigned int) - sizeof(unsigned int)];
+};
+#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+#endif
+#endif
diff --git a/adb/transport.h b/adb/transport.h
index 6f53e6e..71e4857 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,6 +28,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <string_view>
 #include <thread>
 #include <unordered_set>
 
@@ -399,4 +400,14 @@
 
 asocket* create_device_tracker(bool long_output);
 
+#if !ADB_HOST
+void server_socket_thread(std::string_view spec);
+
+#if defined(__ANDROID__)
+void qemu_socket_thread(int port);
+bool use_qemu_goldfish();
+#endif
+
+#endif
+
 #endif   /* __TRANSPORT_H */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index b384085..c254d1d 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 
 #include <condition_variable>
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <thread>
@@ -74,14 +75,15 @@
     unique_fd fd;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
     std::string serial;
-    if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
+    std::string prefix_addr = address.starts_with("vsock:") ? address : "tcp:" + address;
+    if (socket_spec_connect(&fd, prefix_addr, &port, &serial, response)) {
         close_on_exec(fd);
         if (!set_tcp_keepalive(fd, 1)) {
             D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
         }
         return std::make_tuple(std::move(fd), port, serial);
     }
-    return std::make_tuple(unique_fd(), 0, "");
+    return std::make_tuple(unique_fd(), 0, serial);
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -95,6 +97,9 @@
     int port;
     std::string serial;
     std::tie(fd, port, serial) = tcp_connect(address, response);
+    if (fd.get() == -1) {
+        return;
+    }
     auto reconnect = [address](atransport* t) {
         std::string response;
         unique_fd fd;
@@ -229,18 +234,22 @@
     }
 }
 
-#else // ADB_HOST
+#else  // !ADB_HOST
 
-static void server_socket_thread(int port) {
+void server_socket_thread(std::string_view spec) {
     unique_fd serverfd;
 
     adb_thread_setname("server socket");
     D("transport: server_socket_thread() starting");
+    int port;
     while (serverfd == -1) {
-        std::string spec = android::base::StringPrintf("tcp:%d", port);
         std::string error;
-        serverfd.reset(socket_spec_listen(spec, &error));
-        if (serverfd < 0) {
+        errno = 0;
+        serverfd.reset(socket_spec_listen(spec, &error, &port));
+        if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
+            D("unrecoverable error: '%s'", error.c_str());
+            return;
+        } else if (serverfd < 0) {
             D("server: cannot bind socket yet: %s", error.c_str());
             std::this_thread::sleep_for(1s);
             continue;
@@ -249,7 +258,8 @@
     }
 
     while (true) {
-        D("server: trying to get new connection from %d", port);
+        std::string spec_str{spec};
+        D("server: trying to get new connection from %s", spec_str.c_str());
         unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr));
         if (fd >= 0) {
             D("server: new connection on fd %d", fd.get());
@@ -263,152 +273,28 @@
     D("transport: server_socket_thread() exiting");
 }
 
-/* This is relevant only for ADB daemon running inside the emulator. */
-/*
- * Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redefine them back after qemu_pipe.h inclusion.
- */
-#undef open
-#undef read
-#undef write
-#define open    adb_open
-#define read    adb_read
-#define write   adb_write
-#include <qemu_pipe.h>
-#undef open
-#undef read
-#undef write
-#define open    ___xxx_open
-#define read    ___xxx_read
-#define write   ___xxx_write
+#endif
 
-/* A worker thread that monitors host connections, and registers a transport for
- * every new host connection. This thread replaces server_socket_thread on
- * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
- * pipe to communicate with adbd daemon inside the guest. This is done in order
- * to provide more robust communication channel between ADB host and guest. The
- * main issue with server_socket_thread approach is that it runs on top of TCP,
- * and thus is sensitive to network disruptions. For instance, the
- * ConnectionManager may decide to reset all network connections, in which case
- * the connection between ADB host and guest will be lost. To make ADB traffic
- * independent from the network, we use here 'adb' QEMUD service to transfer data
- * between the host, and the guest. See external/qemu/android/adb-*.* that
- * implements the emulator's side of the protocol. Another advantage of using
- * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
- * anymore on network being set up.
- * The guest side of the protocol contains the following phases:
- * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
- *   is opened, and it becomes clear whether or not emulator supports that
- *   protocol.
- * - Wait for the ADB host to create connection with the guest. This is done by
- *   sending an 'accept' request to the adb QEMUD service, and waiting on
- *   response.
- * - When new ADB host connection is accepted, the connection with adb QEMUD
- *   service is registered as the transport, and a 'start' request is sent to the
- *   adb QEMUD service, indicating that the guest is ready to receive messages.
- *   Note that the guest will ignore messages sent down from the emulator before
- *   the transport registration is completed. That's why we need to send the
- *   'start' request after the transport is registered.
- */
-static void qemu_socket_thread(int port) {
-    /* 'accept' request to the adb QEMUD service. */
-    static const char _accept_req[] = "accept";
-    /* 'start' request to the adb QEMUD service. */
-    static const char _start_req[] = "start";
-    /* 'ok' reply from the adb QEMUD service. */
-    static const char _ok_resp[] = "ok";
-
-    char tmp[256];
-    char con_name[32];
-
-    adb_thread_setname("qemu socket");
-    D("transport: qemu_socket_thread() starting");
-
-    /* adb QEMUD service connection request. */
-    snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
-
-    /* Connect to the adb QEMUD service. */
-    unique_fd fd(qemu_pipe_open(con_name));
-    if (fd < 0) {
-        /* This could be an older version of the emulator, that doesn't
-         * implement adb QEMUD service. Fall back to the old TCP way. */
-        D("adb service is not available. Falling back to TCP socket.");
-        std::thread(server_socket_thread, port).detach();
-        return;
-    }
-
-    while (true) {
-        /*
-         * Wait till the host creates a new connection.
-         */
-
-        /* Send the 'accept' request. */
-        if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) {
-            /* Wait for the response. In the response we expect 'ok' on success,
-             * or 'ko' on failure. */
-            if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
-                D("Accepting ADB host connection has failed.");
-            } else {
-                /* Host is connected. Register the transport, and start the
-                 * exchange. */
-                std::string serial = android::base::StringPrintf("host-%d", fd.get());
-                WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
-                register_socket_transport(std::move(fd), std::move(serial), port, 1,
-                                          [](atransport*) { return ReconnectResult::Abort; });
-            }
-
-            /* Prepare for accepting of the next ADB host connection. */
-            fd.reset(qemu_pipe_open(con_name));
-            if (fd < 0) {
-                D("adb service become unavailable.");
-                return;
-            }
-        } else {
-            D("Unable to send the '%s' request to ADB service.", _accept_req);
-            return;
-        }
-    }
-    D("transport: qemu_socket_thread() exiting");
-    return;
-}
-
-// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
-// goldfish) as the transport. This can either be explicitly set by the
-// service.adb.transport property, or be inferred from ro.kernel.qemu that is
-// set to "1" for ranchu/goldfish.
-static bool use_qemu_goldfish() {
-    // Legacy way to detect if adbd should use the goldfish pipe is to check for
-    // ro.kernel.qemu, keep that behaviour for backward compatibility.
-    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
-        return true;
-    }
-    // If service.adb.transport is present and is set to "goldfish", use the
-    // QEMUD pipe.
-    if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
-        return true;
-    }
-    return false;
-}
-
-#endif  // !ADB_HOST
-
-void local_init(int port)
-{
-    void (*func)(int);
-    const char* debug_name = "";
-
+void local_init(int port) {
 #if ADB_HOST
-    func = client_socket_thread;
-    debug_name = "client";
+    D("transport: local client init");
+    std::thread(client_socket_thread, port).detach();
+#elif !defined(__ANDROID__)
+    // Host adbd.
+    D("transport: local server init");
+    std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #else
+    D("transport: local server init");
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
-    debug_name = "server";
+    if (use_qemu_goldfish()) {
+        std::thread(qemu_socket_thread, port).detach();
+    } else {
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    }
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #endif // !ADB_HOST
-
-    D("transport: local %s init", debug_name);
-    std::thread(func, port).detach();
 }
 
 #if ADB_HOST
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 9d4f280..aeab893 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -686,6 +686,7 @@
     userdata.fs_mgr_flags.logical = true;
     userdata.fs_mgr_flags.quota = true;
     userdata.fs_mgr_flags.late_mount = true;
+    userdata.fs_mgr_flags.formattable = true;
     fstab->emplace_back(userdata);
 }
 
@@ -719,10 +720,10 @@
 }
 
 // Returns fstab entries parsed from the device tree if they exist
-bool ReadFstabFromDt(Fstab* fstab) {
+bool ReadFstabFromDt(Fstab* fstab, bool log) {
     std::string fstab_buf = read_fstab_from_dt();
     if (fstab_buf.empty()) {
-        LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
+        if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
         return false;
     }
 
@@ -730,13 +731,15 @@
         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
                  fstab_buf.length(), "r"), fclose);
     if (!fstab_file) {
-        PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+        if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
         return false;
     }
 
     if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
-        LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
-               << std::endl << fstab_buf;
+        if (log) {
+            LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
+                   << fstab_buf;
+        }
         return false;
     }
 
@@ -778,7 +781,7 @@
 // Loads the fstab file and combines with fstab entries passed in from device tree.
 bool ReadDefaultFstab(Fstab* fstab) {
     Fstab dt_fstab;
-    ReadFstabFromDt(&dt_fstab);
+    ReadFstabFromDt(&dt_fstab, false);
 
     *fstab = std::move(dt_fstab);
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 38f96c0..9c4d2da 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -192,7 +192,7 @@
 using Fstab = std::vector<FstabEntry>;
 
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
-bool ReadFstabFromDt(Fstab* fstab);
+bool ReadFstabFromDt(Fstab* fstab, bool log = true);
 bool ReadDefaultFstab(Fstab* fstab);
 
 // Temporary conversion functions.
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 110d56e..c39fbe7 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -838,9 +838,10 @@
                << block_device.size << ")";
         return false;
     }
-    if (device_info.logical_block_size != geometry_.logical_block_size) {
-        LERROR << "Device logical block size does not match (got " << device_info.logical_block_size
-               << ", expected " << geometry_.logical_block_size << ")";
+    if (geometry_.logical_block_size % device_info.logical_block_size) {
+        LERROR << "Device logical block size is misaligned (block size="
+               << device_info.logical_block_size << ", alignment=" << geometry_.logical_block_size
+               << ")";
         return false;
     }
 
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 7d615a3..8f08169 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -495,6 +495,11 @@
     EXPECT_EQ(new_info.size, 1024 * 1024);
 
     new_info.logical_block_size = 512;
+    ASSERT_TRUE(builder->UpdateBlockDeviceInfo("super", new_info));
+    ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
+    EXPECT_EQ(new_info.logical_block_size, 4096);
+
+    new_info.logical_block_size = 7;
     ASSERT_FALSE(builder->UpdateBlockDeviceInfo("super", new_info));
     ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
     EXPECT_EQ(new_info.logical_block_size, 4096);
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 1922a69..4582401 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -138,38 +138,32 @@
 }
 
 TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
-    auto fstab = fs_mgr_read_fstab("/proc/mounts");
-    ASSERT_NE(fstab, nullptr);
+    Fstab fstab;
+    ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab));
 
     std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "re"),
                                                            endmntent);
     ASSERT_NE(mounts, nullptr);
 
     mntent* mentry;
-    int i = 0;
+    size_t i = 0;
     while ((mentry = getmntent(mounts.get())) != nullptr) {
-        ASSERT_LT(i, fstab->num_entries);
-        auto fsrec = &fstab->recs[i];
+        ASSERT_LT(i, fstab.size());
+        auto& entry = fstab[i];
 
-        std::string mnt_fsname(mentry->mnt_fsname ?: "nullptr");
-        std::string blk_device(fsrec->blk_device ?: "nullptr");
-        EXPECT_EQ(mnt_fsname, blk_device);
-
-        std::string mnt_dir(mentry->mnt_dir ?: "nullptr");
-        std::string mount_point(fsrec->mount_point ?: "nullptr");
-        EXPECT_EQ(mnt_dir, mount_point);
-
-        std::string mnt_type(mentry->mnt_type ?: "nullptr");
-        std::string fs_type(fsrec->fs_type ?: "nullptr");
-        EXPECT_EQ(mnt_type, fs_type);
+        EXPECT_EQ(mentry->mnt_fsname, entry.blk_device);
+        EXPECT_EQ(mentry->mnt_dir, entry.mount_point);
+        EXPECT_EQ(mentry->mnt_type, entry.fs_type);
 
         std::set<std::string> mnt_opts;
-        for (auto& s : android::base::Split(mentry->mnt_opts ?: "nullptr", ",")) {
+        for (auto& s : android::base::Split(mentry->mnt_opts, ",")) {
             mnt_opts.emplace(s);
         }
         std::set<std::string> fs_options;
-        for (auto& s : android::base::Split(fsrec->fs_options ?: "nullptr", ",")) {
-            fs_options.emplace(s);
+        if (!entry.fs_options.empty()) {
+            for (auto& s : android::base::Split(entry.fs_options, ",")) {
+                fs_options.emplace(s);
+            }
         }
         // matches private content in fs_mgr_fstab.c
         static struct flag_list {
@@ -194,14 +188,17 @@
                 {0, 0},
         };
         for (auto f = 0; mount_flags[f].name; ++f) {
-            if (mount_flags[f].flag & fsrec->flags) {
+            if (mount_flags[f].flag & entry.flags) {
                 fs_options.emplace(mount_flags[f].name);
             }
         }
-        if (!(fsrec->flags & MS_RDONLY)) fs_options.emplace("rw");
+        if (!(entry.flags & MS_RDONLY)) {
+            fs_options.emplace("rw");
+        }
         EXPECT_EQ(mnt_opts, fs_options);
         ++i;
     }
+    EXPECT_EQ(i, fstab.size());
 }
 
 TEST(fs_mgr, ReadFstabFromFile_FsOptions) {
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 80bf84a..2127b96 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -109,6 +109,7 @@
     libbase \
     libutils \
     libcutils \
+    libprocessgroup \
     liblog \
     libm \
     libc \
diff --git a/init/selinux.cpp b/init/selinux.cpp
index d93e9ec..ee302c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -34,16 +34,18 @@
 // identical to the system image shipped on a vendor's device.
 
 // The split SEPolicy is loaded as described below:
-// 1) There is a precompiled SEPolicy located at /vendor/etc/selinux/precompiled_sepolicy.
-//    Stored along with this file is the sha256 hash of the parts of the SEPolicy on /system that
-//    were used to compile this precompiled policy.  The system partition contains a similar sha256
-//    of the parts of the SEPolicy that it currently contains.  If these two hashes match, then the
-//    system loads this precompiled_sepolicy directly.
-// 2) If these hashes do not match, then /system has been updated out of sync with /vendor and the
-//    init needs to compile the SEPolicy.  /system contains the SEPolicy compiler, secilc, and it
-//    is used by the LoadSplitPolicy() function below to compile the SEPolicy to a temp directory
-//    and load it.  That function contains even more documentation with the specific implementation
-//    details of how the SEPolicy is compiled if needed.
+// 1) There is a precompiled SEPolicy located at either /vendor/etc/selinux/precompiled_sepolicy or
+//    /odm/etc/selinux/precompiled_sepolicy if odm parition is present.  Stored along with this file
+//    are the sha256 hashes of the parts of the SEPolicy on /system and /product that were used to
+//    compile this precompiled policy.  The system partition contains a similar sha256 of the parts
+//    of the SEPolicy that it currently contains.  Symmetrically, product paritition contains a
+//    sha256 of its SEPolicy.  System loads this precompiled_sepolicy directly if and only if hashes
+//    for system policy match and hashes for product policy match.
+// 2) If these hashes do not match, then either /system or /product (or both) have been updated out
+//    of sync with /vendor and the init needs to compile the SEPolicy.  /system contains the
+//    SEPolicy compiler, secilc, and it is used by the LoadSplitPolicy() function below to compile
+//    the SEPolicy to a temp directory and load it.  That function contains even more documentation
+//    with the specific implementation details of how the SEPolicy is compiled if needed.
 
 #include "selinux.h"
 
@@ -217,20 +219,35 @@
         return false;
     }
     std::string actual_plat_id;
-    if (!ReadFirstLine("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256", &actual_plat_id)) {
+    if (!ReadFirstLine("/system/etc/selinux/plat_sepolicy_and_mapping.sha256", &actual_plat_id)) {
         PLOG(INFO) << "Failed to read "
-                      "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
+                      "/system/etc/selinux/plat_sepolicy_and_mapping.sha256";
+        return false;
+    }
+    std::string actual_product_id;
+    if (!ReadFirstLine("/product/etc/selinux/product_sepolicy_and_mapping.sha256",
+                       &actual_product_id)) {
+        PLOG(INFO) << "Failed to read "
+                      "/product/etc/selinux/product_sepolicy_and_mapping.sha256";
         return false;
     }
 
     std::string precompiled_plat_id;
-    std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256";
-    if (!ReadFirstLine(precompiled_sha256.c_str(), &precompiled_plat_id)) {
-        PLOG(INFO) << "Failed to read " << precompiled_sha256;
+    std::string precompiled_plat_sha256 = *file + ".plat_sepolicy_and_mapping.sha256";
+    if (!ReadFirstLine(precompiled_plat_sha256.c_str(), &precompiled_plat_id)) {
+        PLOG(INFO) << "Failed to read " << precompiled_plat_sha256;
         file->clear();
         return false;
     }
-    if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
+    std::string precompiled_product_id;
+    std::string precompiled_product_sha256 = *file + ".product_sepolicy_and_mapping.sha256";
+    if (!ReadFirstLine(precompiled_product_sha256.c_str(), &precompiled_product_id)) {
+        PLOG(INFO) << "Failed to read " << precompiled_product_sha256;
+        file->clear();
+        return false;
+    }
+    if (actual_plat_id.empty() || actual_plat_id != precompiled_plat_id ||
+        actual_product_id.empty() || actual_product_id != precompiled_product_id) {
         file->clear();
         return false;
     }
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 4291212..0dbbc3f 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -66,7 +66,6 @@
         "load_file.cpp",
         "native_handle.cpp",
         "record_stream.cpp",
-        "sched_policy.cpp",
         "sockets.cpp",
         "strdup16to8.cpp",
         "strdup8to16.cpp",
@@ -178,8 +177,12 @@
         "libbase_headers",
         "libcutils_headers",
         "libutils_headers",
+        "libprocessgroup_headers",
     ],
-    export_header_lib_headers: ["libcutils_headers"],
+    export_header_lib_headers: [
+        "libcutils_headers",
+        "libprocessgroup_headers",
+    ],
     local_include_dirs: ["include"],
 
     cflags: [
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index cf91b76..538ff6b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -17,67 +17,10 @@
 #ifndef __CUTILS_SCHED_POLICY_H
 #define __CUTILS_SCHED_POLICY_H
 
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
- * Check if Linux kernel enables CPUSETS feature.
- *
- * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ * For backwards compatibility only
+ * New users should include processgroup/sched_policy.h directly
  */
-extern bool cpusets_enabled();
-
-/*
- * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
- * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
- *
- * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
- */
-extern bool schedboost_enabled();
-
-/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
-typedef enum {
-    SP_DEFAULT = -1,
-    SP_BACKGROUND = 0,
-    SP_FOREGROUND = 1,
-    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
-    SP_AUDIO_APP = 3,
-    SP_AUDIO_SYS = 4,
-    SP_TOP_APP = 5,
-    SP_RT_APP = 6,
-    SP_RESTRICTED = 7,
-    SP_CNT,
-    SP_MAX = SP_CNT - 1,
-    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
-} SchedPolicy;
-
-extern int set_cpuset_policy(int tid, SchedPolicy policy);
-
-/* Assign thread tid to the cgroup associated with the specified policy.
- * If the thread is a thread group leader, that is it's gettid() == getpid(),
- * then the other threads in the same thread group are _not_ affected.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -errno for error.
- */
-extern int set_sched_policy(int tid, SchedPolicy policy);
-
-/* Return the policy associated with the cgroup of thread tid via policy pointer.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -1 for error and set errno.
- */
-extern int get_sched_policy(int tid, SchedPolicy *policy);
-
-/* Return a displayable string corresponding to policy.
- * Return value: non-NULL NUL-terminated name of unspecified length;
- * the caller is responsible for displaying the useful part of the string.
- */
-extern const char *get_sched_policy_name(SchedPolicy policy);
-
-#ifdef __cplusplus
-}
-#endif
+#include <processgroup/sched_policy.h>
 
 #endif /* __CUTILS_SCHED_POLICY_H */ 
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 7884190..72ae559 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -59,6 +59,7 @@
     "libcutils",
     "liblog",
     "libbase",
+    "libprocessgroup",
 ]
 
 cc_test {
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c38279d..d04a79a 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,10 +1,45 @@
+cc_library_headers {
+    name: "libprocessgroup_headers",
+    vendor_available: true,
+    recovery_available: true,
+    host_supported: true,
+    export_include_dirs: ["include"],
+    target: {
+        linux_bionic: {
+            enabled: true,
+        },
+        windows: {
+            enabled: true,
+        },
+    },
+}
+
 cc_library {
-    srcs: ["processgroup.cpp"],
+    srcs: [
+        "processgroup.cpp",
+        "sched_policy.cpp",
+    ],
     name: "libprocessgroup",
     host_supported: true,
     recovery_available: true,
-    shared_libs: ["libbase"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    // for cutils/android_filesystem_config.h
+    header_libs: [
+        "libcutils_headers",
+        "libprocessgroup_headers",
+    ],
     export_include_dirs: ["include"],
+    export_header_lib_headers: [
+        "libprocessgroup_headers",
+    ],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
new file mode 100644
index 0000000..79a32fd
--- /dev/null
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Check if Linux kernel enables CPUSETS feature.
+ *
+ * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ */
+extern bool cpusets_enabled();
+
+/*
+ * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
+ * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
+ *
+ * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
+ */
+extern bool schedboost_enabled();
+
+/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
+typedef enum {
+    SP_DEFAULT = -1,
+    SP_BACKGROUND = 0,
+    SP_FOREGROUND = 1,
+    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
+    SP_AUDIO_APP = 3,
+    SP_AUDIO_SYS = 4,
+    SP_TOP_APP = 5,
+    SP_RT_APP = 6,
+    SP_RESTRICTED = 7,
+    SP_CNT,
+    SP_MAX = SP_CNT - 1,
+    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
+} SchedPolicy;
+
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
+/* Assign thread tid to the cgroup associated with the specified policy.
+ * If the thread is a thread group leader, that is it's gettid() == getpid(),
+ * then the other threads in the same thread group are _not_ affected.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -errno for error.
+ */
+extern int set_sched_policy(int tid, SchedPolicy policy);
+
+/* Return the policy associated with the cgroup of thread tid via policy pointer.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -1 for error and set errno.
+ */
+extern int get_sched_policy(int tid, SchedPolicy *policy);
+
+/* Return a displayable string corresponding to policy.
+ * Return value: non-NULL NUL-terminated name of unspecified length;
+ * the caller is responsible for displaying the useful part of the string.
+ */
+extern const char *get_sched_policy_name(SchedPolicy policy);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9df8dd9..8d2ac3d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -42,7 +42,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <private/android_filesystem_config.h>
+#include <cutils/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
diff --git a/libcutils/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
similarity index 99%
rename from libcutils/sched_policy.cpp
rename to libprocessgroup/sched_policy.cpp
index 3fa548f..f95d7e4 100644
--- a/libcutils/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -14,7 +14,7 @@
 ** limitations under the License.
 */
 
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
 
 #define LOG_TAG "SchedPolicy"
 
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 8ad339f..2ec4754 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -67,3 +67,18 @@
 
     cflags: ["-Werror"],
 }
+
+python_binary_host {
+    name: "simg_dump.py",
+    main: "simg_dump.py",
+    srcs: ["simg_dump.py"],
+    version: {
+        py2: {
+            embedded_launcher: true,
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
deleted file mode 100644
index 05e68bc..0000000
--- a/libsparse/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := simg_dump.py
-LOCAL_SRC_FILES := simg_dump.py
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS := -Werror
-include $(BUILD_PREBUILT)
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 5bc60b9..393eb3e 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -32,8 +32,1451 @@
 
 namespace unwindstack {
 
+enum DwarfOpHandleFunc : uint8_t {
+  OP_ILLEGAL = 0,
+  OP_DEREF,
+  OP_DEREF_SIZE,
+  OP_PUSH,
+  OP_DUP,
+  OP_DROP,
+  OP_OVER,
+  OP_PICK,
+  OP_SWAP,
+  OP_ROT,
+  OP_ABS,
+  OP_AND,
+  OP_DIV,
+  OP_MINUS,
+  OP_MOD,
+  OP_MUL,
+  OP_NEG,
+  OP_NOT,
+  OP_OR,
+  OP_PLUS,
+  OP_PLUS_UCONST,
+  OP_SHL,
+  OP_SHR,
+  OP_SHRA,
+  OP_XOR,
+  OP_BRA,
+  OP_EQ,
+  OP_GE,
+  OP_GT,
+  OP_LE,
+  OP_LT,
+  OP_NE,
+  OP_SKIP,
+  OP_LIT,
+  OP_REG,
+  OP_REGX,
+  OP_BREG,
+  OP_BREGX,
+  OP_NOP,
+  OP_NOT_IMPLEMENTED,
+};
+
+struct OpCallback {
+  // It may seem tempting to "clean this up" by replacing "const char[26]" with
+  // "const char*", but doing so would place the entire callback table in
+  // .data.rel.ro section, instead of .rodata section, and thus increase
+  // dirty memory usage.  Libunwindstack is used by the linker and therefore
+  // loaded for every running process, so every bit of memory counts.
+  // Unlike C standard, C++ standard guarantees this array is big enough to
+  // store the names, or else we would get a compilation error.
+  const char name[26];
+
+  // Similarily for this field, we do NOT want to directly store function
+  // pointers here. Not only would that cause the callback table to be placed
+  // in .data.rel.ro section, but it would be duplicated for each AddressType.
+  // Instead, we use DwarfOpHandleFunc enum to decouple the callback table from
+  // the function pointers.
+  DwarfOpHandleFunc handle_func;
+
+  uint8_t num_required_stack_values;
+  uint8_t num_operands;
+  uint8_t operands[2];
+};
+
+constexpr static OpCallback kCallbackTable[256] = {
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x00 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x01 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x02 illegal op
+    {
+        // 0x03 DW_OP_addr
+        "DW_OP_addr",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_absptr},
+    },
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x04 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x05 illegal op
+    {
+        // 0x06 DW_OP_deref
+        "DW_OP_deref",
+        OP_DEREF,
+        1,
+        0,
+        {},
+    },
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0x07 illegal op
+    {
+        // 0x08 DW_OP_const1u
+        "DW_OP_const1u",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_udata1},
+    },
+    {
+        // 0x09 DW_OP_const1s
+        "DW_OP_const1s",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_sdata1},
+    },
+    {
+        // 0x0a DW_OP_const2u
+        "DW_OP_const2u",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_udata2},
+    },
+    {
+        // 0x0b DW_OP_const2s
+        "DW_OP_const2s",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_sdata2},
+    },
+    {
+        // 0x0c DW_OP_const4u
+        "DW_OP_const4u",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_udata4},
+    },
+    {
+        // 0x0d DW_OP_const4s
+        "DW_OP_const4s",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_sdata4},
+    },
+    {
+        // 0x0e DW_OP_const8u
+        "DW_OP_const8u",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_udata8},
+    },
+    {
+        // 0x0f DW_OP_const8s
+        "DW_OP_const8s",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_sdata8},
+    },
+    {
+        // 0x10 DW_OP_constu
+        "DW_OP_constu",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_uleb128},
+    },
+    {
+        // 0x11 DW_OP_consts
+        "DW_OP_consts",
+        OP_PUSH,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x12 DW_OP_dup
+        "DW_OP_dup",
+        OP_DUP,
+        1,
+        0,
+        {},
+    },
+    {
+        // 0x13 DW_OP_drop
+        "DW_OP_drop",
+        OP_DROP,
+        1,
+        0,
+        {},
+    },
+    {
+        // 0x14 DW_OP_over
+        "DW_OP_over",
+        OP_OVER,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x15 DW_OP_pick
+        "DW_OP_pick",
+        OP_PICK,
+        0,
+        1,
+        {DW_EH_PE_udata1},
+    },
+    {
+        // 0x16 DW_OP_swap
+        "DW_OP_swap",
+        OP_SWAP,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x17 DW_OP_rot
+        "DW_OP_rot",
+        OP_ROT,
+        3,
+        0,
+        {},
+    },
+    {
+        // 0x18 DW_OP_xderef
+        "DW_OP_xderef",
+        OP_NOT_IMPLEMENTED,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x19 DW_OP_abs
+        "DW_OP_abs",
+        OP_ABS,
+        1,
+        0,
+        {},
+    },
+    {
+        // 0x1a DW_OP_and
+        "DW_OP_and",
+        OP_AND,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x1b DW_OP_div
+        "DW_OP_div",
+        OP_DIV,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x1c DW_OP_minus
+        "DW_OP_minus",
+        OP_MINUS,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x1d DW_OP_mod
+        "DW_OP_mod",
+        OP_MOD,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x1e DW_OP_mul
+        "DW_OP_mul",
+        OP_MUL,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x1f DW_OP_neg
+        "DW_OP_neg",
+        OP_NEG,
+        1,
+        0,
+        {},
+    },
+    {
+        // 0x20 DW_OP_not
+        "DW_OP_not",
+        OP_NOT,
+        1,
+        0,
+        {},
+    },
+    {
+        // 0x21 DW_OP_or
+        "DW_OP_or",
+        OP_OR,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x22 DW_OP_plus
+        "DW_OP_plus",
+        OP_PLUS,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x23 DW_OP_plus_uconst
+        "DW_OP_plus_uconst",
+        OP_PLUS_UCONST,
+        1,
+        1,
+        {DW_EH_PE_uleb128},
+    },
+    {
+        // 0x24 DW_OP_shl
+        "DW_OP_shl",
+        OP_SHL,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x25 DW_OP_shr
+        "DW_OP_shr",
+        OP_SHR,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x26 DW_OP_shra
+        "DW_OP_shra",
+        OP_SHRA,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x27 DW_OP_xor
+        "DW_OP_xor",
+        OP_XOR,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x28 DW_OP_bra
+        "DW_OP_bra",
+        OP_BRA,
+        1,
+        1,
+        {DW_EH_PE_sdata2},
+    },
+    {
+        // 0x29 DW_OP_eq
+        "DW_OP_eq",
+        OP_EQ,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2a DW_OP_ge
+        "DW_OP_ge",
+        OP_GE,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2b DW_OP_gt
+        "DW_OP_gt",
+        OP_GT,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2c DW_OP_le
+        "DW_OP_le",
+        OP_LE,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2d DW_OP_lt
+        "DW_OP_lt",
+        OP_LT,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2e DW_OP_ne
+        "DW_OP_ne",
+        OP_NE,
+        2,
+        0,
+        {},
+    },
+    {
+        // 0x2f DW_OP_skip
+        "DW_OP_skip",
+        OP_SKIP,
+        0,
+        1,
+        {DW_EH_PE_sdata2},
+    },
+    {
+        // 0x30 DW_OP_lit0
+        "DW_OP_lit0",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x31 DW_OP_lit1
+        "DW_OP_lit1",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x32 DW_OP_lit2
+        "DW_OP_lit2",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x33 DW_OP_lit3
+        "DW_OP_lit3",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x34 DW_OP_lit4
+        "DW_OP_lit4",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x35 DW_OP_lit5
+        "DW_OP_lit5",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x36 DW_OP_lit6
+        "DW_OP_lit6",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x37 DW_OP_lit7
+        "DW_OP_lit7",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x38 DW_OP_lit8
+        "DW_OP_lit8",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x39 DW_OP_lit9
+        "DW_OP_lit9",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3a DW_OP_lit10
+        "DW_OP_lit10",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3b DW_OP_lit11
+        "DW_OP_lit11",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3c DW_OP_lit12
+        "DW_OP_lit12",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3d DW_OP_lit13
+        "DW_OP_lit13",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3e DW_OP_lit14
+        "DW_OP_lit14",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x3f DW_OP_lit15
+        "DW_OP_lit15",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x40 DW_OP_lit16
+        "DW_OP_lit16",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x41 DW_OP_lit17
+        "DW_OP_lit17",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x42 DW_OP_lit18
+        "DW_OP_lit18",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x43 DW_OP_lit19
+        "DW_OP_lit19",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x44 DW_OP_lit20
+        "DW_OP_lit20",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x45 DW_OP_lit21
+        "DW_OP_lit21",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x46 DW_OP_lit22
+        "DW_OP_lit22",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x47 DW_OP_lit23
+        "DW_OP_lit23",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x48 DW_OP_lit24
+        "DW_OP_lit24",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x49 DW_OP_lit25
+        "DW_OP_lit25",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4a DW_OP_lit26
+        "DW_OP_lit26",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4b DW_OP_lit27
+        "DW_OP_lit27",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4c DW_OP_lit28
+        "DW_OP_lit28",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4d DW_OP_lit29
+        "DW_OP_lit29",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4e DW_OP_lit30
+        "DW_OP_lit30",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x4f DW_OP_lit31
+        "DW_OP_lit31",
+        OP_LIT,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x50 DW_OP_reg0
+        "DW_OP_reg0",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x51 DW_OP_reg1
+        "DW_OP_reg1",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x52 DW_OP_reg2
+        "DW_OP_reg2",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x53 DW_OP_reg3
+        "DW_OP_reg3",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x54 DW_OP_reg4
+        "DW_OP_reg4",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x55 DW_OP_reg5
+        "DW_OP_reg5",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x56 DW_OP_reg6
+        "DW_OP_reg6",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x57 DW_OP_reg7
+        "DW_OP_reg7",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x58 DW_OP_reg8
+        "DW_OP_reg8",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x59 DW_OP_reg9
+        "DW_OP_reg9",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5a DW_OP_reg10
+        "DW_OP_reg10",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5b DW_OP_reg11
+        "DW_OP_reg11",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5c DW_OP_reg12
+        "DW_OP_reg12",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5d DW_OP_reg13
+        "DW_OP_reg13",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5e DW_OP_reg14
+        "DW_OP_reg14",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x5f DW_OP_reg15
+        "DW_OP_reg15",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x60 DW_OP_reg16
+        "DW_OP_reg16",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x61 DW_OP_reg17
+        "DW_OP_reg17",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x62 DW_OP_reg18
+        "DW_OP_reg18",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x63 DW_OP_reg19
+        "DW_OP_reg19",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x64 DW_OP_reg20
+        "DW_OP_reg20",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x65 DW_OP_reg21
+        "DW_OP_reg21",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x66 DW_OP_reg22
+        "DW_OP_reg22",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x67 DW_OP_reg23
+        "DW_OP_reg23",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x68 DW_OP_reg24
+        "DW_OP_reg24",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x69 DW_OP_reg25
+        "DW_OP_reg25",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6a DW_OP_reg26
+        "DW_OP_reg26",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6b DW_OP_reg27
+        "DW_OP_reg27",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6c DW_OP_reg28
+        "DW_OP_reg28",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6d DW_OP_reg29
+        "DW_OP_reg29",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6e DW_OP_reg30
+        "DW_OP_reg30",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x6f DW_OP_reg31
+        "DW_OP_reg31",
+        OP_REG,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x70 DW_OP_breg0
+        "DW_OP_breg0",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x71 DW_OP_breg1
+        "DW_OP_breg1",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x72 DW_OP_breg2
+        "DW_OP_breg2",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x73 DW_OP_breg3
+        "DW_OP_breg3",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x74 DW_OP_breg4
+        "DW_OP_breg4",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x75 DW_OP_breg5
+        "DW_OP_breg5",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x76 DW_OP_breg6
+        "DW_OP_breg6",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x77 DW_OP_breg7
+        "DW_OP_breg7",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x78 DW_OP_breg8
+        "DW_OP_breg8",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x79 DW_OP_breg9
+        "DW_OP_breg9",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7a DW_OP_breg10
+        "DW_OP_breg10",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7b DW_OP_breg11
+        "DW_OP_breg11",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7c DW_OP_breg12
+        "DW_OP_breg12",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7d DW_OP_breg13
+        "DW_OP_breg13",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7e DW_OP_breg14
+        "DW_OP_breg14",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x7f DW_OP_breg15
+        "DW_OP_breg15",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x80 DW_OP_breg16
+        "DW_OP_breg16",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x81 DW_OP_breg17
+        "DW_OP_breg17",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x82 DW_OP_breg18
+        "DW_OP_breg18",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x83 DW_OP_breg19
+        "DW_OP_breg19",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x84 DW_OP_breg20
+        "DW_OP_breg20",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x85 DW_OP_breg21
+        "DW_OP_breg21",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x86 DW_OP_breg22
+        "DW_OP_breg22",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x87 DW_OP_breg23
+        "DW_OP_breg23",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x88 DW_OP_breg24
+        "DW_OP_breg24",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x89 DW_OP_breg25
+        "DW_OP_breg25",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8a DW_OP_breg26
+        "DW_OP_breg26",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8b DW_OP_breg27
+        "DW_OP_breg27",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8c DW_OP_breg28
+        "DW_OP_breg28",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8d DW_OP_breg29
+        "DW_OP_breg29",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8e DW_OP_breg30
+        "DW_OP_breg30",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x8f DW_OP_breg31
+        "DW_OP_breg31",
+        OP_BREG,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x90 DW_OP_regx
+        "DW_OP_regx",
+        OP_REGX,
+        0,
+        1,
+        {DW_EH_PE_uleb128},
+    },
+    {
+        // 0x91 DW_OP_fbreg
+        "DW_OP_fbreg",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_sleb128},
+    },
+    {
+        // 0x92 DW_OP_bregx
+        "DW_OP_bregx",
+        OP_BREGX,
+        0,
+        2,
+        {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
+    },
+    {
+        // 0x93 DW_OP_piece
+        "DW_OP_piece",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_uleb128},
+    },
+    {
+        // 0x94 DW_OP_deref_size
+        "DW_OP_deref_size",
+        OP_DEREF_SIZE,
+        1,
+        1,
+        {DW_EH_PE_udata1},
+    },
+    {
+        // 0x95 DW_OP_xderef_size
+        "DW_OP_xderef_size",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_udata1},
+    },
+    {
+        // 0x96 DW_OP_nop
+        "DW_OP_nop",
+        OP_NOP,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x97 DW_OP_push_object_address
+        "DW_OP_push_object_address",
+        OP_NOT_IMPLEMENTED,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x98 DW_OP_call2
+        "DW_OP_call2",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_udata2},
+    },
+    {
+        // 0x99 DW_OP_call4
+        "DW_OP_call4",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_udata4},
+    },
+    {
+        // 0x9a DW_OP_call_ref
+        "DW_OP_call_ref",
+        OP_NOT_IMPLEMENTED,
+        0,
+        0,  // Has a different sized operand (4 bytes or 8 bytes).
+        {},
+    },
+    {
+        // 0x9b DW_OP_form_tls_address
+        "DW_OP_form_tls_address",
+        OP_NOT_IMPLEMENTED,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x9c DW_OP_call_frame_cfa
+        "DW_OP_call_frame_cfa",
+        OP_NOT_IMPLEMENTED,
+        0,
+        0,
+        {},
+    },
+    {
+        // 0x9d DW_OP_bit_piece
+        "DW_OP_bit_piece",
+        OP_NOT_IMPLEMENTED,
+        0,
+        2,
+        {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
+    },
+    {
+        // 0x9e DW_OP_implicit_value
+        "DW_OP_implicit_value",
+        OP_NOT_IMPLEMENTED,
+        0,
+        1,
+        {DW_EH_PE_uleb128},
+    },
+    {
+        // 0x9f DW_OP_stack_value
+        "DW_OP_stack_value",
+        OP_NOT_IMPLEMENTED,
+        1,
+        0,
+        {},
+    },
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa0 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xa9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xaa illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xab illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xac illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xad illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xae illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xaf illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb0 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xb9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xba illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xbb illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xbc illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xbd illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xbe illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xbf illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc0 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xc9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xca illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xcb illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xcc illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xcd illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xce illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xcf illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd0 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xd9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xda illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xdb illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xdc illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xdd illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xde illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xdf illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe0 DW_OP_lo_user
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xe9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xea illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xeb illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xec illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xed illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xee illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xef illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf0 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf1 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf2 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf3 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf4 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf5 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf6 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf7 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf8 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xf9 illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xfa illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xfb illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xfc illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xfd illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xfe illegal op
+    {"", OP_ILLEGAL, 0, 0, {}},  // 0xff DW_OP_hi_user
+};
+
 template <typename AddressType>
-constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
+const typename DwarfOp<AddressType>::OpHandleFuncPtr DwarfOp<AddressType>::kOpHandleFuncList[] = {
+    [OP_ILLEGAL] = nullptr,
+    [OP_DEREF] = &DwarfOp<AddressType>::op_deref,
+    [OP_DEREF_SIZE] = &DwarfOp<AddressType>::op_deref_size,
+    [OP_PUSH] = &DwarfOp<AddressType>::op_push,
+    [OP_DUP] = &DwarfOp<AddressType>::op_dup,
+    [OP_DROP] = &DwarfOp<AddressType>::op_drop,
+    [OP_OVER] = &DwarfOp<AddressType>::op_over,
+    [OP_PICK] = &DwarfOp<AddressType>::op_pick,
+    [OP_SWAP] = &DwarfOp<AddressType>::op_swap,
+    [OP_ROT] = &DwarfOp<AddressType>::op_rot,
+    [OP_ABS] = &DwarfOp<AddressType>::op_abs,
+    [OP_AND] = &DwarfOp<AddressType>::op_and,
+    [OP_DIV] = &DwarfOp<AddressType>::op_div,
+    [OP_MINUS] = &DwarfOp<AddressType>::op_minus,
+    [OP_MOD] = &DwarfOp<AddressType>::op_mod,
+    [OP_MUL] = &DwarfOp<AddressType>::op_mul,
+    [OP_NEG] = &DwarfOp<AddressType>::op_neg,
+    [OP_NOT] = &DwarfOp<AddressType>::op_not,
+    [OP_OR] = &DwarfOp<AddressType>::op_or,
+    [OP_PLUS] = &DwarfOp<AddressType>::op_plus,
+    [OP_PLUS_UCONST] = &DwarfOp<AddressType>::op_plus_uconst,
+    [OP_SHL] = &DwarfOp<AddressType>::op_shl,
+    [OP_SHR] = &DwarfOp<AddressType>::op_shr,
+    [OP_SHRA] = &DwarfOp<AddressType>::op_shra,
+    [OP_XOR] = &DwarfOp<AddressType>::op_xor,
+    [OP_BRA] = &DwarfOp<AddressType>::op_bra,
+    [OP_EQ] = &DwarfOp<AddressType>::op_eq,
+    [OP_GE] = &DwarfOp<AddressType>::op_ge,
+    [OP_GT] = &DwarfOp<AddressType>::op_gt,
+    [OP_LE] = &DwarfOp<AddressType>::op_le,
+    [OP_LT] = &DwarfOp<AddressType>::op_lt,
+    [OP_NE] = &DwarfOp<AddressType>::op_ne,
+    [OP_SKIP] = &DwarfOp<AddressType>::op_skip,
+    [OP_LIT] = &DwarfOp<AddressType>::op_lit,
+    [OP_REG] = &DwarfOp<AddressType>::op_reg,
+    [OP_REGX] = &DwarfOp<AddressType>::op_regx,
+    [OP_BREG] = &DwarfOp<AddressType>::op_breg,
+    [OP_BREGX] = &DwarfOp<AddressType>::op_bregx,
+    [OP_NOP] = &DwarfOp<AddressType>::op_nop,
+    [OP_NOT_IMPLEMENTED] = &DwarfOp<AddressType>::op_not_implemented,
+};
 
 template <typename AddressType>
 bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end) {
@@ -97,12 +1540,13 @@
   }
 
   const auto* op = &kCallbackTable[cur_op_];
-  const auto handle_func = op->handle_func;
-  if (handle_func == nullptr) {
+  if (op->handle_func == OP_ILLEGAL) {
     last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
 
+  const auto handle_func = kOpHandleFuncList[op->handle_func];
+
   // Make sure that the required number of stack elements is available.
   if (stack_.size() < op->num_required_stack_values) {
     last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
@@ -135,7 +1579,7 @@
     std::string raw_string(android::base::StringPrintf("Raw Data: 0x%02x", cur_op));
     std::string log_string;
     const auto* op = &kCallbackTable[cur_op];
-    if (op->handle_func == nullptr) {
+    if (op->handle_func == OP_ILLEGAL) {
       log_string = "Illegal";
     } else {
       log_string = op->name;
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 4c69b3d..ac9fd2d 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -42,14 +42,6 @@
   // Signed version of AddressType
   typedef typename std::make_signed<AddressType>::type SignedType;
 
-  struct OpCallback {
-    const char* name;
-    bool (DwarfOp::*handle_func)();
-    uint8_t num_required_stack_values;
-    uint8_t num_operands;
-    uint8_t operands[2];
-  };
-
  public:
   DwarfOp(DwarfMemory* memory, Memory* regular_memory)
       : memory_(memory), regular_memory_(regular_memory) {}
@@ -143,1342 +135,8 @@
   bool op_nop();
   bool op_not_implemented();
 
-  constexpr static OpCallback kCallbackTable[256] = {
-      {nullptr, nullptr, 0, 0, {}},  // 0x00 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0x01 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0x02 illegal op
-      {
-          // 0x03 DW_OP_addr
-          "DW_OP_addr",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_absptr},
-      },
-      {nullptr, nullptr, 0, 0, {}},  // 0x04 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0x05 illegal op
-      {
-          // 0x06 DW_OP_deref
-          "DW_OP_deref",
-          &DwarfOp::op_deref,
-          1,
-          0,
-          {},
-      },
-      {nullptr, nullptr, 0, 0, {}},  // 0x07 illegal op
-      {
-          // 0x08 DW_OP_const1u
-          "DW_OP_const1u",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_udata1},
-      },
-      {
-          // 0x09 DW_OP_const1s
-          "DW_OP_const1s",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_sdata1},
-      },
-      {
-          // 0x0a DW_OP_const2u
-          "DW_OP_const2u",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_udata2},
-      },
-      {
-          // 0x0b DW_OP_const2s
-          "DW_OP_const2s",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_sdata2},
-      },
-      {
-          // 0x0c DW_OP_const4u
-          "DW_OP_const4u",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_udata4},
-      },
-      {
-          // 0x0d DW_OP_const4s
-          "DW_OP_const4s",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_sdata4},
-      },
-      {
-          // 0x0e DW_OP_const8u
-          "DW_OP_const8u",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_udata8},
-      },
-      {
-          // 0x0f DW_OP_const8s
-          "DW_OP_const8s",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_sdata8},
-      },
-      {
-          // 0x10 DW_OP_constu
-          "DW_OP_constu",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_uleb128},
-      },
-      {
-          // 0x11 DW_OP_consts
-          "DW_OP_consts",
-          &DwarfOp::op_push,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x12 DW_OP_dup
-          "DW_OP_dup",
-          &DwarfOp::op_dup,
-          1,
-          0,
-          {},
-      },
-      {
-          // 0x13 DW_OP_drop
-          "DW_OP_drop",
-          &DwarfOp::op_drop,
-          1,
-          0,
-          {},
-      },
-      {
-          // 0x14 DW_OP_over
-          "DW_OP_over",
-          &DwarfOp::op_over,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x15 DW_OP_pick
-          "DW_OP_pick",
-          &DwarfOp::op_pick,
-          0,
-          1,
-          {DW_EH_PE_udata1},
-      },
-      {
-          // 0x16 DW_OP_swap
-          "DW_OP_swap",
-          &DwarfOp::op_swap,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x17 DW_OP_rot
-          "DW_OP_rot",
-          &DwarfOp::op_rot,
-          3,
-          0,
-          {},
-      },
-      {
-          // 0x18 DW_OP_xderef
-          "DW_OP_xderef",
-          &DwarfOp::op_not_implemented,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x19 DW_OP_abs
-          "DW_OP_abs",
-          &DwarfOp::op_abs,
-          1,
-          0,
-          {},
-      },
-      {
-          // 0x1a DW_OP_and
-          "DW_OP_and",
-          &DwarfOp::op_and,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x1b DW_OP_div
-          "DW_OP_div",
-          &DwarfOp::op_div,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x1c DW_OP_minus
-          "DW_OP_minus",
-          &DwarfOp::op_minus,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x1d DW_OP_mod
-          "DW_OP_mod",
-          &DwarfOp::op_mod,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x1e DW_OP_mul
-          "DW_OP_mul",
-          &DwarfOp::op_mul,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x1f DW_OP_neg
-          "DW_OP_neg",
-          &DwarfOp::op_neg,
-          1,
-          0,
-          {},
-      },
-      {
-          // 0x20 DW_OP_not
-          "DW_OP_not",
-          &DwarfOp::op_not,
-          1,
-          0,
-          {},
-      },
-      {
-          // 0x21 DW_OP_or
-          "DW_OP_or",
-          &DwarfOp::op_or,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x22 DW_OP_plus
-          "DW_OP_plus",
-          &DwarfOp::op_plus,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x23 DW_OP_plus_uconst
-          "DW_OP_plus_uconst",
-          &DwarfOp::op_plus_uconst,
-          1,
-          1,
-          {DW_EH_PE_uleb128},
-      },
-      {
-          // 0x24 DW_OP_shl
-          "DW_OP_shl",
-          &DwarfOp::op_shl,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x25 DW_OP_shr
-          "DW_OP_shr",
-          &DwarfOp::op_shr,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x26 DW_OP_shra
-          "DW_OP_shra",
-          &DwarfOp::op_shra,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x27 DW_OP_xor
-          "DW_OP_xor",
-          &DwarfOp::op_xor,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x28 DW_OP_bra
-          "DW_OP_bra",
-          &DwarfOp::op_bra,
-          1,
-          1,
-          {DW_EH_PE_sdata2},
-      },
-      {
-          // 0x29 DW_OP_eq
-          "DW_OP_eq",
-          &DwarfOp::op_eq,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2a DW_OP_ge
-          "DW_OP_ge",
-          &DwarfOp::op_ge,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2b DW_OP_gt
-          "DW_OP_gt",
-          &DwarfOp::op_gt,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2c DW_OP_le
-          "DW_OP_le",
-          &DwarfOp::op_le,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2d DW_OP_lt
-          "DW_OP_lt",
-          &DwarfOp::op_lt,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2e DW_OP_ne
-          "DW_OP_ne",
-          &DwarfOp::op_ne,
-          2,
-          0,
-          {},
-      },
-      {
-          // 0x2f DW_OP_skip
-          "DW_OP_skip",
-          &DwarfOp::op_skip,
-          0,
-          1,
-          {DW_EH_PE_sdata2},
-      },
-      {
-          // 0x30 DW_OP_lit0
-          "DW_OP_lit0",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x31 DW_OP_lit1
-          "DW_OP_lit1",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x32 DW_OP_lit2
-          "DW_OP_lit2",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x33 DW_OP_lit3
-          "DW_OP_lit3",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x34 DW_OP_lit4
-          "DW_OP_lit4",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x35 DW_OP_lit5
-          "DW_OP_lit5",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x36 DW_OP_lit6
-          "DW_OP_lit6",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x37 DW_OP_lit7
-          "DW_OP_lit7",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x38 DW_OP_lit8
-          "DW_OP_lit8",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x39 DW_OP_lit9
-          "DW_OP_lit9",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3a DW_OP_lit10
-          "DW_OP_lit10",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3b DW_OP_lit11
-          "DW_OP_lit11",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3c DW_OP_lit12
-          "DW_OP_lit12",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3d DW_OP_lit13
-          "DW_OP_lit13",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3e DW_OP_lit14
-          "DW_OP_lit14",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x3f DW_OP_lit15
-          "DW_OP_lit15",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x40 DW_OP_lit16
-          "DW_OP_lit16",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x41 DW_OP_lit17
-          "DW_OP_lit17",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x42 DW_OP_lit18
-          "DW_OP_lit18",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x43 DW_OP_lit19
-          "DW_OP_lit19",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x44 DW_OP_lit20
-          "DW_OP_lit20",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x45 DW_OP_lit21
-          "DW_OP_lit21",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x46 DW_OP_lit22
-          "DW_OP_lit22",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x47 DW_OP_lit23
-          "DW_OP_lit23",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x48 DW_OP_lit24
-          "DW_OP_lit24",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x49 DW_OP_lit25
-          "DW_OP_lit25",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4a DW_OP_lit26
-          "DW_OP_lit26",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4b DW_OP_lit27
-          "DW_OP_lit27",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4c DW_OP_lit28
-          "DW_OP_lit28",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4d DW_OP_lit29
-          "DW_OP_lit29",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4e DW_OP_lit30
-          "DW_OP_lit30",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x4f DW_OP_lit31
-          "DW_OP_lit31",
-          &DwarfOp::op_lit,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x50 DW_OP_reg0
-          "DW_OP_reg0",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x51 DW_OP_reg1
-          "DW_OP_reg1",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x52 DW_OP_reg2
-          "DW_OP_reg2",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x53 DW_OP_reg3
-          "DW_OP_reg3",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x54 DW_OP_reg4
-          "DW_OP_reg4",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x55 DW_OP_reg5
-          "DW_OP_reg5",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x56 DW_OP_reg6
-          "DW_OP_reg6",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x57 DW_OP_reg7
-          "DW_OP_reg7",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x58 DW_OP_reg8
-          "DW_OP_reg8",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x59 DW_OP_reg9
-          "DW_OP_reg9",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5a DW_OP_reg10
-          "DW_OP_reg10",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5b DW_OP_reg11
-          "DW_OP_reg11",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5c DW_OP_reg12
-          "DW_OP_reg12",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5d DW_OP_reg13
-          "DW_OP_reg13",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5e DW_OP_reg14
-          "DW_OP_reg14",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x5f DW_OP_reg15
-          "DW_OP_reg15",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x60 DW_OP_reg16
-          "DW_OP_reg16",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x61 DW_OP_reg17
-          "DW_OP_reg17",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x62 DW_OP_reg18
-          "DW_OP_reg18",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x63 DW_OP_reg19
-          "DW_OP_reg19",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x64 DW_OP_reg20
-          "DW_OP_reg20",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x65 DW_OP_reg21
-          "DW_OP_reg21",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x66 DW_OP_reg22
-          "DW_OP_reg22",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x67 DW_OP_reg23
-          "DW_OP_reg23",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x68 DW_OP_reg24
-          "DW_OP_reg24",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x69 DW_OP_reg25
-          "DW_OP_reg25",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6a DW_OP_reg26
-          "DW_OP_reg26",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6b DW_OP_reg27
-          "DW_OP_reg27",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6c DW_OP_reg28
-          "DW_OP_reg28",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6d DW_OP_reg29
-          "DW_OP_reg29",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6e DW_OP_reg30
-          "DW_OP_reg30",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x6f DW_OP_reg31
-          "DW_OP_reg31",
-          &DwarfOp::op_reg,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x70 DW_OP_breg0
-          "DW_OP_breg0",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x71 DW_OP_breg1
-          "DW_OP_breg1",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x72 DW_OP_breg2
-          "DW_OP_breg2",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x73 DW_OP_breg3
-          "DW_OP_breg3",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x74 DW_OP_breg4
-          "DW_OP_breg4",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x75 DW_OP_breg5
-          "DW_OP_breg5",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x76 DW_OP_breg6
-          "DW_OP_breg6",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x77 DW_OP_breg7
-          "DW_OP_breg7",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x78 DW_OP_breg8
-          "DW_OP_breg8",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x79 DW_OP_breg9
-          "DW_OP_breg9",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7a DW_OP_breg10
-          "DW_OP_breg10",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7b DW_OP_breg11
-          "DW_OP_breg11",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7c DW_OP_breg12
-          "DW_OP_breg12",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7d DW_OP_breg13
-          "DW_OP_breg13",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7e DW_OP_breg14
-          "DW_OP_breg14",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x7f DW_OP_breg15
-          "DW_OP_breg15",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x80 DW_OP_breg16
-          "DW_OP_breg16",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x81 DW_OP_breg17
-          "DW_OP_breg17",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x82 DW_OP_breg18
-          "DW_OP_breg18",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x83 DW_OP_breg19
-          "DW_OP_breg19",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x84 DW_OP_breg20
-          "DW_OP_breg20",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x85 DW_OP_breg21
-          "DW_OP_breg21",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x86 DW_OP_breg22
-          "DW_OP_breg22",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x87 DW_OP_breg23
-          "DW_OP_breg23",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x88 DW_OP_breg24
-          "DW_OP_breg24",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x89 DW_OP_breg25
-          "DW_OP_breg25",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8a DW_OP_breg26
-          "DW_OP_breg26",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8b DW_OP_breg27
-          "DW_OP_breg27",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8c DW_OP_breg28
-          "DW_OP_breg28",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8d DW_OP_breg29
-          "DW_OP_breg29",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8e DW_OP_breg30
-          "DW_OP_breg30",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x8f DW_OP_breg31
-          "DW_OP_breg31",
-          &DwarfOp::op_breg,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x90 DW_OP_regx
-          "DW_OP_regx",
-          &DwarfOp::op_regx,
-          0,
-          1,
-          {DW_EH_PE_uleb128},
-      },
-      {
-          // 0x91 DW_OP_fbreg
-          "DW_OP_fbreg",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_sleb128},
-      },
-      {
-          // 0x92 DW_OP_bregx
-          "DW_OP_bregx",
-          &DwarfOp::op_bregx,
-          0,
-          2,
-          {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
-      },
-      {
-          // 0x93 DW_OP_piece
-          "DW_OP_piece",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_uleb128},
-      },
-      {
-          // 0x94 DW_OP_deref_size
-          "DW_OP_deref_size",
-          &DwarfOp::op_deref_size,
-          1,
-          1,
-          {DW_EH_PE_udata1},
-      },
-      {
-          // 0x95 DW_OP_xderef_size
-          "DW_OP_xderef_size",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_udata1},
-      },
-      {
-          // 0x96 DW_OP_nop
-          "DW_OP_nop",
-          &DwarfOp::op_nop,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x97 DW_OP_push_object_address
-          "DW_OP_push_object_address",
-          &DwarfOp::op_not_implemented,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x98 DW_OP_call2
-          "DW_OP_call2",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_udata2},
-      },
-      {
-          // 0x99 DW_OP_call4
-          "DW_OP_call4",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_udata4},
-      },
-      {
-          // 0x9a DW_OP_call_ref
-          "DW_OP_call_ref",
-          &DwarfOp::op_not_implemented,
-          0,
-          0,  // Has a different sized operand (4 bytes or 8 bytes).
-          {},
-      },
-      {
-          // 0x9b DW_OP_form_tls_address
-          "DW_OP_form_tls_address",
-          &DwarfOp::op_not_implemented,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x9c DW_OP_call_frame_cfa
-          "DW_OP_call_frame_cfa",
-          &DwarfOp::op_not_implemented,
-          0,
-          0,
-          {},
-      },
-      {
-          // 0x9d DW_OP_bit_piece
-          "DW_OP_bit_piece",
-          &DwarfOp::op_not_implemented,
-          0,
-          2,
-          {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
-      },
-      {
-          // 0x9e DW_OP_implicit_value
-          "DW_OP_implicit_value",
-          &DwarfOp::op_not_implemented,
-          0,
-          1,
-          {DW_EH_PE_uleb128},
-      },
-      {
-          // 0x9f DW_OP_stack_value
-          "DW_OP_stack_value",
-          &DwarfOp::op_not_implemented,
-          1,
-          0,
-          {},
-      },
-      {nullptr, nullptr, 0, 0, {}},  // 0xa0 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xa9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xaa illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xab illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xac illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xad illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xae illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xaf illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb0 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xb9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xba illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xbb illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xbc illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xbd illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xbe illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xbf illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc0 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xc9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xca illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xcb illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xcc illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xcd illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xce illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xcf illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd0 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xd9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xda illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xdb illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xdc illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xdd illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xde illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xdf illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe0 DW_OP_lo_user
-      {nullptr, nullptr, 0, 0, {}},  // 0xe1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xe9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xea illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xeb illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xec illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xed illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xee illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xef illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf0 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf1 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf2 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf3 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf4 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf5 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf6 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf7 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf8 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xf9 illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xfa illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xfb illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xfc illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xfd illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xfe illegal op
-      {nullptr, nullptr, 0, 0, {}},  // 0xff DW_OP_hi_user
-  };
+  using OpHandleFuncPtr = bool (DwarfOp::*)();
+  static const OpHandleFuncPtr kOpHandleFuncList[];
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 0dd95cf..2734cf8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -247,7 +247,7 @@
         // or the pc in the first frame is in a valid map.
         // This allows for a case where the code jumps into the middle of
         // nowhere, but there is no other unwind information after that.
-        if (frames_.size() != 2 || maps_->Find(frames_[0].pc) != nullptr) {
+        if (frames_.size() > 2 || (frames_.size() > 0 && maps_->Find(frames_[0].pc) != nullptr)) {
           // Remove the speculative frame.
           frames_.pop_back();
         }
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 49aeeb3..d88531f 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -749,6 +749,23 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+// Verify that a speculative frame does not cause a crash when it wasn't
+// really added due to a filter.
+TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) {
+  regs_.set_pc(0x23000);
+  regs_.set_sp(0x10000);
+  regs_.FakeSetReturnAddress(0x23100);
+  regs_.FakeSetReturnAddressValid(true);
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+
+  std::vector<std::string> skip_names{"libanother.so"};
+  unwinder.Unwind(&skip_names);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(0U, unwinder.NumFrames());
+}
+
 // Verify that an unwind stops when a frame is in given suffix.
 TEST_F(UnwinderTest, map_ignore_suffixes) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3e8417e..fb7ca32 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,11 +22,13 @@
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
+        "libprocessgroup_headers",
     ],
     export_header_lib_headers: [
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
+        "libprocessgroup_headers",
     ],
     export_include_dirs: ["include"],
 
@@ -82,6 +84,7 @@
 
             shared_libs: [
                 "libcutils",
+                "libprocessgroup",
                 "libdl",
                 "libvndksupport",
             ],
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 64bc402..31ca138 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -36,7 +36,7 @@
 
 #include <utils/Log.h>
 
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
 
 #if defined(__ANDROID__)
 # define __android_unused
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 5f0a51f..24a745a 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -275,25 +275,6 @@
   return ss-s;
 }
 
-
-char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
-{
-  char16_t *q = dst;
-  const char16_t *p = src;
-  char ch;
-
-  while (n) {
-    n--;
-    *q++ = ch = *p++;
-    if ( !ch )
-      break;
-  }
-
-  *q = 0;
-
-  return dst;
-}
-
 size_t strnlen16(const char16_t *s, size_t maxlen)
 {
   const char16_t *ss = s;
diff --git a/libutils/include/utils/Unicode.h b/libutils/include/utils/Unicode.h
index 61a1b4f..a2aaa47 100644
--- a/libutils/include/utils/Unicode.h
+++ b/libutils/include/utils/Unicode.h
@@ -28,7 +28,6 @@
 size_t strlen16(const char16_t *);
 size_t strnlen16(const char16_t *, size_t);
 char16_t *strcpy16(char16_t *, const char16_t *);
-char16_t *strncpy16(char16_t *, const char16_t *, size_t);
 char16_t *strstr16(const char16_t*, const char16_t*);
 
 // Version of comparison that supports embedded NULs.
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 903d0e2..f9ed57c 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -5,6 +5,7 @@
     shared_libs: [
         "libcutils",
         "liblog",
+        "libprocessgroup",
     ],
     static_libs: [
         "libstatslogc",
diff --git a/logcat/Android.bp b/logcat/Android.bp
index 0543aba..5030b15 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -24,8 +24,8 @@
     ],
     shared_libs: [
         "libbase",
-        "libcutils",
         "libpcrecpp",
+        "libprocessgroup",
     ],
     static_libs: ["liblog"],
     logtags: ["event.logtags"],
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 87bc6ae..15e07fe 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -49,11 +49,11 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <log/logprint.h>
 #include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
 #include <system/thread_defs.h>
 
 #include <pcrecpp.h>
diff --git a/logd/Android.bp b/logd/Android.bp
index 3abfc21..360f2fe 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -73,8 +73,16 @@
         "libcutils",
         "libbase",
         "libpackagelistparser",
+        "libprocessgroup",
         "libcap",
     ],
 
     cflags: ["-Werror"],
 }
+
+
+prebuilt_etc {
+    name: "logtagd.rc",
+    src: "logtagd.rc",
+    sub_dir: "init",
+}
diff --git a/logd/Android.mk b/logd/Android.mk
deleted file mode 100644
index aafa28d..0000000
--- a/logd/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logtagd.rc
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
-
-include $(BUILD_PREBUILT)
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 470ffed..a21555c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -111,7 +111,7 @@
 }
 
 std::map<std::string, std::string> LogAudit::populateDenialMap() {
-    std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
+    std::ifstream bug_file("/vendor/etc/selinux/selinux_denial_metadata");
     std::string line;
     // allocate a map for the static map pointer in auditParse to keep track of,
     // this function only runs once
diff --git a/logd/main.cpp b/logd/main.cpp
index 8c38d9a..fd3cdf8 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,12 +38,12 @@
 #include <android-base/macros.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
-#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
diff --git a/mkbootimg/mkbootimg.py b/mkbootimg/mkbootimg.py
index 859b1e4..92b11a5 100644
--- a/mkbootimg/mkbootimg.py
+++ b/mkbootimg/mkbootimg.py
@@ -62,7 +62,13 @@
 
 
 def write_header(args):
+    BOOT_IMAGE_HEADER_V1_SIZE = 1648
+    BOOT_IMAGE_HEADER_V2_SIZE = 1660
     BOOT_MAGIC = 'ANDROID!'.encode()
+
+    if (args.header_version > 2):
+        raise ValueError('Boot header version %d not supported' % args.header_version)
+
     args.output.write(pack('8s', BOOT_MAGIC))
     args.output.write(pack('10I',
         filesize(args.kernel),                          # size in bytes
@@ -99,8 +105,12 @@
             args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
         else:
             args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
-        args.output.write(pack('I', args.output.tell() + 4))         # size of boot header
 
+    # Populate boot image header size for header versions 1 and 2.
+    if args.header_version == 1:
+        args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
+    elif args.header_version == 2:
+        args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
 
     if args.header_version > 1:
         args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 1871ca7..5a6f41b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -24,6 +24,26 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
 
+# Start of runtime APEX compatibility.
+#
+# Meta-comment:
+# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
+# entries need to be associated with something that goes into /system.
+# init-debug.rc qualifies but it could be anything else in /system until soong
+# supports creation of symlinks. http://b/123333111
+#
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# End of runtime APEX compatibilty.
+
 include $(BUILD_PREBUILT)
 
 #######################################
@@ -129,19 +149,6 @@
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
 
-# Start of runtime APEX compatibility.
-# Keeping the appearance of files/dirs having old locations for apps that have
-# come to rely on them.
-
-# http://b/121248172 - create a link from /system/usr/icu to
-# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
-# A symlink can't overwrite a directory and the /system/usr/icu directory once
-# existed so the required structure must be created whatever we find.
-LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
-LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
-
-# End of runtime APEX compatibilty.
-
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 461184a..83eb3b6 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -32,6 +32,73 @@
 namespace.default.asan.search.paths +=           /odm/${LIB}
 
 ###############################################################################
+# APEX related namespaces.
+###############################################################################
+
+additional.namespaces = runtime,conscrypt,media
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime
+namespace.default.asan.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
+namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = default
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only one default namespace is defined and it has no directories other than
 # /system/lib and /product/lib in the search paths. This is because linker
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 54e7c7e..05f75bf 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -148,6 +148,7 @@
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 ###############################################################################
@@ -329,6 +330,9 @@
 # partition (VNDK and LLNDK libraries) are not loaded here but from the
 # separate namespace 'system'. The delegation to the system namespace is done
 # via the 'namespace.default.link.system.shared_libs' property below.
+#
+# '#VNDK27#' TAG is only for building ld.config.27.txt for backward
+# compatibility. (TODO:b/123390078) Move them to a separate file.
 ###############################################################################
 namespace.default.isolated = true
 namespace.default.visible = true
@@ -338,11 +342,17 @@
 
 namespace.default.permitted.paths  = /odm
 namespace.default.permitted.paths += /vendor
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
 
 namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.default.asan.search.paths +=           /odm/${LIB}
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/egl
+#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/egl
 
 namespace.default.asan.permitted.paths  = /data/asan/odm
 namespace.default.asan.permitted.paths +=           /odm
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 39f69ca..335369e 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -97,6 +97,7 @@
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 ###############################################################################
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 537bf86..d081666 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -47,7 +47,7 @@
 
     # Mix device-specific information into the entropy pool
     copy /proc/cmdline /dev/urandom
-    copy /default.prop /dev/urandom
+    copy /system/etc/prop.default /dev/urandom
 
     symlink /proc/self/fd/0 /dev/stdin
     symlink /proc/self/fd/1 /dev/stdout
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 79bed7b..450be66 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -88,6 +88,7 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
 $(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
 $(LOCAL_BUILT_MODULE): PRIVATE_COMP_CHECK_SCRIPT := $(compatibility_check_script)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_TAG := \#VNDK$(vndk_version)\#
 deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
   $(vndkprivate_libraries_file)
 ifeq ($(check_backward_compatibility),true)
@@ -114,10 +115,12 @@
 	paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
 	sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
 
-	$(hide) sed -i.bak -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
-	$(hide) sed -i.bak -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@
-	$(hide) sed -i.bak -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@
-	$(hide) sed -i.bak -e 's?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g' $@
+	$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
+	$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
+	$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
+	$(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
+	$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
+	$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
 	$(hide) rm -f $@.bak
 
 ld_config_template :=