Merge "adb: get libusb compiling on Windows."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 304ce4e..e2e9577 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -60,4 +60,14 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/vendor)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libtrusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libtrusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/keystore.trusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/keystore.trusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.trusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.trusty.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/secure-storage-unit-test)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/storageproxyd)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/tipc-test)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/trusty_keymaster_tipc)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/root)
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/adb/OWNERS b/adb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/adb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 2e999ee..b15d28a 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -305,6 +305,7 @@
         handle->devpath = devpath;
         usb_handle* handle_p = handle.get();
         VLOG(USB) << "Add usb device " << serial;
+        LOG(INFO) << "reported max packet size for " << serial << " is " << handle->max_packet_size;
         AddDevice(std::move(handle));
         register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(),
                                1);
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index 253d14a..49e0363 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -93,21 +93,9 @@
 /* Helper function to get A/B suffix, if any. If the device isn't
  * using A/B the empty string is returned. Otherwise either "_a",
  * "_b", ... is returned.
- *
- * Note that since sometime in O androidboot.slot_suffix is deprecated
- * and androidboot.slot should be used instead. Since bootloaders may
- * be out of sync with the OS, we check both and for extra safety
- * prepend a leading underscore if there isn't one already.
  */
 static std::string get_ab_suffix() {
-    std::string ab_suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
-    if (ab_suffix == "") {
-        ab_suffix = android::base::GetProperty("ro.boot.slot", "");
-    }
-    if (ab_suffix.size() > 0 && ab_suffix[0] != '_') {
-        ab_suffix = std::string("_") + ab_suffix;
-    }
-    return ab_suffix;
+    return android::base::GetProperty("ro.boot.slot_suffix", "");
 }
 
 /* Use AVB to turn verity on/off */
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 895f922..c3ac344 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -27,11 +27,18 @@
 
 #if ADB_HOST
 
+#if defined(__APPLE__)
+#define CHECK_PACKET_OVERFLOW 0
+#else
+#define CHECK_PACKET_OVERFLOW 1
+#endif
+
 // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
 // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
 static int UsbReadMessage(usb_handle* h, amessage* msg) {
     D("UsbReadMessage");
 
+#if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
     CHECK_GE(usb_packet_size, sizeof(*msg));
     CHECK_LT(usb_packet_size, 4096ULL);
@@ -44,6 +51,9 @@
     }
     memcpy(msg, buffer, sizeof(*msg));
     return n;
+#else
+    return usb_read(h, msg, sizeof(*msg));
+#endif
 }
 
 // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
@@ -51,6 +61,7 @@
 static int UsbReadPayload(usb_handle* h, apacket* p) {
     D("UsbReadPayload(%d)", p->msg.data_length);
 
+#if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
     CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
 
@@ -64,6 +75,9 @@
     }
     CHECK_LE(len, sizeof(p->data));
     return usb_read(h, &p->data, len);
+#else
+    return usb_read(h, &p->data, p->msg.data_length);
+#endif
 }
 
 static int remote_read(apacket* p, atransport* t) {
diff --git a/adf/OWNERS b/adf/OWNERS
new file mode 100644
index 0000000..72b8b5a
--- /dev/null
+++ b/adf/OWNERS
@@ -0,0 +1,2 @@
+ghackmann@google.com
+marissaw@google.com
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
index c276c53..8eef2ea 100644
--- a/adf/libadf/Android.bp
+++ b/adf/libadf/Android.bp
@@ -12,8 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_static {
+cc_library {
     name: "libadf",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     srcs: ["adf.cpp"],
     cflags: ["-Werror"],
     local_include_dirs: ["include"],
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..97777f7
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,3 @@
+enh@google.com
+jmgao@google.com
+tomcherry@google.com
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 07a5edd..4cfa06b 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -24,6 +24,7 @@
 class TemporaryFile {
  public:
   TemporaryFile();
+  explicit TemporaryFile(const std::string& tmp_dir);
   ~TemporaryFile();
 
   // Release the ownership of fd, caller is reponsible for closing the
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 1cfa9e6..9d8dfb2 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -84,6 +84,10 @@
   init(GetSystemTempDir());
 }
 
+TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
+  init(tmp_dir);
+}
+
 TemporaryFile::~TemporaryFile() {
   if (fd != -1) {
     close(fd);
diff --git a/bootstat/OWNERS b/bootstat/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/bootstat/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/debuggerd/OWNERS b/debuggerd/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/debuggerd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/demangle/OWNERS b/demangle/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/demangle/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e0f702d..10ef356 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs sload_f2fs
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -79,6 +79,7 @@
 my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
 my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
 my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 ifdef HOST_CROSS_OS
 # Archive fastboot.exe for win_sdk build.
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
new file mode 100644
index 0000000..2d12d50
--- /dev/null
+++ b/fastboot/OWNERS
@@ -0,0 +1,3 @@
+dpursell@google.com
+enh@google.com
+jmgao@google.com
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9949eae..a1e1677 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -28,7 +28,7 @@
 using android::base::unique_fd;
 
 #ifdef WIN32
-static int exec_e2fs_cmd(const char* /*path*/, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
     std::string cmd;
     int i = 0;
     while (argv[i] != nullptr) {
@@ -76,10 +76,14 @@
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
 
-    return exit_code != 0;
+    if (exit_code != 0) {
+        fprintf(stderr, "%s failed: %lu\n", path, exit_code);
+        return -1;
+    }
+    return 0;
 }
 #else
-static int exec_e2fs_cmd(const char* path, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
     int status;
     pid_t child;
     if ((child = fork()) == 0) {
@@ -97,11 +101,13 @@
     int ret = -1;
     if (WIFEXITED(status)) {
         ret = WEXITSTATUS(status);
-        if (ret != 0) {
-            fprintf(stderr, "%s failed with status %d\n", path, ret);
-        }
     }
-    return ret;
+
+    if (ret != 0) {
+        fprintf(stderr, "%s failed with status %d\n", path, ret);
+        return -1;
+    }
+    return 0;
 }
 #endif
 
@@ -140,9 +146,8 @@
     const std::string mke2fs_env = "MKE2FS_CONFIG=" + GetExecutableDirectory() + "/mke2fs.conf";
     std::vector<const char*> mke2fs_envp = {mke2fs_env.c_str(), nullptr};
 
-    int ret = exec_e2fs_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
+    int ret = exec_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
     if (ret != 0) {
-        fprintf(stderr, "mke2fs failed: %d\n", ret);
         return -1;
     }
 
@@ -154,19 +159,12 @@
     std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
                                                fileName, nullptr};
 
-    ret = exec_e2fs_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
-    if (ret != 0) {
-        fprintf(stderr, "e2fsdroid failed: %d\n", ret);
-        return -1;
-    }
-
-    return 0;
+    return exec_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
 }
 
 static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
                                unsigned /* unused */, unsigned /* unused */)
 {
-#ifndef WIN32
     const std::string exec_dir = android::base::GetExecutableDirectory();
     const std::string mkf2fs_path = exec_dir + "/make_f2fs";
     std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
@@ -182,22 +180,20 @@
     mkf2fs_args.push_back(fileName);
     mkf2fs_args.push_back(nullptr);
 
-    int ret = exec_e2fs_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
+    int ret = exec_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
     if (ret != 0) {
-        fprintf(stderr, "mkf2fs failed: %d\n", ret);
         return -1;
     }
 
-    if (!initial_dir.empty()) {
-        fprintf(stderr, "sload.f2s not supported yet\n");
+    if (initial_dir.empty()) {
         return 0;
     }
-    return 0;
-#else
-    UNUSED(fileName, partSize, initial_dir);
-    fprintf(stderr, "make_f2fs not supported on Windows\n");
-    return -1;
-#endif
+
+    const std::string sload_path = exec_dir + "/sload_f2fs";
+    std::vector<const char*> sload_args = {sload_path.c_str(), "-S",
+                                       "-f", initial_dir.c_str(), fileName, nullptr};
+
+    return exec_cmd(sload_args[0], sload_args.data(), nullptr);
 }
 
 static const struct fs_generator {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
deleted file mode 100644
index 007189d..0000000
--- a/fs_mgr/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-common_static_libraries := \
-    liblogwrap \
-    libfec \
-    libfec_rs \
-    libbase \
-    libcrypto_utils \
-    libcrypto \
-    libext4_utils \
-    libsquashfs_utils \
-    libselinux \
-    libavb
-
-include $(CLEAR_VARS)
-LOCAL_SANITIZE := integer
-LOCAL_SRC_FILES:= fs_mgr_main.cpp
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_MODULE:= fs_mgr
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libfs_mgr \
-    $(common_static_libraries) \
-    libcutils \
-    liblog \
-    libc \
-    libsparse \
-    libz \
-    libselinux
-LOCAL_CXX_STL := libc++_static
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
new file mode 100644
index 0000000..817a0b8
--- /dev/null
+++ b/fs_mgr/OWNERS
@@ -0,0 +1,2 @@
+bowgotsai@google.com
+tomcherry@google.com
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 75feee7..85a593f 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -34,24 +34,35 @@
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+static int get_dev_sz(char *fs_blkdev, uint64_t *dev_sz)
 {
-    uint64_t dev_sz;
-    int fd, rc = 0;
-    int status;
+    int fd;
 
-    if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
+    if ((fd = open(fs_blkdev, O_RDONLY)) < 0) {
         PERROR << "Cannot open block device";
         return -1;
     }
 
-    if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
+    if ((ioctl(fd, BLKGETSIZE64, dev_sz)) == -1) {
         PERROR << "Cannot get block device size";
         close(fd);
         return -1;
     }
 
     close(fd);
+    return 0;
+}
+
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+{
+    uint64_t dev_sz;
+    int rc = 0;
+    int status;
+
+    rc = get_dev_sz(fs_blkdev, &dev_sz);
+    if (rc) {
+        return rc;
+    }
 
     /* Format the partition using the calculated length */
     if (crypt_footer) {
@@ -62,7 +73,7 @@
     const char* const mke2fs_args[] = {
         "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr};
 
-    rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), &status,
+    rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), NULL,
                                  true, LOG_KLOG, true, nullptr, nullptr, 0);
     if (rc) {
         LERROR << "mke2fs returned " << rc;
@@ -78,7 +89,7 @@
         nullptr};
 
     rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args),
-                                 &status, true, LOG_KLOG, true, nullptr, nullptr, 0);
+                                 NULL, true, LOG_KLOG, true, nullptr, nullptr, 0);
     if (rc) {
         LERROR << "e2fsdroid returned " << rc;
     }
@@ -86,12 +97,27 @@
     return rc;
 }
 
-static int format_f2fs(char *fs_blkdev)
+static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer)
 {
     int status;
-    const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
 
-    return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), &status, true,
+    if (!dev_sz) {
+        int rc = get_dev_sz(fs_blkdev, &dev_sz);
+        if (rc) {
+            return rc;
+        }
+    }
+
+    /* Format the partition using the calculated length */
+    if (crypt_footer) {
+        dev_sz -= CRYPT_FOOTER_OFFSET;
+    }
+
+    std::string size_str = std::to_string(dev_sz / 4096);
+    const char* const args[] = {
+        "/system/bin/make_f2fs", "-f", "-O", "encrypt", fs_blkdev, size_str.c_str(), nullptr};
+
+    return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
                                    LOG_KLOG, true, nullptr, nullptr, 0);
 }
 
@@ -103,7 +129,7 @@
            << " as '" << fstab->fs_type << "'";
 
     if (!strncmp(fstab->fs_type, "f2fs", 4)) {
-        rc = format_f2fs(fstab->blk_device);
+        rc = format_f2fs(fstab->blk_device, fstab->length, crypt_footer);
     } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
         rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
     } else {
diff --git a/fs_mgr/fs_mgr_main.cpp b/fs_mgr/fs_mgr_main.cpp
deleted file mode 100644
index f3919d9..0000000
--- a/fs_mgr/fs_mgr_main.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 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 <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "fs_mgr_priv.h"
-
-#ifdef _LIBGEN_H
-#warning "libgen.h must not be included"
-#endif
-
-char *me = nullptr;
-
-static void usage(void)
-{
-    LERROR << me << ": usage: " << me
-           << " <-a | -n mnt_point blk_dev | -u> <fstab_file>";
-    exit(1);
-}
-
-/* Parse the command line.  If an error is encountered, print an error message
- * and exit the program, do not return to the caller.
- * Return the number of argv[] entries consumed.
- */
-static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
-                     const char **n_name, const char **n_blk_dev)
-{
-    me = basename(argv[0]);
-
-    if (argc <= 1) {
-        usage();
-    }
-
-    if (!strcmp(argv[1], "-a")) {
-        if (argc != 3) {
-            usage();
-        }
-        *a_flag = 1;
-    }
-    if (!strcmp(argv[1], "-n")) {
-        if (argc != 5) {
-            usage();
-        }
-        *n_flag = 1;
-        *n_name = argv[2];
-        *n_blk_dev = argv[3];
-    }
-    if (!strcmp(argv[1], "-u")) {
-        if (argc != 3) {
-            usage();
-        }
-        *u_flag = 1;
-    }
-
-    /* If no flag is specified, it's an error */
-    if (!(*a_flag | *n_flag | *u_flag)) {
-        usage();
-    }
-
-    /* If more than one flag is specified, it's an error */
-    if ((*a_flag + *n_flag + *u_flag) > 1) {
-        usage();
-    }
-
-    return;
-}
-
-int main(int argc, char * const argv[])
-{
-    int a_flag=0;
-    int u_flag=0;
-    int n_flag=0;
-    const char *n_name=NULL;
-    const char *n_blk_dev=NULL;
-    const char *fstab_file=NULL;
-    struct fstab *fstab=NULL;
-
-    setenv("ANDROID_LOG_TAGS", "*:i", 1); // Set log level to INFO
-    android::base::InitLogging(
-        const_cast<char **>(argv), &android::base::KernelLogger);
-
-    parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
-
-    /* The name of the fstab file is last, after the option */
-    fstab_file = argv[argc - 1];
-
-    fstab = fs_mgr_read_fstab(fstab_file);
-
-    if (a_flag) {
-        return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
-    } else if (n_flag) {
-        return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
-    } else if (u_flag) {
-        return fs_mgr_unmount_all(fstab);
-    } else {
-        LERROR << me << ": Internal error, unknown option";
-        exit(1);
-    }
-
-    fs_mgr_free_fstab(fstab);
-
-    /* Should not get here */
-    exit(1);
-}
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index f604bcf..0a113b4 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,19 +21,12 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
-// Returns "_a" or "_b" based on two possible values in kernel cmdline:
-//   - androidboot.slot = a or b OR
-//   - androidboot.slot_suffix = _a or _b
-// TODO: remove slot_suffix once it's deprecated.
+// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
+// if that parameter does not exist.
 std::string fs_mgr_get_slot_suffix() {
-    std::string slot;
     std::string ab_suffix;
 
-    if (fs_mgr_get_boot_config("slot", &slot)) {
-        ab_suffix = "_" + slot;
-    } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) {
-        ab_suffix = "";
-    }
+    fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
     return ab_suffix;
 }
 
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 0dfd9d8..28f0b07 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -21,8 +21,7 @@
 LOCAL_SRC_FILES := \
 	SoftGateKeeperDevice.cpp \
 	IGateKeeperService.cpp \
-	gatekeeperd.cpp \
-	IUserManager.cpp
+	gatekeeperd.cpp
 
 LOCAL_MODULE := gatekeeperd
 LOCAL_SHARED_LIBRARIES := \
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
deleted file mode 100644
index 8167d19..0000000
--- a/gatekeeperd/IUserManager.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 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 LOG_TAG "IUserManager"
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-
-#include "IUserManager.h"
-
-namespace android {
-
-class BpUserManager : public BpInterface<IUserManager>
-{
-public:
-    explicit BpUserManager(const sp<IBinder>& impl) :
-            BpInterface<IUserManager>(impl) {
-    }
-    virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
-        data.writeInt32(user_id);
-        status_t rc = remote()->transact(GET_CREDENTIAL_OWNER_PROFILE, data, &reply, 0);
-        if (rc != NO_ERROR) {
-            ALOGE("%s: failed (%d)\n", __func__, rc);
-            return -1;
-        }
-
-        int32_t exception = reply.readExceptionCode();
-        if (exception != 0) {
-            ALOGE("%s: got exception (%d)\n", __func__, exception);
-            return -1;
-        }
-
-        return reply.readInt32();
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(UserManager, "android.os.IUserManager");
-
-}; // namespace android
-
diff --git a/gatekeeperd/IUserManager.h b/gatekeeperd/IUserManager.h
deleted file mode 100644
index 640e9b5..0000000
--- a/gatekeeperd/IUserManager.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef IUSERMANAGER_H_
-#define IUSERMANAGER_H_
-
-#include <inttypes.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-/*
-* Communication channel to UserManager
-*/
-class IUserManager : public IInterface {
-    public:
-        // must be kept in sync with IUserManager.aidl
-        enum {
-            GET_CREDENTIAL_OWNER_PROFILE = IBinder::FIRST_CALL_TRANSACTION + 0,
-        };
-
-        virtual int32_t getCredentialOwnerProfile(int32_t user_id) = 0;
-
-        DECLARE_META_INTERFACE(UserManager);
-};
-
-}; // namespace android
-
-#endif // IUSERMANAGER_H_
-
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index d581736..61c8804 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -38,7 +38,6 @@
 #include <utils/String16.h>
 
 #include "SoftGateKeeperDevice.h"
-#include "IUserManager.h"
 
 #include <hidl/HidlSupport.h>
 #include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
@@ -335,23 +334,7 @@
         return ret;
     }
 
-    virtual uint64_t getSecureUserId(uint32_t uid) {
-        uint64_t sid = read_sid(uid);
-         if (sid == 0) {
-            // might be a work profile, look up the parent
-            sp<IServiceManager> sm = defaultServiceManager();
-            sp<IBinder> binder = sm->getService(String16("user"));
-            sp<IUserManager> um = interface_cast<IUserManager>(binder);
-            int32_t parent = um->getCredentialOwnerProfile(uid);
-            if (parent < 0) {
-                return 0;
-            } else if (parent != (int32_t) uid) {
-                return read_sid(parent);
-            }
-        }
-        return sid;
-
-    }
+    virtual uint64_t getSecureUserId(uint32_t uid) { return read_sid(uid); }
 
     virtual void clearSecureUserId(uint32_t uid) {
         IPCThreadState* ipc = IPCThreadState::self();
diff --git a/healthd/Android.bp b/healthd/Android.bp
new file mode 100644
index 0000000..56f5148
--- /dev/null
+++ b/healthd/Android.bp
@@ -0,0 +1,7 @@
+cc_library_headers {
+    name: "libhealthd_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    header_libs: ["libbatteryservice_headers"],
+    export_header_lib_headers: ["libbatteryservice_headers"],
+}
diff --git a/healthd/OWNERS b/healthd/OWNERS
new file mode 100644
index 0000000..2375f7c
--- /dev/null
+++ b/healthd/OWNERS
@@ -0,0 +1 @@
+toddpoynor@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 45ee754..0ec348c 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -118,6 +118,8 @@
     required: [
         "e2fsdroid",
         "mke2fs",
+        "sload_f2fs",
+        "make_f2fs",
     ],
     static_executable: true,
     srcs: [
diff --git a/init/Android.mk b/init/Android.mk
index 44300f6..516f1b3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -88,6 +88,8 @@
 LOCAL_REQUIRED_MODULES := \
     e2fsdroid \
     mke2fs \
+    sload_f2fs \
+    make_f2fs \
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/OWNERS b/init/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/init/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/init/selinux.cpp b/init/selinux.cpp
index b548615..1febccd 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -418,7 +418,6 @@
     selinux_android_restorecon("/dev/urandom", 0);
     selinux_android_restorecon("/dev/__properties__", 0);
 
-    selinux_android_restorecon("/file_contexts.bin", 0);
     selinux_android_restorecon("/plat_file_contexts", 0);
     selinux_android_restorecon("/nonplat_file_contexts", 0);
     selinux_android_restorecon("/plat_property_contexts", 0);
@@ -437,6 +436,9 @@
 
     selinux_android_restorecon("/sbin/mke2fs_static", 0);
     selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
+
+    selinux_android_restorecon("/sbin/mkfs.f2fs", 0);
+    selinux_android_restorecon("/sbin/sload.f2fs", 0);
 }
 
 // This function sets up SELinux logging to be written to kmsg, to match init's logging.
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 0792307..8b0c53e 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -179,7 +179,11 @@
         }
 
         const uint32_t opcode = buffer_.request.header.opcode;
-        LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+        const uint64_t unique = buffer_.request.header.unique;
+        LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode << " unique=" << unique;
+        if (unique == 0) {
+            return FuseBridgeState::kWaitToReadEither;
+        }
         switch (opcode) {
             case FUSE_FORGET:
                 // Do not reply to FUSE_FORGET.
diff --git a/libappfuse/OWNERS b/libappfuse/OWNERS
new file mode 100644
index 0000000..cd7cb74
--- /dev/null
+++ b/libappfuse/OWNERS
@@ -0,0 +1 @@
+hirono@google.com
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
index 51d6051..0a28451 100644
--- a/libappfuse/tests/FuseBridgeLoopTest.cc
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -67,6 +67,7 @@
     memset(&request_, 0, sizeof(FuseRequest));
     request_.header.opcode = opcode;
     request_.header.len = sizeof(fuse_in_header);
+    request_.header.unique = 1;
     ASSERT_TRUE(request_.Write(dev_sockets_[0]));
 
     memset(&response_, 0, sizeof(FuseResponse));
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 0b2ce1d..9eaeae8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -229,6 +229,7 @@
 
     srcs: [
         "backtrace_benchmarks.cpp",
+        "backtrace_read_benchmarks.cpp",
     ],
 
     shared_libs: [
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 0a2f5a3..3041492 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -320,7 +320,7 @@
   }
   if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
     unw_dyn_info_t di;
-    unw_word_t segbase = map.start - map.offset;
+    unw_word_t segbase = map.start - debug_frame->min_vaddr;
     // TODO: http://b/32916571
     // TODO: Do it ourselves is more efficient than calling libunwind functions.
     int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
index 760817b..d110b48 100644
--- a/libbacktrace/BacktracePtrace.h
+++ b/libbacktrace/BacktracePtrace.h
@@ -29,9 +29,9 @@
   BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
   virtual ~BacktracePtrace() {}
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
 
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/OWNERS b/libbacktrace/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/libbacktrace/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 3a38839..56a6c68 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -99,8 +99,7 @@
     // one extra function call appearing in the unwind.
     unwindstack::RegsGetLocal(regs.get());
   } else {
-    regs.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
+    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
@@ -109,7 +108,7 @@
 }
 
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
-    : BacktracePtrace(pid, tid, map) {}
+    : BacktracePtrace(pid, tid, map), memory_(pid) {}
 
 std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
   return GetMap()->GetFunctionName(pc, offset);
@@ -120,10 +119,13 @@
   if (context == nullptr) {
     regs.reset(unwindstack::Regs::RemoteGet(Tid()));
   } else {
-    regs.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
+    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
   return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
 }
+
+size_t UnwindStackPtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+  return memory_.Read(addr, buffer, bytes);
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index be9ef63..ee2a706 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -45,6 +45,11 @@
   bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
 
   std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+
+ private:
+  unwindstack::MemoryRemote memory_;
 };
 
 #endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index bb4134f..a23e3b4 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -103,8 +103,9 @@
       exit(1);
     }
 
-    if (num_maps != kNumMaps) {
-      fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected.\n", num_maps, kNumMaps);
+    if (num_maps < kNumMaps) {
+      fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected at least.\n", num_maps,
+              kNumMaps);
       std::string str;
       android::base::ReadFileToString("/proc/self/maps", &str);
       fprintf(stderr, "%s\n", str.c_str());
@@ -121,12 +122,12 @@
 
   size_t num_maps = 0;
   for (size_t i = 0; i < 2000; i++) {
-    if (CountMaps(pid, &num_maps) && num_maps == kNumMaps) {
+    if (CountMaps(pid, &num_maps) && num_maps >= kNumMaps) {
       break;
     }
     usleep(1000);
   }
-  if (num_maps != kNumMaps) {
+  if (num_maps < kNumMaps) {
     fprintf(stderr, "Timed out waiting for the number of maps available: %zu\n", num_maps);
     return;
   }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 0935660..d1b44a1 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -251,12 +252,21 @@
         return false;
       }
       HexStringToRawData(&line[pos], &testdata->unw_context, size);
+#if defined(__arm__)
+    } else if (android::base::StartsWith(line, "regs:")) {
+      uint64_t pc;
+      uint64_t sp;
+      sscanf(line.c_str(), "regs: pc: %" SCNx64 " sp: %" SCNx64, &pc, &sp);
+      testdata->unw_context.regs[13] = sp;
+      testdata->unw_context.regs[15] = pc;
+#endif
     } else if (android::base::StartsWith(line, "stack:")) {
       size_t size;
       int pos;
       sscanf(line.c_str(),
              "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
              &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
+      CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size);
       testdata->stack.resize(size);
       HexStringToRawData(&line[pos], &testdata->stack[0], size);
       testdata->stack_info.data = testdata->stack.data();
@@ -391,3 +401,44 @@
     ASSERT_EQ(name, testdata.symbols[i].name);
   }
 }
+
+TEST(libbacktrace, offline_debug_frame_with_load_bias) {
+  if (std::string(ABI_STRING) != "arm") {
+    GTEST_LOG_(INFO) << "Skipping test since offline for arm on " << ABI_STRING
+                     << " isn't supported.";
+    return;
+  }
+  const std::string testlib_path(GetTestPath("libandroid_runtime.so"));
+  struct stat st;
+  ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
+
+  const std::string offline_testdata_path(GetTestPath("offline_testdata_for_libandroid_runtime"));
+  OfflineTestData testdata;
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+
+  // Fix path of /system/lib/libandroid_runtime.so.
+  for (auto& map : testdata.maps) {
+    if (map.name.find("libandroid_runtime.so") != std::string::npos) {
+      map.name = testlib_path;
+    }
+  }
+
+  // Do offline backtrace.
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
+  ASSERT_TRUE(map != nullptr);
+
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+  ASSERT_TRUE(backtrace != nullptr);
+
+  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
+  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
+    uintptr_t vaddr_in_file =
+        backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
+    std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+    ASSERT_EQ(name, testdata.symbols[i].name);
+  }
+}
diff --git a/libbacktrace/backtrace_read_benchmarks.cpp b/libbacktrace/backtrace_read_benchmarks.cpp
new file mode 100644
index 0000000..6a688b0
--- /dev/null
+++ b/libbacktrace/backtrace_read_benchmarks.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+
+#include <backtrace/Backtrace.h>
+
+#define AT_COMMON_SIZES Arg(1)->Arg(4)->Arg(8)->Arg(16)->Arg(100)->Arg(200)->Arg(500)->Arg(1024)
+
+static void Attach(pid_t pid) {
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+    perror("Failed to attach");
+    abort();
+  }
+
+  siginfo_t si;
+  // Wait for up to 5 seconds.
+  for (size_t i = 0; i < 5000; i++) {
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+      return;
+    }
+    usleep(1000);
+  }
+  printf("Remote process failed to stop in five seconds.\n");
+  abort();
+}
+
+class ScopedPidReaper {
+ public:
+  ScopedPidReaper(pid_t pid) : pid_(pid) {}
+  ~ScopedPidReaper() {
+    kill(pid_, SIGKILL);
+    waitpid(pid_, nullptr, 0);
+  }
+
+ private:
+  pid_t pid_;
+};
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
+  struct iovec dst_iov = {
+      .iov_base = dst, .iov_len = len,
+  };
+
+  struct iovec src_iov = {
+      .iov_base = reinterpret_cast<void*>(remote_src), .iov_len = len,
+  };
+
+  ssize_t rc = process_vm_readv(pid, &dst_iov, 1, &src_iov, 1, 0);
+  return rc == -1 ? 0 : rc;
+}
+
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+  if (*value == -1 && errno) {
+    return false;
+  }
+  return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+  size_t bytes_read = 0;
+  long data;
+  for (size_t i = 0; i < bytes / sizeof(long); i++) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, sizeof(long));
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+    addr += sizeof(long);
+    bytes_read += sizeof(long);
+  }
+
+  size_t left_over = bytes & (sizeof(long) - 1);
+  if (left_over) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+}
+
+static void CreateRemoteProcess(size_t size, void** map, pid_t* pid) {
+  *map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (*map == MAP_FAILED) {
+    perror("Can't allocate memory");
+    abort();
+  }
+  memset(*map, 0xaa, size);
+
+  if ((*pid = fork()) == 0) {
+    for (volatile int i = 0;; i++)
+      ;
+    exit(1);
+  }
+  if (*pid < 0) {
+    perror("Failed to fork");
+    abort();
+  }
+  Attach(*pid);
+  // Don't need this map in the current process any more.
+  munmap(*map, size);
+}
+
+static void BM_read_with_ptrace(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::vector<uint8_t> read_buffer(state.range(0));
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  while (state.KeepRunning()) {
+    if (PtraceRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_ptrace)->AT_COMMON_SIZES;
+
+static void BM_read_with_process_vm_read(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::vector<uint8_t> read_buffer(state.range(0));
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  while (state.KeepRunning()) {
+    if (ProcessVmRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_process_vm_read)->AT_COMMON_SIZES;
+
+static void BM_read_with_backtrace_object(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+  if (backtrace.get() == nullptr) {
+    printf("Failed to create backtrace.\n");
+    abort();
+  }
+
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  std::vector<uint8_t> read_buffer(state.range(0));
+  while (state.KeepRunning()) {
+    if (backtrace->Read(addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_backtrace_object)->AT_COMMON_SIZES;
diff --git a/libbacktrace/testdata/arm/libandroid_runtime.so b/libbacktrace/testdata/arm/libandroid_runtime.so
new file mode 100644
index 0000000..e4283e6
--- /dev/null
+++ b/libbacktrace/testdata/arm/libandroid_runtime.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
new file mode 100644
index 0000000..a12bc3c
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
@@ -0,0 +1,6 @@
+pid: 7288 tid: 31656
+regs: pc: f1f6dc49 sp: d8fe6930
+map: start: f1f10000 end: f2049000 offset: 0 load_bias: 10000 flags: 5 name: /system/lib/libandroid_runtime.so
+stack: start: d8fe6954 end: d8fe6958 size: 4 e7dcf6f1
+function: start: 6dbf9 end: 6dce5 name: android::AndroidRuntime::javaThreadShell
+function: start: 6dce5 end: 6dd79 name: android::AndroidRuntime::javaCreateThreadEtc
diff --git a/liblog/OWNERS b/liblog/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/liblog/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 275a2d6..39b52ac 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -54,7 +54,7 @@
     -Werror \
     -fno-builtin \
 
-test_src_files := \
+cts_src_files := \
     libc_test.cpp \
     liblog_test_default.cpp \
     liblog_test_local.cpp \
@@ -67,6 +67,9 @@
     log_time_test.cpp \
     log_wrap_test.cpp
 
+test_src_files := \
+    $(cts_src_files) \
+
 # Build tests for the device (with .so). Run with:
 #   adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
 include $(CLEAR_VARS)
@@ -82,15 +85,15 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(cts_executable)
 LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_CFLAGS += $(test_c_flags) -DNO_PSTORE
+LOCAL_SRC_FILES := $(cts_src_files)
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.core.liblog
 include $(BUILD_CTS_EXECUTABLE)
 
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index e2d5aeb..597a6bb 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -116,6 +116,7 @@
   return ret;
 }
 
+#ifndef NO_PSTORE
 static bool isPmsgActive() {
   pid_t pid = getpid();
 
@@ -125,6 +126,7 @@
 
   return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
 }
+#endif /* NO_PSTORE */
 
 static bool isLogdwActive() {
   std::string logdwSignature =
@@ -189,22 +191,25 @@
   EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
 #ifdef USING_LOGGER_DEFAULT
   // Check that we can close and reopen the logger
-  bool pmsgActiveAfter__android_log_btwrite;
   bool logdwActiveAfter__android_log_btwrite;
   if (getuid() == AID_ROOT) {
     tested__android_log_close = true;
-    pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-    logdwActiveAfter__android_log_btwrite = isLogdwActive();
+#ifndef NO_PSTORE
+    bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
     EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+#endif /* NO_PSTORE */
+    logdwActiveAfter__android_log_btwrite = isLogdwActive();
     EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
   } else if (!tested__android_log_close) {
     fprintf(stderr, "WARNING: can not test __android_log_close()\n");
   }
   __android_log_close();
   if (getuid() == AID_ROOT) {
+#ifndef NO_PSTORE
     bool pmsgActiveAfter__android_log_close = isPmsgActive();
-    bool logdwActiveAfter__android_log_close = isLogdwActive();
     EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+#endif /* NO_PSTORE */
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
     EXPECT_FALSE(logdwActiveAfter__android_log_close);
   }
 #endif
@@ -213,9 +218,11 @@
   EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
 #ifdef USING_LOGGER_DEFAULT
   if (getuid() == AID_ROOT) {
-    pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-    logdwActiveAfter__android_log_btwrite = isLogdwActive();
+#ifndef NO_PSTORE
+    bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
     EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+#endif /* NO_PSTORE */
+    logdwActiveAfter__android_log_btwrite = isLogdwActive();
     EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
   }
 #endif
@@ -3036,12 +3043,15 @@
 
 #ifdef USING_LOGGER_DEFAULT  // Do not retest pmsg functionality
 #ifdef __ANDROID__
+#ifndef NO_PSTORE
 static const char __pmsg_file[] =
     "/data/william-shakespeare/MuchAdoAboutNothing.txt";
+#endif /* NO_PSTORE */
 #endif
 
 TEST(liblog, __android_log_pmsg_file_write) {
 #ifdef __ANDROID__
+#ifndef NO_PSTORE
   __android_log_close();
   if (getuid() == AID_ROOT) {
     tested__android_log_close = true;
@@ -3092,12 +3102,16 @@
     EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
     EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
   }
+#else  /* NO_PSTORE */
+  GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
+#endif /* NO_PSTORE */
 #else
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
 
 #ifdef __ANDROID__
+#ifndef NO_PSTORE
 static ssize_t __pmsg_fn(log_id_t logId, char prio, const char* filename,
                          const char* buf, size_t len, void* arg) {
   EXPECT_TRUE(NULL == arg);
@@ -3118,10 +3132,12 @@
              ? -ENOEXEC
              : 1;
 }
+#endif /* NO_PSTORE */
 #endif
 
 TEST(liblog, __android_log_pmsg_file_read) {
 #ifdef __ANDROID__
+#ifndef NO_PSTORE
   signaled = 0;
 
   __android_log_close();
@@ -3155,6 +3171,9 @@
 
   EXPECT_LT(0, ret);
   EXPECT_EQ(1U, signaled);
+#else  /* NO_PSTORE */
+  GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
+#endif /* NO_PSTORE */
 #else
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/libmemtrack/OWNERS b/libmemtrack/OWNERS
new file mode 100644
index 0000000..70b375f
--- /dev/null
+++ b/libmemtrack/OWNERS
@@ -0,0 +1 @@
+ccross@google.com
diff --git a/libmemunreachable/OWNERS b/libmemunreachable/OWNERS
new file mode 100644
index 0000000..9127a93
--- /dev/null
+++ b/libmemunreachable/OWNERS
@@ -0,0 +1,2 @@
+ccross@google.com
+cferris@google.com
diff --git a/libmetricslogger/OWNERS b/libmetricslogger/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/libmetricslogger/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/libnativebridge/OWNERS b/libnativebridge/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativebridge/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnativeloader/OWNERS b/libnativeloader/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativeloader/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 99ae3a7..3563fc1 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -34,6 +34,7 @@
                                    int32_t target_sdk_version,
                                    jobject class_loader,
                                    bool is_shared,
+                                   bool is_for_vendor,
                                    jstring library_path,
                                    jstring permitted_path);
 
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 7ccd7db..5d160ee 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -82,6 +82,11 @@
                                   "/etc/public.libraries.txt";
 static constexpr const char* kPublicNativeLibrariesVendorConfig =
                                   "/vendor/etc/public.libraries.txt";
+static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot =
+                                  "/etc/llndk.libraries.txt";
+static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot =
+                                  "/etc/vndksp.libraries.txt";
+
 
 // The device may be configured to have the vendor libraries loaded to a separate namespace.
 // For historical reasons this namespace was named sphal but effectively it is intended
@@ -89,6 +94,11 @@
 // vendor and system namespaces.
 static constexpr const char* kVendorNamespaceName = "sphal";
 
+static constexpr const char* kVndkNamespaceName = "vndk";
+
+static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
+static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
+
 // (http://b/27588281) This is a workaround for apps using custom classloaders and calling
 // System.load() with an absolute path which is outside of the classloader library search path.
 // This list includes all directories app is allowed to access this way.
@@ -108,6 +118,7 @@
               uint32_t target_sdk_version,
               jobject class_loader,
               bool is_shared,
+              bool is_for_vendor,
               jstring java_library_path,
               jstring java_permitted_path,
               NativeLoaderNamespace* ns,
@@ -163,9 +174,39 @@
       is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
     }
 
+    std::string system_exposed_libraries = system_public_libraries_;
+    const char* namespace_name = kClassloaderNamespaceName;
+    android_namespace_t* vndk_ns = nullptr;
+    if (is_for_vendor && !is_shared) {
+      LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture");
+
+      // For vendor apks, give access to the vendor lib even though
+      // they are treated as unbundled; the libs and apks are still bundled
+      // together in the vendor partition.
+#if defined(__LP64__)
+      std::string vendor_lib_path = "/vendor/lib64";
+#else
+      std::string vendor_lib_path = "/vendor/lib";
+#endif
+      library_path = library_path + ":" + vendor_lib_path.c_str();
+      permitted_path = permitted_path + ":" + vendor_lib_path.c_str();
+
+      // Also give access to LLNDK libraries since they are available to vendors
+      system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
+
+      // Give access to VNDK-SP libraries from the 'vndk' namespace.
+      vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
+      LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr,
+                          "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName);
+
+      // Different name is useful for debugging
+      namespace_name = kVendorClassloaderNamespaceName;
+      ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+    }
+
     NativeLoaderNamespace native_loader_ns;
     if (!is_native_bridge) {
-      android_namespace_t* ns = android_create_namespace("classloader-namespace",
+      android_namespace_t* ns = android_create_namespace(namespace_name,
                                                          nullptr,
                                                          library_path.c_str(),
                                                          namespace_type,
@@ -181,11 +222,19 @@
       // which is expected behavior in this case.
       android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
 
-      if (!android_link_namespaces(ns, nullptr, system_public_libraries_.c_str())) {
+      if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
         *error_msg = dlerror();
         return false;
       }
 
+      if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
+        // vendor apks are allowed to use VNDK-SP libraries.
+        if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
+          *error_msg = dlerror();
+          return false;
+        }
+      }
+
       if (!vendor_public_libraries_.empty()) {
         if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
           *error_msg = dlerror();
@@ -195,7 +244,7 @@
 
       native_loader_ns = NativeLoaderNamespace(ns);
     } else {
-      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
                                                                   nullptr,
                                                                   library_path.c_str(),
                                                                   namespace_type,
@@ -209,7 +258,7 @@
 
       native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
 
-      if (!NativeBridgeLinkNamespaces(ns, nullptr, system_public_libraries_.c_str())) {
+      if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
         *error_msg = NativeBridgeGetError();
         return false;
       }
@@ -259,6 +308,10 @@
     std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
     std::string public_native_libraries_system_config =
             root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
+    std::string llndk_native_libraries_system_config =
+            root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
+    std::string vndksp_native_libraries_system_config =
+            root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
 
     std::string error_msg;
     LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
@@ -294,6 +347,14 @@
     system_public_libraries_ = base::Join(sonames, ':');
 
     sonames.clear();
+    ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames);
+    system_llndk_libraries_ = base::Join(sonames, ':');
+
+    sonames.clear();
+    ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames);
+    system_vndksp_libraries_ = base::Join(sonames, ':');
+
+    sonames.clear();
     // This file is optional, quietly ignore if the file does not exist.
     ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
 
@@ -404,6 +465,8 @@
   std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string system_public_libraries_;
   std::string vendor_public_libraries_;
+  std::string system_llndk_libraries_;
+  std::string system_vndksp_libraries_;
 
   DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
 };
@@ -430,6 +493,7 @@
                                    int32_t target_sdk_version,
                                    jobject class_loader,
                                    bool is_shared,
+                                   bool is_for_vendor,
                                    jstring library_path,
                                    jstring permitted_path) {
 #if defined(__ANDROID__)
@@ -441,6 +505,7 @@
                                       target_sdk_version,
                                       class_loader,
                                       is_shared,
+                                      is_for_vendor,
                                       library_path,
                                       permitted_path,
                                       &ns,
@@ -449,7 +514,7 @@
     return env->NewStringUTF(error_msg.c_str());
   }
 #else
-  UNUSED(env, target_sdk_version, class_loader, is_shared,
+  UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor,
          library_path, permitted_path);
 #endif
   return nullptr;
@@ -478,7 +543,8 @@
     if (!g_namespaces->Create(env,
                               target_sdk_version,
                               class_loader,
-                              false,
+                              false /* is_shared */,
+                              false /* is_for_vendor */,
                               library_path,
                               nullptr,
                               &ns,
diff --git a/libnetutils/OWNERS b/libnetutils/OWNERS
new file mode 100644
index 0000000..e3ec950
--- /dev/null
+++ b/libnetutils/OWNERS
@@ -0,0 +1,3 @@
+# TODO: should this be in system/netd?
+ek@google.com
+lorenzo@google.com
diff --git a/libprocinfo/OWNERS b/libprocinfo/OWNERS
new file mode 100644
index 0000000..a70cc57
--- /dev/null
+++ b/libprocinfo/OWNERS
@@ -0,0 +1 @@
+jmgao@google.com
diff --git a/libsystem/include/system/thread_defs.h b/libsystem/include/system/thread_defs.h
index 377a48c..80d1160 100644
--- a/libsystem/include/system/thread_defs.h
+++ b/libsystem/include/system/thread_defs.h
@@ -55,6 +55,9 @@
     /* ui service treads might want to run at a urgent display (uncommon) */
     ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,
 
+    /* all normal video threads */
+    ANDROID_PRIORITY_VIDEO          = -10,
+
     /* all normal audio threads */
     ANDROID_PRIORITY_AUDIO          = -16,
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 74930d6..4125b12 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -60,6 +60,10 @@
         "Maps.cpp",
         "Memory.cpp",
         "Regs.cpp",
+        "RegsArm.cpp",
+        "RegsArm64.cpp",
+        "RegsX86.cpp",
+        "RegsX86_64.cpp",
         "Unwinder.cpp",
         "Symbols.cpp",
     ],
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index fed3e0e..6b0646f 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -23,11 +23,11 @@
 
 #include <unwindstack/Log.h>
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "Check.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 5f307ed..025429f 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -31,7 +31,6 @@
 #include <unwindstack/Regs.h>
 
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
 #include "Symbols.h"
 
 namespace unwindstack {
@@ -183,18 +182,15 @@
       return nullptr;
     }
 
-    if (e_machine != EM_ARM && e_machine != EM_386) {
-      // Unsupported.
-      ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
-      return nullptr;
-    }
-
     machine_type_ = e_machine;
     if (e_machine == EM_ARM) {
+      arch_ = ARCH_ARM;
       interface.reset(new ElfInterfaceArm(memory));
     } else if (e_machine == EM_386) {
+      arch_ = ARCH_X86;
       interface.reset(new ElfInterface32(memory));
     } else {
+      // Unsupported.
       ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
       return nullptr;
     }
@@ -203,12 +199,17 @@
     if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
       return nullptr;
     }
-    if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
+
+    machine_type_ = e_machine;
+    if (e_machine == EM_AARCH64) {
+      arch_ = ARCH_ARM64;
+    } else if (e_machine == EM_X86_64) {
+      arch_ = ARCH_X86_64;
+    } else {
       // Unsupported.
       ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
       return nullptr;
     }
-    machine_type_ = e_machine;
     interface.reset(new ElfInterface64(memory));
   }
 
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 170a5cd..9841e24 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -18,11 +18,11 @@
 #include <stdint.h>
 
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h
deleted file mode 100644
index 1fb9309..0000000
--- a/libunwindstack/Machine.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MACHINE_H
-#define _LIBUNWINDSTACK_MACHINE_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum ArmReg : uint16_t {
-  ARM_REG_R0 = 0,
-  ARM_REG_R1,
-  ARM_REG_R2,
-  ARM_REG_R3,
-  ARM_REG_R4,
-  ARM_REG_R5,
-  ARM_REG_R6,
-  ARM_REG_R7,
-  ARM_REG_R8,
-  ARM_REG_R9,
-  ARM_REG_R10,
-  ARM_REG_R11,
-  ARM_REG_R12,
-  ARM_REG_R13,
-  ARM_REG_R14,
-  ARM_REG_R15,
-  ARM_REG_LAST,
-
-  ARM_REG_SP = ARM_REG_R13,
-  ARM_REG_LR = ARM_REG_R14,
-  ARM_REG_PC = ARM_REG_R15,
-};
-
-enum Arm64Reg : uint16_t {
-  ARM64_REG_R0 = 0,
-  ARM64_REG_R1,
-  ARM64_REG_R2,
-  ARM64_REG_R3,
-  ARM64_REG_R4,
-  ARM64_REG_R5,
-  ARM64_REG_R6,
-  ARM64_REG_R7,
-  ARM64_REG_R8,
-  ARM64_REG_R9,
-  ARM64_REG_R10,
-  ARM64_REG_R11,
-  ARM64_REG_R12,
-  ARM64_REG_R13,
-  ARM64_REG_R14,
-  ARM64_REG_R15,
-  ARM64_REG_R16,
-  ARM64_REG_R17,
-  ARM64_REG_R18,
-  ARM64_REG_R19,
-  ARM64_REG_R20,
-  ARM64_REG_R21,
-  ARM64_REG_R22,
-  ARM64_REG_R23,
-  ARM64_REG_R24,
-  ARM64_REG_R25,
-  ARM64_REG_R26,
-  ARM64_REG_R27,
-  ARM64_REG_R28,
-  ARM64_REG_R29,
-  ARM64_REG_R30,
-  ARM64_REG_R31,
-  ARM64_REG_PC,
-  ARM64_REG_LAST,
-
-  ARM64_REG_SP = ARM64_REG_R31,
-  ARM64_REG_LR = ARM64_REG_R30,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86Reg : uint16_t {
-  X86_REG_EAX = 0,
-  X86_REG_ECX = 1,
-  X86_REG_EDX = 2,
-  X86_REG_EBX = 3,
-  X86_REG_ESP = 4,
-  X86_REG_EBP = 5,
-  X86_REG_ESI = 6,
-  X86_REG_EDI = 7,
-  X86_REG_EIP = 8,
-  X86_REG_EFL = 9,
-  X86_REG_CS = 10,
-  X86_REG_SS = 11,
-  X86_REG_DS = 12,
-  X86_REG_ES = 13,
-  X86_REG_FS = 14,
-  X86_REG_GS = 15,
-  X86_REG_LAST,
-
-  X86_REG_SP = X86_REG_ESP,
-  X86_REG_PC = X86_REG_EIP,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86_64Reg : uint16_t {
-  X86_64_REG_RAX = 0,
-  X86_64_REG_RDX = 1,
-  X86_64_REG_RCX = 2,
-  X86_64_REG_RBX = 3,
-  X86_64_REG_RSI = 4,
-  X86_64_REG_RDI = 5,
-  X86_64_REG_RBP = 6,
-  X86_64_REG_RSP = 7,
-  X86_64_REG_R8 = 8,
-  X86_64_REG_R9 = 9,
-  X86_64_REG_R10 = 10,
-  X86_64_REG_R11 = 11,
-  X86_64_REG_R12 = 12,
-  X86_64_REG_R13 = 13,
-  X86_64_REG_R14 = 14,
-  X86_64_REG_R15 = 15,
-  X86_64_REG_RIP = 16,
-  X86_64_REG_LAST,
-
-  X86_64_REG_SP = X86_64_REG_RSP,
-  X86_64_REG_PC = X86_64_REG_RIP,
-};
-
-}  // namespace unwindstack
-
-#endif  // _LIBUNWINDSTACK_MACHINE_H
diff --git a/libunwindstack/MachineArm.h b/libunwindstack/MachineArm.h
new file mode 100644
index 0000000..3f902b1
--- /dev/null
+++ b/libunwindstack/MachineArm.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM_H
+#define _LIBUNWINDSTACK_MACHINE_ARM_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum ArmReg : uint16_t {
+  ARM_REG_R0 = 0,
+  ARM_REG_R1,
+  ARM_REG_R2,
+  ARM_REG_R3,
+  ARM_REG_R4,
+  ARM_REG_R5,
+  ARM_REG_R6,
+  ARM_REG_R7,
+  ARM_REG_R8,
+  ARM_REG_R9,
+  ARM_REG_R10,
+  ARM_REG_R11,
+  ARM_REG_R12,
+  ARM_REG_R13,
+  ARM_REG_R14,
+  ARM_REG_R15,
+  ARM_REG_LAST,
+
+  ARM_REG_SP = ARM_REG_R13,
+  ARM_REG_LR = ARM_REG_R14,
+  ARM_REG_PC = ARM_REG_R15,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/MachineArm64.h
new file mode 100644
index 0000000..e8b778b
--- /dev/null
+++ b/libunwindstack/MachineArm64.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM64_H
+#define _LIBUNWINDSTACK_MACHINE_ARM64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum Arm64Reg : uint16_t {
+  ARM64_REG_R0 = 0,
+  ARM64_REG_R1,
+  ARM64_REG_R2,
+  ARM64_REG_R3,
+  ARM64_REG_R4,
+  ARM64_REG_R5,
+  ARM64_REG_R6,
+  ARM64_REG_R7,
+  ARM64_REG_R8,
+  ARM64_REG_R9,
+  ARM64_REG_R10,
+  ARM64_REG_R11,
+  ARM64_REG_R12,
+  ARM64_REG_R13,
+  ARM64_REG_R14,
+  ARM64_REG_R15,
+  ARM64_REG_R16,
+  ARM64_REG_R17,
+  ARM64_REG_R18,
+  ARM64_REG_R19,
+  ARM64_REG_R20,
+  ARM64_REG_R21,
+  ARM64_REG_R22,
+  ARM64_REG_R23,
+  ARM64_REG_R24,
+  ARM64_REG_R25,
+  ARM64_REG_R26,
+  ARM64_REG_R27,
+  ARM64_REG_R28,
+  ARM64_REG_R29,
+  ARM64_REG_R30,
+  ARM64_REG_R31,
+  ARM64_REG_PC,
+  ARM64_REG_LAST,
+
+  ARM64_REG_SP = ARM64_REG_R31,
+  ARM64_REG_LR = ARM64_REG_R30,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_ARM64_H
diff --git a/libunwindstack/MachineX86.h b/libunwindstack/MachineX86.h
new file mode 100644
index 0000000..02adb98
--- /dev/null
+++ b/libunwindstack/MachineX86.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_H
+#define _LIBUNWINDSTACK_MACHINE_X86_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86Reg : uint16_t {
+  X86_REG_EAX = 0,
+  X86_REG_ECX = 1,
+  X86_REG_EDX = 2,
+  X86_REG_EBX = 3,
+  X86_REG_ESP = 4,
+  X86_REG_EBP = 5,
+  X86_REG_ESI = 6,
+  X86_REG_EDI = 7,
+  X86_REG_EIP = 8,
+  X86_REG_EFL = 9,
+  X86_REG_CS = 10,
+  X86_REG_SS = 11,
+  X86_REG_DS = 12,
+  X86_REG_ES = 13,
+  X86_REG_FS = 14,
+  X86_REG_GS = 15,
+  X86_REG_LAST,
+
+  X86_REG_SP = X86_REG_ESP,
+  X86_REG_PC = X86_REG_EIP,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/MachineX86_64.h
new file mode 100644
index 0000000..af33fea
--- /dev/null
+++ b/libunwindstack/MachineX86_64.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_64_H
+#define _LIBUNWINDSTACK_MACHINE_X86_64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86_64Reg : uint16_t {
+  X86_64_REG_RAX = 0,
+  X86_64_REG_RDX = 1,
+  X86_64_REG_RCX = 2,
+  X86_64_REG_RBX = 3,
+  X86_64_REG_RSI = 4,
+  X86_64_REG_RDI = 5,
+  X86_64_REG_RBP = 6,
+  X86_64_REG_RSP = 7,
+  X86_64_REG_R8 = 8,
+  X86_64_REG_R9 = 9,
+  X86_64_REG_R10 = 10,
+  X86_64_REG_R11 = 11,
+  X86_64_REG_R12 = 12,
+  X86_64_REG_R13 = 13,
+  X86_64_REG_R14 = 14,
+  X86_64_REG_R15 = 15,
+  X86_64_REG_RIP = 16,
+  X86_64_REG_LAST,
+
+  X86_64_REG_SP = X86_64_REG_RSP,
+  X86_64_REG_PC = X86_64_REG_RIP,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index b1b39a0..1f3c6c3 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,7 +32,9 @@
 
 #include "Check.h"
 
-static size_t ProcessVmRead(pid_t pid, void* dst, uint64_t remote_src, size_t len) {
+namespace unwindstack {
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
   struct iovec dst_iov = {
       .iov_base = dst,
       .iov_len = len,
@@ -82,7 +84,59 @@
   return rc == -1 ? 0 : rc;
 }
 
-namespace unwindstack {
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+  if (*value == -1 && errno) {
+    return false;
+  }
+  return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+  // Make sure that there is no overflow.
+  uint64_t max_size;
+  if (__builtin_add_overflow(addr, bytes, &max_size)) {
+    return 0;
+  }
+
+  size_t bytes_read = 0;
+  long data;
+  size_t align_bytes = addr & (sizeof(long) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
+      return 0;
+    }
+    size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
+    memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
+  }
+
+  for (size_t i = 0; i < bytes / sizeof(long); i++) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, sizeof(long));
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+    addr += sizeof(long);
+    bytes_read += sizeof(long);
+  }
+
+  size_t left_over = bytes & (sizeof(long) - 1);
+  if (left_over) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+}
 
 bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
   size_t rc = Read(addr, dst, size);
@@ -198,72 +252,39 @@
   return actual_len;
 }
 
-static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
-  // ptrace() returns -1 and sets errno when the operation fails.
-  // To disambiguate -1 from a valid result, we clear errno beforehand.
-  errno = 0;
-  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
-  if (*value == -1 && errno) {
-    return false;
-  }
-  return true;
-}
-
-static size_t ReadWithPtrace(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
-  // Make sure that there is no overflow.
-  uint64_t max_size;
-  if (__builtin_add_overflow(addr, bytes, &max_size)) {
-    return 0;
-  }
-
-  size_t bytes_read = 0;
-  long data;
-  size_t align_bytes = addr & (sizeof(long) - 1);
-  if (align_bytes != 0) {
-    if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
-      return 0;
-    }
-    size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
-    memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
-    addr += copy_bytes;
-    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
-    bytes -= copy_bytes;
-    bytes_read += copy_bytes;
-  }
-
-  for (size_t i = 0; i < bytes / sizeof(long); i++) {
-    if (!PtraceReadLong(pid, addr, &data)) {
-      return bytes_read;
-    }
-    memcpy(dst, &data, sizeof(long));
-    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
-    addr += sizeof(long);
-    bytes_read += sizeof(long);
-  }
-
-  size_t left_over = bytes & (sizeof(long) - 1);
-  if (left_over) {
-    if (!PtraceReadLong(pid, addr, &data)) {
-      return bytes_read;
-    }
-    memcpy(dst, &data, left_over);
-    bytes_read += left_over;
-  }
-  return bytes_read;
-}
-
 size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
 #if !defined(__LP64__)
-  // Cannot read an address greater than 32 bits.
+  // Cannot read an address greater than 32 bits in a 32 bit context.
   if (addr > UINT32_MAX) {
     return 0;
   }
 #endif
-  return ReadWithPtrace(pid_, addr, dst, size);
+
+  size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
+      reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
+  if (read_func != nullptr) {
+    return read_func(pid_, addr, dst, size);
+  } else {
+    // Prefer process_vm_read, try it first. If it doesn't work, use the
+    // ptrace function. If at least one of them returns at least some data,
+    // set that as the permanent function to use.
+    // This assumes that if process_vm_read works once, it will continue
+    // to work.
+    size_t bytes = ProcessVmRead(pid_, addr, dst, size);
+    if (bytes > 0) {
+      read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
+      return bytes;
+    }
+    bytes = PtraceRead(pid_, addr, dst, size);
+    if (bytes > 0) {
+      read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
+    }
+    return bytes;
+  }
 }
 
 size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
-  return ProcessVmRead(getpid(), dst, addr, size);
+  return ProcessVmRead(getpid(), addr, dst, size);
 }
 
 MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
diff --git a/libunwindstack/OWNERS b/libunwindstack/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/libunwindstack/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 28a77dc..29dbf9d 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <elf.h>
 #include <stdint.h>
 #include <sys/ptrace.h>
 #include <sys/uio.h>
@@ -23,315 +22,21 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Check.h"
-#include "Machine.h"
-#include "Ucontext.h"
-#include "User.h"
+#include "UserArm.h"
+#include "UserArm64.h"
+#include "UserX86.h"
+#include "UserX86_64.h"
 
 namespace unwindstack {
 
-RegsArm::RegsArm()
-    : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
-
-uint32_t RegsArm::MachineType() {
-  return EM_ARM;
-}
-
-uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  uint64_t load_bias = elf->GetLoadBias();
-  if (rel_pc < load_bias) {
-    return rel_pc;
-  }
-  uint64_t adjusted_rel_pc = rel_pc - load_bias;
-
-  if (adjusted_rel_pc < 5) {
-    return rel_pc;
-  }
-
-  if (adjusted_rel_pc & 1) {
-    // This is a thumb instruction, it could be 2 or 4 bytes.
-    uint32_t value;
-    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
-        (value & 0xe000f000) != 0xe000f000) {
-      return rel_pc - 2;
-    }
-  }
-  return rel_pc - 4;
-}
-
-void RegsArm::SetFromRaw() {
-  set_pc(regs_[ARM_REG_PC]);
-  set_sp(regs_[ARM_REG_SP]);
-}
-
-bool RegsArm::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM_REG_LR]) {
-    return false;
-  }
-
-  set_pc(regs_[ARM_REG_LR]);
-  return true;
-}
-
-void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("r0", regs_[ARM_REG_R0]);
-  fn("r1", regs_[ARM_REG_R1]);
-  fn("r2", regs_[ARM_REG_R2]);
-  fn("r3", regs_[ARM_REG_R3]);
-  fn("r4", regs_[ARM_REG_R4]);
-  fn("r5", regs_[ARM_REG_R5]);
-  fn("r6", regs_[ARM_REG_R6]);
-  fn("r7", regs_[ARM_REG_R7]);
-  fn("r8", regs_[ARM_REG_R8]);
-  fn("r9", regs_[ARM_REG_R9]);
-  fn("r10", regs_[ARM_REG_R10]);
-  fn("r11", regs_[ARM_REG_R11]);
-  fn("ip", regs_[ARM_REG_R12]);
-  fn("sp", regs_[ARM_REG_SP]);
-  fn("lr", regs_[ARM_REG_LR]);
-  fn("pc", regs_[ARM_REG_PC]);
-}
-
-RegsArm64::RegsArm64()
-    : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
-
-uint32_t RegsArm64::MachineType() {
-  return EM_AARCH64;
-}
-
-uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc < 4) {
-    return rel_pc;
-  }
-  return rel_pc - 4;
-}
-
-void RegsArm64::SetFromRaw() {
-  set_pc(regs_[ARM64_REG_PC]);
-  set_sp(regs_[ARM64_REG_SP]);
-}
-
-bool RegsArm64::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM64_REG_LR]) {
-    return false;
-  }
-
-  set_pc(regs_[ARM64_REG_LR]);
-  return true;
-}
-
-void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("x0", regs_[ARM64_REG_R0]);
-  fn("x1", regs_[ARM64_REG_R1]);
-  fn("x2", regs_[ARM64_REG_R2]);
-  fn("x3", regs_[ARM64_REG_R3]);
-  fn("x4", regs_[ARM64_REG_R4]);
-  fn("x5", regs_[ARM64_REG_R5]);
-  fn("x6", regs_[ARM64_REG_R6]);
-  fn("x7", regs_[ARM64_REG_R7]);
-  fn("x8", regs_[ARM64_REG_R8]);
-  fn("x9", regs_[ARM64_REG_R9]);
-  fn("x10", regs_[ARM64_REG_R10]);
-  fn("x11", regs_[ARM64_REG_R11]);
-  fn("x12", regs_[ARM64_REG_R12]);
-  fn("x13", regs_[ARM64_REG_R13]);
-  fn("x14", regs_[ARM64_REG_R14]);
-  fn("x15", regs_[ARM64_REG_R15]);
-  fn("x16", regs_[ARM64_REG_R16]);
-  fn("x17", regs_[ARM64_REG_R17]);
-  fn("x18", regs_[ARM64_REG_R18]);
-  fn("x19", regs_[ARM64_REG_R19]);
-  fn("x20", regs_[ARM64_REG_R20]);
-  fn("x21", regs_[ARM64_REG_R21]);
-  fn("x22", regs_[ARM64_REG_R22]);
-  fn("x23", regs_[ARM64_REG_R23]);
-  fn("x24", regs_[ARM64_REG_R24]);
-  fn("x25", regs_[ARM64_REG_R25]);
-  fn("x26", regs_[ARM64_REG_R26]);
-  fn("x27", regs_[ARM64_REG_R27]);
-  fn("x28", regs_[ARM64_REG_R28]);
-  fn("x29", regs_[ARM64_REG_R29]);
-  fn("sp", regs_[ARM64_REG_SP]);
-  fn("lr", regs_[ARM64_REG_LR]);
-  fn("pc", regs_[ARM64_REG_PC]);
-}
-
-RegsX86::RegsX86()
-    : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
-
-uint32_t RegsX86::MachineType() {
-  return EM_386;
-}
-
-uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
-    return 0;
-  }
-  return rel_pc - 1;
-}
-
-void RegsX86::SetFromRaw() {
-  set_pc(regs_[X86_REG_PC]);
-  set_sp(regs_[X86_REG_SP]);
-}
-
-bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
-  // Attempt to get the return address from the top of the stack.
-  uint32_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
-    return false;
-  }
-
-  set_pc(new_pc);
-  return true;
-}
-
-void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("eax", regs_[X86_REG_EAX]);
-  fn("ebx", regs_[X86_REG_EBX]);
-  fn("ecx", regs_[X86_REG_ECX]);
-  fn("edx", regs_[X86_REG_EDX]);
-  fn("ebp", regs_[X86_REG_EBP]);
-  fn("edi", regs_[X86_REG_EDI]);
-  fn("esi", regs_[X86_REG_ESI]);
-  fn("esp", regs_[X86_REG_ESP]);
-  fn("eip", regs_[X86_REG_EIP]);
-}
-
-RegsX86_64::RegsX86_64()
-    : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
-
-uint32_t RegsX86_64::MachineType() {
-  return EM_X86_64;
-}
-
-uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
-    return 0;
-  }
-
-  return rel_pc - 1;
-}
-
-void RegsX86_64::SetFromRaw() {
-  set_pc(regs_[X86_64_REG_PC]);
-  set_sp(regs_[X86_64_REG_SP]);
-}
-
-bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
-  // Attempt to get the return address from the top of the stack.
-  uint64_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
-    return false;
-  }
-
-  set_pc(new_pc);
-  return true;
-}
-
-void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("rax", regs_[X86_64_REG_RAX]);
-  fn("rbx", regs_[X86_64_REG_RBX]);
-  fn("rcx", regs_[X86_64_REG_RCX]);
-  fn("rdx", regs_[X86_64_REG_RDX]);
-  fn("r8", regs_[X86_64_REG_R8]);
-  fn("r9", regs_[X86_64_REG_R9]);
-  fn("r10", regs_[X86_64_REG_R10]);
-  fn("r11", regs_[X86_64_REG_R11]);
-  fn("r12", regs_[X86_64_REG_R12]);
-  fn("r13", regs_[X86_64_REG_R13]);
-  fn("r14", regs_[X86_64_REG_R14]);
-  fn("r15", regs_[X86_64_REG_R15]);
-  fn("rdi", regs_[X86_64_REG_RDI]);
-  fn("rsi", regs_[X86_64_REG_RSI]);
-  fn("rbp", regs_[X86_64_REG_RBP]);
-  fn("rsp", regs_[X86_64_REG_RSP]);
-  fn("rip", regs_[X86_64_REG_RIP]);
-}
-
-static Regs* ReadArm(void* remote_data) {
-  arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
-
-  RegsArm* regs = new RegsArm();
-  memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadArm64(void* remote_data) {
-  arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
-
-  RegsArm64* regs = new RegsArm64();
-  memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
-  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
-  reg_data[ARM64_REG_PC] = user->pc;
-  reg_data[ARM64_REG_SP] = user->sp;
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadX86(void* remote_data) {
-  x86_user_regs* user = reinterpret_cast<x86_user_regs*>(remote_data);
-
-  RegsX86* regs = new RegsX86();
-  (*regs)[X86_REG_EAX] = user->eax;
-  (*regs)[X86_REG_EBX] = user->ebx;
-  (*regs)[X86_REG_ECX] = user->ecx;
-  (*regs)[X86_REG_EDX] = user->edx;
-  (*regs)[X86_REG_EBP] = user->ebp;
-  (*regs)[X86_REG_EDI] = user->edi;
-  (*regs)[X86_REG_ESI] = user->esi;
-  (*regs)[X86_REG_ESP] = user->esp;
-  (*regs)[X86_REG_EIP] = user->eip;
-
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadX86_64(void* remote_data) {
-  x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
-
-  RegsX86_64* regs = new RegsX86_64();
-  (*regs)[X86_64_REG_RAX] = user->rax;
-  (*regs)[X86_64_REG_RBX] = user->rbx;
-  (*regs)[X86_64_REG_RCX] = user->rcx;
-  (*regs)[X86_64_REG_RDX] = user->rdx;
-  (*regs)[X86_64_REG_R8] = user->r8;
-  (*regs)[X86_64_REG_R9] = user->r9;
-  (*regs)[X86_64_REG_R10] = user->r10;
-  (*regs)[X86_64_REG_R11] = user->r11;
-  (*regs)[X86_64_REG_R12] = user->r12;
-  (*regs)[X86_64_REG_R13] = user->r13;
-  (*regs)[X86_64_REG_R14] = user->r14;
-  (*regs)[X86_64_REG_R15] = user->r15;
-  (*regs)[X86_64_REG_RDI] = user->rdi;
-  (*regs)[X86_64_REG_RSI] = user->rsi;
-  (*regs)[X86_64_REG_RBP] = user->rbp;
-  (*regs)[X86_64_REG_RSP] = user->rsp;
-  (*regs)[X86_64_REG_RIP] = user->rip;
-
-  regs->SetFromRaw();
-  return regs;
-}
+// The largest user structure.
+constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
 
 // This function assumes that reg_data is already aligned to a 64 bit value.
 // If not this could crash with an unaligned access.
@@ -348,106 +53,42 @@
 
   switch (io.iov_len) {
   case sizeof(x86_user_regs):
-    return ReadX86(buffer.data());
+    return RegsX86::Read(buffer.data());
   case sizeof(x86_64_user_regs):
-    return ReadX86_64(buffer.data());
+    return RegsX86_64::Read(buffer.data());
   case sizeof(arm_user_regs):
-    return ReadArm(buffer.data());
+    return RegsArm::Read(buffer.data());
   case sizeof(arm64_user_regs):
-    return ReadArm64(buffer.data());
+    return RegsArm64::Read(buffer.data());
   }
   return nullptr;
 }
 
-static Regs* CreateFromArmUcontext(void* ucontext) {
-  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
-
-  RegsArm* regs = new RegsArm();
-  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* CreateFromArm64Ucontext(void* ucontext) {
-  arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
-
-  RegsArm64* regs = new RegsArm64();
-  memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
-  // Put the registers in the expected order.
-  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
-  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
-  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
-  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
-  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
-  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
-  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
-  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
-  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
-  SetFromRaw();
-}
-
-static Regs* CreateFromX86Ucontext(void* ucontext) {
-  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
-
-  RegsX86* regs = new RegsX86();
-  regs->SetFromUcontext(x86_ucontext);
-  return regs;
-}
-
-void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
-  // R8-R15
-  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
-  // Rest of the registers.
-  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
-  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
-  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
-  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
-  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
-  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
-  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
-  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
-  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
-
-  SetFromRaw();
-}
-
-static Regs* CreateFromX86_64Ucontext(void* ucontext) {
-  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
-
-  RegsX86_64* regs = new RegsX86_64();
-  regs->SetFromUcontext(x86_64_ucontext);
-  return regs;
-}
-
-Regs* Regs::CreateFromUcontext(uint32_t machine_type, void* ucontext) {
-  switch (machine_type) {
-    case EM_386:
-      return CreateFromX86Ucontext(ucontext);
-    case EM_X86_64:
-      return CreateFromX86_64Ucontext(ucontext);
-    case EM_ARM:
-      return CreateFromArmUcontext(ucontext);
-    case EM_AARCH64:
-      return CreateFromArm64Ucontext(ucontext);
+Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
+  switch (arch) {
+    case ARCH_X86:
+      return RegsX86::CreateFromUcontext(ucontext);
+    case ARCH_X86_64:
+      return RegsX86_64::CreateFromUcontext(ucontext);
+    case ARCH_ARM:
+      return RegsArm::CreateFromUcontext(ucontext);
+    case ARCH_ARM64:
+      return RegsArm64::CreateFromUcontext(ucontext);
+    case ARCH_UNKNOWN:
+    default:
+      return nullptr;
   }
-  return nullptr;
 }
 
-uint32_t Regs::CurrentMachineType() {
+ArchEnum Regs::CurrentArch() {
 #if defined(__arm__)
-  return EM_ARM;
+  return ARCH_ARM;
 #elif defined(__aarch64__)
-  return EM_AARCH64;
+  return ARCH_ARM64;
 #elif defined(__i386__)
-  return EM_386;
+  return ARCH_X86;
 #elif defined(__x86_64__)
-  return EM_X86_64;
+  return ARCH_X86_64;
 #else
   abort();
 #endif
@@ -469,192 +110,4 @@
   return regs;
 }
 
-bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint32_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  uint64_t offset = 0;
-  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
-    // non-RT sigreturn call.
-    // __restore:
-    //
-    // Form 1 (arm):
-    // 0x77 0x70              mov r7, #0x77
-    // 0xa0 0xe3              svc 0x00000000
-    //
-    // Form 2 (arm):
-    // 0x77 0x00 0x90 0xef    svc 0x00900077
-    //
-    // Form 3 (thumb):
-    // 0x77 0x27              movs r7, #77
-    // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
-      return false;
-    }
-    if (data == 0x5ac3c35a) {
-      // SP + uc_mcontext offset + r0 offset.
-      offset = sp() + 0x14 + 0xc;
-    } else {
-      // SP + r0 offset
-      offset = sp() + 0xc;
-    }
-  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
-    // RT sigreturn call.
-    // __restore_rt:
-    //
-    // Form 1 (arm):
-    // 0xad 0x70      mov r7, #0xad
-    // 0xa0 0xe3      svc 0x00000000
-    //
-    // Form 2 (arm):
-    // 0xad 0x00 0x90 0xef    svc 0x009000ad
-    //
-    // Form 3 (thumb):
-    // 0xad 0x27              movs r7, #ad
-    // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
-      return false;
-    }
-    if (data == sp() + 8) {
-      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
-    } else {
-      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 0x80 + 0x14 + 0xc;
-    }
-  }
-  if (offset == 0) {
-    return false;
-  }
-
-  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
-    return false;
-  }
-  SetFromRaw();
-  return true;
-}
-
-bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  // Look for the kernel sigreturn function.
-  // __kernel_rt_sigreturn:
-  // 0xd2801168     mov x8, #0x8b
-  // 0xd4000001     svc #0x0
-  if (data != 0xd4000001d2801168ULL) {
-    return false;
-  }
-
-  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
-  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
-                                 sizeof(uint64_t) * ARM64_REG_LAST)) {
-    return false;
-  }
-
-  SetFromRaw();
-  return true;
-}
-
-bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  if (data == 0x80cd00000077b858ULL) {
-    // Without SA_SIGINFO set, the return sequence is:
-    //
-    //   __restore:
-    //   0x58                            pop %eax
-    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
-    //   0xcd 0x80                       int 0x80
-    //
-    // SP points at arguments:
-    //   int signum
-    //   struct sigcontext (same format as mcontext)
-    struct x86_mcontext_t context;
-    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
-      return false;
-    }
-    regs_[X86_REG_EBP] = context.ebp;
-    regs_[X86_REG_ESP] = context.esp;
-    regs_[X86_REG_EBX] = context.ebx;
-    regs_[X86_REG_EDX] = context.edx;
-    regs_[X86_REG_ECX] = context.ecx;
-    regs_[X86_REG_EAX] = context.eax;
-    regs_[X86_REG_EIP] = context.eip;
-    SetFromRaw();
-    return true;
-  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
-    // With SA_SIGINFO set, the return sequence is:
-    //
-    //   __restore_rt:
-    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
-    //   0xcd 0x80                       int 0x80
-    //
-    // SP points at arguments:
-    //   int signum
-    //   siginfo*
-    //   ucontext*
-
-    // Get the location of the sigcontext data.
-    uint32_t ptr;
-    if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
-      return false;
-    }
-    // Only read the portion of the data structure we care about.
-    x86_ucontext_t x86_ucontext;
-    if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
-      return false;
-    }
-    SetFromUcontext(&x86_ucontext);
-    return true;
-  }
-  return false;
-}
-
-bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
-    return false;
-  }
-
-  uint16_t data2;
-  if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
-    return false;
-  }
-
-  // __restore_rt:
-  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
-  // 0x0f 0x05                            syscall
-  // 0x0f                                 nopl 0x0($rax)
-
-  // Read the mcontext data from the stack.
-  // sp points to the ucontext data structure, read only the mcontext part.
-  x86_64_ucontext_t x86_64_ucontext;
-  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
-                                 sizeof(x86_64_mcontext_t))) {
-    return false;
-  }
-  SetFromUcontext(&x86_64_ucontext);
-  return true;
-}
-
 }  // namespace unwindstack
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
new file mode 100644
index 0000000..34f29bd
--- /dev/null
+++ b/libunwindstack/RegsArm.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 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 <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsArm.h>
+
+#include "MachineArm.h"
+#include "UcontextArm.h"
+#include "UserArm.h"
+
+namespace unwindstack {
+
+RegsArm::RegsArm()
+    : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
+
+ArchEnum RegsArm::Arch() {
+  return ARCH_ARM;
+}
+
+uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  uint64_t load_bias = elf->GetLoadBias();
+  if (rel_pc < load_bias) {
+    return rel_pc;
+  }
+  uint64_t adjusted_rel_pc = rel_pc - load_bias;
+
+  if (adjusted_rel_pc < 5) {
+    return rel_pc;
+  }
+
+  if (adjusted_rel_pc & 1) {
+    // This is a thumb instruction, it could be 2 or 4 bytes.
+    uint32_t value;
+    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+        (value & 0xe000f000) != 0xe000f000) {
+      return rel_pc - 2;
+    }
+  }
+  return rel_pc - 4;
+}
+
+void RegsArm::SetFromRaw() {
+  set_pc(regs_[ARM_REG_PC]);
+  set_sp(regs_[ARM_REG_SP]);
+}
+
+bool RegsArm::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[ARM_REG_LR]) {
+    return false;
+  }
+
+  set_pc(regs_[ARM_REG_LR]);
+  return true;
+}
+
+void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("r0", regs_[ARM_REG_R0]);
+  fn("r1", regs_[ARM_REG_R1]);
+  fn("r2", regs_[ARM_REG_R2]);
+  fn("r3", regs_[ARM_REG_R3]);
+  fn("r4", regs_[ARM_REG_R4]);
+  fn("r5", regs_[ARM_REG_R5]);
+  fn("r6", regs_[ARM_REG_R6]);
+  fn("r7", regs_[ARM_REG_R7]);
+  fn("r8", regs_[ARM_REG_R8]);
+  fn("r9", regs_[ARM_REG_R9]);
+  fn("r10", regs_[ARM_REG_R10]);
+  fn("r11", regs_[ARM_REG_R11]);
+  fn("ip", regs_[ARM_REG_R12]);
+  fn("sp", regs_[ARM_REG_SP]);
+  fn("lr", regs_[ARM_REG_LR]);
+  fn("pc", regs_[ARM_REG_PC]);
+}
+
+Regs* RegsArm::Read(void* remote_data) {
+  arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
+
+  RegsArm* regs = new RegsArm();
+  memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsArm::CreateFromUcontext(void* ucontext) {
+  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
+
+  RegsArm* regs = new RegsArm();
+  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint32_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  uint64_t offset = 0;
+  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+    // non-RT sigreturn call.
+    // __restore:
+    //
+    // Form 1 (arm):
+    // 0x77 0x70              mov r7, #0x77
+    // 0xa0 0xe3              svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0x77 0x00 0x90 0xef    svc 0x00900077
+    //
+    // Form 3 (thumb):
+    // 0x77 0x27              movs r7, #77
+    // 0x00 0xdf              svc 0
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == 0x5ac3c35a) {
+      // SP + uc_mcontext offset + r0 offset.
+      offset = sp() + 0x14 + 0xc;
+    } else {
+      // SP + r0 offset
+      offset = sp() + 0xc;
+    }
+  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+    // RT sigreturn call.
+    // __restore_rt:
+    //
+    // Form 1 (arm):
+    // 0xad 0x70      mov r7, #0xad
+    // 0xa0 0xe3      svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0xad 0x00 0x90 0xef    svc 0x009000ad
+    //
+    // Form 3 (thumb):
+    // 0xad 0x27              movs r7, #ad
+    // 0x00 0xdf              svc 0
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == sp() + 8) {
+      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+    } else {
+      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 0x80 + 0x14 + 0xc;
+    }
+  }
+  if (offset == 0) {
+    return false;
+  }
+
+  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+    return false;
+  }
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
new file mode 100644
index 0000000..2077bc5
--- /dev/null
+++ b/libunwindstack/RegsArm64.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 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 <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsArm64.h>
+
+#include "MachineArm64.h"
+#include "UcontextArm64.h"
+#include "UserArm64.h"
+
+namespace unwindstack {
+
+RegsArm64::RegsArm64()
+    : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
+
+ArchEnum RegsArm64::Arch() {
+  return ARCH_ARM64;
+}
+
+uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc < 4) {
+    return rel_pc;
+  }
+  return rel_pc - 4;
+}
+
+void RegsArm64::SetFromRaw() {
+  set_pc(regs_[ARM64_REG_PC]);
+  set_sp(regs_[ARM64_REG_SP]);
+}
+
+bool RegsArm64::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[ARM64_REG_LR]) {
+    return false;
+  }
+
+  set_pc(regs_[ARM64_REG_LR]);
+  return true;
+}
+
+void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("x0", regs_[ARM64_REG_R0]);
+  fn("x1", regs_[ARM64_REG_R1]);
+  fn("x2", regs_[ARM64_REG_R2]);
+  fn("x3", regs_[ARM64_REG_R3]);
+  fn("x4", regs_[ARM64_REG_R4]);
+  fn("x5", regs_[ARM64_REG_R5]);
+  fn("x6", regs_[ARM64_REG_R6]);
+  fn("x7", regs_[ARM64_REG_R7]);
+  fn("x8", regs_[ARM64_REG_R8]);
+  fn("x9", regs_[ARM64_REG_R9]);
+  fn("x10", regs_[ARM64_REG_R10]);
+  fn("x11", regs_[ARM64_REG_R11]);
+  fn("x12", regs_[ARM64_REG_R12]);
+  fn("x13", regs_[ARM64_REG_R13]);
+  fn("x14", regs_[ARM64_REG_R14]);
+  fn("x15", regs_[ARM64_REG_R15]);
+  fn("x16", regs_[ARM64_REG_R16]);
+  fn("x17", regs_[ARM64_REG_R17]);
+  fn("x18", regs_[ARM64_REG_R18]);
+  fn("x19", regs_[ARM64_REG_R19]);
+  fn("x20", regs_[ARM64_REG_R20]);
+  fn("x21", regs_[ARM64_REG_R21]);
+  fn("x22", regs_[ARM64_REG_R22]);
+  fn("x23", regs_[ARM64_REG_R23]);
+  fn("x24", regs_[ARM64_REG_R24]);
+  fn("x25", regs_[ARM64_REG_R25]);
+  fn("x26", regs_[ARM64_REG_R26]);
+  fn("x27", regs_[ARM64_REG_R27]);
+  fn("x28", regs_[ARM64_REG_R28]);
+  fn("x29", regs_[ARM64_REG_R29]);
+  fn("sp", regs_[ARM64_REG_SP]);
+  fn("lr", regs_[ARM64_REG_LR]);
+  fn("pc", regs_[ARM64_REG_PC]);
+}
+
+Regs* RegsArm64::Read(void* remote_data) {
+  arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
+
+  RegsArm64* regs = new RegsArm64();
+  memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
+  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+  reg_data[ARM64_REG_PC] = user->pc;
+  reg_data[ARM64_REG_SP] = user->sp;
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsArm64::CreateFromUcontext(void* ucontext) {
+  arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
+
+  RegsArm64* regs = new RegsArm64();
+  memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  // Look for the kernel sigreturn function.
+  // __kernel_rt_sigreturn:
+  // 0xd2801168     mov x8, #0x8b
+  // 0xd4000001     svc #0x0
+  if (data != 0xd4000001d2801168ULL) {
+    return false;
+  }
+
+  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+                                 sizeof(uint64_t) * ARM64_REG_LAST)) {
+    return false;
+  }
+
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
new file mode 100644
index 0000000..ef2f3de
--- /dev/null
+++ b/libunwindstack/RegsX86.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 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 <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsX86.h>
+
+#include "MachineX86.h"
+#include "UcontextX86.h"
+#include "UserX86.h"
+
+namespace unwindstack {
+
+RegsX86::RegsX86()
+    : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
+
+ArchEnum RegsX86::Arch() {
+  return ARCH_X86;
+}
+
+uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc == 0) {
+    return 0;
+  }
+  return rel_pc - 1;
+}
+
+void RegsX86::SetFromRaw() {
+  set_pc(regs_[X86_REG_PC]);
+  set_sp(regs_[X86_REG_SP]);
+}
+
+bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
+  // Attempt to get the return address from the top of the stack.
+  uint32_t new_pc;
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+    return false;
+  }
+
+  set_pc(new_pc);
+  return true;
+}
+
+void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("eax", regs_[X86_REG_EAX]);
+  fn("ebx", regs_[X86_REG_EBX]);
+  fn("ecx", regs_[X86_REG_ECX]);
+  fn("edx", regs_[X86_REG_EDX]);
+  fn("ebp", regs_[X86_REG_EBP]);
+  fn("edi", regs_[X86_REG_EDI]);
+  fn("esi", regs_[X86_REG_ESI]);
+  fn("esp", regs_[X86_REG_ESP]);
+  fn("eip", regs_[X86_REG_EIP]);
+}
+
+Regs* RegsX86::Read(void* user_data) {
+  x86_user_regs* user = reinterpret_cast<x86_user_regs*>(user_data);
+
+  RegsX86* regs = new RegsX86();
+  (*regs)[X86_REG_EAX] = user->eax;
+  (*regs)[X86_REG_EBX] = user->ebx;
+  (*regs)[X86_REG_ECX] = user->ecx;
+  (*regs)[X86_REG_EDX] = user->edx;
+  (*regs)[X86_REG_EBP] = user->ebp;
+  (*regs)[X86_REG_EDI] = user->edi;
+  (*regs)[X86_REG_ESI] = user->esi;
+  (*regs)[X86_REG_ESP] = user->esp;
+  (*regs)[X86_REG_EIP] = user->eip;
+
+  regs->SetFromRaw();
+  return regs;
+}
+
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+  // Put the registers in the expected order.
+  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+  SetFromRaw();
+}
+
+Regs* RegsX86::CreateFromUcontext(void* ucontext) {
+  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
+
+  RegsX86* regs = new RegsX86();
+  regs->SetFromUcontext(x86_ucontext);
+  return regs;
+}
+
+bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  if (data == 0x80cd00000077b858ULL) {
+    // Without SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore:
+    //   0x58                            pop %eax
+    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   struct sigcontext (same format as mcontext)
+    struct x86_mcontext_t context;
+    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
+      return false;
+    }
+    regs_[X86_REG_EBP] = context.ebp;
+    regs_[X86_REG_ESP] = context.esp;
+    regs_[X86_REG_EBX] = context.ebx;
+    regs_[X86_REG_EDX] = context.edx;
+    regs_[X86_REG_ECX] = context.ecx;
+    regs_[X86_REG_EAX] = context.eax;
+    regs_[X86_REG_EIP] = context.eip;
+    SetFromRaw();
+    return true;
+  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+    // With SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore_rt:
+    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   siginfo*
+    //   ucontext*
+
+    // Get the location of the sigcontext data.
+    uint32_t ptr;
+    if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
+      return false;
+    }
+    // Only read the portion of the data structure we care about.
+    x86_ucontext_t x86_ucontext;
+    if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+      return false;
+    }
+    SetFromUcontext(&x86_ucontext);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
new file mode 100644
index 0000000..70921f8
--- /dev/null
+++ b/libunwindstack/RegsX86_64.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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 <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsX86_64.h>
+
+#include "MachineX86_64.h"
+#include "UcontextX86_64.h"
+#include "UserX86_64.h"
+
+namespace unwindstack {
+
+RegsX86_64::RegsX86_64()
+    : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
+
+ArchEnum RegsX86_64::Arch() {
+  return ARCH_X86_64;
+}
+
+uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc == 0) {
+    return 0;
+  }
+
+  return rel_pc - 1;
+}
+
+void RegsX86_64::SetFromRaw() {
+  set_pc(regs_[X86_64_REG_PC]);
+  set_sp(regs_[X86_64_REG_SP]);
+}
+
+bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
+  // Attempt to get the return address from the top of the stack.
+  uint64_t new_pc;
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+    return false;
+  }
+
+  set_pc(new_pc);
+  return true;
+}
+
+void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("rax", regs_[X86_64_REG_RAX]);
+  fn("rbx", regs_[X86_64_REG_RBX]);
+  fn("rcx", regs_[X86_64_REG_RCX]);
+  fn("rdx", regs_[X86_64_REG_RDX]);
+  fn("r8", regs_[X86_64_REG_R8]);
+  fn("r9", regs_[X86_64_REG_R9]);
+  fn("r10", regs_[X86_64_REG_R10]);
+  fn("r11", regs_[X86_64_REG_R11]);
+  fn("r12", regs_[X86_64_REG_R12]);
+  fn("r13", regs_[X86_64_REG_R13]);
+  fn("r14", regs_[X86_64_REG_R14]);
+  fn("r15", regs_[X86_64_REG_R15]);
+  fn("rdi", regs_[X86_64_REG_RDI]);
+  fn("rsi", regs_[X86_64_REG_RSI]);
+  fn("rbp", regs_[X86_64_REG_RBP]);
+  fn("rsp", regs_[X86_64_REG_RSP]);
+  fn("rip", regs_[X86_64_REG_RIP]);
+}
+
+Regs* RegsX86_64::Read(void* remote_data) {
+  x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
+
+  RegsX86_64* regs = new RegsX86_64();
+  (*regs)[X86_64_REG_RAX] = user->rax;
+  (*regs)[X86_64_REG_RBX] = user->rbx;
+  (*regs)[X86_64_REG_RCX] = user->rcx;
+  (*regs)[X86_64_REG_RDX] = user->rdx;
+  (*regs)[X86_64_REG_R8] = user->r8;
+  (*regs)[X86_64_REG_R9] = user->r9;
+  (*regs)[X86_64_REG_R10] = user->r10;
+  (*regs)[X86_64_REG_R11] = user->r11;
+  (*regs)[X86_64_REG_R12] = user->r12;
+  (*regs)[X86_64_REG_R13] = user->r13;
+  (*regs)[X86_64_REG_R14] = user->r14;
+  (*regs)[X86_64_REG_R15] = user->r15;
+  (*regs)[X86_64_REG_RDI] = user->rdi;
+  (*regs)[X86_64_REG_RSI] = user->rsi;
+  (*regs)[X86_64_REG_RBP] = user->rbp;
+  (*regs)[X86_64_REG_RSP] = user->rsp;
+  (*regs)[X86_64_REG_RIP] = user->rip;
+
+  regs->SetFromRaw();
+  return regs;
+}
+
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+  // R8-R15
+  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+  // Rest of the registers.
+  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+  SetFromRaw();
+}
+
+Regs* RegsX86_64::CreateFromUcontext(void* ucontext) {
+  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
+
+  RegsX86_64* regs = new RegsX86_64();
+  regs->SetFromUcontext(x86_64_ucontext);
+  return regs;
+}
+
+bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+    return false;
+  }
+
+  uint16_t data2;
+  if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+    return false;
+  }
+
+  // __restore_rt:
+  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
+  // 0x0f 0x05                            syscall
+  // 0x0f                                 nopl 0x0($rax)
+
+  // Read the mcontext data from the stack.
+  // sp points to the ucontext data structure, read only the mcontext part.
+  x86_64_ucontext_t x86_64_ucontext;
+  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
+                                 sizeof(x86_64_mcontext_t))) {
+    return false;
+  }
+  SetFromUcontext(&x86_64_ucontext);
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
deleted file mode 100644
index 22f6a89..0000000
--- a/libunwindstack/Ucontext.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_H
-#define _LIBUNWINDSTACK_UCONTEXT_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-//-------------------------------------------------------------------
-// ARM ucontext structures
-//-------------------------------------------------------------------
-struct arm_stack_t {
-  uint32_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint32_t ss_size;  // size_t
-};
-
-struct arm_mcontext_t {
-  uint32_t trap_no;             // unsigned long
-  uint32_t error_code;          // unsigned long
-  uint32_t oldmask;             // unsigned long
-  uint32_t regs[ARM_REG_LAST];  // unsigned long
-  uint32_t cpsr;                // unsigned long
-  uint32_t fault_address;       // unsigned long
-};
-
-struct arm_ucontext_t {
-  uint32_t uc_flags;  // unsigned long
-  uint32_t uc_link;   // struct ucontext*
-  arm_stack_t uc_stack;
-  arm_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// ARM64 ucontext structures
-//-------------------------------------------------------------------
-struct arm64_stack_t {
-  uint64_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint64_t ss_size;  // size_t
-};
-
-struct arm64_sigset_t {
-  uint64_t sig;  // unsigned long
-};
-
-struct arm64_mcontext_t {
-  uint64_t fault_address;         // __u64
-  uint64_t regs[ARM64_REG_LAST];  // __u64
-  uint64_t pstate;                // __u64
-  // Nothing else is used, so don't define it.
-};
-
-struct arm64_ucontext_t {
-  uint64_t uc_flags;  // unsigned long
-  uint64_t uc_link;   // struct ucontext*
-  arm64_stack_t uc_stack;
-  arm64_sigset_t uc_sigmask;
-  // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
-  char __padding[128 - sizeof(arm64_sigset_t)];
-  // The full structure requires 16 byte alignment, but our partial structure
-  // doesn't, so force the alignment.
-  arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86 ucontext structures
-//-------------------------------------------------------------------
-struct x86_stack_t {
-  uint32_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint32_t ss_size;  // size_t
-};
-
-struct x86_mcontext_t {
-  uint32_t gs;
-  uint32_t fs;
-  uint32_t es;
-  uint32_t ds;
-  uint32_t edi;
-  uint32_t esi;
-  uint32_t ebp;
-  uint32_t esp;
-  uint32_t ebx;
-  uint32_t edx;
-  uint32_t ecx;
-  uint32_t eax;
-  uint32_t trapno;
-  uint32_t err;
-  uint32_t eip;
-  uint32_t cs;
-  uint32_t efl;
-  uint32_t uesp;
-  uint32_t ss;
-  // Only care about the registers, skip everything else.
-};
-
-struct x86_ucontext_t {
-  uint32_t uc_flags;  // unsigned long
-  uint32_t uc_link;   // struct ucontext*
-  x86_stack_t uc_stack;
-  x86_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86_64 ucontext structures
-//-------------------------------------------------------------------
-struct x86_64_stack_t {
-  uint64_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint64_t ss_size;  // size_t
-};
-
-struct x86_64_mcontext_t {
-  uint64_t r8;
-  uint64_t r9;
-  uint64_t r10;
-  uint64_t r11;
-  uint64_t r12;
-  uint64_t r13;
-  uint64_t r14;
-  uint64_t r15;
-  uint64_t rdi;
-  uint64_t rsi;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t rdx;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rsp;
-  uint64_t rip;
-  uint64_t efl;
-  uint64_t csgsfs;
-  uint64_t err;
-  uint64_t trapno;
-  uint64_t oldmask;
-  uint64_t cr2;
-  // Only care about the registers, skip everything else.
-};
-
-struct x86_64_ucontext_t {
-  uint64_t uc_flags;  // unsigned long
-  uint64_t uc_link;   // struct ucontext*
-  x86_64_stack_t uc_stack;
-  x86_64_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-}  // namespace unwindstack
-
-#endif  // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/UcontextArm.h
new file mode 100644
index 0000000..8c94166
--- /dev/null
+++ b/libunwindstack/UcontextArm.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
+
+#include <stdint.h>
+
+#include "MachineArm.h"
+
+namespace unwindstack {
+
+struct arm_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct arm_mcontext_t {
+  uint32_t trap_no;             // unsigned long
+  uint32_t error_code;          // unsigned long
+  uint32_t oldmask;             // unsigned long
+  uint32_t regs[ARM_REG_LAST];  // unsigned long
+  uint32_t cpsr;                // unsigned long
+  uint32_t fault_address;       // unsigned long
+};
+
+struct arm_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  arm_stack_t uc_stack;
+  arm_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/UcontextArm64.h
new file mode 100644
index 0000000..655719f
--- /dev/null
+++ b/libunwindstack/UcontextArm64.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+
+#include <stdint.h>
+
+#include "MachineArm64.h"
+
+namespace unwindstack {
+
+struct arm64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
+};
+
+struct arm64_sigset_t {
+  uint64_t sig;  // unsigned long
+};
+
+struct arm64_mcontext_t {
+  uint64_t fault_address;         // __u64
+  uint64_t regs[ARM64_REG_LAST];  // __u64
+  uint64_t pstate;                // __u64
+  // Nothing else is used, so don't define it.
+};
+
+struct arm64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  arm64_stack_t uc_stack;
+  arm64_sigset_t uc_sigmask;
+  // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
+  char __padding[128 - sizeof(arm64_sigset_t)];
+  // The full structure requires 16 byte alignment, but our partial structure
+  // doesn't, so force the alignment.
+  arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
diff --git a/libunwindstack/User.h b/libunwindstack/UcontextX86.h
similarity index 62%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86.h
index 53f7e50..f79d92b 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86.h
@@ -26,75 +26,52 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_H
+
+#include <stdint.h>
+
+#include "MachineX86.h"
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
+struct x86_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct x86_mcontext_t {
+  uint32_t gs;
+  uint32_t fs;
+  uint32_t es;
+  uint32_t ds;
   uint32_t edi;
+  uint32_t esi;
   uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
   uint32_t esp;
-  uint32_t xss;
+  uint32_t ebx;
+  uint32_t edx;
+  uint32_t ecx;
+  uint32_t eax;
+  uint32_t trapno;
+  uint32_t err;
+  uint32_t eip;
+  uint32_t cs;
+  uint32_t efl;
+  uint32_t uesp;
+  uint32_t ss;
+  // Only care about the registers, skip everything else.
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
+struct x86_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  x86_stack_t uc_stack;
+  x86_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UcontextX86_64.h
similarity index 67%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86_64.h
index 53f7e50..d689796 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86_64.h
@@ -26,75 +26,56 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+
+#include <stdint.h>
+
+#include "MachineX86_64.h"
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
+struct x86_64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
+struct x86_64_mcontext_t {
+  uint64_t r8;
+  uint64_t r9;
+  uint64_t r10;
+  uint64_t r11;
   uint64_t r12;
+  uint64_t r13;
+  uint64_t r14;
+  uint64_t r15;
+  uint64_t rdi;
+  uint64_t rsi;
   uint64_t rbp;
   uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
+  uint64_t rdx;
   uint64_t rax;
   uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
   uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
+  uint64_t rip;
+  uint64_t efl;
+  uint64_t csgsfs;
+  uint64_t err;
+  uint64_t trapno;
+  uint64_t oldmask;
+  uint64_t cr2;
+  // Only care about the registers, skip everything else.
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
+struct x86_64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  x86_64_stack_t uc_stack;
+  x86_64_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
 };
 
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 3092a62..a83f85b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -174,8 +174,7 @@
   if (frame_num >= frames_.size()) {
     return "";
   }
-  return FormatFrame(frames_[frame_num],
-                     regs_->MachineType() == EM_ARM || regs_->MachineType() == EM_386);
+  return FormatFrame(frames_[frame_num], regs_->Format32Bit());
 }
 
 std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {
diff --git a/libunwindstack/UserArm.h b/libunwindstack/UserArm.h
new file mode 100644
index 0000000..7388c03
--- /dev/null
+++ b/libunwindstack/UserArm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_USER_ARM_H
+#define _LIBUNWINDSTACK_USER_ARM_H
+
+namespace unwindstack {
+
+struct arm_user_regs {
+  uint32_t regs[18];
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserArm64.h
similarity index 60%
copy from libunwindstack/User.h
copy to libunwindstack/UserArm64.h
index 53f7e50..d74983f 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserArm64.h
@@ -26,65 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_ARM64_H
+#define _LIBUNWINDSTACK_USER_ARM64_H
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
-};
-
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
-};
-
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
 struct arm64_user_regs {
   uint64_t regs[31];
   uint64_t sp;
@@ -92,9 +38,6 @@
   uint64_t pstate;
 };
 
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_ARM64_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserX86.h
similarity index 68%
copy from libunwindstack/User.h
copy to libunwindstack/UserX86.h
index 53f7e50..a040560 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86.h
@@ -26,8 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_H
+#define _LIBUNWINDSTACK_USER_X86_H
 
 namespace unwindstack {
 
@@ -51,50 +51,6 @@
   uint32_t xss;
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
-};
-
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserX86_64.h
similarity index 74%
rename from libunwindstack/User.h
rename to libunwindstack/UserX86_64.h
index 53f7e50..b80d201 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86_64.h
@@ -26,31 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_64_H
+#define _LIBUNWINDSTACK_USER_X86_64_H
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
-};
-
 struct x86_64_user_regs {
   uint64_t r15;
   uint64_t r14;
@@ -81,20 +61,6 @@
   uint64_t gs;
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index d9ea9c4..d27727b 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -36,6 +36,14 @@
 struct MapInfo;
 class Regs;
 
+enum ArchEnum : uint8_t {
+  ARCH_UNKNOWN = 0,
+  ARCH_ARM,
+  ARCH_ARM64,
+  ARCH_X86,
+  ARCH_X86_64,
+};
+
 class Elf {
  public:
   Elf(Memory* memory) : memory_(memory) {}
@@ -64,6 +72,8 @@
 
   uint8_t class_type() { return class_type_; }
 
+  ArchEnum arch() { return arch_; }
+
   Memory* memory() { return memory_.get(); }
 
   ElfInterface* interface() { return interface_.get(); }
@@ -83,6 +93,7 @@
   std::unique_ptr<Memory> memory_;
   uint32_t machine_type_;
   uint8_t class_type_;
+  ArchEnum arch_;
   // Protect calls that can modify internal state of the interface object.
   std::mutex lock_;
 
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 8163152..94ceaab 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <memory>
 #include <string>
 #include <vector>
@@ -99,7 +100,7 @@
 
 class MemoryRemote : public Memory {
  public:
-  MemoryRemote(pid_t pid) : pid_(pid) {}
+  MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
   virtual ~MemoryRemote() = default;
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
@@ -108,6 +109,7 @@
 
  private:
   pid_t pid_;
+  std::atomic_uintptr_t read_redirect_func_;
 };
 
 class MemoryLocal : public Memory {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 6576e4c..613682f 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -27,10 +27,8 @@
 
 // Forward declarations.
 class Elf;
-struct MapInfo;
+enum ArchEnum : uint8_t;
 class Memory;
-struct x86_ucontext_t;
-struct x86_64_ucontext_t;
 
 class Regs {
  public:
@@ -51,7 +49,9 @@
       : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {}
   virtual ~Regs() = default;
 
-  virtual uint32_t MachineType() = 0;
+  virtual ArchEnum Arch() = 0;
+
+  virtual bool Format32Bit() = 0;
 
   virtual void* RawData() = 0;
   virtual uint64_t pc() = 0;
@@ -70,9 +70,9 @@
   uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
-  static uint32_t CurrentMachineType();
+  static ArchEnum CurrentArch();
   static Regs* RemoteGet(pid_t pid);
-  static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext);
+  static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext);
   static Regs* CreateFromLocal();
 
  protected:
@@ -94,6 +94,8 @@
   void set_pc(AddressType pc) { pc_ = pc; }
   void set_sp(AddressType sp) { sp_ = sp; }
 
+  bool Format32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
+
   inline AddressType& operator[](size_t reg) { return regs_[reg]; }
 
   void* RawData() override { return regs_.data(); }
@@ -110,82 +112,6 @@
   std::vector<AddressType> regs_;
 };
 
-class RegsArm : public RegsImpl<uint32_t> {
- public:
-  RegsArm();
-  virtual ~RegsArm() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsArm64 : public RegsImpl<uint64_t> {
- public:
-  RegsArm64();
-  virtual ~RegsArm64() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsX86 : public RegsImpl<uint32_t> {
- public:
-  RegsX86();
-  virtual ~RegsX86() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  void SetFromUcontext(x86_ucontext_t* ucontext);
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsX86_64 : public RegsImpl<uint64_t> {
- public:
-  RegsX86_64();
-  virtual ~RegsX86_64() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  void SetFromUcontext(x86_64_ucontext_t* ucontext);
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
new file mode 100644
index 0000000..b5d344b
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_ARM_H
+#define _LIBUNWINDSTACK_REGS_ARM_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm : public RegsImpl<uint32_t> {
+ public:
+  RegsArm();
+  virtual ~RegsArm() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
new file mode 100644
index 0000000..30e626c
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_ARM64_H
+#define _LIBUNWINDSTACK_REGS_ARM64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm64 : public RegsImpl<uint64_t> {
+ public:
+  RegsArm64();
+  virtual ~RegsArm64() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_ARM64_H
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
new file mode 100644
index 0000000..a695bbf
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_X86_H
+#define _LIBUNWINDSTACK_REGS_X86_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_ucontext_t;
+
+class RegsX86 : public RegsImpl<uint32_t> {
+ public:
+  RegsX86();
+  virtual ~RegsX86() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
new file mode 100644
index 0000000..23a3f20
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_X86_64_H
+#define _LIBUNWINDSTACK_REGS_X86_64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_64_ucontext_t;
+
+class RegsX86_64 : public RegsImpl<uint64_t> {
+ public:
+  RegsX86_64();
+  virtual ~RegsX86_64() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_64_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_X86_64_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 94cb493..8d6d00d 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -24,7 +24,7 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/Log.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4b621c9..5f7cf60 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,10 +20,10 @@
 
 #include <vector>
 
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index afd113d..00192f1 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -25,6 +25,7 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ElfFake.h"
 #include "ElfTestUtils.h"
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 8aa8605..f5492a2 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -225,7 +225,7 @@
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
-  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
   // Some read methods can read PROT_NONE maps, allow that.
   ASSERT_LE(page_size, read_size);
   for (size_t i = 0; i < read_size; ++i) {
@@ -260,7 +260,7 @@
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
-  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
   ASSERT_EQ(page_size, read_size);
   for (size_t i = 0; i < read_size; ++i) {
     ASSERT_EQ(0xFF, dst[i]);
@@ -270,4 +270,55 @@
   }
 }
 
+// Verify that the memory remote object chooses a memory read function
+// properly. Either process_vm_readv or ptrace.
+TEST_F(MemoryRemoteTest, read_choose_correctly) {
+  size_t page_size = getpagesize();
+  void* mapping =
+      mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFC, 2 * page_size);
+  ASSERT_EQ(0, mprotect(static_cast<char*>(mapping), page_size, PROT_NONE));
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_EQ(0, munmap(mapping, 2 * page_size));
+
+  ASSERT_TRUE(Attach(pid));
+
+  // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
+  // Read from the PROT_NONE area first to force the choice of ptrace.
+  MemoryRemote remote_ptrace(pid);
+  uint32_t value;
+  size_t bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+
+  // Now verify that choosing process_vm_readv results in failing reads of
+  // the PROT_NONE part of the map. Read from a valid map first which
+  // should prefer process_vm_readv, and keep that as the read function.
+  MemoryRemote remote_readv(pid);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(0U, bytes);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index fedaf87..b81b2ca 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <unwindstack/Elf.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
@@ -30,7 +31,7 @@
       : Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsFake() = default;
 
-  uint32_t MachineType() override { return fake_type_; }
+  ArchEnum Arch() override { return fake_arch_; }
   void* RawData() override { return nullptr; }
   uint64_t pc() override { return fake_pc_; }
   uint64_t sp() override { return fake_sp_; }
@@ -44,20 +45,22 @@
 
   void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
 
+  bool Format32Bit() { return false; }
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
 
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
   void SetFromRaw() override {}
 
-  void FakeSetMachineType(uint32_t type) { fake_type_ = type; }
+  void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
   void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
   void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
   void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
   void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
 
  private:
-  uint32_t fake_type_ = 0;
+  ArchEnum fake_arch_ = ARCH_UNKNOWN;
   uint64_t fake_pc_ = 0;
   uint64_t fake_sp_ = 0;
   bool fake_return_address_valid_ = false;
@@ -71,7 +74,7 @@
       : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsImplFake() = default;
 
-  uint32_t MachineType() override { return 0; }
+  ArchEnum Arch() override { return ARCH_UNKNOWN; }
 
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
   void SetFromRaw() override {}
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index c8d1d98..0cb70ba 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -25,9 +25,15 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index 85192d5..ae57caf 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -19,9 +19,15 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
 
 #include "MemoryFake.h"
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3320f77..a932973 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -21,7 +21,10 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
@@ -212,4 +215,18 @@
   EXPECT_EQ(0x4900000000U, x86_64.pc());
 }
 
+TEST_F(RegsTest, machine_type) {
+  RegsArm arm_regs;
+  EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
+
+  RegsArm64 arm64_regs;
+  EXPECT_EQ(ARCH_ARM64, arm64_regs.Arch());
+
+  RegsX86 x86_regs;
+  EXPECT_EQ(ARCH_X86, x86_regs.Arch());
+
+  RegsX86_64 x86_64_regs;
+  EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index d24abe4..962f744 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -27,10 +27,12 @@
 
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
 #include <unwindstack/Unwinder.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
 
 #include "ElfTestUtils.h"
 
@@ -73,7 +75,7 @@
   BufferMaps maps(buffer.data());
   ASSERT_TRUE(maps.Parse());
 
-  ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
+  ASSERT_EQ(ARCH_ARM, regs.Arch());
 
   std::shared_ptr<Memory> process_memory(memory);
 
@@ -125,7 +127,7 @@
   BufferMaps maps(buffer.data());
   ASSERT_TRUE(maps.Parse());
 
-  ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
+  ASSERT_EQ(ARCH_ARM64, regs.Arch());
 
   std::shared_ptr<Memory> process_memory(memory);
 
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index b372fd0..242cc6a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -250,7 +250,7 @@
 
   LocalMaps maps;
   ASSERT_TRUE(maps.Parse());
-  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
+  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
 
   VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
 
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 098459e..2034191 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -28,6 +28,10 @@
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 #include <unwindstack/Unwinder.h>
 
 #include "ElfFake.h"
@@ -53,7 +57,7 @@
   static void SetUpTestCase() {
     maps_.FakeClear();
     MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
-    ElfFake* elf = new ElfFake(nullptr);
+    ElfFake* elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
@@ -66,36 +70,38 @@
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
-    elf = new ElfFake(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
-    elf = new ElfFake(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
-    elf = new ElfFake(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
-    elf = new ElfFake(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
     maps_.FakeAddMapInfo(info);
+
+    process_memory_.reset(new MemoryFake);
   }
 
   void SetUp() override {
     ElfInterfaceFake::FakeClear();
-    regs_.FakeSetMachineType(EM_ARM);
+    regs_.FakeSetArch(ARCH_ARM);
     regs_.FakeSetReturnAddressValid(false);
   }
 
@@ -690,29 +696,67 @@
   EXPECT_EQ("  #01 pc 00001000  <unknown>", Unwinder::FormatFrame(frame, true));
 }
 
+static std::string ArchToString(ArchEnum arch) {
+  if (arch == ARCH_ARM) {
+    return "Arm";
+  } else if (arch == ARCH_ARM64) {
+    return "Arm64";
+  } else if (arch == ARCH_X86) {
+    return "X86";
+  } else if (arch == ARCH_X86_64) {
+    return "X86_64";
+  } else {
+    return "Unknown";
+  }
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
-  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
+  std::vector<Regs*> reg_list;
+  RegsArm* arm = new RegsArm;
+  arm->set_pc(0x2300);
+  arm->set_sp(0x10000);
+  reg_list.push_back(arm);
 
-  regs_.FakeSetPc(0x2300);
-  regs_.FakeSetSp(0x10000);
+  RegsArm64* arm64 = new RegsArm64;
+  arm64->set_pc(0x2300);
+  arm64->set_sp(0x10000);
+  reg_list.push_back(arm64);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
-  unwinder.Unwind();
+  RegsX86* x86 = new RegsX86;
+  x86->set_pc(0x2300);
+  x86->set_sp(0x10000);
+  reg_list.push_back(x86);
 
-  ASSERT_EQ(1U, unwinder.NumFrames());
+  RegsX86_64* x86_64 = new RegsX86_64;
+  x86_64->set_pc(0x2300);
+  x86_64->set_sp(0x10000);
+  reg_list.push_back(x86_64);
 
-  regs_.FakeSetMachineType(EM_ARM);
-  EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetMachineType(EM_386);
-  EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
+  for (auto regs : reg_list) {
+    ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
 
-  regs_.FakeSetMachineType(EM_AARCH64);
-  EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetMachineType(EM_X86_64);
-  EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
+    Unwinder unwinder(64, &maps_, regs, process_memory_);
+    unwinder.Unwind();
 
-  EXPECT_EQ("", unwinder.FormatFrame(1));
+    ASSERT_EQ(1U, unwinder.NumFrames());
+    std::string expected;
+    switch (regs->Arch()) {
+      case ARCH_ARM:
+      case ARCH_X86:
+        expected = "  #00 pc 00001300  /system/fake/libc.so (Frame0+10)";
+        break;
+      case ARCH_ARM64:
+      case ARCH_X86_64:
+        expected = "  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)";
+        break;
+      default:
+        expected = "";
+    }
+    EXPECT_EQ(expected, unwinder.FormatFrame(0))
+        << "Mismatch of frame format for regs arch " << ArchToString(regs->Arch());
+    delete regs;
+  }
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index f2530d7..7896279 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -63,17 +63,17 @@
   }
 
   printf("ABI: ");
-  switch (regs->MachineType()) {
-    case EM_ARM:
+  switch (regs->Arch()) {
+    case unwindstack::ARCH_ARM:
       printf("arm");
       break;
-    case EM_386:
+    case unwindstack::ARCH_X86:
       printf("x86");
       break;
-    case EM_AARCH64:
+    case unwindstack::ARCH_ARM64:
       printf("arm64");
       break;
-    case EM_X86_64:
+    case unwindstack::ARCH_X86_64:
       printf("x86_64");
       break;
     default:
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 44b878d..4d286bf 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -324,29 +324,39 @@
 
 struct usb_device *usb_device_open(const char *dev_name)
 {
-    int fd, did_retry = 0, writeable = 1;
-
+    int fd, attempts, writeable = 1;
+    const int SLEEP_BETWEEN_ATTEMPTS_US = 100000; /* 100 ms */
+    const int64_t MAX_ATTEMPTS = 10;              /* 1s */
     D("usb_device_open %s\n", dev_name);
 
-retry:
-    fd = open(dev_name, O_RDWR);
-    if (fd < 0) {
-        /* if we fail, see if have read-only access */
-        fd = open(dev_name, O_RDONLY);
-        D("usb_device_open open returned %d errno %d\n", fd, errno);
-        if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
-            /* work around race condition between inotify and permissions management */
-            sleep(1);
-            did_retry = 1;
-            goto retry;
+    /* Hack around waiting for permissions to be set on the USB device node.
+     * Should really be a timeout instead of attempt count, and should REALLY
+     * be triggered by the perm change via inotify rather than polling.
+     */
+    for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
+        if (access(dev_name, R_OK | W_OK) == 0) {
+            writeable = 1;
+            break;
+        } else {
+            if (access(dev_name, R_OK) == 0) {
+                /* double check that write permission didn't just come along too! */
+                writeable = (access(dev_name, R_OK | W_OK) == 0);
+                break;
+            }
         }
-
-        if (fd < 0)
-            return NULL;
-        writeable = 0;
-        D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
+        /* not writeable or readable - sleep and try again. */
+        D("usb_device_open no access sleeping\n");
+        usleep(SLEEP_BETWEEN_ATTEMPTS_US);
     }
 
+    if (writeable) {
+        fd = open(dev_name, O_RDWR);
+    } else {
+        fd = open(dev_name, O_RDONLY);
+    }
+    D("usb_device_open open returned %d writeable %d errno %d\n", fd, writeable, errno);
+    if (fd < 0) return NULL;
+
     struct usb_device* result = usb_device_new(dev_name, fd);
     if (result)
         result->writeable = writeable;
diff --git a/libutils/OWNERS b/libutils/OWNERS
new file mode 100644
index 0000000..40164aa
--- /dev/null
+++ b/libutils/OWNERS
@@ -0,0 +1 @@
+smoreland@google.com
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index e7520a8..1086831 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -180,7 +180,15 @@
     size_t ret = 0;
     const char32_t *end = src + src_len;
     while (src < end) {
-        ret += utf32_codepoint_utf8_length(*src++);
+        size_t char_len = utf32_codepoint_utf8_length(*src++);
+        if (SSIZE_MAX - char_len < ret) {
+            // If this happens, we would overflow the ssize_t type when
+            // returning from this function, so we cannot express how
+            // long this string is in an ssize_t.
+            android_errorWriteLog(0x534e4554, "37723026");
+            return -1;
+        }
+        ret += char_len;
     }
     return ret;
 }
@@ -439,14 +447,23 @@
     size_t ret = 0;
     const char16_t* const end = src + src_len;
     while (src < end) {
+        size_t char_len;
         if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
                 && (*(src + 1) & 0xFC00) == 0xDC00) {
             // surrogate pairs are always 4 bytes.
-            ret += 4;
+            char_len = 4;
             src += 2;
         } else {
-            ret += utf32_codepoint_utf8_length((char32_t) *src++);
+            char_len = utf32_codepoint_utf8_length((char32_t)*src++);
         }
+        if (SSIZE_MAX - char_len < ret) {
+            // If this happens, we would overflow the ssize_t type when
+            // returning from this function, so we cannot express how
+            // long this string is in an ssize_t.
+            android_errorWriteLog(0x534e4554, "37723026");
+            return -1;
+        }
+        ret += char_len;
     }
     return ret;
 }
diff --git a/libvndksupport/OWNERS b/libvndksupport/OWNERS
new file mode 100644
index 0000000..c7efc16
--- /dev/null
+++ b/libvndksupport/OWNERS
@@ -0,0 +1,2 @@
+jiyong@google.com
+smoreland@google.com
diff --git a/libziparchive/OWNERS b/libziparchive/OWNERS
new file mode 100644
index 0000000..fcc567a
--- /dev/null
+++ b/libziparchive/OWNERS
@@ -0,0 +1 @@
+narayan@google.com
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6da5c99..5ccbcc2 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -385,6 +385,22 @@
       return -1;
     }
   }
+
+  uint32_t lfh_start_bytes;
+  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>(&lfh_start_bytes),
+                                        sizeof(uint32_t), 0)) {
+    ALOGW("Zip: Unable to read header for entry at offset == 0.");
+    return -1;
+  }
+
+  if (lfh_start_bytes != LocalFileHeader::kSignature) {
+    ALOGW("Zip: Entry at offset zero has invalid LFH signature %" PRIx32, lfh_start_bytes);
+#if defined(__ANDROID__)
+    android_errorWriteLog(0x534e4554, "64211847");
+#endif
+    return -1;
+  }
+
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
   return 0;
diff --git a/lmkd/OWNERS b/lmkd/OWNERS
new file mode 100644
index 0000000..b15bb48
--- /dev/null
+++ b/lmkd/OWNERS
@@ -0,0 +1 @@
+surenb@google.com
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 8a6168c..5cfa2c8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,19 +18,21 @@
 
 #include <arpa/inet.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
 #include <sys/cdefs.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
 
+#include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <processgroup/processgroup.h>
@@ -40,7 +42,10 @@
 #endif
 
 #define MEMCG_SYSFS_PATH "/dev/memcg/"
-#define MEMPRESSURE_WATCH_LEVEL "low"
+#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
+#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
+#define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium"
+#define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical"
 #define ZONEINFO_PATH "/proc/zoneinfo"
 #define LINE_MAX 128
 
@@ -48,6 +53,7 @@
 #define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
 
 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
+#define EIGHT_MEGA (1 << 23)
 
 enum lmk_cmd {
     LMK_TARGET,
@@ -64,17 +70,28 @@
 
 /* default to old in-kernel interface if no memory pressure events */
 static int use_inkernel_interface = 1;
+static bool has_inkernel_module;
 
 /* memory pressure level medium event */
-static int mpevfd;
+static int mpevfd[2];
+#define CRITICAL_INDEX 1
+#define MEDIUM_INDEX 0
+
+static int medium_oomadj;
+static int critical_oomadj;
+static bool debug_process_killing;
+static bool enable_pressure_upgrade;
+static int64_t upgrade_pressure;
+static int64_t downgrade_pressure;
+static bool is_go_device;
 
 /* control socket listen and data */
 static int ctrl_lfd;
 static int ctrl_dfd = -1;
 static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
 
-/* 1 memory pressure level, 1 ctrl listen socket, 1 ctrl data socket */
-#define MAX_EPOLL_EVENTS 3
+/* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
+#define MAX_EPOLL_EVENTS 4
 static int epollfd;
 static int maxevents;
 
@@ -113,14 +130,6 @@
 #define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
 static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
 
-/*
- * Wait 1-2 seconds for the death report of a killed process prior to
- * considering killing more processes.
- */
-#define KILL_TIMEOUT 2
-/* Time of last process kill we initiated, stop me before I kill again */
-static time_t kill_lasttime;
-
 /* PAGE_SIZE / 1024 */
 static long page_k;
 
@@ -241,6 +250,7 @@
     struct proc *procp;
     char path[80];
     char val[20];
+    int soft_limit_mult;
 
     if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
         ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
@@ -254,6 +264,38 @@
     if (use_inkernel_interface)
         return;
 
+    if (oomadj >= 900) {
+        soft_limit_mult = 0;
+    } else if (oomadj >= 800) {
+        soft_limit_mult = 0;
+    } else if (oomadj >= 700) {
+        soft_limit_mult = 0;
+    } else if (oomadj >= 600) {
+        // Launcher should be perceptible, don't kill it.
+        oomadj = 200;
+        soft_limit_mult = 1;
+    } else if (oomadj >= 500) {
+        soft_limit_mult = 0;
+    } else if (oomadj >= 400) {
+        soft_limit_mult = 0;
+    } else if (oomadj >= 300) {
+        soft_limit_mult = 1;
+    } else if (oomadj >= 200) {
+        soft_limit_mult = 2;
+    } else if (oomadj >= 100) {
+        soft_limit_mult = 10;
+    } else if (oomadj >=   0) {
+        soft_limit_mult = 20;
+    } else {
+        // Persistent processes will have a large
+        // soft limit 512MB.
+        soft_limit_mult = 64;
+    }
+
+    snprintf(path, sizeof(path), "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes", uid, pid);
+    snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
+    writefilestring(path, val);
+
     procp = pid_lookup(pid);
     if (!procp) {
             procp = malloc(sizeof(struct proc));
@@ -278,7 +320,6 @@
         return;
 
     pid_remove(pid);
-    kill_lasttime = 0;
 }
 
 static void cmd_target(int ntargets, int *params) {
@@ -294,7 +335,7 @@
 
     lowmem_targets_size = ntargets;
 
-    if (use_inkernel_interface) {
+    if (has_inkernel_module) {
         char minfreestr[128];
         char killpriostr[128];
 
@@ -309,9 +350,9 @@
                 strlcat(killpriostr, ",", sizeof(killpriostr));
             }
 
-            snprintf(val, sizeof(val), "%d", lowmem_minfree[i]);
+            snprintf(val, sizeof(val), "%d", use_inkernel_interface ? lowmem_minfree[i] : 0);
             strlcat(minfreestr, val, sizeof(minfreestr));
-            snprintf(val, sizeof(val), "%d", lowmem_adj[i]);
+            snprintf(val, sizeof(val), "%d", use_inkernel_interface ? lowmem_adj[i] : 0);
             strlcat(killpriostr, val, sizeof(killpriostr));
         }
 
@@ -546,9 +587,7 @@
 }
 
 /* Kill one process specified by procp.  Returns the size of the process killed */
-static int kill_one_process(struct proc *procp, int other_free, int other_file,
-        int minfree, int min_score_adj, bool first)
-{
+static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) {
     int pid = procp->pid;
     uid_t uid = procp->uid;
     char *taskname;
@@ -567,14 +606,12 @@
         return -1;
     }
 
-    ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
-          "   to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
-          "   Free memory is %s%ldkB %s reserved",
-          taskname, pid, uid, procp->oomadj, tasksize * page_k,
-          first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
-          first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
+    ALOGI(
+        "Killing '%s' (%d), uid %d, adj %d\n"
+        "   to free %ldkB because system is under %s memory pressure oom_adj %d\n",
+        taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium",
+        min_score_adj);
     r = kill(pid, SIGKILL);
-    killProcessGroup(uid, pid, SIGKILL);
     pid_remove(pid);
 
     if (r) {
@@ -589,23 +626,10 @@
  * Find a process to kill based on the current (possibly estimated) free memory
  * and cached memory sizes.  Returns the size of the killed processes.
  */
-static int find_and_kill_process(int other_free, int other_file, bool first)
-{
+static int find_and_kill_process(bool is_critical) {
     int i;
-    int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
-    int minfree = 0;
     int killed_size = 0;
-
-    for (i = 0; i < lowmem_targets_size; i++) {
-        minfree = lowmem_minfree[i];
-        if (other_free < minfree && other_file < minfree) {
-            min_score_adj = lowmem_adj[i];
-            break;
-        }
-    }
-
-    if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
-        return 0;
+    int min_score_adj = is_critical ? critical_oomadj : medium_oomadj;
 
     for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
         struct proc *procp;
@@ -614,7 +638,7 @@
         procp = proc_adj_lru(i);
 
         if (procp) {
-            killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
+            killed_size = kill_one_process(procp, min_score_adj, is_critical);
             if (killed_size < 0) {
                 goto retry;
             } else {
@@ -626,42 +650,91 @@
     return 0;
 }
 
-static void mp_event(uint32_t events __unused) {
+static int64_t get_memory_usage(const char* path) {
+    int ret;
+    int64_t mem_usage;
+    char buf[32];
+    int fd = open(path, O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        ALOGE("%s open: errno=%d", path, errno);
+        return -1;
+    }
+
+    ret = read_all(fd, buf, sizeof(buf) - 1);
+    close(fd);
+    if (ret < 0) {
+        ALOGE("%s error: errno=%d", path, errno);
+        return -1;
+    }
+    sscanf(buf, "%" SCNd64, &mem_usage);
+    if (mem_usage == 0) {
+        ALOGE("No memory!");
+        return -1;
+    }
+    return mem_usage;
+}
+
+static void mp_event_common(bool is_critical) {
     int ret;
     unsigned long long evcount;
-    struct sysmeminfo mi;
-    int other_free;
-    int other_file;
-    int killed_size;
-    bool first = true;
+    int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
+    int64_t mem_usage, memsw_usage;
+    int64_t mem_pressure;
 
-    ret = read(mpevfd, &evcount, sizeof(evcount));
+    ret = read(mpevfd[index], &evcount, sizeof(evcount));
     if (ret < 0)
         ALOGE("Error reading memory pressure event fd; errno=%d",
               errno);
 
-    if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
+    mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
+    memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
+    if (memsw_usage < 0 || mem_usage < 0) {
+        find_and_kill_process(is_critical);
         return;
-
-    while (zoneinfo_parse(&mi) < 0) {
-        // Failed to read /proc/zoneinfo, assume ENOMEM and kill something
-        find_and_kill_process(0, 0, true);
     }
 
-    other_free = mi.nr_free_pages - mi.totalreserve_pages;
-    other_file = mi.nr_file_pages - mi.nr_shmem;
+    // Calculate percent for swappinness.
+    mem_pressure = (mem_usage * 100) / memsw_usage;
 
-    do {
-        killed_size = find_and_kill_process(other_free, other_file, first);
-        if (killed_size > 0) {
-            first = false;
-            other_free += killed_size;
-            other_file += killed_size;
+    if (enable_pressure_upgrade && !is_critical) {
+        // We are swapping too much.
+        if (mem_pressure < upgrade_pressure) {
+            ALOGI("Event upgraded to critical.");
+            is_critical = true;
         }
-    } while (killed_size > 0);
+    }
+
+    // If the pressure is larger than downgrade_pressure lmk will not
+    // kill any process, since enough memory is available.
+    if (mem_pressure > downgrade_pressure) {
+        if (debug_process_killing) {
+            ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium");
+        }
+        return;
+    } else if (is_critical && mem_pressure > upgrade_pressure) {
+        if (debug_process_killing) {
+            ALOGI("Downgrade critical memory pressure");
+        }
+        // Downgrade event to medium, since enough memory available.
+        is_critical = false;
+    }
+
+    if (find_and_kill_process(is_critical) == 0) {
+        if (debug_process_killing) {
+            ALOGI("Nothing to kill");
+        }
+    }
 }
 
-static int init_mp(char *levelstr, void *event_handler)
+static void mp_event(uint32_t events __unused) {
+    mp_event_common(false);
+}
+
+static void mp_event_critical(uint32_t events __unused) {
+    mp_event_common(true);
+}
+
+static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
 {
     int mpfd;
     int evfd;
@@ -669,6 +742,7 @@
     char buf[256];
     struct epoll_event epev;
     int ret;
+    int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
 
     mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
     if (mpfd < 0) {
@@ -709,7 +783,7 @@
         goto err;
     }
     maxevents++;
-    mpevfd = evfd;
+    mpevfd[mpevfd_index] = evfd;
     return 0;
 
 err:
@@ -722,6 +796,16 @@
     return -1;
 }
 
+static int init_mp_medium()
+{
+    return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false);
+}
+
+static int init_mp_critical()
+{
+    return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true);
+}
+
 static int init(void) {
     struct epoll_event epev;
     int i;
@@ -758,12 +842,14 @@
     }
     maxevents++;
 
-    use_inkernel_interface = !access(INKERNEL_MINFREE_PATH, W_OK);
+    has_inkernel_module = !access(INKERNEL_MINFREE_PATH, W_OK);
+    use_inkernel_interface = has_inkernel_module && !is_go_device;
 
     if (use_inkernel_interface) {
         ALOGI("Using in-kernel low memory killer interface");
     } else {
-        ret = init_mp(MEMPRESSURE_WATCH_LEVEL, (void *)&mp_event);
+        ret = init_mp_medium();
+        ret |= init_mp_critical();
         if (ret)
             ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
     }
@@ -806,6 +892,14 @@
             .sched_priority = 1,
     };
 
+    medium_oomadj = property_get_int32("ro.lmk.medium", 800);
+    critical_oomadj = property_get_int32("ro.lmk.critical", 0);
+    debug_process_killing = property_get_bool("ro.lmk.debug", false);
+    enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false);
+    upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50);
+    downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60);
+    is_go_device = property_get_bool("ro.config.low_ram", false);
+
     mlockall(MCL_FUTURE);
     sched_setscheduler(0, SCHED_FIFO, &param);
     if (!init())
diff --git a/logcat/OWNERS b/logcat/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logcat/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/logd/OWNERS b/logd/OWNERS
new file mode 100644
index 0000000..2394e32
--- /dev/null
+++ b/logd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+tomcherry@google.com
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 1915677..a0875ea 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -63,7 +63,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libselinux
 LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.core.logd
 include $(BUILD_CTS_EXECUTABLE)
 
diff --git a/logwrapper/OWNERS b/logwrapper/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logwrapper/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/qemu_pipe/OWNERS b/qemu_pipe/OWNERS
new file mode 100644
index 0000000..dbc1bf6
--- /dev/null
+++ b/qemu_pipe/OWNERS
@@ -0,0 +1 @@
+bohu@google.com
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aa970d6..777fdb0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -142,6 +142,7 @@
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     sbin dev proc sys system data oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
     ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
@@ -206,16 +207,18 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
-vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
-$(vndk_lib_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
 
-llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
+llndk_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
 
-vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+private_llndk_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
 
-vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_SAMEPROCESS_LIBRARIES))))
+
+vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
 
 sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
 $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
@@ -226,20 +229,20 @@
 $(2ND_TSAN_RUNTIME_LIBRARY)))
 
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $(private_llndk_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in
 	@echo "Generate: $< -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+	$(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
 
-vndk_lib_md5 :=
-vndk_lib_dep :=
 llndk_libraries :=
 vndk_sameprocess_libraries :=
 vndk_core_libraries :=
@@ -266,13 +269,8 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-llndk_dep = $(intermediates)/$(llndk_md5).dep
-$(llndk_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(llndk_dep)
+$(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
 	$(hide) echo -n > $@
@@ -287,13 +285,8 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-vndksp_dep = $(intermediates)/$(vndksp_md5).dep
-$(vndksp_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(vndksp_dep)
+$(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
 	$(hide) echo -n > $@
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
new file mode 100644
index 0000000..f335715
--- /dev/null
+++ b/rootdir/OWNERS
@@ -0,0 +1,3 @@
+jiyong@google.com
+smoreland@google.com
+tomcherry@google.com
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index cae6e13..3183b80 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -63,7 +63,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp${VNDK_VER}/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -91,10 +91,10 @@
 ###############################################################################
 namespace.rs.isolated = true
 namespace.rs.visible = true
-namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
-namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
@@ -108,10 +108,10 @@
 ###############################################################################
 namespace.vndk.isolated = true
 namespace.vndk.visible = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
 
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
 
 # When these NDK libs are required inside this namespace, then it is redirected
@@ -128,6 +128,6 @@
 ###############################################################################
 [vendor]
 namespace.default.isolated = false
-namespace.default.search.paths = /odm/${LIB}/hw:/odm/${LIB}/egl:/odm/${LIB}:/vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/odm/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+namespace.default.search.paths = /odm/${LIB}/hw:/odm/${LIB}/egl:/odm/${LIB}:/vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk${VNDK_VER}:/odm/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}
 
-namespace.default.asan.search.paths = /data/asan/odm/${LIB}/hw:/odm/${LIB}/hw:/data/asan/odm/${LIB}/egl:/odm/${LIB}/egl:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/odm/${LIB}/vndk-sp:/odm/${LIB}/vndk-sp:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+namespace.default.asan.search.paths = /data/asan/odm/${LIB}/hw:/odm/${LIB}/hw:/data/asan/odm/${LIB}/egl:/odm/${LIB}/egl:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/odm/${LIB}/vndk-sp${VNDK_VER}:/odm/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index a6bed8d..2d05fca 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -27,17 +27,13 @@
 # can't be loaded in this namespace.
 ###############################################################################
 namespace.default.isolated = true
-# TODO(b/63553457): remove /vendor/lib from the search path. For now, this is
-# required since the classloader namespace for vendor apks should have access
-# vendor libraries in the directory. These search paths are copied to the search
-# paths of the classloader namespace.
-namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}
 # /vendor/app, /vendor/framework were added since libart should be able to dlopen
 # the odex files from the directory.
-namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
+namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/extractors:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
 
-namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
-namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
+namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/extractors:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
 
 ###############################################################################
 # "sphal" namespace
@@ -55,7 +51,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp${VNDK_VER}/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -83,14 +79,17 @@
 ###############################################################################
 namespace.rs.isolated = true
 namespace.rs.visible = true
-namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
-namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
 namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
 namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
 ###############################################################################
@@ -99,10 +98,11 @@
 # This namespace is exclusively for vndk-sp libs.
 ###############################################################################
 namespace.vndk.isolated = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.visible = true
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
 
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
 
 # When these NDK libs are required inside this namespace, then it is redirected
@@ -123,30 +123,31 @@
 ###############################################################################
 # "default" namespace
 #
-# Vendor-side code runs in this namespace.
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# 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.
 ###############################################################################
 namespace.default.isolated = true
 namespace.default.visible = true
 
-namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}
+namespace.default.permitted.paths = /vendor
 
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor
 
 namespace.default.links = system
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:libmedia.so:libandroid_runtime.so
-# libmedia.so must be removed after we have fix for lib-dplmedia.so (b/64427765)
-# libandroid_runtime.so must be removed after we have a fix for qseeproxydaemon (b/64820887)
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:%VNDK_SAMEPROCESS_LIBRARIES%:%VNDK_CORE_LIBRARIES%
 
 ###############################################################################
 # "system" namespace
 #
-# This is for vendor process to use LL-NDK in system partition.
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
 ###############################################################################
 namespace.system.isolated = false
-namespace.system.search.paths = /system/${LIB}
-namespace.system.permitted.paths = /system/${LIB}
+namespace.system.search.paths = /system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}
 
-namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
-namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.search.paths = /data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index c5e149c..e20b95d 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -15,6 +15,7 @@
 libmediandk.so
 libm.so
 libnativewindow.so
+libneuralnetworks.so
 libOpenMAXAL.so
 libOpenSLES.so
 libRS.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index a4ca683..3c46094 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -15,6 +15,7 @@
 libmediandk.so
 libm.so
 libnativewindow.so
+libneuralnetworks.so
 libOpenMAXAL.so
 libOpenSLES.so
 libRS.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 11b8383..5fa77d8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -48,8 +48,10 @@
     copy /proc/cmdline /dev/urandom
     copy /default.prop /dev/urandom
 
-    # Backward compatibility.
+    symlink /system/bin /bin
     symlink /system/etc /etc
+
+    # Backward compatibility.
     symlink /sys/kernel/debug /d
 
     # Link /vendor to /system/vendor for devices without a vendor partition.
@@ -148,6 +150,9 @@
     write /proc/sys/net/ipv4/conf/all/accept_redirects 0
     write /proc/sys/net/ipv6/conf/all/accept_redirects 0
 
+    # /proc/net/fib_trie leaks interface IP addresses
+    chmod 0400 /proc/net/fib_trie
+
     # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
diff --git a/sdcard/OWNERS b/sdcard/OWNERS
new file mode 100644
index 0000000..199a0f8
--- /dev/null
+++ b/sdcard/OWNERS
@@ -0,0 +1 @@
+drosen@google.com
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 343a903..77d5a91 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -319,17 +319,31 @@
     LOG(FATAL) << "terminated prematurely";
 }
 
-static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, uid_t fsuid,
-                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
-    std::string opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
-            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
+static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path,
+                           uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid,
+                           mode_t mask, bool derive_gid) {
+    std::string opts = android::base::StringPrintf(
+        "fsuid=%d,fsgid=%d,%s%smask=%d,userid=%d,gid=%d", fsuid, fsgid,
+        multi_user ? "multiuser," : "", derive_gid ? "derive_gid," : "", mask, userid, gid);
 
     if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
               MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
-        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
-        return false;
+        if (derive_gid) {
+            PLOG(ERROR) << "trying to mount sdcardfs filesystem without derive_gid";
+            /* Maybe this isn't supported on this kernel. Try without. */
+            opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
+                                               fsuid, fsgid, multi_user ? "multiuser," : "", mask,
+                                               userid, gid);
+            if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
+                      MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
+                PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+                return false;
+            }
+        } else {
+            PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+            return false;
+        }
     }
-
     return true;
 }
 
@@ -355,7 +369,8 @@
 }
 
 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
-        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+                         gid_t gid, userid_t userid, bool multi_user, bool full_write,
+                         bool derive_gid) {
     std::string dest_path_default = "/mnt/runtime/default/" + label;
     std::string dest_path_read = "/mnt/runtime/read/" + label;
     std::string dest_path_write = "/mnt/runtime/write/" + label;
@@ -365,10 +380,10 @@
         // Multi-user storage is fully isolated per user, so "other"
         // permissions are completely masked off.
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
-                                                      AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027)
-                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
-                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
+                            AID_SDCARD_RW, 0006, derive_gid) ||
+            !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) ||
+            !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
+                                         full_write ? 0007 : 0027)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
     } else {
@@ -376,11 +391,11 @@
         // the Android directories are masked off to a single user
         // deep inside attr_from_stat().
         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
-                                                      AID_SDCARD_RW, 0006)
-                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read,
-                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
-                || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write,
-                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
+                            AID_SDCARD_RW, 0006, derive_gid) ||
+            !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY,
+                                         full_write ? 0027 : 0022) ||
+            !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
+                                         full_write ? 0007 : 0022)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
     }
@@ -437,7 +452,8 @@
                << "    -g: specify GID to run as"
                << "    -U: specify user ID that owns device"
                << "    -m: source_path is multi-user"
-               << "    -w: runtime write mount has full write access";
+               << "    -w: runtime write mount has full write access"
+               << "    -P  preserve owners on the lower file system";
     return 1;
 }
 
@@ -449,12 +465,13 @@
     userid_t userid = 0;
     bool multi_user = false;
     bool full_write = false;
+    bool derive_gid = false;
     int i;
     struct rlimit rlim;
     int fs_version;
 
     int opt;
-    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:U:mwG")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -471,6 +488,9 @@
             case 'w':
                 full_write = true;
                 break;
+            case 'G':
+                derive_gid = true;
+                break;
             case '?':
             default:
                 return usage();
@@ -514,7 +534,7 @@
     }
 
     if (should_use_sdcardfs()) {
-        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
+        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid);
     } else {
         run(source_path, label, uid, gid, userid, multi_user, full_write);
     }
diff --git a/shell_and_utilities/OWNERS b/shell_and_utilities/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/shell_and_utilities/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/storaged/Android.mk b/storaged/Android.mk
index 5e6a3c0..a1abe0f 100644
--- a/storaged/Android.mk
+++ b/storaged/Android.mk
@@ -9,7 +9,6 @@
     libcutils \
     liblog \
     libsysutils \
-    libpackagelistparser \
     libbatteryservice \
 
 include $(CLEAR_VARS)
diff --git a/storaged/OWNERS b/storaged/OWNERS
new file mode 100644
index 0000000..7445270
--- /dev/null
+++ b/storaged/OWNERS
@@ -0,0 +1 @@
+jinqian@google.com
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 514798b..fa68406 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -256,6 +256,7 @@
     uid_monitor mUidm;
     time_t mStarttime;
     sp<IBatteryPropertiesRegistrar> battery_properties;
+    std::unique_ptr<storage_info_t> storage_info;
 public:
     storaged_t(void);
     ~storaged_t() {}
@@ -285,6 +286,8 @@
     void init_battery_service();
     virtual void batteryPropertiesChanged(struct BatteryProperties props);
     void binderDied(const wp<IBinder>& who);
+
+    void report_storage_info();
 };
 
 // Eventlog tag
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 913c814..7d04c7a 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -27,39 +27,46 @@
 class storage_info_t {
 protected:
     FRIEND_TEST(storaged_test, storage_info_t);
+    // emmc lifetime
     uint16_t eol;                   // pre-eol (end of life) information
     uint16_t lifetime_a;            // device life time estimation (type A)
     uint16_t lifetime_b;            // device life time estimation (type B)
     string version;                 // version string
+    // free space
+    const string userdata_path = "/data";
+    uint64_t userdata_total_kb;
+    uint64_t userdata_free_kb;
+
+    storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0),
+        userdata_total_kb(0), userdata_free_kb(0) {}
     void publish();
+    storage_info_t* s_info;
 public:
-    storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0) {}
+    static storage_info_t* get_storage_info();
     virtual ~storage_info_t() {}
-    virtual bool report() = 0;
+    virtual void report() {};
+    void refresh();
 };
 
 class emmc_info_t : public storage_info_t {
 private:
-    const string emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
-    const string emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
-    const char* emmc_ver_str[9] = {
-        "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
-    };
-public:
-    virtual ~emmc_info_t() {}
-    bool report();
     bool report_sysfs();
     bool report_debugfs();
+public:
+    static const string emmc_sysfs;
+    static const string emmc_debugfs;
+    static const char* emmc_ver_str[];
+
+    virtual ~emmc_info_t() {}
+    virtual void report();
 };
 
 class ufs_info_t : public storage_info_t {
-private:
-    const string health_file = "/sys/devices/soc/624000.ufshc/health";
 public:
-    virtual ~ufs_info_t() {}
-    bool report();
-};
+    static const string health_file;
 
-void report_storage_health();
+    virtual ~ufs_info_t() {}
+    virtual void report();
+};
 
 #endif /* _STORAGED_INFO_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 4d1e430..6b82904 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -49,6 +49,7 @@
     storaged = new storaged_t();
 
     storaged->init_battery_service();
+    storaged->report_storage_info();
 
     LOG_TO(SYSTEM, INFO) << "storaged: Start";
 
@@ -113,7 +114,6 @@
     }
 
     if (flag_main_service) { // start main thread
-        report_storage_health();
         // Start the main thread of storaged
         pthread_t storaged_main_thread;
         errno = pthread_create(&storaged_main_thread, NULL, storaged_main, NULL);
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 54d429c..06afea6 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -200,6 +200,10 @@
     }
 }
 
+void storaged_t::report_storage_info() {
+    storage_info->report();
+}
+
 /* storaged_t */
 storaged_t::storaged_t(void) {
     if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
@@ -222,6 +226,8 @@
     mConfig.periodic_chores_interval_uid_io =
         property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
 
+    storage_info.reset(storage_info_t::get_storage_info());
+
     mStarttime = time(NULL);
 }
 
@@ -229,6 +235,7 @@
     if (mConfig.diskstats_available) {
         mDiskStats.update();
         mDsm.update();
+        storage_info->refresh();
         if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
             mDiskStats.publish();
         }
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 434bd74..b5fb13e 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <sys/statvfs.h>
 
 #include <android-base/file.h>
 #include <android-base/parseint.h>
@@ -30,13 +31,42 @@
 using namespace std;
 using namespace android::base;
 
-void report_storage_health()
-{
-    emmc_info_t mmc;
-    ufs_info_t ufs;
+const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
+const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
+const char* emmc_info_t::emmc_ver_str[9] = {
+    "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
+};
 
-    mmc.report();
-    ufs.report();
+const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
+
+static bool FileExists(const std::string& filename)
+{
+  struct stat buffer;
+  return stat(filename.c_str(), &buffer) == 0;
+}
+
+storage_info_t* storage_info_t::get_storage_info()
+{
+    if (FileExists(emmc_info_t::emmc_sysfs) ||
+        FileExists(emmc_info_t::emmc_debugfs)) {
+        return new emmc_info_t;
+    }
+    if (FileExists(ufs_info_t::health_file)) {
+        return new ufs_info_t;
+    }
+    return new storage_info_t;
+}
+
+void storage_info_t::refresh()
+{
+    struct statvfs buf;
+    if (statvfs(userdata_path.c_str(), &buf) != 0) {
+        PLOG_TO(SYSTEM, WARNING) << "Failed to get userdata info";
+        return;
+    }
+
+    userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
+    userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
 }
 
 void storage_info_t::publish()
@@ -46,13 +76,12 @@
         << LOG_ID_EVENTS;
 }
 
-bool emmc_info_t::report()
+void emmc_info_t::report()
 {
     if (!report_sysfs() && !report_debugfs())
-        return false;
+        return;
 
     publish();
-    return true;
 }
 
 bool emmc_info_t::report_sysfs()
@@ -136,21 +165,21 @@
     return true;
 }
 
-bool ufs_info_t::report()
+void ufs_info_t::report()
 {
     string buffer;
     if (!ReadFileToString(health_file, &buffer)) {
-        return false;
+        return;
     }
 
     vector<string> lines = Split(buffer, "\n");
     if (lines.empty()) {
-        return false;
+        return;
     }
 
     char rev[8];
     if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
-        return false;
+        return;
     }
 
     version = "ufs " + string(rev);
@@ -175,10 +204,9 @@
     }
 
     if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
-        return false;
+        return;
     }
 
     publish();
-    return true;
 }
 
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 5bb98e1..dd8bdd6 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -22,33 +22,24 @@
 #include <string>
 #include <unordered_map>
 
+#include <android/content/pm/IPackageManagerNative.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <binder/IServiceManager.h>
 #include <log/log_event_list.h>
-#include <packagelistparser/packagelistparser.h>
 
 #include "storaged.h"
 #include "storaged_uid_monitor.h"
 
 using namespace android;
 using namespace android::base;
+using namespace android::content::pm;
 
-static bool packagelist_parse_cb(pkg_info* info, void* userdata)
-{
-    std::unordered_map<uint32_t, struct uid_info>* uids =
-        reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata);
-
-    if (uids->find(info->uid) != uids->end()) {
-        (*uids)[info->uid].name = info->name;
-    }
-
-    packagelist_free(info);
-    return true;
-}
+static bool refresh_uid_names;
 
 std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
 {
@@ -56,6 +47,38 @@
     return get_uid_io_stats_locked();
 };
 
+static void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
+{
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) {
+        LOG_TO(SYSTEM, ERROR) << "defaultServiceManager failed";
+        return;
+    }
+
+    sp<IBinder> binder = sm->getService(String16("package_native"));
+    if (binder == NULL) {
+        LOG_TO(SYSTEM, ERROR) << "getService package_native failed";
+        return;
+    }
+
+    sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+    std::vector<std::string> names;
+    binder::Status status = package_mgr->getNamesForUids(uids, &names);
+    if (!status.isOk()) {
+        LOG_TO(SYSTEM, ERROR) << "package_native::getNamesForUids failed: "
+                              << status.exceptionMessage();
+        return;
+    }
+
+    for (uint32_t i = 0; i < uid_names.size(); i++) {
+        if (!names[i].empty()) {
+            *uid_names[i] = names[i];
+        }
+    }
+
+    refresh_uid_names = false;
+}
+
 std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
 {
     std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
@@ -67,7 +90,8 @@
 
     std::vector<std::string> io_stats = Split(buffer, "\n");
     struct uid_info u;
-    bool refresh_uid = false;
+    vector<int> uids;
+    vector<std::string*> uid_names;
 
     for (uint32_t i = 0; i < io_stats.size(); i++) {
         if (io_stats[i].empty()) {
@@ -91,17 +115,19 @@
             continue;
         }
 
-        if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
-            refresh_uid = true;
-            u.name = std::to_string(u.uid);
-        } else {
-            u.name = last_uid_io_stats[u.uid].name;
-        }
         uid_io_stats[u.uid] = u;
+        uid_io_stats[u.uid].name = std::to_string(u.uid);
+        uids.push_back(u.uid);
+        uid_names.push_back(&uid_io_stats[u.uid].name);
+        if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
+            refresh_uid_names = true;
+        } else {
+            uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
+        }
     }
 
-    if (refresh_uid) {
-        packagelist_parse(packagelist_parse_cb, &uid_io_stats);
+    if (!uids.empty() && refresh_uid_names) {
+        get_uid_names(uids, uid_names);
     }
 
     return uid_io_stats;
@@ -228,13 +254,13 @@
             last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
 
         usage.bytes[READ][FOREGROUND][charger_stat] +=
-            (fg_rd_delta < 0) ? uid.io[FOREGROUND].read_bytes : fg_rd_delta;
+            (fg_rd_delta < 0) ? 0 : fg_rd_delta;
         usage.bytes[READ][BACKGROUND][charger_stat] +=
-            (bg_rd_delta < 0) ? uid.io[BACKGROUND].read_bytes : bg_rd_delta;
+            (bg_rd_delta < 0) ? 0 : bg_rd_delta;
         usage.bytes[WRITE][FOREGROUND][charger_stat] +=
-            (fg_wr_delta < 0) ? uid.io[FOREGROUND].write_bytes : fg_wr_delta;
+            (fg_wr_delta < 0) ? 0 : fg_wr_delta;
         usage.bytes[WRITE][BACKGROUND][charger_stat] +=
-            (bg_wr_delta < 0) ? uid.io[BACKGROUND].write_bytes : bg_wr_delta;
+            (bg_wr_delta < 0) ? 0 : bg_wr_delta;
     }
 
     last_uid_io_stats = uid_io_stats;
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 8db8327..9c2cafa 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -40,6 +40,10 @@
     cflags: common_cflags,
     local_include_dirs: ["upstream-netbsd/include/"],
     symlinks: ["egrep", "fgrep"],
+
+    sanitize: {
+        integer_overflow: false,
+    },
 }
 
 cc_binary {
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/toolbox/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/trusty/Android.bp b/trusty/Android.bp
index 386fbe6..2fb2e19 100644
--- a/trusty/Android.bp
+++ b/trusty/Android.bp
@@ -2,6 +2,5 @@
     "gatekeeper",
     "keymaster",
     "libtrusty",
-    "nvram",
     "storage/*",
 ]
diff --git a/trusty/OWNERS b/trusty/OWNERS
new file mode 100644
index 0000000..25291fd
--- /dev/null
+++ b/trusty/OWNERS
@@ -0,0 +1 @@
+bohr@google.com
diff --git a/trusty/gatekeeper/Android.bp b/trusty/gatekeeper/Android.bp
index a9566a1..65b271a 100644
--- a/trusty/gatekeeper/Android.bp
+++ b/trusty/gatekeeper/Android.bp
@@ -22,6 +22,7 @@
 
 cc_library_shared {
     name: "gatekeeper.trusty",
+    vendor: true,
 
     relative_install_path: "hw",
 
@@ -43,4 +44,5 @@
         "libcutils",
         "libtrusty",
     ],
+    header_libs: ["libhardware_headers"],
 }
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 7735684..322a63d 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -25,6 +25,7 @@
 // and ECDSA keys.
 cc_binary {
     name: "trusty_keymaster_tipc",
+    vendor: true,
     srcs: [
         "trusty_keymaster_device.cpp",
         "trusty_keymaster_ipc.cpp",
@@ -46,6 +47,7 @@
 // keystore.trusty is the HAL used by keystore on Trusty devices.
 cc_library_shared {
     name: "keystore.trusty",
+    vendor: true,
     relative_install_path: "hw",
     srcs: [
         "module.cpp",
@@ -66,4 +68,5 @@
         "liblog",
         "libcutils",
     ],
+    header_libs: ["libhardware_headers"],
 }
diff --git a/trusty/libtrusty/Android.bp b/trusty/libtrusty/Android.bp
index 1a8db2f..c48deed 100644
--- a/trusty/libtrusty/Android.bp
+++ b/trusty/libtrusty/Android.bp
@@ -18,6 +18,7 @@
 
 cc_library {
     name: "libtrusty",
+    vendor: true,
 
     srcs: ["trusty.c"],
     export_include_dirs: ["include"],
diff --git a/trusty/libtrusty/tipc-test/Android.bp b/trusty/libtrusty/tipc-test/Android.bp
index 6ec8c23..1e8467f 100644
--- a/trusty/libtrusty/tipc-test/Android.bp
+++ b/trusty/libtrusty/tipc-test/Android.bp
@@ -14,12 +14,14 @@
 
 cc_test {
     name: "tipc-test",
-    static_executable: true,
+    vendor: true,
 
     srcs: ["tipc_test.c"],
     static_libs: [
-        "libc",
         "libtrusty",
+    ],
+    shared_libs: [
+        "libc",
         "liblog",
     ],
     gtest: false,
diff --git a/trusty/nvram/Android.bp b/trusty/nvram/Android.bp
deleted file mode 100644
index 15e6c3e..0000000
--- a/trusty/nvram/Android.bp
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// Copyright (C) 2016 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.
-//
-
-// nvram.trusty is the Trusty NVRAM HAL module.
-cc_library_shared {
-    name: "nvram.trusty",
-    relative_install_path: "hw",
-    srcs: [
-        "module.c",
-        "trusty_nvram_device.cpp",
-        "trusty_nvram_implementation.cpp",
-    ],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-        "-fvisibility=hidden",
-    ],
-    static_libs: ["libnvram-hal"],
-    shared_libs: [
-        "libtrusty",
-        "libnvram-messages",
-        "liblog",
-    ],
-}
-
-// nvram-wipe is a helper tool for clearing NVRAM state.
-cc_binary {
-    name: "nvram-wipe",
-    srcs: [
-        "nvram_wipe.cpp",
-        "trusty_nvram_implementation.cpp",
-    ],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-        "-fvisibility=hidden",
-    ],
-    static_libs: ["libnvram-hal"],
-    shared_libs: [
-        "libtrusty",
-        "libnvram-messages",
-        "liblog",
-    ],
-}
diff --git a/trusty/nvram/module.c b/trusty/nvram/module.c
deleted file mode 100644
index a2e64d3..0000000
--- a/trusty/nvram/module.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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 <hardware/nvram.h>
-
-// This function is defined in trusty_nvram_device.cpp.
-int trusty_nvram_open(const hw_module_t* module,
-                      const char* device_id,
-                      hw_device_t** device_ptr);
-
-static struct hw_module_methods_t nvram_module_methods = {
-    .open = trusty_nvram_open,
-};
-
-struct nvram_module HAL_MODULE_INFO_SYM
-    __attribute__((visibility("default"))) = {
-        .common = {.tag = HARDWARE_MODULE_TAG,
-                   .module_api_version = NVRAM_MODULE_API_VERSION_0_1,
-                   .hal_api_version = HARDWARE_HAL_API_VERSION,
-                   .id = NVRAM_HARDWARE_MODULE_ID,
-                   .name = "Trusty NVRAM HAL",
-                   .author = "The Android Open Source Project",
-                   .methods = &nvram_module_methods,
-                   .dso = 0,
-                   .reserved = {}},
-};
diff --git a/trusty/nvram/nvram_wipe.cpp b/trusty/nvram/nvram_wipe.cpp
deleted file mode 100644
index d0f4fad..0000000
--- a/trusty/nvram/nvram_wipe.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <nvram/messages/nvram_messages.h>
-
-#include "trusty_nvram_implementation.h"
-
-void usage(const char* program_name) {
-  fprintf(stderr, "Usage: %s [status|disable|wipe]\n", program_name);
-  exit(-1);
-}
-
-int main(int argc, char* argv[]) {
-  if (argc < 2) {
-    usage(argv[0]);
-  }
-
-  nvram::TrustyNvramImplementation nvram_proxy;
-  nvram::Request request;
-  nvram::Response response;
-
-  if (!strcmp(argv[1], "status")) {
-    request.payload.Activate<nvram::COMMAND_GET_INFO>();
-    nvram_proxy.Execute(request, &response);
-    const nvram::GetInfoResponse* get_info_response =
-        response.payload.get<nvram::COMMAND_GET_INFO>();
-    if (response.result == NV_RESULT_SUCCESS) {
-      int status = get_info_response && get_info_response->wipe_disabled;
-      printf("Wiping disabled: %d\n", status);
-      return status;
-    }
-  } else if (!strcmp(argv[1], "disable")) {
-    request.payload.Activate<nvram::COMMAND_DISABLE_WIPE>();
-    nvram_proxy.Execute(request, &response);
-  } else if (!strcmp(argv[1], "wipe")) {
-    request.payload.Activate<nvram::COMMAND_WIPE_STORAGE>();
-    nvram_proxy.Execute(request, &response);
-  } else {
-    usage(argv[0]);
-  }
-
-  if (response.result != NV_RESULT_SUCCESS) {
-    fprintf(stderr, "Command execution failure: %u\n", response.result);
-    return -1;
-  }
-
-  return 0;
-}
-
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp
deleted file mode 100644
index 82a1228..0000000
--- a/trusty/nvram/trusty_nvram_device.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 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 <errno.h>
-
-#include <nvram/hal/nvram_device_adapter.h>
-
-#include "trusty_nvram_implementation.h"
-
-extern "C" int trusty_nvram_open(const hw_module_t* module,
-                                 const char* device_id,
-                                 hw_device_t** device_ptr) {
-  if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
-    return -EINVAL;
-  }
-
-  nvram::NvramDeviceAdapter* adapter = new nvram::NvramDeviceAdapter(
-      module, new nvram::TrustyNvramImplementation);
-  *device_ptr = adapter->as_device();
-  return 0;
-}
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
deleted file mode 100644
index 9215c85..0000000
--- a/trusty/nvram/trusty_nvram_implementation.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2016 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 LOG_TAG "TrustyNVRAM"
-
-#include "trusty_nvram_implementation.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <hardware/nvram.h>
-#include <log/log.h>
-#include <trusty/tipc.h>
-
-#include <nvram/messages/blob.h>
-
-namespace nvram {
-namespace {
-
-// Character device to open for Trusty IPC connections.
-const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
-
-// App identifier of the NVRAM app.
-const char kTrustyNvramAppId[] = "com.android.trusty.nvram";
-
-}  // namespace
-
-TrustyNvramImplementation::~TrustyNvramImplementation() {
-  if (tipc_nvram_fd_ != -1) {
-    tipc_close(tipc_nvram_fd_);
-    tipc_nvram_fd_ = -1;
-  }
-}
-
-void TrustyNvramImplementation::Execute(const nvram::Request& request,
-                                        nvram::Response* response) {
-  if (!SendRequest(request, response)) {
-    response->result = NV_RESULT_INTERNAL_ERROR;
-  }
-}
-
-bool TrustyNvramImplementation::Connect() {
-  if (tipc_nvram_fd_ != -1) {
-    return true;
-  }
-
-  int rc = tipc_connect(kTrustyDeviceName, kTrustyNvramAppId);
-  if (rc < 0) {
-    ALOGE("Failed to connect to Trusty NVRAM app: %s\n", strerror(-rc));
-    return false;
-  }
-
-  tipc_nvram_fd_ = rc;
-  return true;
-}
-
-bool TrustyNvramImplementation::SendRequest(const nvram::Request& request,
-                                            nvram::Response* response) {
-  if (!Connect()) {
-    return false;
-  }
-
-  nvram::Blob request_buffer;
-  if (!nvram::Encode(request, &request_buffer)) {
-    ALOGE("Failed to encode NVRAM request.\n");
-    return false;
-  }
-
-  ssize_t rc =
-      write(tipc_nvram_fd_, request_buffer.data(), request_buffer.size());
-  if (rc < 0) {
-    ALOGE("Failed to send NVRAM request: %s\n", strerror(-rc));
-    return false;
-  }
-  if (static_cast<size_t>(rc) != request_buffer.size()) {
-    ALOGE("Failed to send full request buffer: %zd\n", rc);
-    return false;
-  }
-
-  rc = read(tipc_nvram_fd_, response_buffer_, sizeof(response_buffer_));
-  if (rc < 0) {
-    ALOGE("Failed to read NVRAM response: %s\n", strerror(-rc));
-    return false;
-  }
-
-  if (static_cast<size_t>(rc) >= sizeof(response_buffer_)) {
-    ALOGE("NVRAM response exceeds response buffer size.\n");
-    return false;
-  }
-
-  if (!nvram::Decode(response_buffer_, static_cast<size_t>(rc), response)) {
-    ALOGE("Failed to decode NVRAM response.\n");
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace nvram
diff --git a/trusty/nvram/trusty_nvram_implementation.h b/trusty/nvram/trusty_nvram_implementation.h
deleted file mode 100644
index 60758f7..0000000
--- a/trusty/nvram/trusty_nvram_implementation.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
-#define TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
-
-#include <stdint.h>
-
-#include <nvram/hal/nvram_device_adapter.h>
-#include <nvram/messages/nvram_messages.h>
-
-namespace nvram {
-
-// |TrustyNvramImplementation| proxies requests to the Trusty NVRAM app. It
-// serializes the request objects, sends it to the Trusty app and finally reads
-// back the result and decodes it.
-class TrustyNvramImplementation : public nvram::NvramImplementation {
- public:
-  ~TrustyNvramImplementation() override;
-
-  void Execute(const nvram::Request& request,
-               nvram::Response* response) override;
-
- private:
-  // Connects the IPC channel to the Trusty app if it is not already open.
-  // Returns true if the channel is open, false on errors.
-  bool Connect();
-
-  // Dispatches a command to the trust app. Returns true if successful (note
-  // that the response may still indicate an error on the Trusty side), false if
-  // there are any I/O or encoding/decoding errors.
-  bool SendRequest(const nvram::Request& request,
-                   nvram::Response* response);
-
-  // The file descriptor for the IPC connection to the Trusty app.
-  int tipc_nvram_fd_ = -1;
-
-  // Response buffer. This puts a hard size limit on the responses from the
-  // Trusty app. 4096 matches the maximum IPC message size currently supported
-  // by Trusty.
-  uint8_t response_buffer_[4096];
-};
-
-}  // namespace nvram
-
-#endif  // TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
diff --git a/trusty/storage/interface/Android.bp b/trusty/storage/interface/Android.bp
index a551c37..18b4a5f 100644
--- a/trusty/storage/interface/Android.bp
+++ b/trusty/storage/interface/Android.bp
@@ -16,5 +16,6 @@
 
 cc_library_static {
     name: "libtrustystorageinterface",
+    vendor: true,
     export_include_dirs: ["include"],
 }
diff --git a/trusty/storage/lib/Android.bp b/trusty/storage/lib/Android.bp
index 5eb3f07..4e41674 100644
--- a/trusty/storage/lib/Android.bp
+++ b/trusty/storage/lib/Android.bp
@@ -16,16 +16,19 @@
 
 cc_library_static {
     name: "libtrustystorage",
+    vendor: true,
 
     srcs: ["storage.c"],
 
     export_include_dirs: ["include"],
 
     static_libs: [
-        "liblog",
         "libtrusty",
         "libtrustystorageinterface",
     ],
+    shared_libs: [
+        "liblog",
+    ],
 
     cflags: [
         "-fvisibility=hidden",
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index eb34df0..da8542d 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -16,6 +16,7 @@
 
 cc_binary {
     name: "storageproxyd",
+    vendor: true,
 
     srcs: [
         "ipc.c",
@@ -25,6 +26,7 @@
     ],
 
     shared_libs: ["liblog"],
+    header_libs: ["libcutils_headers"],
 
     static_libs: [
         "libtrustystorageinterface",
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 27e5891..41263e5 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -24,7 +24,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include <private/android_filesystem_config.h>
+#include <cutils/android_filesystem_config.h>
 
 #include "ipc.h"
 #include "log.h"
diff --git a/trusty/storage/tests/Android.bp b/trusty/storage/tests/Android.bp
index 1e4fced..536c3ca 100644
--- a/trusty/storage/tests/Android.bp
+++ b/trusty/storage/tests/Android.bp
@@ -16,6 +16,7 @@
 
 cc_test {
     name: "secure-storage-unit-test",
+    vendor: true,
 
     cflags: [
         "-g",
@@ -28,6 +29,8 @@
         "libtrustystorageinterface",
         "libtrustystorage",
         "libtrusty",
+    ],
+    shared_libs: [
         "liblog",
     ],