Merge "Define priority for video threads" into oc-mr1-dev
am: 04907ad6d7

Change-Id: I36ae4c633cf5327b63766ea09fbf1077902c0034
diff --git a/adb/Android.mk b/adb/Android.mk
index ece0645..2b6df70 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -108,7 +108,6 @@
     sysdeps_win32_test.cpp \
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := libadbd_usb
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := daemon/usb.cpp
@@ -117,12 +116,11 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libasyncio
 
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := libadbd
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
@@ -171,7 +169,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := \
@@ -330,8 +327,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CLANG := true
-
 LOCAL_SRC_FILES := \
     daemon/main.cpp \
     daemon/mdns.cpp \
@@ -365,6 +360,7 @@
 LOCAL_STRIP_MODULE := keep_symbols
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
+    libasyncio \
     libavb_user \
     libbase \
     libqemu_pipe \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ff7b71f..8c24bbb 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -956,8 +956,8 @@
 // Try to handle a network forwarding request.
 // This returns 1 on success, 0 on failure, and -1 to indicate this is not
 // a forwarding-related request.
-int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd)
-{
+int handle_forward_request(const char* service, TransportType type, const char* serial,
+                           TransportId transport_id, int reply_fd) {
     if (!strcmp(service, "list-forward")) {
         // Create the list of forward redirections.
         std::string listeners = format_listeners();
@@ -1010,7 +1010,8 @@
         }
 
         std::string error_msg;
-        atransport* transport = acquire_one_transport(type, serial, nullptr, &error_msg);
+        atransport* transport =
+            acquire_one_transport(type, serial, transport_id, nullptr, &error_msg);
         if (!transport) {
             SendFail(reply_fd, error_msg);
             return 1;
@@ -1068,8 +1069,8 @@
     return 0;
 }
 
-int handle_host_request(const char* service, TransportType type,
-                        const char* serial, int reply_fd, asocket* s) {
+int handle_host_request(const char* service, TransportType type, const char* serial,
+                        TransportId transport_id, int reply_fd, asocket* s) {
     if (strcmp(service, "kill") == 0) {
         fprintf(stderr, "adb server killed by remote request\n");
         fflush(stdout);
@@ -1089,7 +1090,14 @@
     if (!strncmp(service, "transport", strlen("transport"))) {
         TransportType type = kTransportAny;
 
-        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
+        if (!strncmp(service, "transport-id:", strlen("transport-id:"))) {
+            service += strlen("transport-id:");
+            transport_id = strtoll(service, const_cast<char**>(&service), 10);
+            if (*service != '\0') {
+                SendFail(reply_fd, "invalid transport id");
+                return 1;
+            }
+        } else if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
             type = kTransportUsb;
         } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
             type = kTransportLocal;
@@ -1101,7 +1109,7 @@
         }
 
         std::string error;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t != nullptr) {
             s->transport = t;
             SendOkay(reply_fd);
@@ -1144,7 +1152,7 @@
 
     if (!strcmp(service, "features")) {
         std::string error;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t != nullptr) {
             SendOkay(reply_fd, FeatureSetToString(t->features()));
         } else {
@@ -1197,7 +1205,7 @@
     // These always report "unknown" rather than the actual error, for scripts.
     if (!strcmp(service, "get-serialno")) {
         std::string error;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t) {
             return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
         } else {
@@ -1206,7 +1214,7 @@
     }
     if (!strcmp(service, "get-devpath")) {
         std::string error;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t) {
             return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
         } else {
@@ -1215,7 +1223,7 @@
     }
     if (!strcmp(service, "get-state")) {
         std::string error;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t) {
             return SendOkay(reply_fd, t->connection_state_name());
         } else {
@@ -1233,7 +1241,7 @@
 
     if (!strcmp(service, "reconnect")) {
         std::string response;
-        atransport* t = acquire_one_transport(type, serial, nullptr, &response, true);
+        atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &response, true);
         if (t != nullptr) {
             kick_transport(t);
             response =
@@ -1242,7 +1250,7 @@
         return SendOkay(reply_fd, response);
     }
 
-    int ret = handle_forward_request(service, type, serial, reply_fd);
+    int ret = handle_forward_request(service, type, serial, transport_id, reply_fd);
     if (ret >= 0)
       return ret - 1;
     return -1;
diff --git a/adb/adb.h b/adb/adb.h
index d6b2b81..6a9897f 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -31,8 +31,7 @@
 #include "usb.h"
 
 constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
-constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024;
-constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
+constexpr size_t MAX_PAYLOAD = 1024 * 1024;
 
 constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
 
@@ -56,6 +55,7 @@
 // Increment this when we want to force users to start a new adb server.
 #define ADB_SERVER_VERSION 39
 
+using TransportId = uint64_t;
 class atransport;
 
 struct amessage {
@@ -149,7 +149,7 @@
 
 int service_to_fd(const char* name, const atransport* transport);
 #if ADB_HOST
-asocket *host_service_to_socket(const char*  name, const char *serial);
+asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id);
 #endif
 
 #if !ADB_HOST
@@ -159,7 +159,8 @@
 int       create_jdwp_connection_fd(int  jdwp_pid);
 #endif
 
-int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd);
+int handle_forward_request(const char* service, TransportType type, const char* serial,
+                           TransportId transport_id, int reply_fd);
 
 #if !ADB_HOST
 void framebuffer_service(int fd, void *cookie);
@@ -216,7 +217,8 @@
 #define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
 #endif
 
-int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket *s);
+int handle_host_request(const char* service, TransportType type, const char* serial,
+                        TransportId transport_id, int reply_fd, asocket* s);
 
 void handle_online(atransport *t);
 void handle_offline(atransport *t);
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index e533a00..849a6e7 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -20,6 +20,7 @@
 #include "adb_client.h"
 
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -46,12 +47,20 @@
 
 static TransportType __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
+static TransportId __adb_transport_id = 0;
 
 static const char* __adb_server_socket_spec;
 
-void adb_set_transport(TransportType type, const char* serial) {
+void adb_set_transport(TransportType type, const char* serial, TransportId transport_id) {
     __adb_transport = type;
     __adb_serial = serial;
+    __adb_transport_id = transport_id;
+}
+
+void adb_get_transport(TransportType* type, const char** serial, TransportId* transport_id) {
+    if (type) *type = __adb_transport;
+    if (serial) *serial = __adb_serial;
+    if (transport_id) *transport_id = __adb_transport_id;
 }
 
 void adb_set_socket_spec(const char* socket_spec) {
@@ -63,7 +72,10 @@
 
 static int switch_socket_transport(int fd, std::string* error) {
     std::string service;
-    if (__adb_serial) {
+    if (__adb_transport_id) {
+        service += "host:transport-id:";
+        service += std::to_string(__adb_transport_id);
+    } else if (__adb_serial) {
         service += "host:transport:";
         service += __adb_serial;
     } else {
@@ -292,15 +304,18 @@
     return true;
 }
 
-std::string format_host_command(const char* command, TransportType type, const char* serial) {
-    if (serial) {
-        return android::base::StringPrintf("host-serial:%s:%s", serial, command);
+std::string format_host_command(const char* command) {
+    if (__adb_transport_id) {
+        return android::base::StringPrintf("host-transport-id:%" PRIu64 ":%s", __adb_transport_id,
+                                           command);
+    } else if (__adb_serial) {
+        return android::base::StringPrintf("host-serial:%s:%s", __adb_serial, command);
     }
 
     const char* prefix = "host";
-    if (type == kTransportUsb) {
+    if (__adb_transport == kTransportUsb) {
         prefix = "host-usb";
-    } else if (type == kTransportLocal) {
+    } else if (__adb_transport == kTransportLocal) {
         prefix = "host-local";
     }
     return android::base::StringPrintf("%s:%s", prefix, command);
@@ -308,7 +323,7 @@
 
 bool adb_get_feature_set(FeatureSet* feature_set, std::string* error) {
     std::string result;
-    if (adb_query(format_host_command("features", __adb_transport, __adb_serial), &result, error)) {
+    if (adb_query(format_host_command("features"), &result, error)) {
         *feature_set = StringToFeatureSet(result);
         return true;
     }
diff --git a/adb/adb_client.h b/adb/adb_client.h
index fabec00..fca435e 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -40,7 +40,9 @@
                std::string* _Nonnull error);
 
 // Set the preferred transport to connect to.
-void adb_set_transport(TransportType type, const char* _Nullable serial);
+void adb_set_transport(TransportType type, const char* _Nullable serial, TransportId transport_id);
+void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial,
+                       TransportId* _Nullable transport_id);
 
 // Set the socket specification for the adb server.
 // This function can only be called once, and the argument must live to the end of the process.
@@ -57,8 +59,7 @@
 bool adb_status(int fd, std::string* _Nonnull error);
 
 // Create a host command corresponding to selected transport type/serial.
-std::string format_host_command(const char* _Nonnull command, TransportType type,
-                                const char* _Nullable serial);
+std::string format_host_command(const char* _Nonnull command);
 
 // Get the feature set of the current preferred transport.
 bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error);
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 372a3b4..abef86a 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -102,7 +102,7 @@
             std::vector<const char*> srcs{src_file_.c_str()};
             SetLineMessage("pulling");
             status_ =
-                br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
+                br_->DoSyncPull(srcs, destination.c_str(), false, line_message_.c_str()) ? 0 : 1;
             if (status_ != 0) {
                 fprintf(stderr,
                         "Bug report finished but could not be copied to '%s'.\n"
@@ -195,13 +195,13 @@
     DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
 };
 
-int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) {
+int Bugreport::DoIt(int argc, const char** argv) {
     if (argc > 2) return syntax_error("adb bugreport [PATH]");
 
     // Gets bugreportz version.
     std::string bugz_stdout, bugz_stderr;
     DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
-    int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback);
+    int status = SendShellCommand("bugreportz -v", false, &version_callback);
     std::string bugz_version = android::base::Trim(bugz_stderr);
     std::string bugz_output = android::base::Trim(bugz_stdout);
 
@@ -214,7 +214,7 @@
             fprintf(stderr,
                     "Failed to get bugreportz version, which is only available on devices "
                     "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
-            return SendShellCommand(transport_type, serial, "bugreport", false);
+            return SendShellCommand("bugreport", false);
         }
 
         // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
@@ -265,7 +265,7 @@
         bugz_command = "bugreportz";
     }
     BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this);
-    return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback);
+    return SendShellCommand(bugz_command, false, &bugz_callback);
 }
 
 void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) {
@@ -274,10 +274,9 @@
         LinePrinter::INFO);
 }
 
-int Bugreport::SendShellCommand(TransportType transport_type, const char* serial,
-                                const std::string& command, bool disable_shell_protocol,
+int Bugreport::SendShellCommand(const std::string& command, bool disable_shell_protocol,
                                 StandardStreamsCallbackInterface* callback) {
-    return send_shell_command(transport_type, serial, command, disable_shell_protocol, callback);
+    return send_shell_command(command, disable_shell_protocol, callback);
 }
 
 bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
diff --git a/adb/bugreport.h b/adb/bugreport.h
index d9a4468..413439b 100644
--- a/adb/bugreport.h
+++ b/adb/bugreport.h
@@ -29,14 +29,13 @@
   public:
     Bugreport() : line_printer_() {
     }
-    int DoIt(TransportType transport_type, const char* serial, int argc, const char** argv);
+    int DoIt(int argc, const char** argv);
 
   protected:
     // Functions below are abstractions of external functions so they can be
     // mocked on tests.
     virtual int SendShellCommand(
-        TransportType transport_type, const char* serial, const std::string& command,
-        bool disable_shell_protocol,
+        const std::string& command, bool disable_shell_protocol,
         StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
 
     virtual bool DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index d3787b4..72ca59a 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -51,8 +51,8 @@
 // Empty functions so tests don't need to be linked against commandline.cpp
 DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr);
 
-int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
-                       bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) {
+int send_shell_command(const std::string& command, bool disable_shell_protocol,
+                       StandardStreamsCallbackInterface* callback) {
     ADD_FAILURE() << "send_shell_command() should have been mocked";
     return -42;
 }
@@ -62,7 +62,7 @@
     kStreamStderr,
 };
 
-// gmock black magic to provide a WithArg<4>(WriteOnStdout(output)) matcher
+// gmock black magic to provide a WithArg<2>(WriteOnStdout(output)) matcher
 typedef void OnStandardStreamsCallbackFunction(StandardStreamsCallbackInterface*);
 
 class OnStandardStreamsCallbackAction : public ActionInterface<OnStandardStreamsCallbackFunction> {
@@ -118,9 +118,8 @@
 
 class BugreportMock : public Bugreport {
   public:
-    MOCK_METHOD5(SendShellCommand,
-                 int(TransportType transport_type, const char* serial, const std::string& command,
-                     bool disable_shell_protocol, StandardStreamsCallbackInterface* callback));
+    MOCK_METHOD3(SendShellCommand, int(const std::string& command, bool disable_shell_protocol,
+                                       StandardStreamsCallbackInterface* callback));
     MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
                                   bool copy_attrs, const char* name));
     MOCK_METHOD2(UpdateProgress, void(const std::string&, int));
@@ -136,10 +135,9 @@
     }
 
     void ExpectBugreportzVersion(const std::string& version) {
-        EXPECT_CALL(br_,
-                    SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
-            .WillOnce(DoAll(WithArg<4>(WriteOnStderr(version.c_str())),
-                            WithArg<4>(ReturnCallbackDone(0))));
+        EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
+            .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
+                            WithArg<2>(ReturnCallbackDone(0))));
     }
 
     void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") {
@@ -153,26 +151,26 @@
 // Tests when called with invalid number of arguments
 TEST_F(BugreportTest, InvalidNumberArgs) {
     const char* args[] = {"bugreport", "to", "principal"};
-    ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args));
+    ASSERT_EQ(1, br_.DoIt(3, args));
 }
 
 // Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back
 // to the flat-file format ('bugreport' binary on device)
 TEST_F(BugreportTest, NoArgumentsPreNDevice) {
     // clang-format off
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStderr("")),
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStderr("")),
                         // Write some bogus output on stdout to make sure it's ignored
-                        WithArg<4>(WriteOnStdout("Dude, where is my bugreportz?")),
-                        WithArg<4>(ReturnCallbackDone(0))));
+                        WithArg<2>(WriteOnStdout("Dude, where is my bugreportz?")),
+                        WithArg<2>(ReturnCallbackDone(0))));
     // clang-format on
     std::string bugreport = "Reported the bug was.";
     CaptureStdout();
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout(bugreport)), Return(0)));
+    EXPECT_CALL(br_, SendShellCommand("bugreport", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout(bugreport)), Return(0)));
 
     const char* args[] = {"bugreport"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+    ASSERT_EQ(0, br_.DoIt(1, args));
     ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport));
 }
 
@@ -183,15 +181,15 @@
 
     std::string dest_file =
         android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("pulling da_bugreport.zip")))
+                                false, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+    ASSERT_EQ(0, br_.DoIt(1, args));
 }
 
 // Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will
@@ -201,47 +199,47 @@
     std::string dest_file =
         android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
     ExpectProgress(50, "da_bugreport.zip");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
-                        WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")),
-                        WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+                        WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")),
+                        WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("pulling da_bugreport.zip")))
+                                false, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+    ASSERT_EQ(0, br_.DoIt(1, args));
 }
 
 // Tests 'adb bugreport file.zip' when it succeeds and device does not support progress.
 TEST_F(BugreportTest, OkNDevice) {
     ExpectBugreportzVersion("1.0");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when it succeeds but response was sent in
 // multiple buffer writers and without progress updates.
 TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
     ExpectBugreportzVersion("1.0");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device")),
-                        WithArg<4>(WriteOnStdout("/bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device")),
+                        WithArg<2>(WriteOnStdout("/bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when it succeeds and displays progress.
@@ -252,32 +250,32 @@
     ExpectProgress(50);
     ExpectProgress(99);
     // clang-format off
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
         .WillOnce(DoAll(
             // Name might change on OK, so make sure the right one is picked.
-            WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")),
+            WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")),
             // Progress line in one write
-            WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")),
+            WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")),
             // Add some bogus lines
-            WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")),
+            WithArg<2>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")),
             // Multiple progress lines in one write
-            WithArg<4>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")),
+            WithArg<2>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")),
             // Progress line in multiple writes
-            WithArg<4>(WriteOnStdout("PROG")),
-            WithArg<4>(WriteOnStdout("RESS:99")),
-            WithArg<4>(WriteOnStdout("/100\n")),
+            WithArg<2>(WriteOnStdout("PROG")),
+            WithArg<2>(WriteOnStdout("RESS:99")),
+            WithArg<2>(WriteOnStdout("/100\n")),
             // Split last message as well, just in case
-            WithArg<4>(WriteOnStdout("OK:/device/bugreport")),
-            WithArg<4>(WriteOnStdout(".zip")),
-            WithArg<4>(ReturnCallbackDone())));
+            WithArg<2>(WriteOnStdout("OK:/device/bugreport")),
+            WithArg<2>(WriteOnStdout(".zip")),
+            WithArg<2>(ReturnCallbackDone())));
     // clang-format on
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes.
@@ -287,28 +285,28 @@
     ExpectProgress(50);
     ExpectProgress(75);
     // clang-format off
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
         .WillOnce(DoAll(
-            WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
-            WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
-            WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
+            WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
+            WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
+            WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
             // 25% should be ignored becaused it receded.
-            WithArg<4>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
-            WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
+            WithArg<2>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
+            WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
             // 75% should be ignored becaused it didn't change.
-            WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
+            WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
             // Try a receeding percentage with a different max progress
-            WithArg<4>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
-            WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
-            WithArg<4>(ReturnCallbackDone())));
+            WithArg<2>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
+            WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
+            WithArg<2>(ReturnCallbackDone())));
     // clang-format on
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0%
@@ -317,21 +315,21 @@
     ExpectProgress(0);
     ExpectProgress(1);
     // clang-format off
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
         // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
         .WillOnce(DoAll(
-            WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
-            WithArg<4>(WriteOnStdout("PROGRESS:1/100000\n")),
-            WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
-            WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
-            WithArg<4>(ReturnCallbackDone())));
+            WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
+            WithArg<2>(WriteOnStdout("PROGRESS:1/100000\n")),
+            WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
+            WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
+            WithArg<2>(ReturnCallbackDone())));
     // clang-format on
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport dir' when it succeeds and destination is a directory.
@@ -341,30 +339,30 @@
     std::string dest_file =
         android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
 
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
-                        WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+                        WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("pulling da_bugreport.zip")))
+                                false, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", td.path};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file' when it succeeds
 TEST_F(BugreportTest, OkNoExtension) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, StrEq("pulling file.zip")))
+                                false, StrEq("pulling file.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", "file"};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N.
@@ -374,28 +372,28 @@
     std::string dest_file =
         android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
 
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
-                        WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+                        WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
-                                true, StrEq("pulling da_bugreport.zip")))
+                                false, StrEq("pulling da_bugreport.zip")))
         .WillOnce(Return(true));
 
     const char* args[] = {"bugreport", td.path};
-    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(0, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when the bugreport itself failed
 TEST_F(BugreportTest, BugreportzReturnedFail) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
         .WillOnce(
-            DoAll(WithArg<4>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<4>(ReturnCallbackDone())));
+            DoAll(WithArg<2>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<2>(ReturnCallbackDone())));
 
     CaptureStderr();
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(-1, br_.DoIt(2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
 }
 
@@ -404,13 +402,13 @@
 // multiple buffer writes
 TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("FAIL")), WithArg<4>(WriteOnStdout(":D'OH!\n")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("FAIL")), WithArg<2>(WriteOnStdout(":D'OH!\n")),
+                        WithArg<2>(ReturnCallbackDone())));
 
     CaptureStderr();
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(-1, br_.DoIt(2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
 }
 
@@ -418,23 +416,22 @@
 // response.
 TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("bugreportz? What am I, a zombie?")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("bugreportz? What am I, a zombie?")),
+                        WithArg<2>(ReturnCallbackDone())));
 
     CaptureStderr();
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(-1, br_.DoIt(2, args));
     ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
 }
 
 // Tests 'adb bugreport file.zip' when the bugreportz -v command failed
 TEST_F(BugreportTest, BugreportzVersionFailed) {
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
-        .WillOnce(Return(666));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)).WillOnce(Return(666));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(666, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output.
@@ -442,29 +439,28 @@
     ExpectBugreportzVersion("");
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(-1, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when the main bugreportz command failed
 TEST_F(BugreportTest, BugreportzFailed) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(Return(666));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)).WillOnce(Return(666));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(666, br_.DoIt(2, args));
 }
 
 // Tests 'adb bugreport file.zip' when the bugreport could not be pulled
 TEST_F(BugreportTest, PullFails) {
     ExpectBugreportzVersion("1.1");
-    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
-        .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
-                        WithArg<4>(ReturnCallbackDone())));
+    EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
+        .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
+                        WithArg<2>(ReturnCallbackDone())));
     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
-                                true, HasSubstr("file.zip")))
+                                false, HasSubstr("file.zip")))
         .WillOnce(Return(false));
 
     const char* args[] = {"bugreport", "file.zip"};
-    ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+    ASSERT_EQ(1, br_.DoIt(2, args));
 }
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index c9f1ee9..d126f52 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -62,11 +62,11 @@
 #include "shell_service.h"
 #include "sysdeps/chrono.h"
 
-static int install_app(TransportType t, const char* serial, int argc, const char** argv);
-static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
-static int uninstall_app(TransportType t, const char* serial, int argc, const char** argv);
-static int install_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
-static int uninstall_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
+static int install_app(int argc, const char** argv);
+static int install_multiple_app(int argc, const char** argv);
+static int uninstall_app(int argc, const char** argv);
+static int install_app_legacy(int argc, const char** argv);
+static int uninstall_app_legacy(int argc, const char** argv);
 
 extern int gListenAll;
 
@@ -90,6 +90,7 @@
         " -d         use USB device (error if multiple devices connected)\n"
         " -e         use TCP/IP device (error if multiple TCP/IP devices available)\n"
         " -s SERIAL  use device with given serial (overrides $ANDROID_SERIAL)\n"
+        " -t ID      use device with given transport id\n"
         " -H         name of adb server host [default=localhost]\n"
         " -P         port of adb server [default=5037]\n"
         " -L SOCKET  listen on given socket for adb server [default=tcp:localhost:5037]\n"
@@ -685,6 +686,10 @@
 
     // Parse shell-specific command-line options.
     argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
+#ifdef _WIN32
+    // fixes "adb shell -l" crash on Windows, b/37284906
+    __argv = const_cast<char**>(argv);
+#endif
     optind = 1; // argv[0] is always "shell", so set `optind` appropriately.
     int opt;
     while ((opt = getopt(argc, const_cast<char**>(argv), "+e:ntTx")) != -1) {
@@ -986,13 +991,16 @@
 #endif /* !defined(_WIN32) */
 }
 
-static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+static bool wait_for_device(const char* service) {
     std::vector<std::string> components = android::base::Split(service, "-");
     if (components.size() < 3 || components.size() > 4) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
         return false;
     }
 
+    TransportType t;
+    adb_get_transport(&t, nullptr, nullptr);
+
     // Was the caller vague about what they'd like us to wait for?
     // If so, check they weren't more specific in their choice of transport type.
     if (components.size() == 3) {
@@ -1019,7 +1027,7 @@
         return false;
     }
 
-    std::string cmd = format_host_command(android::base::Join(components, "-").c_str(), t, serial);
+    std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
     return adb_command(cmd);
 }
 
@@ -1065,8 +1073,8 @@
     return true;
 }
 
-int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
-                       bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) {
+int send_shell_command(const std::string& command, bool disable_shell_protocol,
+                       StandardStreamsCallbackInterface* callback) {
     int fd;
     bool use_shell_protocol = false;
 
@@ -1097,7 +1105,7 @@
         }
 
         fprintf(stderr, "- waiting for device -\n");
-        if (!wait_for_device("wait-for-device", transport_type, serial)) {
+        if (!wait_for_device("wait-for-device")) {
             return 1;
         }
     }
@@ -1111,7 +1119,7 @@
     return exit_code;
 }
 
-static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
+static int logcat(int argc, const char** argv) {
     char* log_tags = getenv("ANDROID_LOG_TAGS");
     std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
 
@@ -1128,7 +1136,7 @@
     }
 
     // No need for shell protocol with logcat, always disable for simplicity.
-    return send_shell_command(transport, serial, cmd, true);
+    return send_shell_command(cmd, true);
 }
 
 static void write_zeros(int bytes, int fd) {
@@ -1340,6 +1348,7 @@
 
     // We need to check for -d and -e before we look at $ANDROID_SERIAL.
     const char* serial = nullptr;
+    TransportId transport_id = 0;
 
     while (argc > 0) {
         if (!strcmp(argv[0],"server")) {
@@ -1359,7 +1368,7 @@
                 fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
                 return 1;
             }
-        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
+        } else if (!strncmp(argv[0], "-s", 2)) {
             if (isdigit(argv[0][2])) {
                 serial = argv[0] + 2;
             } else {
@@ -1368,6 +1377,19 @@
                 argc--;
                 argv++;
             }
+        } else if (!strncmp(argv[0], "-t", 2)) {
+            const char* id;
+            if (isdigit(argv[0][2])) {
+                id = argv[0] + 2;
+            } else {
+                id = argv[1];
+                argc--;
+                argv++;
+            }
+            transport_id = strtoll(id, const_cast<char**>(&id), 10);
+            if (*id != '\0') {
+                return syntax_error("invalid transport id");
+            }
         } else if (!strcmp(argv[0],"-d")) {
             transport_type = kTransportUsb;
         } else if (!strcmp(argv[0],"-e")) {
@@ -1451,7 +1473,7 @@
         serial = getenv("ANDROID_SERIAL");
     }
 
-    adb_set_transport(transport_type, serial);
+    adb_set_transport(transport_type, serial, transport_id);
 
     if (is_server) {
         if (no_daemon || is_daemon) {
@@ -1478,7 +1500,7 @@
     if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
         const char* service = argv[0];
 
-        if (!wait_for_device(service, transport_type, serial)) {
+        if (!wait_for_device(service)) {
             return 1;
         }
 
@@ -1566,9 +1588,13 @@
         } else {
             return 0;
         }
-    }
-    else if (!strcmp(argv[0], "tcpip") && argc > 1) {
-        return adb_connect_command(android::base::StringPrintf("tcpip:%s", argv[1]));
+    } else if (!strcmp(argv[0], "tcpip")) {
+        if (argc != 2) return syntax_error("tcpip requires an argument");
+        int port;
+        if (!android::base::ParseInt(argv[1], &port, 1, 65535)) {
+            return syntax_error("tcpip: invalid port: %s", argv[1]);
+        }
+        return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
     }
     else if (!strcmp(argv[0], "remount") ||
              !strcmp(argv[0], "reboot") ||
@@ -1589,7 +1615,7 @@
         return adb_root(argv[0]) ? 0 : 1;
     } else if (!strcmp(argv[0], "bugreport")) {
         Bugreport bugreport;
-        return bugreport.DoIt(transport_type, serial, argc, argv);
+        return bugreport.DoIt(argc, argv);
     } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
         bool reverse = !strcmp(argv[0], "reverse");
         ++argv;
@@ -1685,20 +1711,20 @@
     else if (!strcmp(argv[0], "install")) {
         if (argc < 2) return syntax_error("install requires an argument");
         if (_use_legacy_install()) {
-            return install_app_legacy(transport_type, serial, argc, argv);
+            return install_app_legacy(argc, argv);
         }
-        return install_app(transport_type, serial, argc, argv);
+        return install_app(argc, argv);
     }
     else if (!strcmp(argv[0], "install-multiple")) {
         if (argc < 2) return syntax_error("install-multiple requires an argument");
-        return install_multiple_app(transport_type, serial, argc, argv);
+        return install_multiple_app(argc, argv);
     }
     else if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) return syntax_error("uninstall requires an argument");
         if (_use_legacy_install()) {
-            return uninstall_app_legacy(transport_type, serial, argc, argv);
+            return uninstall_app_legacy(argc, argv);
         }
-        return uninstall_app(transport_type, serial, argc, argv);
+        return uninstall_app(argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
         std::string src;
@@ -1752,11 +1778,11 @@
         !strcmp(argv[0],"get-serialno") ||
         !strcmp(argv[0],"get-devpath"))
     {
-        return adb_query_command(format_host_command(argv[0], transport_type, serial));
+        return adb_query_command(format_host_command(argv[0]));
     }
     /* other commands */
     else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
-        return logcat(transport_type, serial, argc, argv);
+        return logcat(argc, argv);
     }
     else if (!strcmp(argv[0],"ppp")) {
         return ppp(argc, argv);
@@ -1819,7 +1845,7 @@
         return adb_query_command("host:host-features");
     } else if (!strcmp(argv[0], "reconnect")) {
         if (argc == 1) {
-            return adb_query_command(format_host_command(argv[0], transport_type, serial));
+            return adb_query_command(format_host_command(argv[0]));
         } else if (argc == 2) {
             if (!strcmp(argv[1], "device")) {
                 std::string err;
@@ -1838,7 +1864,7 @@
     return 1;
 }
 
-static int uninstall_app(TransportType transport, const char* serial, int argc, const char** argv) {
+static int uninstall_app(int argc, const char** argv) {
     // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
     std::string cmd = "cmd package";
     while (argc-- > 0) {
@@ -1854,10 +1880,10 @@
         cmd += " " + escape_arg(*argv++);
     }
 
-    return send_shell_command(transport, serial, cmd, false);
+    return send_shell_command(cmd, false);
 }
 
-static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
+static int install_app(int argc, const char** argv) {
     // The last argument must be the APK file
     const char* file = argv[argc - 1];
     if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
@@ -1910,9 +1936,7 @@
     return 1;
 }
 
-static int install_multiple_app(TransportType transport, const char* serial, int argc,
-                                const char** argv)
-{
+static int install_multiple_app(int argc, const char** argv) {
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
@@ -2037,17 +2061,17 @@
     return EXIT_FAILURE;
 }
 
-static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
+static int pm_command(int argc, const char** argv) {
     std::string cmd = "pm";
 
     while (argc-- > 0) {
         cmd += " " + escape_arg(*argv++);
     }
 
-    return send_shell_command(transport, serial, cmd, false);
+    return send_shell_command(cmd, false);
 }
 
-static int uninstall_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
+static int uninstall_app_legacy(int argc, const char** argv) {
     /* if the user choose the -k option, we refuse to do it until devices are
        out with the option to uninstall the remaining data somehow (adb/ui) */
     int i;
@@ -2063,15 +2087,15 @@
     }
 
     /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
-    return pm_command(transport, serial, argc, argv);
+    return pm_command(argc, argv);
 }
 
-static int delete_file(TransportType transport, const char* serial, const std::string& filename) {
+static int delete_file(const std::string& filename) {
     std::string cmd = "rm -f " + escape_arg(filename);
-    return send_shell_command(transport, serial, cmd, false);
+    return send_shell_command(cmd, false);
 }
 
-static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
+static int install_app_legacy(int argc, const char** argv) {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
     const char* where = DATA_DEST;
@@ -2100,9 +2124,9 @@
         where, android::base::Basename(argv[last_apk]).c_str());
     if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
     argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
-    result = pm_command(transport, serial, argc, argv);
+    result = pm_command(argc, argv);
 
 cleanup_apk:
-    delete_file(transport, serial, apk_dest);
+    delete_file(apk_dest);
     return result;
 }
diff --git a/adb/commandline.h b/adb/commandline.h
index 9ba69a3..36cd798 100644
--- a/adb/commandline.h
+++ b/adb/commandline.h
@@ -91,8 +91,8 @@
 // Connects to the device "shell" service with |command| and prints the
 // resulting output.
 // if |callback| is non-null, stdout/stderr output will be handled by it.
-int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
-                       bool disable_shell_protocol, StandardStreamsCallbackInterface* callback =
-                                                        &DEFAULT_STANDARD_STREAMS_CALLBACK);
+int send_shell_command(
+    const std::string& command, bool disable_shell_protocol,
+    StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
 
 #endif  // COMMANDLINE_H
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 0f92282..87ed3db 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -49,16 +50,11 @@
 #define MAX_PACKET_SIZE_HS 512
 #define MAX_PACKET_SIZE_SS 1024
 
-// Kernels before 3.3 have a 16KiB transfer limit  That limit was replaced
-// with a 16MiB global limit in 3.3, but each URB submitted required a
-// contiguous kernel allocation, so you would get ENOMEM if you tried to
-// send something larger than the biggest available contiguous kernel
-// memory region. Large contiguous allocations could be unreliable
-// on a device kernel that has been running for a while fragmenting its
-// memory so we start with a larger allocation, and shrink the amount if
-// necessary.
 #define USB_FFS_BULK_SIZE 16384
 
+// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
+#define USB_FFS_NUM_BUFS ((MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
+
 #define cpu_to_le16(x) htole16(x)
 #define cpu_to_le32(x) htole32(x)
 
@@ -234,6 +230,26 @@
     },
 };
 
+static void aio_block_init(aio_block* aiob) {
+    aiob->iocb.resize(USB_FFS_NUM_BUFS);
+    aiob->iocbs.resize(USB_FFS_NUM_BUFS);
+    aiob->events.resize(USB_FFS_NUM_BUFS);
+    aiob->num_submitted = 0;
+    for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
+        aiob->iocbs[i] = &aiob->iocb[i];
+    }
+}
+
+static int getMaxPacketSize(int ffs_fd) {
+    usb_endpoint_descriptor desc;
+    if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
+        D("[ could not get endpoint descriptor! (%d) ]", errno);
+        return MAX_PACKET_SIZE_HS;
+    } else {
+        return desc.wMaxPacketSize;
+    }
+}
+
 bool init_functionfs(struct usb_handle* h) {
     LOG(INFO) << "initializing functionfs";
 
@@ -301,6 +317,14 @@
         goto err;
     }
 
+    if (io_setup(USB_FFS_NUM_BUFS, &h->read_aiob.ctx) ||
+        io_setup(USB_FFS_NUM_BUFS, &h->write_aiob.ctx)) {
+        D("[ aio: got error on io_setup (%d) ]", errno);
+    }
+
+    h->read_aiob.fd = h->bulk_out;
+    h->write_aiob.fd = h->bulk_in;
+
     h->max_rw = MAX_PAYLOAD;
     while (h->max_rw >= USB_FFS_BULK_SIZE && retries < ENDPOINT_ALLOC_RETRIES) {
         int ret_in = ioctl(h->bulk_in, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
@@ -410,6 +434,65 @@
     return 0;
 }
 
+static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
+    aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
+    bool zero_packet = false;
+
+    int num_bufs = len / USB_FFS_BULK_SIZE + (len % USB_FFS_BULK_SIZE == 0 ? 0 : 1);
+    const char* cur_data = reinterpret_cast<const char*>(data);
+    int packet_size = getMaxPacketSize(aiob->fd);
+
+    if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
+        0) {
+        D("[ Failed to madvise: %d ]", errno);
+    }
+
+    for (int i = 0; i < num_bufs; i++) {
+        int buf_len = std::min(len, USB_FFS_BULK_SIZE);
+        io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);
+
+        len -= buf_len;
+        cur_data += buf_len;
+
+        if (len == 0 && buf_len % packet_size == 0 && read) {
+            // adb does not expect the device to send a zero packet after data transfer,
+            // but the host *does* send a zero packet for the device to read.
+            zero_packet = true;
+        }
+    }
+    if (zero_packet) {
+        io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
+                packet_size, 0, read);
+        num_bufs += 1;
+    }
+
+    if (io_submit(aiob->ctx, num_bufs, aiob->iocbs.data()) < num_bufs) {
+        D("[ aio: got error submitting %s (%d) ]", read ? "read" : "write", errno);
+        return -1;
+    }
+    if (TEMP_FAILURE_RETRY(
+            io_getevents(aiob->ctx, num_bufs, num_bufs, aiob->events.data(), nullptr)) < num_bufs) {
+        D("[ aio: got error waiting %s (%d) ]", read ? "read" : "write", errno);
+        return -1;
+    }
+    for (int i = 0; i < num_bufs; i++) {
+        if (aiob->events[i].res < 0) {
+            errno = aiob->events[i].res;
+            D("[ aio: got error event on %s (%d) ]", read ? "read" : "write", errno);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int usb_ffs_aio_read(usb_handle* h, void* data, int len) {
+    return usb_ffs_do_aio(h, data, len, true);
+}
+
+static int usb_ffs_aio_write(usb_handle* h, const void* data, int len) {
+    return usb_ffs_do_aio(h, data, len, false);
+}
+
 static void usb_ffs_kick(usb_handle* h) {
     int err;
 
@@ -438,6 +521,9 @@
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
+    io_destroy(h->read_aiob.ctx);
+    io_destroy(h->write_aiob.ctx);
+
     // Notify usb_adb_open_thread to open a new connection.
     h->lock.lock();
     h->open_new_connection = true;
@@ -450,8 +536,17 @@
 
     usb_handle* h = new usb_handle();
 
-    h->write = usb_ffs_write;
-    h->read = usb_ffs_read;
+    if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
+        // Devices on older kernels (< 3.18) will not have aio support for ffs
+        // unless backported. Fall back on the non-aio functions instead.
+        h->write = usb_ffs_write;
+        h->read = usb_ffs_read;
+    } else {
+        h->write = usb_ffs_aio_write;
+        h->read = usb_ffs_aio_read;
+        aio_block_init(&h->read_aiob);
+        aio_block_init(&h->write_aiob);
+    }
     h->kick = usb_ffs_kick;
     h->close = usb_ffs_close;
 
diff --git a/adb/daemon/usb.h b/adb/daemon/usb.h
index 55b5995..db1a6d6 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/usb.h
@@ -20,6 +20,17 @@
 #include <condition_variable>
 #include <mutex>
 
+#include <asyncio/AsyncIO.h>
+
+struct aio_block {
+    std::vector<struct iocb> iocb;
+    std::vector<struct iocb*> iocbs;
+    std::vector<struct io_event> events;
+    aio_context_t ctx;
+    int num_submitted;
+    int fd;
+};
+
 struct usb_handle {
     usb_handle() : kicked(false) {
     }
@@ -39,7 +50,11 @@
     int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
     int bulk_in = -1;  /* "in" from the host's perspective => sink for adbd */
 
+    // Access to these blocks is very not thread safe. Have one block for both the
+    // read and write threads.
+    struct aio_block read_aiob;
+    struct aio_block write_aiob;
+
     int max_rw;
 };
 
-bool init_functionfs(struct usb_handle* h);
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 2576fb1..26f8d83 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -441,7 +441,7 @@
         syncsendbuf sbuf;
         sbuf.id = ID_DATA;
         while (true) {
-            int bytes_read = adb_read(lfd, sbuf.data, max);
+            int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
             if (bytes_read == -1) {
                 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
                 adb_close(lfd);
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 3448ee0..c6f3e66 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -206,6 +206,12 @@
     __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
 
     int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) <
+        0) {
+        D("[ Failed to fadvise: %d ]", errno);
+    }
+
     if (fd < 0 && errno == ENOENT) {
         if (!secure_mkdirs(android::base::Dirname(path))) {
             SendSyncFailErrno(s, "secure_mkdirs failed");
@@ -413,10 +419,14 @@
         return false;
     }
 
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
+        D("[ Failed to fadvise: %d ]", errno);
+    }
+
     syncmsg msg;
     msg.data.id = ID_DATA;
     while (true) {
-        int r = adb_read(fd, &buffer[0], buffer.size());
+        int r = adb_read(fd, &buffer[0], buffer.size() - sizeof(msg.data));
         if (r <= 0) {
             if (r == 0) break;
             SendSyncFailErrno(s, "read failed");
diff --git a/adb/services.cpp b/adb/services.cpp
index 9605e6e..dbf71d3 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -187,7 +187,7 @@
         return -1;
     }
     VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1];
-    if (handle_forward_request(command, kTransportAny, nullptr, s[1]) < 0) {
+    if (handle_forward_request(command, kTransportAny, nullptr, 0, s[1]) < 0) {
         SendFail(s[1], "not a reverse forwarding command");
     }
     adb_close(s[1]);
@@ -334,6 +334,7 @@
 struct state_info {
     TransportType transport_type;
     std::string serial;
+    TransportId transport_id;
     ConnectionState state;
 };
 
@@ -346,7 +347,8 @@
         bool is_ambiguous = false;
         std::string error = "unknown error";
         const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
-        atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
+        atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
+                                              &is_ambiguous, &error);
         if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
             SendOkay(fd);
             break;
@@ -437,9 +439,11 @@
 #endif
 
 #if ADB_HOST
-asocket* host_service_to_socket(const char* name, const char* serial) {
+asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id) {
     if (!strcmp(name,"track-devices")) {
-        return create_device_tracker();
+        return create_device_tracker(false);
+    } else if (!strcmp(name, "track-devices-l")) {
+        return create_device_tracker(true);
     } else if (android::base::StartsWith(name, "wait-for-")) {
         name += strlen("wait-for-");
 
@@ -450,6 +454,7 @@
         }
 
         if (serial) sinfo->serial = serial;
+        sinfo->transport_id = transport_id;
 
         if (android::base::StartsWith(name, "local")) {
             name += strlen("local");
@@ -478,11 +483,17 @@
             return nullptr;
         }
 
-        int fd = create_service_thread(wait_for_state, sinfo.release());
+        int fd = create_service_thread(wait_for_state, sinfo.get());
+        if (fd != -1) {
+            sinfo.release();
+        }
         return create_local_socket(fd);
     } else if (!strncmp(name, "connect:", 8)) {
         char* host = strdup(name + 8);
         int fd = create_service_thread(connect_service, host);
+        if (fd == -1) {
+            free(host);
+        }
         return create_local_socket(fd);
     }
     return NULL;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index e0143c6..f28a3df 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -430,10 +430,11 @@
 }
 
 #if ADB_HOST
-static asocket* create_host_service_socket(const char* name, const char* serial) {
+static asocket* create_host_service_socket(const char* name, const char* serial,
+                                           TransportId transport_id) {
     asocket* s;
 
-    s = host_service_to_socket(name, serial);
+    s = host_service_to_socket(name, serial, transport_id);
 
     if (s != NULL) {
         D("LS(%d) bound to '%s'", s->id, name);
@@ -658,6 +659,7 @@
 #if ADB_HOST
     char* service = nullptr;
     char* serial = nullptr;
+    TransportId transport_id = 0;
     TransportType type = kTransportAny;
 #endif
 
@@ -715,6 +717,14 @@
             serial = service;
             service = serial_end + 1;
         }
+    } else if (!strncmp(service, "host-transport-id:", strlen("host-transport-id:"))) {
+        service += strlen("host-transport-id:");
+        transport_id = strtoll(service, &service, 10);
+
+        if (*service != ':') {
+            return -1;
+        }
+        service++;
     } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
         type = kTransportUsb;
         service += strlen("host-usb:");
@@ -736,7 +746,7 @@
         ** the OKAY or FAIL message and all we have to do
         ** is clean up.
         */
-        if (handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
+        if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s) == 0) {
             /* XXX fail message? */
             D("SS(%d): handled host service '%s'", s->id, service);
             goto fail;
@@ -751,7 +761,7 @@
         ** if no such service exists, we'll fail out
         ** and tear down here.
         */
-        s2 = create_host_service_socket(service, serial);
+        s2 = create_host_service_socket(service, serial, transport_id);
         if (s2 == 0) {
             D("SS(%d): couldn't create host service '%s'", s->id, service);
             SendFail(s->peer->fd, "unknown host service");
@@ -783,7 +793,7 @@
 #else /* !ADB_HOST */
     if (s->transport == nullptr) {
         std::string error_msg = "unknown failure";
-        s->transport = acquire_one_transport(kTransportAny, nullptr, nullptr, &error_msg);
+        s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg);
         if (s->transport == nullptr) {
             SendFail(s->peer->fd, error_msg);
             goto fail;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 49c7847..0abb680 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -582,18 +582,12 @@
 #ifdef __APPLE__
     return pthread_setname_np(name.c_str());
 #else
-    const char *s = name.c_str();
-
-    // pthread_setname_np fails rather than truncating long strings.
-    const int max_task_comm_len = 16; // including the null terminator
-    if (name.length() > (max_task_comm_len - 1)) {
-        char buf[max_task_comm_len];
-        strncpy(buf, name.c_str(), sizeof(buf) - 1);
-        buf[sizeof(buf) - 1] = '\0';
-        s = buf;
-    }
-
-    return pthread_setname_np(pthread_self(), s) ;
+    // Both bionic and glibc's pthread_setname_np fails rather than truncating long strings.
+    // glibc doesn't have strlcpy, so we have to fake it.
+    char buf[16];  // MAX_TASK_COMM_LEN, but that's not exported by the kernel headers.
+    strncpy(buf, name.c_str(), sizeof(buf) - 1);
+    buf[sizeof(buf) - 1] = '\0';
+    return pthread_setname_np(pthread_self(), buf);
 #endif
 }
 
diff --git a/adb/test_adb.py b/adb/test_adb.py
index cb3e0d8..98c8a59 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -60,13 +60,13 @@
                              stderr=subprocess.STDOUT)
         out, _ = p.communicate()
         self.assertEqual(1, p.returncode)
-        self.assertIn('help message', out)
+        self.assertIn('requires an argument', out)
 
         p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT)
         out, _ = p.communicate()
         self.assertEqual(1, p.returncode)
-        self.assertIn('error', out)
+        self.assertIn('invalid port', out)
 
     # Helper method that reads a pipe until it is closed, then sets the event.
     def _read_pipe_and_set_event(self, pipe, event):
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 2bbbefd..b2e03a0 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -21,6 +21,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -36,6 +37,7 @@
 #include <android-base/quick_exit.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
 
 #include "adb.h"
 #include "adb_auth.h"
@@ -46,10 +48,11 @@
 
 static void transport_unref(atransport *t);
 
+// TODO: unordered_map<TransportId, atransport*>
 static auto& transport_list = *new std::list<atransport*>();
 static auto& pending_list = *new std::list<atransport*>();
 
-static std::mutex& transport_lock = *new std::mutex();
+static auto& transport_lock = *new std::recursive_mutex();
 
 const char* const kFeatureShell2 = "shell_v2";
 const char* const kFeatureCmd = "cmd";
@@ -57,6 +60,11 @@
 const char* const kFeatureLibusb = "libusb";
 const char* const kFeaturePushSync = "push_sync";
 
+TransportId NextTransportId() {
+    static std::atomic<TransportId> next(1);
+    return next++;
+}
+
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
     unsigned command = p->msg.command;
     int len = p->msg.data_length;
@@ -298,9 +306,11 @@
 }
 
 void kick_transport(atransport* t) {
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     // As kick_transport() can be called from threads without guarantee that t is valid,
     // check if the transport is in transport_list first.
+    //
+    // TODO(jmgao): WTF? Is this actually true?
     if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
         t->Kick();
     }
@@ -319,7 +329,8 @@
  */
 struct device_tracker {
     asocket socket;
-    int update_needed;
+    bool update_needed;
+    bool long_output;
     device_tracker* next;
 };
 
@@ -330,7 +341,7 @@
     device_tracker** pnode = &device_tracker_list;
     device_tracker* node = *pnode;
 
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     while (node) {
         if (node == tracker) {
             *pnode = node->next;
@@ -376,15 +387,15 @@
 
     // We want to send the device list when the tracker connects
     // for the first time, even if no update occurred.
-    if (tracker->update_needed > 0) {
-        tracker->update_needed = 0;
+    if (tracker->update_needed) {
+        tracker->update_needed = false;
 
-        std::string transports = list_transports(false);
+        std::string transports = list_transports(tracker->long_output);
         device_tracker_send(tracker, transports);
     }
 }
 
-asocket* create_device_tracker(void) {
+asocket* create_device_tracker(bool long_output) {
     device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
     if (tracker == nullptr) fatal("cannot allocate device tracker");
 
@@ -393,7 +404,8 @@
     tracker->socket.enqueue = device_tracker_enqueue;
     tracker->socket.ready = device_tracker_ready;
     tracker->socket.close = device_tracker_close;
-    tracker->update_needed = 1;
+    tracker->update_needed = true;
+    tracker->long_output = long_output;
 
     tracker->next = device_tracker_list;
     device_tracker_list = tracker;
@@ -403,7 +415,7 @@
 
 // Check if all of the USB transports are connected.
 bool iterate_transports(std::function<bool(const atransport*)> fn) {
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         if (!fn(t)) {
             return false;
@@ -507,7 +519,7 @@
         adb_close(t->fd);
 
         {
-            std::lock_guard<std::mutex> lock(transport_lock);
+            std::lock_guard<std::recursive_mutex> lock(transport_lock);
             transport_list.remove(t);
         }
 
@@ -546,7 +558,7 @@
     }
 
     {
-        std::lock_guard<std::mutex> lock(transport_lock);
+        std::lock_guard<std::recursive_mutex> lock(transport_lock);
         pending_list.remove(t);
         transport_list.push_front(t);
     }
@@ -573,7 +585,7 @@
 
 void kick_all_transports() {
     // To avoid only writing part of a packet to a transport after exit, kick all transports.
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto t : transport_list) {
         t->Kick();
     }
@@ -638,11 +650,15 @@
     return !*to_test;
 }
 
-atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
-                                  std::string* error_out, bool accept_any_state) {
+atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
+                                  bool* is_ambiguous, std::string* error_out,
+                                  bool accept_any_state) {
     atransport* result = nullptr;
 
-    if (serial) {
+    if (transport_id != 0) {
+        *error_out =
+            android::base::StringPrintf("no device with transport id '%" PRIu64 "'", transport_id);
+    } else if (serial) {
         *error_out = android::base::StringPrintf("device '%s' not found", serial);
     } else if (type == kTransportLocal) {
         *error_out = "no emulators found";
@@ -652,7 +668,7 @@
         *error_out = "no devices found";
     }
 
-    std::unique_lock<std::mutex> lock(transport_lock);
+    std::unique_lock<std::recursive_mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         if (t->GetConnectionState() == kCsNoPerm) {
 #if ADB_HOST
@@ -661,8 +677,12 @@
             continue;
         }
 
-        // Check for matching serial number.
-        if (serial) {
+        if (transport_id) {
+            if (t->id == transport_id) {
+                result = t;
+                break;
+            }
+        } else if (serial) {
             if (t->MatchesTarget(serial)) {
                 if (result) {
                     *error_out = "more than one device";
@@ -889,18 +909,23 @@
 
 #if ADB_HOST
 
+// We use newline as our delimiter, make sure to never output it.
+static std::string sanitize(std::string str, bool alphanumeric) {
+    auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
+                             : [](const char c) { return c == '\n'; };
+    std::replace_if(str.begin(), str.end(), pred, '_');
+    return str;
+}
+
 static void append_transport_info(std::string* result, const char* key, const char* value,
-                                  bool sanitize) {
+                                  bool alphanumeric) {
     if (value == nullptr || *value == '\0') {
         return;
     }
 
     *result += ' ';
     *result += key;
-
-    for (const char* p = value; *p; ++p) {
-        result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
-    }
+    *result += sanitize(value, alphanumeric);
 }
 
 static void append_transport(const atransport* t, std::string* result, bool long_listing) {
@@ -920,6 +945,11 @@
         append_transport_info(result, "product:", t->product, false);
         append_transport_info(result, "model:", t->model, true);
         append_transport_info(result, "device:", t->device, false);
+
+        // Put id at the end, so that anyone parsing the output here can always find it by scanning
+        // backwards from newlines, even with hypothetical devices named 'transport_id:1'.
+        *result += " transport_id:";
+        *result += std::to_string(t->id);
     }
     *result += '\n';
 }
@@ -927,7 +957,7 @@
 std::string list_transports(bool long_listing) {
     std::string result;
 
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         append_transport(t, &result, long_listing);
     }
@@ -935,7 +965,7 @@
 }
 
 void close_usb_devices(std::function<bool(const atransport*)> predicate) {
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto& t : transport_list) {
         if (predicate(t)) {
             t->Kick();
@@ -964,7 +994,7 @@
         return -1;
     }
 
-    std::unique_lock<std::mutex> lock(transport_lock);
+    std::unique_lock<std::recursive_mutex> lock(transport_lock);
     for (const auto& transport : pending_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             VLOG(TRANSPORT) << "socket transport " << transport->serial
@@ -996,7 +1026,7 @@
 atransport* find_transport(const char* serial) {
     atransport* result = nullptr;
 
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto& t : transport_list) {
         if (t->serial && strcmp(serial, t->serial) == 0) {
             result = t;
@@ -1008,7 +1038,7 @@
 }
 
 void kick_all_tcp_devices() {
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto& t : transport_list) {
         if (t->IsTcpDevice()) {
             // Kicking breaks the read_transport thread of this transport out of any read, then
@@ -1037,7 +1067,7 @@
     }
 
     {
-        std::lock_guard<std::mutex> lock(transport_lock);
+        std::lock_guard<std::recursive_mutex> lock(transport_lock);
         pending_list.push_front(t);
     }
 
@@ -1046,7 +1076,7 @@
 
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb) {
-    std::lock_guard<std::mutex> lock(transport_lock);
+    std::lock_guard<std::recursive_mutex> lock(transport_lock);
     transport_list.remove_if(
         [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
 }
diff --git a/adb/transport.h b/adb/transport.h
index 4a89ed9..00fad56 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -54,14 +54,17 @@
 // The server supports `push --sync`.
 extern const char* const kFeaturePushSync;
 
+TransportId NextTransportId();
+
 class atransport {
-public:
+  public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
     // historically just a struct, but making the whole thing a more idiomatic
     // class in one go is a very large change. Given how bad our testing is,
     // it's better to do this piece by piece.
 
-    atransport(ConnectionState state = kCsOffline) : ref_count(0), connection_state_(state) {
+    atransport(ConnectionState state = kCsOffline)
+        : id(NextTransportId()), ref_count(0), connection_state_(state) {
         transport_fde = {};
         protocol_version = A_VERSION;
         max_payload = MAX_PAYLOAD;
@@ -72,12 +75,8 @@
     void (*close)(atransport* t) = nullptr;
 
     void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
-    void SetKickFunction(void (*kick_func)(atransport*)) {
-        kick_func_ = kick_func;
-    }
-    bool IsKicked() {
-        return kicked_;
-    }
+    void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
+    bool IsKicked() { return kicked_; }
     int Write(apacket* p);
     void Kick();
 
@@ -85,6 +84,7 @@
     ConnectionState GetConnectionState() const;
     void SetConnectionState(ConnectionState state);
 
+    const TransportId id;
     int fd = -1;
     int transport_socket = -1;
     fdevent transport_fde;
@@ -191,12 +191,14 @@
 /*
  * Obtain a transport from the available transports.
  * If serial is non-null then only the device with that serial will be chosen.
+ * If transport_id is non-zero then only the device with that transport ID will be chosen.
  * If multiple devices/emulators would match, *is_ambiguous (if non-null)
  * is set to true and nullptr returned.
  * If no suitable transport is found, error is set and nullptr returned.
  */
-atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
-                                  std::string* error_out, bool accept_any_state = false);
+atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
+                                  bool* is_ambiguous, std::string* error_out,
+                                  bool accept_any_state = false);
 void kick_transport(atransport* t);
 void update_transports(void);
 
@@ -231,6 +233,6 @@
 
 void send_packet(apacket* p, atransport* t);
 
-asocket* create_device_tracker(void);
+asocket* create_device_tracker(bool long_output);
 
 #endif   /* __TRANSPORT_H */
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 7e8ae67..6768d31 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -33,8 +33,8 @@
     D("UsbReadMessage");
 
     size_t usb_packet_size = usb_get_max_packet_size(h);
-    CHECK(usb_packet_size >= sizeof(*msg));
-    CHECK(usb_packet_size < 4096);
+    CHECK_GE(usb_packet_size, sizeof(*msg));
+    CHECK_LT(usb_packet_size, 4096ULL);
 
     char buffer[4096];
     int n = usb_read(h, buffer, usb_packet_size);
@@ -52,7 +52,7 @@
     D("UsbReadPayload(%d)", p->msg.data_length);
 
     size_t usb_packet_size = usb_get_max_packet_size(h);
-    CHECK(sizeof(p->data) % usb_packet_size == 0);
+    CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
 
     // Round the data length up to the nearest packet size boundary.
     // The device won't send a zero packet for packet size aligned payloads,
@@ -62,7 +62,7 @@
     if (rem_size) {
         len += usb_packet_size - rem_size;
     }
-    CHECK(len <= sizeof(p->data));
+    CHECK_LE(len, sizeof(p->data));
     return usb_read(h, &p->data, len);
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index 6c3a593..82aee2a 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -39,7 +39,6 @@
 cc_library {
     name: "libbase",
     vendor_available: true,
-    clang: true,
     host_supported: true,
     vndk: {
         enabled: true,
@@ -113,7 +112,6 @@
 cc_test {
     name: "libbase_test",
     host_supported: true,
-    clang: true,
     srcs: [
         "endian_test.cpp",
         "errors_test.cpp",
diff --git a/base/file.cpp b/base/file.cpp
index a2f2887..2f697a1 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -153,6 +153,37 @@
   return true;
 }
 
+#if defined(_WIN32)
+// Windows implementation of pread. Note that this DOES move the file descriptors read position,
+// but it does so atomically.
+static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
+  DWORD bytes_read;
+  OVERLAPPED overlapped;
+  memset(&overlapped, 0, sizeof(OVERLAPPED));
+  overlapped.Offset = static_cast<DWORD>(offset);
+  overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+  if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count),
+                &bytes_read, &overlapped)) {
+    // In case someone tries to read errno (since this is masquerading as a POSIX call)
+    errno = EIO;
+    return -1;
+  }
+  return static_cast<ssize_t>(bytes_read);
+}
+#endif
+
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
+  uint8_t* p = reinterpret_cast<uint8_t*>(data);
+  while (byte_count > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset));
+    if (n <= 0) return false;
+    p += n;
+    byte_count -= n;
+    offset += n;
+  }
+  return true;
+}
+
 bool WriteFully(int fd, const void* data, size_t byte_count) {
   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
   size_t remaining = byte_count;
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 651f529..667d6fb 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -18,12 +18,18 @@
 #define ANDROID_BASE_FILE_H
 
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <string>
 
 #if !defined(_WIN32) && !defined(O_BINARY)
 #define O_BINARY 0
 #endif
 
+#if defined(__APPLE__)
+/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
+typedef off_t off64_t;
+#endif
+
 namespace android {
 namespace base {
 
@@ -42,6 +48,17 @@
 #endif
 
 bool ReadFully(int fd, void* data, size_t byte_count);
+
+// Reads `byte_count` bytes from the file descriptor at the specified offset.
+// Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes.
+//
+// NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without
+// modifying the read pointer of the file descriptor. On Windows, however, the read pointer does
+// get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the
+// same function, but concurrently seeking or reading incrementally can lead to unexpected
+// behavior.
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset);
+
 bool WriteFully(int fd, const void* data, size_t byte_count);
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 88bbe8a..25f2ff4 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -179,4 +179,19 @@
   } while (0)
 #endif
 
+// Current ABI string
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#elif defined(__mips__) && !defined(__LP64__)
+#define ABI_STRING "mips"
+#elif defined(__mips__) && defined(__LP64__)
+#define ABI_STRING "mips64"
+#endif
+
 #endif  // ANDROID_BASE_MACROS_H
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 6cfcfcd..5d89271 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -17,6 +17,13 @@
 #ifndef ANDROID_BASE_UNIQUE_FD_H
 #define ANDROID_BASE_UNIQUE_FD_H
 
+#include <fcntl.h>
+
+#if !defined(_WIN32)
+#include <sys/socket.h>
+#endif
+
+#include <sys/types.h>
 #include <unistd.h>
 
 // DO NOT INCLUDE OTHER LIBBASE HEADERS!
@@ -88,6 +95,49 @@
 
 using unique_fd = unique_fd_impl<DefaultCloser>;
 
+#if !defined(_WIN32)
+
+// Inline functions, so that they can be used header-only.
+inline bool Pipe(unique_fd* read, unique_fd* write) {
+  int pipefd[2];
+
+#if defined(__linux__)
+  if (pipe2(pipefd, O_CLOEXEC) != 0) {
+    return false;
+  }
+#else  // defined(__APPLE__)
+  if (pipe(pipefd) != 0) {
+    return false;
+  }
+
+  if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
+    close(pipefd[0]);
+    close(pipefd[1]);
+    return false;
+  }
+#endif
+
+  read->reset(pipefd[0]);
+  write->reset(pipefd[1]);
+  return true;
+}
+
+inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) {
+  int sockfd[2];
+  if (socketpair(domain, type, protocol, sockfd) != 0) {
+    return false;
+  }
+  left->reset(sockfd[0]);
+  right->reset(sockfd[1]);
+  return true;
+}
+
+inline bool Socketpair(int type, unique_fd* left, unique_fd* right) {
+  return Socketpair(AF_UNIX, type, 0, left, right);
+}
+
+#endif  // !defined(_WIN32)
+
 }  // namespace base
 }  // namespace android
 
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index bc90a6e..dd357ed 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -32,9 +32,6 @@
         "liblog",
         "libmetricslogger",
     ],
-    whole_static_libs: ["libgtest_prod"],
-    // Clang is required because of C++14
-    clang: true,
 }
 
 // bootstat static library
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index f4756d5..d697efb 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -1,7 +1,39 @@
 # This file is the LOCAL_INIT_RC file for the bootstat command.
 
 on post-fs-data
-    mkdir /data/misc/bootstat 0700 root root
+    mkdir /data/misc/bootstat 0700 system log
+    # To deal with ota transition resulting from a change in DAC from
+    # root.root to system.log, may be deleted after ota has settled.
+    chown system log /data/misc/bootstat/absolute_boot_time
+    chown system log /data/misc/bootstat/boot_complete
+    chown system log /data/misc/bootstat/boot_complete_no_encryption
+    chown system log /data/misc/bootstat/boot_reason
+    chown system log /data/misc/bootstat/bootime.bootloader.1BLE
+    chown system log /data/misc/bootstat/bootime.bootloader.1BLL
+    chown system log /data/misc/bootstat/bootime.bootloader.2BLE
+    chown system log /data/misc/bootstat/bootime.bootloader.2BLL
+    chown system log /data/misc/bootstat/bootime.bootloader.AVB
+    chown system log /data/misc/bootstat/bootime.bootloader.KD
+    chown system log /data/misc/bootstat/bootime.bootloader.KL
+    chown system log /data/misc/bootstat/bootime.bootloader.ODT
+    chown system log /data/misc/bootstat/bootime.bootloader.SW
+    chown system log /data/misc/bootstat/bootime.bootloader.total
+    chown system log /data/misc/bootstat/build_date
+    chown system log /data/misc/bootstat/factory_reset
+    chown system log /data/misc/bootstat/factory_reset_boot_complete
+    chown system log /data/misc/bootstat/factory_reset_boot_complete_no_encryption
+    chown system log /data/misc/bootstat/factory_reset_current_time
+    chown system log /data/misc/bootstat/factory_reset_record_value
+    chown system log /data/misc/bootstat/last_boot_time_utc
+    chown system log /data/misc/bootstat/ota_boot_complete
+    chown system log /data/misc/bootstat/ota_boot_complete_no_encryption
+    chown system log /data/misc/bootstat/post_decrypt_time_elapsed
+    chown system log /data/misc/bootstat/ro.boottime.init
+    chown system log /data/misc/bootstat/ro.boottime.init.cold_boot_wait
+    chown system log /data/misc/bootstat/ro.boottime.init.selinux
+    chown system log /data/misc/bootstat/time_since_factory_reset
+    chown system log /data/misc/bootstat/time_since_last_boot
+    # end ota transitional support
 
 # Record the time at which the user has successfully entered the pin to decrypt
 # the device, /data is decrypted, and the system is entering the main boot phase.
@@ -10,7 +42,7 @@
 # property:init.svc.bootanim=running: The boot animation is running
 # property:ro.crypto.type=block: FDE device
 on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
-    exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
+    exec - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed
 
 # sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
 # This signaling is necessary to prevent logging boot metrics after a runtime
@@ -33,13 +65,13 @@
 # Record boot complete metrics.
 on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
     # Record boot_complete and related stats (decryption, etc).
-    exec - root root -- /system/bin/bootstat --record_boot_complete
+    exec - system log -- /system/bin/bootstat --record_boot_complete
 
     # Record the boot reason.
-    exec - root root -- /system/bin/bootstat --record_boot_reason
+    exec - system log -- /system/bin/bootstat --record_boot_reason
 
     # Record time since factory reset.
-    exec - root root -- /system/bin/bootstat --record_time_since_factory_reset
+    exec - system log -- /system/bin/bootstat --record_time_since_factory_reset
 
     # Log all boot events.
-    exec - root root -- /system/bin/bootstat -l
+    exec - system log -- /system/bin/bootstat -l
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index f86aaa0..2b5f4f6 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -66,7 +66,10 @@
     defaults: ["debuggerd_defaults"],
     srcs: ["handler/debuggerd_handler.cpp"],
 
-    header_libs: ["libdebuggerd_common_headers"],
+    header_libs: [
+        "libbase_headers",
+        "libdebuggerd_common_headers",
+    ],
 
     whole_static_libs: [
         "libasync_safe",
@@ -106,6 +109,7 @@
         "libdebuggerd",
         "libbacktrace",
         "libunwind",
+        "libunwindstack",
         "liblzma",
         "libcutils",
     ],
@@ -171,6 +175,7 @@
     static_libs: [
         "libbacktrace",
         "libunwind",
+        "libunwindstack",
         "liblzma",
         "libbase",
         "libcutils",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 4b1e51d..dfc74fb 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -47,13 +47,14 @@
 #define ATRACE_TAG ATRACE_TAG_BIONIC
 #include <utils/Trace.h>
 
-#include "backtrace.h"
-#include "tombstone.h"
-#include "utility.h"
+#include "libdebuggerd/backtrace.h"
+#include "libdebuggerd/tombstone.h"
+#include "libdebuggerd/utility.h"
 
 #include "debuggerd/handler.h"
-#include "protocol.h"
 #include "tombstoned/tombstoned.h"
+
+#include "protocol.h"
 #include "util.h"
 
 using android::base::unique_fd;
@@ -79,9 +80,27 @@
   return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0;
 }
 
+static pid_t get_tracer(pid_t tracee) {
+  // Check to see if the thread is being ptraced by another process.
+  android::procinfo::ProcessInfo process_info;
+  if (android::procinfo::GetProcessInfo(tracee, &process_info)) {
+    return process_info.tracer;
+  }
+  return -1;
+}
+
 // Attach to a thread, and verify that it's still a member of the given process
 static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) {
   if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
+    if (errno == EPERM) {
+      pid_t tracer = get_tracer(tid);
+      if (tracer != -1) {
+        *error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid,
+                              tracer, get_process_name(tracer).c_str());
+        return false;
+      }
+    }
+
     *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
     return false;
   }
@@ -329,6 +348,11 @@
       LOG(FATAL) << "failed to create backtrace map";
     }
   }
+  std::unique_ptr<BacktraceMap> backtrace_map_new;
+  backtrace_map_new.reset(BacktraceMap::CreateNew(main_tid));
+  if (!backtrace_map_new) {
+    LOG(FATAL) << "failed to create backtrace map new";
+  }
 
   // Collect the list of open files.
   OpenFilesList open_files;
@@ -408,8 +432,9 @@
     dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
   } else {
     ATRACE_NAME("engrave_tombstone");
-    engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
-                      process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
+    engrave_tombstone(output_fd.get(), backtrace_map.get(), backtrace_map_new.get(), &open_files,
+                      target, main_tid, process_name, threads, abort_address,
+                      fatal_signal ? &amfd_data : nullptr);
   }
 
   // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index f73f672..b7b1938 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -2,7 +2,6 @@
     name: "crasher-defaults",
 
     cppflags: [
-        "-std=gnu++14",
         "-W",
         "-Wall",
         "-Wextra",
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index b51fc66..dbf81a4 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -16,10 +16,11 @@
 
 #include <err.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <sys/capability.h>
 #include <sys/prctl.h>
+#include <sys/ptrace.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <chrono>
 #include <regex>
@@ -569,6 +570,40 @@
   ASSERT_BACKTRACE_FRAME(result, "tgkill");
 }
 
+TEST_F(CrasherTest, competing_tracer) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    while (true) {
+    }
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+
+  ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
+  ASSERT_EQ(0, kill(crasher_pid, SIGABRT));
+
+  int status;
+  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+  ASSERT_TRUE(WIFSTOPPED(status));
+  ASSERT_EQ(SIGABRT, WSTOPSIG(status));
+
+  ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  std::string regex = R"(failed to attach to thread \d+, already traced by )";
+  regex += std::to_string(gettid());
+  regex += R"( \(.+debuggerd_test)";
+  ASSERT_MATCH(result, regex.c_str());
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
+  AssertDeath(SIGABRT);
+}
+
 TEST(crash_dump, zombie) {
   pid_t forkpid = fork();
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 43104ec..06d4a9b 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -45,8 +45,8 @@
 #include "tombstoned/tombstoned.h"
 #include "util.h"
 
-#include "backtrace.h"
-#include "tombstone.h"
+#include "libdebuggerd/backtrace.h"
+#include "libdebuggerd/tombstone.h"
 
 using android::base::unique_fd;
 
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 1275229..d41dc67 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -48,10 +48,13 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android-base/unique_fd.h>
 #include <async_safe/log.h>
 
 #include "dump_type.h"
 
+using android::base::unique_fd;
+
 // see man(2) prctl, specifically the section about PR_GET_NAME
 #define MAX_TASK_NAME_LEN (16)
 
@@ -117,13 +120,12 @@
 }
 
 static bool get_main_thread_name(char* buf, size_t len) {
-  int fd = open("/proc/self/comm", O_RDONLY | O_CLOEXEC);
+  unique_fd fd(open("/proc/self/comm", O_RDONLY | O_CLOEXEC));
   if (fd == -1) {
     return false;
   }
 
   ssize_t rc = read(fd, buf, len);
-  close(fd);
   if (rc == -1) {
     return false;
   } else if (rc == 0) {
@@ -302,8 +304,8 @@
   TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO));
   TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO));
 
-  int pipefds[2];
-  if (pipe(pipefds) != 0) {
+  unique_fd pipe_read, pipe_write;
+  if (!android::base::Pipe(&pipe_read, &pipe_write)) {
     fatal_errno("failed to create pipe");
   }
 
@@ -313,9 +315,9 @@
     async_safe_format_log(ANDROID_LOG_FATAL, "libc",
                           "failed to fork in debuggerd signal handler: %s", strerror(errno));
   } else if (forkpid == 0) {
-    TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO));
-    close(pipefds[0]);
-    close(pipefds[1]);
+    TEMP_FAILURE_RETRY(dup2(pipe_write.get(), STDOUT_FILENO));
+    pipe_write.reset();
+    pipe_read.reset();
 
     raise_caps();
 
@@ -333,9 +335,9 @@
 
     fatal_errno("exec failed");
   } else {
-    close(pipefds[1]);
+    pipe_write.reset();
     char buf[4];
-    ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf)));
+    ssize_t rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), &buf, sizeof(buf)));
     if (rc == -1) {
       async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s",
                             strerror(errno));
@@ -351,7 +353,7 @@
         thread_info->crash_dump_started = true;
       }
     }
-    close(pipefds[0]);
+    pipe_read.reset();
 
     // Don't leave a zombie child.
     int status;
diff --git a/debuggerd/libdebuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp
index ac833ae..bfb5ea4 100644
--- a/debuggerd/libdebuggerd/arm/machine.cpp
+++ b/debuggerd/libdebuggerd/arm/machine.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -25,8 +27,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   pt_regs regs;
diff --git a/debuggerd/libdebuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp
index fa73c99a..ad1c951 100644
--- a/debuggerd/libdebuggerd/arm64/machine.cpp
+++ b/debuggerd/libdebuggerd/arm64/machine.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <elf.h>
 #include <errno.h>
 #include <stdint.h>
@@ -27,8 +29,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   struct user_pt_regs regs;
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 334d97f..f616e1b 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/backtrace.h"
+
 #include <errno.h>
 #include <dirent.h>
 #include <limits.h>
@@ -34,9 +36,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "backtrace.h"
-
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
   time_t t = time(NULL);
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
index 4e798e2..a35102f 100644
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ b/debuggerd/libdebuggerd/elf_utils.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/elf_utils.h"
+
 #include <elf.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -27,8 +29,6 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "elf_utils.h"
-
 #define NOTE_ALIGN(size)  (((size) + 3) & ~3)
 
 template <typename HdrType, typename PhdrType, typename NhdrType>
diff --git a/debuggerd/libdebuggerd/include/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
similarity index 100%
rename from debuggerd/libdebuggerd/include/backtrace.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
diff --git a/debuggerd/libdebuggerd/include/elf_utils.h b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
similarity index 100%
rename from debuggerd/libdebuggerd/include/elf_utils.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
diff --git a/debuggerd/libdebuggerd/include/machine.h b/debuggerd/libdebuggerd/include/libdebuggerd/machine.h
similarity index 100%
rename from debuggerd/libdebuggerd/include/machine.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/machine.h
diff --git a/debuggerd/libdebuggerd/include/open_files_list.h b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
similarity index 100%
rename from debuggerd/libdebuggerd/include/open_files_list.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
similarity index 82%
rename from debuggerd/libdebuggerd/include/tombstone.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 79743b6..45740df 100644
--- a/debuggerd/libdebuggerd/include/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -35,10 +35,10 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
-                       pid_t pid, pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
-                       std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
+                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
+                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
+                       uintptr_t abort_msg_address, std::string* amfd_data);
 
 void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
similarity index 81%
rename from debuggerd/libdebuggerd/include/utility.h
rename to debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index e5e5106..f481b78 100644
--- a/debuggerd/libdebuggerd/include/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -24,26 +24,9 @@
 
 #include <string>
 
+#include <android-base/macros.h>
 #include <backtrace/Backtrace.h>
 
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
-
 struct log_t{
     // Tombstone file descriptor.
     int tfd;
diff --git a/debuggerd/libdebuggerd/mips/machine.cpp b/debuggerd/libdebuggerd/mips/machine.cpp
index cbf272a..1fc690b 100644
--- a/debuggerd/libdebuggerd/mips/machine.cpp
+++ b/debuggerd/libdebuggerd/mips/machine.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <errno.h>
 #include <inttypes.h>
 #include <stdint.h>
@@ -25,8 +27,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 #define R(x) (static_cast<uintptr_t>(x))
 
diff --git a/debuggerd/libdebuggerd/mips64/machine.cpp b/debuggerd/libdebuggerd/mips64/machine.cpp
index 0a8d532..955e507 100644
--- a/debuggerd/libdebuggerd/mips64/machine.cpp
+++ b/debuggerd/libdebuggerd/mips64/machine.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <errno.h>
 #include <inttypes.h>
 #include <stdint.h>
@@ -25,8 +27,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 #define R(x) (static_cast<uintptr_t>(x))
 
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
index 5c7ea70..e199db8 100644
--- a/debuggerd/libdebuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/open_files_list.h"
+
 #include <dirent.h>
 #include <errno.h>
 #include <stdio.h>
@@ -31,9 +33,7 @@
 #include <android-base/file.h>
 #include <log/log.h>
 
-#include "open_files_list.h"
-
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 void populate_open_files_list(pid_t pid, OpenFilesList* list) {
   std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd";
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
index 49f3690..0fad2cf 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -22,9 +22,10 @@
 #include <gtest/gtest.h>
 #include <android-base/file.h>
 
+#include "libdebuggerd/utility.h"
+
 #include "BacktraceMock.h"
 #include "log_fake.h"
-#include "utility.h"
 
 const char g_expected_full_dump[] =
 "\nmemory near r1:\n"
diff --git a/debuggerd/libdebuggerd/test/elf_fake.cpp b/debuggerd/libdebuggerd/test/elf_fake.cpp
index bb52b59..f8cbca7 100644
--- a/debuggerd/libdebuggerd/test/elf_fake.cpp
+++ b/debuggerd/libdebuggerd/test/elf_fake.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "elf_fake.h"
+
 #include <stdint.h>
 
 #include <string>
diff --git a/debuggerd/libdebuggerd/test/log_fake.cpp b/debuggerd/libdebuggerd/test/log_fake.cpp
index 3336bcb..68f4013 100644
--- a/debuggerd/libdebuggerd/test/log_fake.cpp
+++ b/debuggerd/libdebuggerd/test/log_fake.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "log_fake.h"
+
 #include <errno.h>
 #include <stdarg.h>
 
diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
index 85e0695..acac72c 100644
--- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp
+++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
@@ -24,7 +24,7 @@
 
 #include "android-base/test_utils.h"
 
-#include "open_files_list.h"
+#include "libdebuggerd/open_files_list.h"
 
 // Check that we can produce a list of open files for the current process, and
 // that it includes a known open file.
diff --git a/debuggerd/libdebuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp
index f40cbd4..0d4080e 100644
--- a/debuggerd/libdebuggerd/test/ptrace_fake.cpp
+++ b/debuggerd/libdebuggerd/test/ptrace_fake.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "ptrace_fake.h"
+
 #include <errno.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -21,8 +23,6 @@
 
 #include <string>
 
-#include "ptrace_fake.h"
-
 siginfo_t g_fake_si = {.si_signo = 0};
 
 void ptrace_set_fake_getsiginfo(const siginfo_t& si) {
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 6be59e7..e79dd96 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -22,7 +22,7 @@
 #include <gtest/gtest.h>
 #include <android-base/file.h>
 
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 #include "BacktraceMock.h"
 #include "elf_fake.h"
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0113131..50d19bd 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/tombstone.h"
+
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -43,22 +45,18 @@
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
 
+// Needed to get DEBUGGER_SIGNAL.
 #include "debuggerd/handler.h"
 
-#include "backtrace.h"
-#include "elf_utils.h"
-#include "machine.h"
-#include "open_files_list.h"
-#include "tombstone.h"
+#include "libdebuggerd/backtrace.h"
+#include "libdebuggerd/elf_utils.h"
+#include "libdebuggerd/machine.h"
+#include "libdebuggerd/open_files_list.h"
 
 using android::base::StringPrintf;
 
 #define STACK_WORDS 16
 
-#define MAX_TOMBSTONES  10
-#define TOMBSTONE_DIR   "/data/tombstones"
-#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
-
 static bool signal_has_si_addr(int si_signo, int si_code) {
   // Manually sent signals won't have si_addr.
   if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
@@ -495,8 +493,55 @@
   _LOG(log, logtype::REGISTERS, "    register dumping unimplemented on this architecture");
 }
 
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
-                        const std::string& thread_name, BacktraceMap* map,
+static bool verify_backtraces_equal(Backtrace* back1, Backtrace* back2) {
+  if (back1->NumFrames() != back2->NumFrames()) {
+    return false;
+  }
+  std::string back1_str;
+  std::string back2_str;
+  for (size_t i = 0; i < back1->NumFrames(); i++) {
+    back1_str += back1->FormatFrameData(i);
+    back2_str += back2->FormatFrameData(i);
+  }
+  return back1_str == back2_str;
+}
+
+static void log_mismatch_data(log_t* log, Backtrace* backtrace) {
+  _LOG(log, logtype::THREAD, "MISMATCH: This unwind is different.\n");
+  if (backtrace->NumFrames() == 0) {
+    _LOG(log, logtype::THREAD, "MISMATCH: No frames in new backtrace.\n");
+    return;
+  }
+  _LOG(log, logtype::THREAD, "MISMATCH: Backtrace from new unwinder.\n");
+  for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+    _LOG(log, logtype::THREAD, "MISMATCH: %s\n", backtrace->FormatFrameData(i).c_str());
+  }
+
+  // Get the stack trace up to 8192 bytes.
+  std::vector<uint64_t> buffer(8192 / sizeof(uint64_t));
+  size_t bytes =
+      backtrace->Read(backtrace->GetFrame(0)->sp, reinterpret_cast<uint8_t*>(buffer.data()),
+                      buffer.size() * sizeof(uint64_t));
+  std::string log_data;
+  for (size_t i = 0; i < bytes / sizeof(uint64_t); i++) {
+    if ((i % 4) == 0) {
+      if (!log_data.empty()) {
+        _LOG(log, logtype::THREAD, "MISMATCH: stack_data%s\n", log_data.c_str());
+        log_data = "";
+      }
+    }
+    log_data += android::base::StringPrintf(" 0x%016" PRIx64, buffer[i]);
+  }
+
+  if (!log_data.empty()) {
+    _LOG(log, logtype::THREAD, "MISMATCH: data%s\n", log_data.c_str());
+  }
+
+  // If there is any leftover (bytes % sizeof(uint64_t) != 0, ignore it for now.
+}
+
+static bool dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
+                        const std::string& thread_name, BacktraceMap* map, BacktraceMap* map_new,
                         uintptr_t abort_msg_address, bool primary_thread) {
   log->current_tid = tid;
   if (!primary_thread) {
@@ -510,7 +555,18 @@
     dump_abort_message(backtrace.get(), log, abort_msg_address);
   }
   dump_registers(log, tid);
+  bool matches = true;
   if (backtrace->Unwind(0)) {
+    // Use the new method and verify it is the same as old.
+    std::unique_ptr<Backtrace> backtrace_new(Backtrace::CreateNew(pid, tid, map_new));
+    if (!backtrace_new->Unwind(0)) {
+      _LOG(log, logtype::THREAD, "Failed to unwind with new unwinder: %s\n",
+           backtrace_new->GetErrorString(backtrace_new->GetError()).c_str());
+      matches = false;
+    } else if (!verify_backtraces_equal(backtrace.get(), backtrace_new.get())) {
+      log_mismatch_data(log, backtrace_new.get());
+      matches = false;
+    }
     dump_backtrace_and_stack(backtrace.get(), log);
   } else {
     ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
@@ -524,6 +580,8 @@
   }
 
   log->current_tid = log->crashed_tid;
+
+  return matches;
 }
 
 // Reads the contents of the specified log device, filters out the entries
@@ -657,9 +715,10 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid,
-                       pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address) {
+static void dump_crash(log_t* log, BacktraceMap* map, BacktraceMap* map_new,
+                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
+                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
+                       uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
   char value[PROPERTY_VALUE_MAX];
   property_get("ro.debuggable", value, "0");
@@ -668,7 +727,8 @@
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(log);
-  dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
+  bool new_unwind_matches = dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map,
+                                        map_new, abort_msg_address, true);
   if (want_logs) {
     dump_logs(log, pid, 5);
   }
@@ -678,7 +738,9 @@
     const std::string& thread_name = it.second;
 
     if (thread_tid != tid) {
-      dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
+      bool match =
+          dump_thread(log, pid, thread_tid, process_name, thread_name, map, map_new, 0, false);
+      new_unwind_matches = new_unwind_matches && match;
     }
   }
 
@@ -690,71 +752,26 @@
   if (want_logs) {
     dump_logs(log, pid, 0);
   }
+  if (!new_unwind_matches) {
+    _LOG(log, logtype::THREAD, "MISMATCH: New and old unwinder do not agree.\n");
+    _LOG(log, logtype::THREAD, "MISMATCH: If you see this please file a bug in:\n");
+    _LOG(log, logtype::THREAD,
+         "MISMATCH: Android > Android OS & Apps > Runtime > native > tools "
+         "(debuggerd/gdb/init/simpleperf/strace/valgrind)\n");
+    _LOG(log, logtype::THREAD, "MISMATCH: and attach this tombstone.\n");
+  }
 }
 
-// open_tombstone - find an available tombstone slot, if any, of the
-// form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
-// file is available, we reuse the least-recently-modified file.
-int open_tombstone(std::string* out_path) {
-  // In a single pass, find an available slot and, in case none
-  // exist, find and record the least-recently-modified file.
-  char path[128];
-  int fd = -1;
-  int oldest = -1;
-  struct stat oldest_sb;
-  for (int i = 0; i < MAX_TOMBSTONES; i++) {
-    snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
-
-    struct stat sb;
-    if (stat(path, &sb) == 0) {
-      if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
-        oldest = i;
-        oldest_sb.st_mtime = sb.st_mtime;
-      }
-      continue;
-    }
-    if (errno != ENOENT) continue;
-
-    fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
-    if (fd < 0) continue;  // raced ?
-
-    if (out_path) {
-      *out_path = path;
-    }
-    fchown(fd, AID_SYSTEM, AID_SYSTEM);
-    return fd;
-  }
-
-  if (oldest < 0) {
-    ALOGE("debuggerd: failed to find a valid tombstone, default to using tombstone 0.\n");
-    oldest = 0;
-  }
-
-  // we didn't find an available file, so we clobber the oldest one
-  snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
-  fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
-  if (fd < 0) {
-    ALOGE("debuggerd: failed to open tombstone file '%s': %s\n", path, strerror(errno));
-    return -1;
-  }
-
-  if (out_path) {
-    *out_path = path;
-  }
-  fchown(fd, AID_SYSTEM, AID_SYSTEM);
-  return fd;
-}
-
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
-                       pid_t pid, pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
-                       std::string* amfd_data) {
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, BacktraceMap* map_new,
+                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
+                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
+                       uintptr_t abort_msg_address, std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
+  dump_crash(&log, map, map_new, open_files, pid, tid, process_name, threads, abort_msg_address);
 }
 
 void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 22fde5e..1b74652 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -16,22 +16,28 @@
 
 #define LOG_TAG "DEBUG"
 
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/ptrace.h>
+#include <sys/uio.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
 #include <string>
 
+#include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
+using android::base::unique_fd;
+
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == HEADER)
@@ -42,6 +48,19 @@
   return false;
 }
 
+static bool should_write_to_kmsg() {
+  // Write to kmsg if tombstoned isn't up, and we're able to do so.
+  if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+    return false;
+  }
+
+  if (android::base::GetProperty("init.svc.tombstoned", "") == "running") {
+    return false;
+  }
+
+  return true;
+}
+
 __attribute__((__weak__, visibility("default")))
 void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
   bool write_to_tombstone = (log->tfd != -1);
@@ -49,6 +68,7 @@
                       && log->crashed_tid != -1
                       && log->current_tid != -1
                       && (log->crashed_tid == log->current_tid);
+  static bool write_to_kmsg = should_write_to_kmsg();
 
   char buf[512];
   va_list ap;
@@ -70,6 +90,30 @@
     if (log->amfd_data != nullptr) {
       *log->amfd_data += buf;
     }
+
+    if (write_to_kmsg) {
+      unique_fd kmsg_fd(open("/dev/kmsg_debug", O_WRONLY | O_APPEND | O_CLOEXEC));
+      if (kmsg_fd.get() >= 0) {
+        // Our output might contain newlines which would otherwise be handled by the android logger.
+        // Split the lines up ourselves before sending to the kernel logger.
+        if (buf[len - 1] == '\n') {
+          buf[len - 1] = '\0';
+        }
+
+        std::vector<std::string> fragments = android::base::Split(buf, "\n");
+        for (const std::string& fragment : fragments) {
+          static constexpr char prefix[] = "<3>DEBUG: ";
+          struct iovec iov[3];
+          iov[0].iov_base = const_cast<char*>(prefix);
+          iov[0].iov_len = strlen(prefix);
+          iov[1].iov_base = const_cast<char*>(fragment.c_str());
+          iov[1].iov_len = fragment.length();
+          iov[2].iov_base = const_cast<char*>("\n");
+          iov[2].iov_len = 1;
+          TEMP_FAILURE_RETRY(writev(kmsg_fd.get(), iov, 3));
+        }
+      }
+    }
   }
 }
 
@@ -205,7 +249,7 @@
 }
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
-  android::base::unique_fd fd(open(path, O_RDONLY));
+  unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
   if (fd != -1) {
     int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
     if (rc != -1) {
diff --git a/debuggerd/libdebuggerd/x86/machine.cpp b/debuggerd/libdebuggerd/x86/machine.cpp
index af10817..09a64cd 100644
--- a/debuggerd/libdebuggerd/x86/machine.cpp
+++ b/debuggerd/libdebuggerd/x86/machine.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -24,8 +26,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   struct pt_regs r;
diff --git a/debuggerd/libdebuggerd/x86_64/machine.cpp b/debuggerd/libdebuggerd/x86_64/machine.cpp
index bf2c2b4..de1c268 100644
--- a/debuggerd/libdebuggerd/x86_64/machine.cpp
+++ b/debuggerd/libdebuggerd/x86_64/machine.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "DEBUG"
 
+#include "libdebuggerd/machine.h"
+
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -25,8 +27,7 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-#include "machine.h"
-#include "utility.h"
+#include "libdebuggerd/utility.h"
 
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   struct user_regs_struct r;
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index c6a997b..0bb07ac 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -86,13 +86,3 @@
 
   return result;
 }
-
-bool Pipe(unique_fd* read, unique_fd* write) {
-  int pipefds[2];
-  if (pipe(pipefds) != 0) {
-    return false;
-  }
-  read->reset(pipefds[0]);
-  write->reset(pipefds[1]);
-  return true;
-}
diff --git a/debuggerd/util.h b/debuggerd/util.h
index 6051714..171e07a 100644
--- a/debuggerd/util.h
+++ b/debuggerd/util.h
@@ -42,5 +42,3 @@
 //   plus any errors returned by the underlying recvmsg.
 ssize_t recv_fd(int sockfd, void* _Nonnull data, size_t len,
                 android::base::unique_fd* _Nullable out_fd);
-
-bool Pipe(android::base::unique_fd* read, android::base::unique_fd* write);
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 9069baa..e95b049 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -93,12 +93,9 @@
     SInt32 score;
     UInt8 interfaceNumEndpoints;
 
-    // Placing the constant KIOUSBFindInterfaceDontCare into the following
-    // fields of the IOUSBFindInterfaceRequest structure will allow us to
-    // find all of the interfaces
-    request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
-    request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
-    request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+    request.bInterfaceClass = 0xff;
+    request.bInterfaceSubClass = 0x42;
+    request.bInterfaceProtocol = 0x03;
     request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
 
     // Get an iterator for the interfaces on the device
@@ -282,7 +279,6 @@
             &plugin, &score);
 
     if ((kr != 0) || (plugin == NULL)) {
-        ERR("Unable to create a plug-in (%08x)\n", kr);
         goto error;
     }
 
@@ -436,8 +432,7 @@
 
         if (try_device(device, &h) != 0) {
             IOObjectRelease(device);
-            ret = -1;
-            break;
+            continue;
         }
 
         if (h.success) {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 9249343..007189d 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -15,7 +15,6 @@
     libavb
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
 LOCAL_SRC_FILES:= fs_mgr_main.cpp
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 91ed496..c9af421 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -249,6 +249,13 @@
            le32_to_cpu(es->s_r_blocks_count_lo);
 }
 
+static bool is_ext4_superblock_valid(const struct ext4_super_block* es) {
+    if (es->s_magic != EXT4_SUPER_MAGIC) return false;
+    if (es->s_rev_level != EXT4_DYNAMIC_REV && es->s_rev_level != EXT4_GOOD_OLD_REV) return false;
+    if (EXT4_INODES_PER_GROUP(es) == 0) return false;
+    return true;
+}
+
 // Read the primary superblock from an ext4 filesystem.  On failure return
 // false.  If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
 static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
@@ -264,9 +271,8 @@
         return false;
     }
 
-    if (sb->s_magic != EXT4_SUPER_MAGIC) {
-        LINFO << "Invalid ext4 magic:0x" << std::hex << sb->s_magic << " "
-              << "on '" << blk_device << "'";
+    if (!is_ext4_superblock_valid(sb)) {
+        LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
         // not a valid fs, tune2fs, fsck, and mount  will all fail.
         *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
         return false;
diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk
index a62b1d4..c38c64b 100644
--- a/gatekeeperd/tests/Android.mk
+++ b/gatekeeperd/tests/Android.mk
@@ -19,7 +19,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := gatekeeperd-unit-tests
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_CFLAGS += -g -Wall -Werror -Wno-missing-field-initializers
 LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto libbase
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := external/scrypt/lib/crypto
diff --git a/init/Android.bp b/init/Android.bp
index aaef7e9..672942e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -54,6 +54,9 @@
                 "-DSHUTDOWN_ZERO_TIMEOUT=1",
             ],
         },
+        uml: {
+            cppflags: ["-DUSER_MODE_LINUX"],
+        }
     },
 }
 
@@ -67,10 +70,15 @@
         "devices.cpp",
         "firmware_handler.cpp",
         "import_parser.cpp",
-        "init_parser.cpp",
         "log.cpp",
         "parser.cpp",
+        "persistent_properties.cpp",
+        "property_service.cpp",
+        "security.cpp",
+        "selinux.cpp",
         "service.cpp",
+        "rlimit_parser.cpp",
+        "tokenizer.cpp",
         "uevent_listener.cpp",
         "ueventd_parser.cpp",
         "util.cpp",
@@ -81,7 +89,12 @@
         "libselinux",
         "liblog",
         "libprocessgroup",
+        "libfs_mgr",
     ],
+    include_dirs: [
+        "system/core/mkbootimg",
+    ],
+
 }
 
 /*
@@ -105,15 +118,11 @@
         "init.cpp",
         "init_first_stage.cpp",
         "keychords.cpp",
-        "property_service.cpp",
         "reboot.cpp",
-        "signal_handler.cpp",
+        "sigchld_handler.cpp",
         "ueventd.cpp",
         "watchdogd.cpp",
     ],
-    include_dirs: [
-        "system/core/mkbootimg"
-    ],
     static_libs: [
         "libinit",
         "libbootloader_message",
@@ -153,9 +162,11 @@
     defaults: ["init_defaults"],
     srcs: [
         "devices_test.cpp",
-        "init_parser_test.cpp",
         "init_test.cpp",
+        "persistent_properties_test.cpp",
         "property_service_test.cpp",
+        "result_test.cpp",
+        "rlimit_parser_test.cpp",
         "service_test.cpp",
         "ueventd_test.cpp",
         "util_test.cpp",
@@ -163,9 +174,12 @@
     shared_libs: [
         "libbase",
         "libcutils",
-        "libselinux",
     ],
-    static_libs: ["libinit"],
+    static_libs: [
+        "libinit",
+        "libselinux",
+        "libcrypto",
+    ],
 }
 
 subdirs = ["*"]
diff --git a/init/Android.mk b/init/Android.mk
index 161256e..6c28517 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -9,12 +9,14 @@
     -DALLOW_LOCAL_PROP_OVERRIDE=1 \
     -DALLOW_PERMISSIVE_SELINUX=1 \
     -DREBOOT_BOOTLOADER_ON_PANIC=1 \
+    -DWORLD_WRITABLE_KMSG=1 \
     -DDUMP_ON_UMOUNT_FAILURE=1
 else
 init_options += \
     -DALLOW_LOCAL_PROP_OVERRIDE=0 \
     -DALLOW_PERMISSIVE_SELINUX=0 \
     -DREBOOT_BOOTLOADER_ON_PANIC=0 \
+    -DWORLD_WRITABLE_KMSG=0 \
     -DDUMP_ON_UMOUNT_FAILURE=0
 endif
 
@@ -28,10 +30,6 @@
 
 init_options += -DLOG_UEVENTS=0
 
-ifeq ($(TARGET_USER_MODE_LINUX), true)
-    init_cflags += -DUSER_MODE_LINUX
-endif
-
 init_cflags += \
     $(init_options) \
     -Wall -Wextra \
@@ -49,15 +47,12 @@
     init.cpp \
     init_first_stage.cpp \
     keychords.cpp \
-    property_service.cpp \
     reboot.cpp \
-    signal_handler.cpp \
+    sigchld_handler.cpp \
     ueventd.cpp \
     watchdogd.cpp \
 
 LOCAL_MODULE:= init
-LOCAL_C_INCLUDES += \
-    system/core/mkbootimg
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
@@ -75,6 +70,7 @@
     libcutils \
     libbase \
     libc \
+    libseccomp_policy \
     libselinux \
     liblog \
     libcrypto_utils \
@@ -97,5 +93,4 @@
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
 
 LOCAL_SANITIZE := signed-integer-overflow
-LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
diff --git a/init/README.md b/init/README.md
index f3b57bc..7df37ff 100644
--- a/init/README.md
+++ b/init/README.md
@@ -216,6 +216,12 @@
   http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
   capabilities.
 
+`setrlimit <resource> <cur> <max>`
+> This applies the given rlimit to the service. rlimits are inherited by child
+  processes, so this effectively applies the given rlimit to the process tree
+  started by this service.
+  It is parsed similarly to the setrlimit command specified below.
+
 `seclabel <seclabel>`
 > Change to 'seclabel' before exec'ing this service.
   Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
@@ -447,12 +453,20 @@
 `rmdir <path>`
 > Calls rmdir(2) on the given path.
 
+`readahead <file|dir> [--fully]`
+> Calls readahead(2) on the file or files within given directory.
+  Use option --fully to read the full file content.
+
 `setprop <name> <value>`
 > Set system property _name_ to _value_. Properties are expanded
   within _value_.
 
 `setrlimit <resource> <cur> <max>`
-> Set the rlimit for a resource.
+> Set the rlimit for a resource. This applies to all processes launched after
+  the limit is set. It is intended to be set early in init and applied globally.
+  _resource_ is best specified using its text representation ('cpu', 'rtio', etc
+  or 'RLIM_CPU', 'RLIM_RTIO', etc). It also may be specified as the int value
+  that the resource enum corresponds to.
 
 `start <service>`
 > Start a service running if it is not already running.
diff --git a/init/action.cpp b/init/action.cpp
index 4ec5f17..60204a8 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -31,14 +31,13 @@
 Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
     : func_(f), args_(args), line_(line) {}
 
-int Command::InvokeFunc() const {
+Result<Success> Command::InvokeFunc() const {
     std::vector<std::string> expanded_args;
     expanded_args.resize(args_.size());
     expanded_args[0] = args_[0];
     for (std::size_t i = 1; i < args_.size(); ++i) {
         if (!expand_props(args_[i], &expanded_args[i])) {
-            LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'";
-            return -EINVAL;
+            return Error() << "cannot expand '" << args_[i] << "'";
         }
     }
 
@@ -54,19 +53,16 @@
 
 const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;
 
-bool Action::AddCommand(const std::vector<std::string>& args, int line, std::string* err) {
+Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) {
     if (!function_map_) {
-        *err = "no function map available";
-        return false;
+        return Error() << "no function map available";
     }
 
-    auto function = function_map_->FindFunction(args, err);
-    if (!function) {
-        return false;
-    }
+    auto function = function_map_->FindFunction(args);
+    if (!function) return Error() << function.error();
 
-    AddCommand(function, args, line);
-    return true;
+    AddCommand(*function, args, line);
+    return Success();
 }
 
 void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) {
@@ -92,81 +88,85 @@
 
 void Action::ExecuteCommand(const Command& command) const {
     android::base::Timer t;
-    int result = command.InvokeFunc();
-
+    auto result = command.InvokeFunc();
     auto duration = t.duration();
+
+    // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
+    // device, such as '/sys/class/leds/jogball-backlight/brightness'.  As of this writing, there
+    // are 198 such failures on bullhead.  Instead of spamming the log reporting them, we do not
+    // report such failures unless we're running at the DEBUG log level.
+    bool report_failure = !result.has_value();
+    if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
+        result.error_errno() == ENOENT) {
+        report_failure = false;
+    }
+
     // Any action longer than 50ms will be warned to user as slow operation
-    if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+    if (report_failure || duration > 50ms ||
+        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
-                  << ":" << command.line() << ") returned " << result << " took "
-                  << duration.count() << "ms.";
+                  << ":" << command.line() << ") took " << duration.count() << "ms and "
+                  << (result ? "succeeded" : "failed: " + result.error_string());
     }
 }
 
-bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) {
+Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
     const static std::string prop_str("property:");
     std::string prop_name(trigger.substr(prop_str.length()));
     size_t equal_pos = prop_name.find('=');
     if (equal_pos == std::string::npos) {
-        *err = "property trigger found without matching '='";
-        return false;
+        return Error() << "property trigger found without matching '='";
     }
 
     std::string prop_value(prop_name.substr(equal_pos + 1));
     prop_name.erase(equal_pos);
 
     if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
-        *err = "multiple property triggers found for same property";
-        return false;
+        return Error() << "multiple property triggers found for same property";
     }
-    return true;
+    return Success();
 }
 
-bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Action::InitTriggers(const std::vector<std::string>& args) {
     const static std::string prop_str("property:");
     for (std::size_t i = 0; i < args.size(); ++i) {
         if (args[i].empty()) {
-            *err = "empty trigger is not valid";
-            return false;
+            return Error() << "empty trigger is not valid";
         }
 
         if (i % 2) {
             if (args[i] != "&&") {
-                *err = "&& is the only symbol allowed to concatenate actions";
-                return false;
+                return Error() << "&& is the only symbol allowed to concatenate actions";
             } else {
                 continue;
             }
         }
 
         if (!args[i].compare(0, prop_str.length(), prop_str)) {
-            if (!ParsePropertyTrigger(args[i], err)) {
-                return false;
+            if (auto result = ParsePropertyTrigger(args[i]); !result) {
+                return result;
             }
         } else {
             if (!event_trigger_.empty()) {
-                *err = "multiple event triggers are not allowed";
-                return false;
+                return Error() << "multiple event triggers are not allowed";
             }
 
             event_trigger_ = args[i];
         }
     }
 
-    return true;
+    return Success();
 }
 
-bool Action::InitSingleTrigger(const std::string& trigger) {
+Result<Success> Action::InitSingleTrigger(const std::string& trigger) {
     std::vector<std::string> name_vector{trigger};
-    std::string err;
-    bool ret = InitTriggers(name_vector, &err);
-    if (!ret) {
-        LOG(ERROR) << "InitSingleTrigger failed due to: " << err;
+    if (auto result = InitTriggers(name_vector); !result) {
+        return Error() << "InitTriggers() failed: " << result.error();
     }
-    return ret;
+    return Success();
 }
 
 // This function checks that all property triggers are satisfied, that is
@@ -264,7 +264,8 @@
     auto action = std::make_unique<Action>(true, "<Builtin Action>", 0);
     std::vector<std::string> name_vector{name};
 
-    if (!action->InitSingleTrigger(name)) {
+    if (auto result = action->InitSingleTrigger(name); !result) {
+        LOG(ERROR) << "Cannot queue BuiltinAction for " << name << ": " << result.error();
         return;
     }
 
@@ -333,25 +334,25 @@
     current_command_ = 0;
 }
 
-bool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                                int line, std::string* err) {
+Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
+                                           const std::string& filename, int line) {
     std::vector<std::string> triggers(args.begin() + 1, args.end());
     if (triggers.size() < 1) {
-        *err = "actions must have a trigger";
-        return false;
+        return Error() << "Actions must have a trigger";
     }
 
     auto action = std::make_unique<Action>(false, filename, line);
-    if (!action->InitTriggers(triggers, err)) {
-        return false;
+
+    if (auto result = action->InitTriggers(triggers); !result) {
+        return Error() << "InitTriggers() failed: " << result.error();
     }
 
     action_ = std::move(action);
-    return true;
+    return Success();
 }
 
-bool ActionParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
-    return action_ ? action_->AddCommand(std::move(args), line, err) : false;
+Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
+    return action_ ? action_->AddCommand(std::move(args), line) : Success();
 }
 
 void ActionParser::EndSection() {
diff --git a/init/action.h b/init/action.h
index ad15f3f..d977f82 100644
--- a/init/action.h
+++ b/init/action.h
@@ -24,8 +24,9 @@
 #include <vector>
 
 #include "builtins.h"
-#include "init_parser.h"
 #include "keyword_map.h"
+#include "parser.h"
+#include "result.h"
 
 namespace android {
 namespace init {
@@ -34,7 +35,7 @@
   public:
     Command(BuiltinFunction f, const std::vector<std::string>& args, int line);
 
-    int InvokeFunc() const;
+    Result<Success> InvokeFunc() const;
     std::string BuildCommandString() const;
 
     int line() const { return line_; }
@@ -53,10 +54,10 @@
   public:
     explicit Action(bool oneshot, const std::string& filename, int line);
 
-    bool AddCommand(const std::vector<std::string>& args, int line, std::string* err);
+    Result<Success> AddCommand(const std::vector<std::string>& args, int line);
     void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
-    bool InitTriggers(const std::vector<std::string>& args, std::string* err);
-    bool InitSingleTrigger(const std::string& trigger);
+    Result<Success> InitTriggers(const std::vector<std::string>& args);
+    Result<Success> InitSingleTrigger(const std::string& trigger);
     std::size_t NumCommands() const;
     void ExecuteOneCommand(std::size_t command) const;
     void ExecuteAllCommands() const;
@@ -78,7 +79,7 @@
     void ExecuteCommand(const Command& command) const;
     bool CheckPropertyTriggers(const std::string& name = "",
                                const std::string& value = "") const;
-    bool ParsePropertyTrigger(const std::string& trigger, std::string* err);
+    Result<Success> ParsePropertyTrigger(const std::string& trigger);
 
     std::map<std::string, std::string> property_triggers_;
     std::string event_trigger_;
@@ -120,9 +121,9 @@
   public:
     ActionParser(ActionManager* action_manager)
         : action_manager_(action_manager), action_(nullptr) {}
-    bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
-                      std::string* err) override;
-    bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override;
+    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+                                 int line) override;
+    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
     void EndSection() override;
 
   private:
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 4727f92..ec84317 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -163,37 +163,37 @@
   LOG(INFO) << "Bootcharting finished";
 }
 
-static int do_bootchart_start() {
-  // We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
-  std::string start;
-  if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
-    LOG(VERBOSE) << "Not bootcharting";
-    return 0;
-  }
+static Result<Success> do_bootchart_start() {
+    // We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
+    std::string start;
+    if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
+        LOG(VERBOSE) << "Not bootcharting";
+        return Success();
+    }
 
-  g_bootcharting_thread = new std::thread(bootchart_thread_main);
-  return 0;
+    g_bootcharting_thread = new std::thread(bootchart_thread_main);
+    return Success();
 }
 
-static int do_bootchart_stop() {
-  if (!g_bootcharting_thread) return 0;
+static Result<Success> do_bootchart_stop() {
+    if (!g_bootcharting_thread) return Success();
 
-  // Tell the worker thread it's time to quit.
-  {
-    std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex);
-    g_bootcharting_finished = true;
-    g_bootcharting_finished_cv.notify_one();
-  }
+    // Tell the worker thread it's time to quit.
+    {
+        std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex);
+        g_bootcharting_finished = true;
+        g_bootcharting_finished_cv.notify_one();
+    }
 
-  g_bootcharting_thread->join();
-  delete g_bootcharting_thread;
-  g_bootcharting_thread = nullptr;
-  return 0;
+    g_bootcharting_thread->join();
+    delete g_bootcharting_thread;
+    g_bootcharting_thread = nullptr;
+    return Success();
 }
 
-int do_bootchart(const std::vector<std::string>& args) {
-  if (args[1] == "start") return do_bootchart_start();
-  return do_bootchart_stop();
+Result<Success> do_bootchart(const std::vector<std::string>& args) {
+    if (args[1] == "start") return do_bootchart_start();
+    return do_bootchart_stop();
 }
 
 }  // namespace init
diff --git a/init/bootchart.h b/init/bootchart.h
index e4f7b59..f614f71 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -20,10 +20,12 @@
 #include <string>
 #include <vector>
 
+#include "result.h"
+
 namespace android {
 namespace init {
 
-int do_bootchart(const std::vector<std::string>& args);
+Result<Success> do_bootchart(const std::vector<std::string>& args);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 56d0ae2..d77abdf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <fts.h>
 #include <linux/loop.h>
 #include <linux/module.h>
 #include <mntent.h>
@@ -44,7 +45,9 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <ext4_utils/ext4_crypt.h>
@@ -53,19 +56,22 @@
 #include <selinux/android.h>
 #include <selinux/label.h>
 #include <selinux/selinux.h>
+#include <system/thread_defs.h>
 
 #include "action.h"
 #include "bootchart.h"
 #include "init.h"
-#include "init_parser.h"
+#include "parser.h"
 #include "property_service.h"
 #include "reboot.h"
+#include "rlimit_parser.h"
 #include "service.h"
-#include "signal_handler.h"
 #include "util.h"
 
 using namespace std::literals::string_literals;
 
+using android::base::unique_fd;
+
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 
 namespace android {
@@ -73,128 +79,124 @@
 
 static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
 
-static int insmod(const char *filename, const char *options, int flags) {
-    int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
-    if (fd == -1) {
-        PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
-        return -1;
-    }
-    int rc = syscall(__NR_finit_module, fd, options, flags);
-    if (rc == -1) {
-        PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
-    }
-    close(fd);
-    return rc;
-}
-
-static int __ifupdown(const char *interface, int up) {
-    struct ifreq ifr;
-    int s, ret;
-
-    strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
-
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0)
-        return -1;
-
-    ret = ioctl(s, SIOCGIFFLAGS, &ifr);
-    if (ret < 0) {
-        goto done;
-    }
-
-    if (up)
-        ifr.ifr_flags |= IFF_UP;
-    else
-        ifr.ifr_flags &= ~IFF_UP;
-
-    ret = ioctl(s, SIOCSIFFLAGS, &ifr);
-
-done:
-    close(s);
-    return ret;
-}
-
-static int reboot_into_recovery(const std::vector<std::string>& options) {
+static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
     std::string err;
     if (!write_bootloader_message(options, &err)) {
-        LOG(ERROR) << "failed to set bootloader message: " << err;
-        return -1;
+        return Error() << "Failed to set bootloader message: " << err;
     }
     property_set("sys.powerctl", "reboot,recovery");
-    return 0;
+    return Success();
 }
 
-static int do_class_start(const std::vector<std::string>& args) {
-        /* Starting a class does not start services
-         * which are explicitly disabled.  They must
-         * be started individually.
-         */
-    ServiceManager::GetInstance().
-        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
-    return 0;
-}
-
-static int do_class_stop(const std::vector<std::string>& args) {
-    ServiceManager::GetInstance().
-        ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
-    return 0;
-}
-
-static int do_class_reset(const std::vector<std::string>& args) {
-    ServiceManager::GetInstance().
-        ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
-    return 0;
-}
-
-static int do_class_restart(const std::vector<std::string>& args) {
-    ServiceManager::GetInstance().
-        ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
-    return 0;
-}
-
-static int do_domainname(const std::vector<std::string>& args) {
-    std::string err;
-    if (!WriteFile("/proc/sys/kernel/domainname", args[1], &err)) {
-        LOG(ERROR) << err;
-        return -1;
+template <typename F>
+static void ForEachServiceInClass(const std::string& classname, F function) {
+    for (const auto& service : ServiceList::GetInstance()) {
+        if (service->classnames().count(classname)) std::invoke(function, service);
     }
-    return 0;
 }
 
-static int do_enable(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
-    if (!svc) {
-        return -1;
+static Result<Success> do_class_start(const std::vector<std::string>& args) {
+    // Starting a class does not start services which are explicitly disabled.
+    // They must  be started individually.
+    ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
+    return Success();
+}
+
+static Result<Success> do_class_stop(const std::vector<std::string>& args) {
+    ForEachServiceInClass(args[1], &Service::Stop);
+    return Success();
+}
+
+static Result<Success> do_class_reset(const std::vector<std::string>& args) {
+    ForEachServiceInClass(args[1], &Service::Reset);
+    return Success();
+}
+
+static Result<Success> do_class_restart(const std::vector<std::string>& args) {
+    ForEachServiceInClass(args[1], &Service::Restart);
+    return Success();
+}
+
+static Result<Success> do_domainname(const std::vector<std::string>& args) {
+    if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
+        return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
     }
-    return svc->Enable();
+    return Success();
 }
 
-static int do_exec(const std::vector<std::string>& args) {
-    return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
-}
+static Result<Success> do_enable(const std::vector<std::string>& args) {
+    Service* svc = ServiceList::GetInstance().FindService(args[1]);
+    if (!svc) return Error() << "Could not find service";
 
-static int do_exec_start(const std::vector<std::string>& args) {
-    return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
-}
-
-static int do_export(const std::vector<std::string>& args) {
-    return add_environment(args[1].c_str(), args[2].c_str());
-}
-
-static int do_hostname(const std::vector<std::string>& args) {
-    std::string err;
-    if (!WriteFile("/proc/sys/kernel/hostname", args[1], &err)) {
-        LOG(ERROR) << err;
-        return -1;
+    if (auto result = svc->Enable(); !result) {
+        return Error() << "Could not enable service: " << result.error();
     }
-    return 0;
+
+    return Success();
 }
 
-static int do_ifup(const std::vector<std::string>& args) {
-    return __ifupdown(args[1].c_str(), 1);
+static Result<Success> do_exec(const std::vector<std::string>& args) {
+    auto service = Service::MakeTemporaryOneshotService(args);
+    if (!service) {
+        return Error() << "Could not create exec service";
+    }
+    if (auto result = service->ExecStart(); !result) {
+        return Error() << "Could not start exec service: " << result.error();
+    }
+
+    ServiceList::GetInstance().AddService(std::move(service));
+    return Success();
 }
 
-static int do_insmod(const std::vector<std::string>& args) {
+static Result<Success> do_exec_start(const std::vector<std::string>& args) {
+    Service* service = ServiceList::GetInstance().FindService(args[1]);
+    if (!service) {
+        return Error() << "Service not found";
+    }
+
+    if (auto result = service->ExecStart(); !result) {
+        return Error() << "Could not start exec service: " << result.error();
+    }
+
+    return Success();
+}
+
+static Result<Success> do_export(const std::vector<std::string>& args) {
+    if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
+        return ErrnoError() << "setenv() failed";
+    }
+    return Success();
+}
+
+static Result<Success> do_hostname(const std::vector<std::string>& args) {
+    if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
+        return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
+    }
+    return Success();
+}
+
+static Result<Success> do_ifup(const std::vector<std::string>& args) {
+    struct ifreq ifr;
+
+    strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
+
+    unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
+    if (s < 0) return ErrnoError() << "opening socket failed";
+
+    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+        return ErrnoError() << "ioctl(..., SIOCGIFFLAGS, ...) failed";
+    }
+
+    ifr.ifr_flags |= IFF_UP;
+
+    if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
+        return ErrnoError() << "ioctl(..., SIOCSIFFLAGS, ...) failed";
+    }
+
+    return Success();
+}
+
+static Result<Success> do_insmod(const std::vector<std::string>& args) {
     int flags = 0;
     auto it = args.begin() + 1;
 
@@ -205,53 +207,56 @@
 
     std::string filename = *it++;
     std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
-    return insmod(filename.c_str(), options.c_str(), flags);
+
+    unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
+    if (fd == -1) return ErrnoError() << "open(\"" << filename << "\") failed";
+
+    int rc = syscall(__NR_finit_module, fd.get(), options.c_str(), flags);
+    if (rc == -1) return ErrnoError() << "finit_module for \"" << filename << "\" failed";
+
+    return Success();
 }
 
-static int do_mkdir(const std::vector<std::string>& args) {
+// mkdir <path> [mode] [owner] [group]
+static Result<Success> do_mkdir(const std::vector<std::string>& args) {
     mode_t mode = 0755;
-    int ret;
-
-    /* mkdir <path> [mode] [owner] [group] */
-
     if (args.size() >= 3) {
         mode = std::strtoul(args[2].c_str(), 0, 8);
     }
 
-    ret = make_dir(args[1].c_str(), mode, sehandle);
-    /* chmod in case the directory already exists */
-    if (ret == -1 && errno == EEXIST) {
-        ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
-    }
-    if (ret == -1) {
-        return -errno;
+    if (!make_dir(args[1], mode)) {
+        /* chmod in case the directory already exists */
+        if (errno == EEXIST) {
+            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
+                return ErrnoError() << "fchmodat() failed";
+            }
+        } else {
+            return ErrnoError() << "mkdir() failed";
+        }
     }
 
     if (args.size() >= 4) {
-        uid_t uid;
-        std::string decode_uid_err;
-        if (!DecodeUid(args[3], &uid, &decode_uid_err)) {
-            LOG(ERROR) << "Unable to find UID for '" << args[3] << "': " << decode_uid_err;
-            return -1;
+        auto uid = DecodeUid(args[3]);
+        if (!uid) {
+            return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
         }
-        gid_t gid = -1;
+        Result<gid_t> gid = -1;
 
         if (args.size() == 5) {
-            if (!DecodeUid(args[4], &gid, &decode_uid_err)) {
-                LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
-                return -1;
+            gid = DecodeUid(args[4]);
+            if (!gid) {
+                return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
             }
         }
 
-        if (lchown(args[1].c_str(), uid, gid) == -1) {
-            return -errno;
+        if (lchown(args[1].c_str(), *uid, *gid) == -1) {
+            return ErrnoError() << "lchown failed";
         }
 
         /* chown may have cleared S_ISUID and S_ISGID, chmod again */
         if (mode & (S_ISUID | S_ISGID)) {
-            ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
-            if (ret == -1) {
-                return -errno;
+            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
+                return ErrnoError() << "fchmodat failed";
             }
         }
     }
@@ -262,15 +267,18 @@
                 "--prompt_and_wipe_data",
                 "--reason=set_policy_failed:"s + args[1]};
             reboot_into_recovery(options);
-            return -1;
+            return Error() << "reboot into recovery failed";
         }
     }
-    return 0;
+    return Success();
 }
 
 /* umount <path> */
-static int do_umount(const std::vector<std::string>& args) {
-  return umount(args[1].c_str());
+static Result<Success> do_umount(const std::vector<std::string>& args) {
+    if (umount(args[1].c_str()) < 0) {
+        return ErrnoError() << "umount() failed";
+    }
+    return Success();
 }
 
 static struct {
@@ -298,16 +306,13 @@
 #define DATA_MNT_POINT "/data"
 
 /* mount <type> <device> <path> <flags ...> <options> */
-static int do_mount(const std::vector<std::string>& args) {
-    char tmp[64];
-    const char *source, *target, *system;
-    const char *options = NULL;
+static Result<Success> do_mount(const std::vector<std::string>& args) {
+    const char* options = nullptr;
     unsigned flags = 0;
-    std::size_t na = 0;
-    int n, i;
-    int wait = 0;
+    bool wait = false;
 
-    for (na = 4; na < args.size(); na++) {
+    for (size_t na = 4; na < args.size(); na++) {
+        size_t i;
         for (i = 0; mount_flags[i].name; i++) {
             if (!args[na].compare(mount_flags[i].name)) {
                 flags |= mount_flags[i].flag;
@@ -316,71 +321,54 @@
         }
 
         if (!mount_flags[i].name) {
-            if (!args[na].compare("wait"))
-                wait = 1;
-            /* if our last argument isn't a flag, wolf it up as an option string */
-            else if (na + 1 == args.size())
+            if (!args[na].compare("wait")) {
+                wait = true;
+                // If our last argument isn't a flag, wolf it up as an option string.
+            } else if (na + 1 == args.size()) {
                 options = args[na].c_str();
+            }
         }
     }
 
-    system = args[1].c_str();
-    source = args[2].c_str();
-    target = args[3].c_str();
+    const char* system = args[1].c_str();
+    const char* source = args[2].c_str();
+    const char* target = args[3].c_str();
 
-    if (!strncmp(source, "loop@", 5)) {
-        int mode, loop, fd;
-        struct loop_info info;
+    if (android::base::StartsWith(source, "loop@")) {
+        int mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
+        unique_fd fd(TEMP_FAILURE_RETRY(open(source + 5, mode | O_CLOEXEC)));
+        if (fd < 0) return ErrnoError() << "open(" << source + 5 << ", " << mode << ") failed";
 
-        mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
-        fd = open(source + 5, mode | O_CLOEXEC);
-        if (fd < 0) {
-            return -1;
-        }
+        for (size_t n = 0;; n++) {
+            std::string tmp = android::base::StringPrintf("/dev/block/loop%zu", n);
+            unique_fd loop(TEMP_FAILURE_RETRY(open(tmp.c_str(), mode | O_CLOEXEC)));
+            if (loop < 0) return ErrnoError() << "open(" << tmp << ", " << mode << ") failed";
 
-        for (n = 0; ; n++) {
-            snprintf(tmp, sizeof(tmp), "/dev/block/loop%d", n);
-            loop = open(tmp, mode | O_CLOEXEC);
-            if (loop < 0) {
-                close(fd);
-                return -1;
-            }
-
+            loop_info info;
             /* if it is a blank loop device */
             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
                 /* if it becomes our loop device */
-                if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
-                    close(fd);
-
-                    if (mount(tmp, target, system, flags, options) < 0) {
+                if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
+                    if (mount(tmp.c_str(), target, system, flags, options) < 0) {
                         ioctl(loop, LOOP_CLR_FD, 0);
-                        close(loop);
-                        return -1;
+                        return ErrnoError() << "mount() failed";
                     }
-
-                    close(loop);
-                    goto exit_success;
+                    return Success();
                 }
             }
-
-            close(loop);
         }
 
-        close(fd);
-        LOG(ERROR) << "out of loopback devices";
-        return -1;
+        return Error() << "out of loopback devices";
     } else {
         if (wait)
             wait_for_file(source, kCommandRetryTimeout);
         if (mount(source, target, system, flags, options) < 0) {
-            return -1;
+            return ErrnoError() << "mount() failed";
         }
 
     }
 
-exit_success:
-    return 0;
-
+    return Success();
 }
 
 /* Imports .rc files from the specified paths. Default ones are applied if none is given.
@@ -388,21 +376,15 @@
  * start_index: index of the first path in the args list
  */
 static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
-    Parser& parser = Parser::GetInstance();
+    auto& action_manager = ActionManager::GetInstance();
+    auto& service_list = ServiceList::GetInstance();
+    Parser parser = CreateParser(action_manager, service_list);
     if (end_index <= start_index) {
         // Fallbacks for partitions on which early mount isn't enabled.
-        if (!parser.is_system_etc_init_loaded()) {
-            parser.ParseConfig("/system/etc/init");
-            parser.set_is_system_etc_init_loaded(true);
+        for (const auto& path : late_import_paths) {
+            parser.ParseConfig(path);
         }
-        if (!parser.is_vendor_etc_init_loaded()) {
-            parser.ParseConfig("/vendor/etc/init");
-            parser.set_is_vendor_etc_init_loaded(true);
-        }
-        if (!parser.is_odm_etc_init_loaded()) {
-            parser.ParseConfig("/odm/etc/init");
-            parser.set_is_odm_etc_init_loaded(true);
-        }
+        late_import_paths.clear();
     } else {
         for (size_t i = start_index; i < end_index; ++i) {
             parser.ParseConfig(args[i]);
@@ -418,9 +400,7 @@
  *
  *  Call fs_mgr_mount_all() to mount the given fstab
  */
-static int mount_fstab(const char* fstabfile, int mount_mode) {
-    int ret = -1;
-
+static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
     /*
      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
      * do the call in the child to provide protection to the main init
@@ -438,9 +418,9 @@
         }
 
         if (WIFEXITED(status)) {
-            ret = WEXITSTATUS(status);
+            return WEXITSTATUS(status);
         } else {
-            ret = -1;
+            return Error() << "child aborted";
         }
     } else if (pid == 0) {
         /* child, call fs_mgr_mount_all() */
@@ -457,10 +437,8 @@
         }
         _exit(child_ret);
     } else {
-        /* fork failed, return an error */
-        return -1;
+        return Error() << "fork() failed";
     }
-    return ret;
 }
 
 /* Queue event based on fs_mgr return code.
@@ -472,29 +450,33 @@
  *
  * return code is processed based on input code
  */
-static int queue_fs_event(int code) {
-    int ret = code;
+static Result<Success> queue_fs_event(int code) {
     if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
         ActionManager::GetInstance().QueueEventTrigger("encrypt");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "block");
         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
         property_set("ro.crypto.state", "unsupported");
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
         PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
         const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
-        ret = reboot_into_recovery(options);
+        reboot_into_recovery(options);
+        return Error() << "reboot_into_recovery() failed";
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
-            return -1;
+            return Error() << "e4crypt_install_keyring() failed";
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
@@ -502,29 +484,32 @@
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
-            return -1;
+            return Error() << "e4crypt_install_keyring() failed";
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
 
         // defaultcrypto detects file/block encryption. init flow is same for each.
         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+        return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
         if (e4crypt_install_keyring()) {
-            return -1;
+            return Error() << "e4crypt_install_keyring() failed";
         }
         property_set("ro.crypto.type", "file");
 
         // encrypt detects file/block encryption. init flow is same for each.
         ActionManager::GetInstance().QueueEventTrigger("encrypt");
+        return Success();
     } else if (code > 0) {
-        PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
+        Error() << "fs_mgr_mount_all() returned unexpected error " << code;
     }
     /* else ... < 0: error */
 
-    return ret;
+    return Error() << "Invalid code: " << code;
 }
 
 /* mount_all <fstab> [ <path> ]* [--<options>]*
@@ -532,7 +517,7 @@
  * This function might request a reboot, in which case it will
  * not return.
  */
-static int do_mount_all(const std::vector<std::string>& args) {
+static Result<Success> do_mount_all(const std::vector<std::string>& args) {
     std::size_t na = 0;
     bool import_rc = true;
     bool queue_event = true;
@@ -557,7 +542,10 @@
 
     std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
     android::base::Timer t;
-    int ret =  mount_fstab(fstabfile, mount_mode);
+    auto mount_fstab_return_code = mount_fstab(fstabfile, mount_mode);
+    if (!mount_fstab_return_code) {
+        return Error() << "mount_fstab() failed " << mount_fstab_return_code.error();
+    }
     property_set(prop_name, std::to_string(t.duration().count()));
 
     if (import_rc) {
@@ -568,13 +556,16 @@
     if (queue_event) {
         /* queue_fs_event will queue event based on mount_fstab return code
          * and return processed return code*/
-        ret = queue_fs_event(ret);
+        auto queue_fs_result = queue_fs_event(*mount_fstab_return_code);
+        if (!queue_fs_result) {
+            return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
+        }
     }
 
-    return ret;
+    return Success();
 }
 
-static int do_swapon_all(const std::vector<std::string>& args) {
+static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
     struct fstab *fstab;
     int ret;
 
@@ -582,89 +573,100 @@
     ret = fs_mgr_swapon_all(fstab);
     fs_mgr_free_fstab(fstab);
 
-    return ret;
+    if (ret != 0) return Error() << "fs_mgr_swapon_all() failed";
+    return Success();
 }
 
-static int do_setprop(const std::vector<std::string>& args) {
+static Result<Success> do_setprop(const std::vector<std::string>& args) {
     property_set(args[1], args[2]);
-    return 0;
+    return Success();
 }
 
-static int do_setrlimit(const std::vector<std::string>& args) {
-    struct rlimit limit;
-    int resource;
-    if (android::base::ParseInt(args[1], &resource) &&
-        android::base::ParseUint(args[2], &limit.rlim_cur) &&
-        android::base::ParseUint(args[3], &limit.rlim_max)) {
-        return setrlimit(resource, &limit);
+static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
+    auto rlimit = ParseRlimit(args);
+    if (!rlimit) return rlimit.error();
+
+    if (setrlimit(rlimit->first, &rlimit->second) == -1) {
+        return ErrnoError() << "setrlimit failed";
     }
-    LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
-    return -1;
+    return Success();
 }
 
-static int do_start(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
-    if (!svc) {
-        LOG(ERROR) << "do_start: Service " << args[1] << " not found";
-        return -1;
+static Result<Success> do_start(const std::vector<std::string>& args) {
+    Service* svc = ServiceList::GetInstance().FindService(args[1]);
+    if (!svc) return Error() << "service " << args[1] << " not found";
+    if (auto result = svc->Start(); !result) {
+        return Error() << "Could not start service: " << result.error();
     }
-    if (!svc->Start())
-        return -1;
-    return 0;
+    return Success();
 }
 
-static int do_stop(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
-    if (!svc) {
-        LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
-        return -1;
-    }
+static Result<Success> do_stop(const std::vector<std::string>& args) {
+    Service* svc = ServiceList::GetInstance().FindService(args[1]);
+    if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Stop();
-    return 0;
+    return Success();
 }
 
-static int do_restart(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
-    if (!svc) {
-        LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
-        return -1;
-    }
+static Result<Success> do_restart(const std::vector<std::string>& args) {
+    Service* svc = ServiceList::GetInstance().FindService(args[1]);
+    if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Restart();
-    return 0;
+    return Success();
 }
 
-static int do_trigger(const std::vector<std::string>& args) {
+static Result<Success> do_trigger(const std::vector<std::string>& args) {
     ActionManager::GetInstance().QueueEventTrigger(args[1]);
-    return 0;
+    return Success();
 }
 
-static int do_symlink(const std::vector<std::string>& args) {
-    return symlink(args[1].c_str(), args[2].c_str());
-}
-
-static int do_rm(const std::vector<std::string>& args) {
-    return unlink(args[1].c_str());
-}
-
-static int do_rmdir(const std::vector<std::string>& args) {
-    return rmdir(args[1].c_str());
-}
-
-static int do_sysclktz(const std::vector<std::string>& args) {
-    struct timezone tz = {};
-    if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
-        return 0;
+static Result<Success> do_symlink(const std::vector<std::string>& args) {
+    if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
+        // The symlink builtin is often used to create symlinks for older devices to be backwards
+        // compatible with new paths, therefore we skip reporting this error.
+        if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
+            return Success();
+        }
+        return ErrnoError() << "symlink() failed";
     }
-    return -1;
+    return Success();
 }
 
-static int do_verity_load_state(const std::vector<std::string>& args) {
+static Result<Success> do_rm(const std::vector<std::string>& args) {
+    if (unlink(args[1].c_str()) < 0) {
+        return ErrnoError() << "unlink() failed";
+    }
+    return Success();
+}
+
+static Result<Success> do_rmdir(const std::vector<std::string>& args) {
+    if (rmdir(args[1].c_str()) < 0) {
+        return ErrnoError() << "rmdir() failed";
+    }
+    return Success();
+}
+
+static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
+    struct timezone tz = {};
+    if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
+        return Error() << "Unable to parse mins_west_of_gmt";
+    }
+
+    if (settimeofday(nullptr, &tz) == -1) {
+        return ErrnoError() << "settimeofday() failed";
+    }
+    return Success();
+}
+
+static Result<Success> do_verity_load_state(const std::vector<std::string>& args) {
     int mode = -1;
     bool loaded = fs_mgr_load_verity_state(&mode);
     if (loaded && mode != VERITY_MODE_DEFAULT) {
         ActionManager::GetInstance().QueueEventTrigger("verity-logging");
     }
-    return loaded ? 0 : 1;
+    if (!loaded) return Error() << "Could not load verity state";
+
+    return Success();
 }
 
 static void verity_update_property(fstab_rec *fstab, const char *mount_point,
@@ -672,55 +674,137 @@
     property_set("partition."s + mount_point + ".verified", std::to_string(mode));
 }
 
-static int do_verity_update_state(const std::vector<std::string>& args) {
-    return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
+static Result<Success> do_verity_update_state(const std::vector<std::string>& args) {
+    if (!fs_mgr_update_verity_state(verity_update_property)) {
+        return Error() << "fs_mgr_update_verity_state() failed";
+    }
+    return Success();
 }
 
-static int do_write(const std::vector<std::string>& args) {
-    std::string err;
-    if (!WriteFile(args[1], args[2], &err)) {
-        LOG(ERROR) << err;
-        return -1;
+static Result<Success> do_write(const std::vector<std::string>& args) {
+    if (auto result = WriteFile(args[1], args[2]); !result) {
+        return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
     }
-    return 0;
+
+    return Success();
 }
 
-static int do_copy(const std::vector<std::string>& args) {
-    std::string data;
-    std::string err;
-    if (!ReadFile(args[1], &data, &err)) {
-        LOG(ERROR) << err;
-        return -1;
+static Result<Success> readahead_file(const std::string& filename, bool fully) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)));
+    if (fd == -1) {
+        return ErrnoError() << "Error opening file";
     }
-    if (!WriteFile(args[2], data, &err)) {
-        LOG(ERROR) << err;
-        return -1;
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) {
+        return ErrnoError() << "Error posix_fadvise file";
     }
-    return 0;
+    if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+        return ErrnoError() << "Error readahead file";
+    }
+    if (fully) {
+        char buf[BUFSIZ];
+        ssize_t n;
+        while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+        }
+        if (n != 0) {
+            return ErrnoError() << "Error reading file";
+        }
+    }
+    return Success();
 }
 
-static int do_chown(const std::vector<std::string>& args) {
-    uid_t uid;
-    std::string decode_uid_err;
-    if (!DecodeUid(args[1], &uid, &decode_uid_err)) {
-        LOG(ERROR) << "Unable to find UID for '" << args[1] << "': " << decode_uid_err;
-        return -1;
+static Result<Success> do_readahead(const std::vector<std::string>& args) {
+    struct stat sb;
+
+    if (stat(args[1].c_str(), &sb)) {
+        return ErrnoError() << "Error opening " << args[1];
+    }
+
+    bool readfully = false;
+    if (args.size() == 3 && args[2] == "--fully") {
+        readfully = true;
+    }
+    // We will do readahead in a forked process in order not to block init
+    // since it may block while it reads the
+    // filesystem metadata needed to locate the requested blocks.  This
+    // occurs frequently with ext[234] on large files using indirect blocks
+    // instead of extents, giving the appearance that the call blocks until
+    // the requested data has been read.
+    pid_t pid = fork();
+    if (pid == 0) {
+        if (setpriority(PRIO_PROCESS, 0, static_cast<int>(ANDROID_PRIORITY_LOWEST)) != 0) {
+            PLOG(WARNING) << "setpriority failed";
+        }
+        if (android_set_ioprio(0, IoSchedClass_IDLE, 7)) {
+            PLOG(WARNING) << "ioprio_get failed";
+        }
+        android::base::Timer t;
+        if (S_ISREG(sb.st_mode)) {
+            if (auto result = readahead_file(args[1], readfully); !result) {
+                LOG(WARNING) << "Unable to readahead '" << args[1] << "': " << result.error();
+                _exit(EXIT_FAILURE);
+            }
+        } else if (S_ISDIR(sb.st_mode)) {
+            char* paths[] = {const_cast<char*>(args[1].data()), nullptr};
+            std::unique_ptr<FTS, decltype(&fts_close)> fts(
+                fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr), fts_close);
+            if (!fts) {
+                PLOG(ERROR) << "Error opening directory: " << args[1];
+                _exit(EXIT_FAILURE);
+            }
+            // Traverse the entire hierarchy and do readahead
+            for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr;
+                 ftsent = fts_read(fts.get())) {
+                if (ftsent->fts_info & FTS_F) {
+                    const std::string filename = ftsent->fts_accpath;
+                    if (auto result = readahead_file(filename, readfully); !result) {
+                        LOG(WARNING)
+                            << "Unable to readahead '" << filename << "': " << result.error();
+                    }
+                }
+            }
+        }
+        LOG(INFO) << "Readahead " << args[1] << " took " << t << " asynchronously";
+        _exit(0);
+    } else if (pid < 0) {
+        return ErrnoError() << "Fork failed";
+    }
+    return Success();
+}
+
+static Result<Success> do_copy(const std::vector<std::string>& args) {
+    auto file_contents = ReadFile(args[1]);
+    if (!file_contents) {
+        return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
+    }
+    if (auto result = WriteFile(args[2], *file_contents); !result) {
+        return Error() << "Could not write to output file '" << args[2] << "': " << result.error();
+    }
+
+    return Success();
+}
+
+static Result<Success> do_chown(const std::vector<std::string>& args) {
+    auto uid = DecodeUid(args[1]);
+    if (!uid) {
+        return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
     }
 
     // GID is optional and pushes the index of path out by one if specified.
     const std::string& path = (args.size() == 4) ? args[3] : args[2];
-    gid_t gid = -1;
+    Result<gid_t> gid = -1;
 
     if (args.size() == 4) {
-        if (!DecodeUid(args[2], &gid, &decode_uid_err)) {
-            LOG(ERROR) << "Unable to find GID for '" << args[2] << "': " << decode_uid_err;
-            return -1;
+        gid = DecodeUid(args[2]);
+        if (!gid) {
+            return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
         }
     }
 
-    if (lchown(path.c_str(), uid, gid) == -1) return -errno;
+    if (lchown(path.c_str(), *uid, *gid) == -1) {
+        return ErrnoError() << "lchown() failed";
+    }
 
-    return 0;
+    return Success();
 }
 
 static mode_t get_mode(const char *s) {
@@ -736,15 +820,15 @@
     return mode;
 }
 
-static int do_chmod(const std::vector<std::string>& args) {
+static Result<Success> do_chmod(const std::vector<std::string>& args) {
     mode_t mode = get_mode(args[1].c_str());
     if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
-        return -errno;
+        return ErrnoError() << "fchmodat() failed";
     }
-    return 0;
+    return Success();
 }
 
-static int do_restorecon(const std::vector<std::string>& args) {
+static Result<Success> do_restorecon(const std::vector<std::string>& args) {
     int ret = 0;
 
     struct flag_type {const char* name; int value;};
@@ -761,8 +845,7 @@
     for (size_t i = 1; i < args.size(); ++i) {
         if (android::base::StartsWith(args[i], "--")) {
             if (!in_flags) {
-                LOG(ERROR) << "restorecon - flags must precede paths";
-                return -1;
+                return Error() << "flags must precede paths";
             }
             bool found = false;
             for (size_t j = 0; flags[j].name; ++j) {
@@ -773,26 +856,27 @@
                 }
             }
             if (!found) {
-                LOG(ERROR) << "restorecon - bad flag " << args[i];
-                return -1;
+                return Error() << "bad flag " << args[i];
             }
         } else {
             in_flags = false;
             if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
-                ret = -errno;
+                ret = errno;
             }
         }
     }
-    return ret;
+
+    if (ret) return ErrnoError() << "selinux_android_restorecon() failed";
+    return Success();
 }
 
-static int do_restorecon_recursive(const std::vector<std::string>& args) {
+static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) {
     std::vector<std::string> non_const_args(args);
     non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
     return do_restorecon(non_const_args);
 }
 
-static int do_loglevel(const std::vector<std::string>& args) {
+static Result<Success> do_loglevel(const std::vector<std::string>& args) {
     // TODO: support names instead/as well?
     int log_level = -1;
     android::base::ParseInt(args[1], &log_level);
@@ -807,88 +891,73 @@
         case 1:
         case 0: severity = android::base::FATAL; break;
         default:
-            LOG(ERROR) << "loglevel: invalid log level " << log_level;
-            return -EINVAL;
+            return Error() << "invalid log level " << log_level;
     }
     android::base::SetMinimumLogSeverity(severity);
-    return 0;
+    return Success();
 }
 
-static int do_load_persist_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_persist_props(const std::vector<std::string>& args) {
     load_persist_props();
-    return 0;
+    return Success();
 }
 
-static int do_load_system_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_system_props(const std::vector<std::string>& args) {
     load_system_props();
-    return 0;
+    return Success();
 }
 
-static int do_wait(const std::vector<std::string>& args) {
-    if (args.size() == 2) {
-        return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
-    } else if (args.size() == 3) {
-        int timeout;
-        if (android::base::ParseInt(args[2], &timeout)) {
-            return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
+static Result<Success> do_wait(const std::vector<std::string>& args) {
+    auto timeout = kCommandRetryTimeout;
+    if (args.size() == 3) {
+        int timeout_int;
+        if (!android::base::ParseInt(args[2], &timeout_int)) {
+            return Error() << "failed to parse timeout";
         }
+        timeout = std::chrono::seconds(timeout_int);
     }
-    return -1;
+
+    if (wait_for_file(args[1].c_str(), timeout) != 0) {
+        return Error() << "wait_for_file() failed";
+    }
+
+    return Success();
 }
 
-static int do_wait_for_prop(const std::vector<std::string>& args) {
+static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) {
     const char* name = args[1].c_str();
     const char* value = args[2].c_str();
     size_t value_len = strlen(value);
 
     if (!is_legal_property_name(name)) {
-        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
-                   << "\") failed: bad name";
-        return -1;
+        return Error() << "is_legal_property_name(" << name << ") failed";
     }
     if (value_len >= PROP_VALUE_MAX) {
-        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
-                   << "\") failed: value too long";
-        return -1;
+        return Error() << "value too long";
     }
     if (!start_waiting_for_property(name, value)) {
-        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
-                   << "\") failed: init already in waiting";
-        return -1;
+        return Error() << "already waiting for a property";
     }
-    return 0;
-}
-
-/*
- * Callback to make a directory from the ext4 code
- */
-static int do_installkeys_ensure_dir_exists(const char* dir) {
-    if (make_dir(dir, 0700, sehandle) && errno != EEXIST) {
-        return -1;
-    }
-
-    return 0;
+    return Success();
 }
 
 static bool is_file_crypto() {
     return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
-static int do_installkey(const std::vector<std::string>& args) {
-    if (!is_file_crypto()) {
-        return 0;
-    }
+static Result<Success> do_installkey(const std::vector<std::string>& args) {
+    if (!is_file_crypto()) return Success();
+
     auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
-    if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
-        PLOG(ERROR) << "Failed to create " << unencrypted_dir;
-        return -1;
+    if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
+        return ErrnoError() << "Failed to create " << unencrypted_dir;
     }
     std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
                                           "enablefilecrypto"};
     return do_exec(exec_args);
 }
 
-static int do_init_user0(const std::vector<std::string>& args) {
+static Result<Success> do_init_user0(const std::vector<std::string>& args) {
     std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
                                           "init_user0"};
     return do_exec(exec_args);
@@ -923,6 +992,7 @@
         {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
         {"umount",                  {1,     1,    do_umount}},
+        {"readahead",               {1,     2,    do_readahead}},
         {"restart",                 {1,     1,    do_restart}},
         {"restorecon",              {1,     kMax, do_restorecon}},
         {"restorecon_recursive",    {1,     kMax, do_restorecon_recursive}},
diff --git a/init/builtins.h b/init/builtins.h
index b110f61..f66ae19 100644
--- a/init/builtins.h
+++ b/init/builtins.h
@@ -23,11 +23,12 @@
 #include <vector>
 
 #include "keyword_map.h"
+#include "result.h"
 
 namespace android {
 namespace init {
 
-using BuiltinFunction = std::function<int(const std::vector<std::string>&)>;
+using BuiltinFunction = std::function<Result<Success>(const std::vector<std::string>&)>;
 class BuiltinFunctionMap : public KeywordMap<BuiltinFunction> {
   public:
     BuiltinFunctionMap() {}
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 0cb639a..6265687 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -28,7 +28,6 @@
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
-#include "init.h"
 #include "util.h"
 
 namespace android {
@@ -62,7 +61,7 @@
                 [] (char& c) { c = isalnum(c) ? c : '_'; });
 
   std::string val = std::to_string(fd);
-  add_environment(publishedName.c_str(), val.c_str());
+  setenv(publishedName.c_str(), val.c_str(), 1);
 
   // make sure we don't close on exec
   fcntl(fd, F_SETFD, 0);
@@ -86,8 +85,7 @@
     int flags =
         ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
     bool passcred = types.size() > 1 && types[1] == "passcred";
-    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str(),
-                        sehandle);
+    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str());
 }
 
 const std::string SocketInfo::key() const {
diff --git a/init/devices.cpp b/init/devices.cpp
index 13cf991..af6b50a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -30,6 +30,7 @@
 #include <selinux/android.h>
 #include <selinux/selinux.h>
 
+#include "selinux.h"
 #include "ueventd.h"
 #include "util.h"
 
@@ -224,18 +225,13 @@
     auto[mode, uid, gid] = GetDevicePermissions(path, links);
     mode |= (block ? S_IFBLK : S_IFCHR);
 
-    char* secontext = nullptr;
-    if (sehandle_) {
-        std::vector<const char*> c_links;
-        for (const auto& link : links) {
-            c_links.emplace_back(link.c_str());
-        }
-        c_links.emplace_back(nullptr);
-        if (selabel_lookup_best_match(sehandle_, &secontext, path.c_str(), &c_links[0], mode)) {
-            PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
-            return;
-        }
-        setfscreatecon(secontext);
+    std::string secontext;
+    if (!SelabelLookupFileContextBestMatch(path, links, mode, &secontext)) {
+        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
+        return;
+    }
+    if (!secontext.empty()) {
+        setfscreatecon(secontext.c_str());
     }
 
     dev_t dev = makedev(major, minor);
@@ -250,7 +246,7 @@
     }
     /* If the node already exists update its SELinux label to handle cases when
      * it was created with the wrong context during coldboot procedure. */
-    if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && secontext) {
+    if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && !secontext.empty()) {
         char* fcon = nullptr;
         int rc = lgetfilecon(path.c_str(), &fcon);
         if (rc < 0) {
@@ -258,10 +254,10 @@
             goto out;
         }
 
-        bool different = strcmp(fcon, secontext) != 0;
+        bool different = fcon != secontext;
         freecon(fcon);
 
-        if (different && lsetfilecon(path.c_str(), secontext)) {
+        if (different && lsetfilecon(path.c_str(), secontext.c_str())) {
             PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
                         << "' device";
         }
@@ -273,8 +269,7 @@
         PLOG(FATAL) << "setegid(AID_ROOT) failed";
     }
 
-    if (secontext) {
-        freecon(secontext);
+    if (!secontext.empty()) {
         setfscreatecon(nullptr);
     }
 }
@@ -351,7 +346,7 @@
     if (action == "add") {
         MakeDevice(devpath, block, major, minor, links);
         for (const auto& link : links) {
-            if (mkdir_recursive(Dirname(link), 0755, sehandle_)) {
+            if (!mkdir_recursive(Dirname(link), 0755)) {
                 PLOG(ERROR) << "Failed to create directory " << Dirname(link);
             }
 
@@ -391,31 +386,29 @@
         if (StartsWith(uevent.path, "/devices")) {
             links = GetBlockDeviceSymlinks(uevent);
         }
-    } else if (StartsWith(uevent.subsystem, "usb")) {
-        if (uevent.subsystem == "usb") {
-            if (!uevent.device_name.empty()) {
-                devpath = "/dev/" + uevent.device_name;
-            } else {
-                // This imitates the file system that would be created
-                // if we were using devfs instead.
-                // Minors are broken up into groups of 128, starting at "001"
-                int bus_id = uevent.minor / 128 + 1;
-                int device_id = uevent.minor % 128 + 1;
-                devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
-            }
-        } else {
-            // ignore other USB events
-            return;
-        }
     } else if (const auto subsystem =
                    std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
                subsystem != subsystems_.cend()) {
         devpath = subsystem->ParseDevPath(uevent);
+    } else if (uevent.subsystem == "usb") {
+        if (!uevent.device_name.empty()) {
+            devpath = "/dev/" + uevent.device_name;
+        } else {
+            // This imitates the file system that would be created
+            // if we were using devfs instead.
+            // Minors are broken up into groups of 128, starting at "001"
+            int bus_id = uevent.minor / 128 + 1;
+            int device_id = uevent.minor % 128 + 1;
+            devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
+        }
+    } else if (StartsWith(uevent.subsystem, "usb")) {
+        // ignore other USB events
+        return;
     } else {
         devpath = "/dev/" + Basename(uevent.path);
     }
 
-    mkdir_recursive(Dirname(devpath), 0755, sehandle_);
+    mkdir_recursive(Dirname(devpath), 0755);
 
     HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
 }
@@ -426,7 +419,6 @@
     : dev_permissions_(std::move(dev_permissions)),
       sysfs_permissions_(std::move(sysfs_permissions)),
       subsystems_(std::move(subsystems)),
-      sehandle_(selinux_android_file_context_handle()),
       skip_restorecon_(skip_restorecon),
       sysfs_mount_point_("/sys") {}
 
diff --git a/init/devices.h b/init/devices.h
index c64f5fb..1f8f1e8 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -72,6 +72,7 @@
     friend class SubsystemParser;
 
     Subsystem() {}
+    Subsystem(std::string name) : name_(std::move(name)) {}
 
     // Returns the full path for a uevent of a device that is a member of this subsystem,
     // according to the rules parsed from ueventd.rc
@@ -124,7 +125,6 @@
     std::vector<Permissions> dev_permissions_;
     std::vector<SysfsPermissions> sysfs_permissions_;
     std::vector<Subsystem> subsystems_;
-    selabel_handle* sehandle_;
     bool skip_restorecon_;
     std::string sysfs_mount_point_;
 };
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index ac4ab9b..eba00cb 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -35,13 +35,13 @@
         device_handler_.sysfs_mount_point_ = fake_sys_root.path;
 
         std::string platform_device_dir = fake_sys_root.path + platform_device;
-        mkdir_recursive(platform_device_dir, 0777, nullptr);
+        mkdir_recursive(platform_device_dir, 0777);
 
         std::string platform_bus = fake_sys_root.path + "/bus/platform"s;
-        mkdir_recursive(platform_bus, 0777, nullptr);
+        mkdir_recursive(platform_bus, 0777);
         symlink(platform_bus.c_str(), (platform_device_dir + "/subsystem").c_str());
 
-        mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
+        mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777);
 
         std::vector<std::string> result;
         result = device_handler_.GetBlockDeviceSymlinks(uevent);
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index b9fa2ce..e335fd1 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -23,24 +23,22 @@
 namespace android {
 namespace init {
 
-bool ImportParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                                int line, std::string* err) {
+Result<Success> ImportParser::ParseSection(std::vector<std::string>&& args,
+                                           const std::string& filename, int line) {
     if (args.size() != 2) {
-        *err = "single argument needed for import\n";
-        return false;
+        return Error() << "single argument needed for import\n";
     }
 
     std::string conf_file;
     bool ret = expand_props(args[1], &conf_file);
     if (!ret) {
-        *err = "error while expanding import";
-        return false;
+        return Error() << "error while expanding import";
     }
 
     LOG(INFO) << "Added '" << conf_file << "' to import list";
     if (filename_.empty()) filename_ = filename;
     imports_.emplace_back(std::move(conf_file), line);
-    return true;
+    return Success();
 }
 
 void ImportParser::EndFile() {
diff --git a/init/import_parser.h b/init/import_parser.h
index b774c57..5a2f894 100644
--- a/init/import_parser.h
+++ b/init/import_parser.h
@@ -17,19 +17,19 @@
 #ifndef _INIT_IMPORT_PARSER_H
 #define _INIT_IMPORT_PARSER_H
 
-#include "init_parser.h"
-
 #include <string>
 #include <vector>
 
+#include "parser.h"
+
 namespace android {
 namespace init {
 
 class ImportParser : public SectionParser {
   public:
     ImportParser(Parser* parser) : parser_(parser) {}
-    bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
-                      std::string* err) override;
+    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+                                 int line) override;
     void EndFile() override;
 
   private:
diff --git a/init/init.cpp b/init/init.cpp
index 9671560..c3e08fb 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -16,26 +16,18 @@
 
 #include "init.h"
 
-#include <ctype.h>
 #include <dirent.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
 #include <paths.h>
+#include <seccomp_policy.h>
 #include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/epoll.h>
 #include <sys/mount.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
+#include <sys/signalfd.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
-#include <sys/un.h>
-#include <sys/wait.h>
 #include <unistd.h>
 
 #include <android-base/chrono_utils.h>
@@ -43,28 +35,24 @@
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
-#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
 #include <keyutils.h>
 #include <libavb/libavb.h>
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
-#include <selinux/selinux.h>
 
-#include <fstream>
 #include <memory>
-#include <vector>
+#include <optional>
 
-#include "action.h"
-#include "bootchart.h"
 #include "import_parser.h"
 #include "init_first_stage.h"
-#include "init_parser.h"
 #include "keychords.h"
 #include "log.h"
 #include "property_service.h"
 #include "reboot.h"
-#include "service.h"
-#include "signal_handler.h"
+#include "security.h"
+#include "selinux.h"
+#include "sigchld_handler.h"
 #include "ueventd.h"
 #include "util.h"
 #include "watchdogd.h"
@@ -78,30 +66,57 @@
 namespace android {
 namespace init {
 
-struct selabel_handle *sehandle;
-struct selabel_handle *sehandle_prop;
-
 static int property_triggers_enabled = 0;
 
 static char qemu[32];
 
 std::string default_console = "/dev/console";
-static time_t process_needs_restart_at;
-
-const char *ENV[32];
 
 static int epoll_fd = -1;
+static int sigterm_signal_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
 static std::string wait_prop_value;
 static bool shutting_down;
 
+std::vector<std::string> late_import_paths;
+
 void DumpState() {
-    ServiceManager::GetInstance().DumpState();
+    ServiceList::GetInstance().DumpState();
     ActionManager::GetInstance().DumpState();
 }
 
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
+    Parser parser;
+
+    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list));
+    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager));
+    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
+
+    return parser;
+}
+
+static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
+    Parser parser = CreateParser(action_manager, service_list);
+
+    std::string bootscript = GetProperty("ro.boot.init_rc", "");
+    if (bootscript.empty()) {
+        parser.ParseConfig("/init.rc");
+        if (!parser.ParseConfig("/system/etc/init")) {
+            late_import_paths.emplace_back("/system/etc/init");
+        }
+        if (!parser.ParseConfig("/vendor/etc/init")) {
+            late_import_paths.emplace_back("/vendor/etc/init");
+        }
+        if (!parser.ParseConfig("/odm/etc/init")) {
+            late_import_paths.emplace_back("/odm/etc/init");
+        }
+    } else {
+        parser.ParseConfig(bootscript);
+    }
+}
+
 void register_epoll_handler(int fd, void (*fn)()) {
     epoll_event ev;
     ev.events = EPOLLIN;
@@ -111,38 +126,6 @@
     }
 }
 
-/* add_environment - add "key=value" to the current environment */
-int add_environment(const char *key, const char *val)
-{
-    size_t n;
-    size_t key_len = strlen(key);
-
-    /* The last environment entry is reserved to terminate the list */
-    for (n = 0; n < (arraysize(ENV) - 1); n++) {
-
-        /* Delete any existing entry for this key */
-        if (ENV[n] != NULL) {
-            size_t entry_key_len = strcspn(ENV[n], "=");
-            if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
-                free((char*)ENV[n]);
-                ENV[n] = NULL;
-            }
-        }
-
-        /* Add entry if a free slot is available */
-        if (ENV[n] == NULL) {
-            char* entry;
-            asprintf(&entry, "%s=%s", key, val);
-            ENV[n] = entry;
-            return 0;
-        }
-    }
-
-    LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
-
-    return -1;
-}
-
 bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
@@ -189,23 +172,36 @@
     }
 }
 
-static void restart_processes()
-{
-    process_needs_restart_at = 0;
-    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
-        s->RestartIfNeeded(&process_needs_restart_at);
-    });
+static std::optional<boot_clock::time_point> RestartProcesses() {
+    std::optional<boot_clock::time_point> next_process_restart_time;
+    for (const auto& s : ServiceList::GetInstance()) {
+        if (!(s->flags() & SVC_RESTARTING)) continue;
+
+        auto restart_time = s->time_started() + 5s;
+        if (boot_clock::now() > restart_time) {
+            if (auto result = s->Start(); !result) {
+                LOG(ERROR) << "Could not restart process '" << s->name() << "': " << result.error();
+            }
+        } else {
+            if (!next_process_restart_time || restart_time < *next_process_restart_time) {
+                next_process_restart_time = restart_time;
+            }
+        }
+    }
+    return next_process_restart_time;
 }
 
 void handle_control_message(const std::string& msg, const std::string& name) {
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
+    Service* svc = ServiceList::GetInstance().FindService(name);
     if (svc == nullptr) {
         LOG(ERROR) << "no such service '" << name << "'";
         return;
     }
 
     if (msg == "start") {
-        svc->Start();
+        if (auto result = svc->Start(); !result) {
+            LOG(ERROR) << "Could not ctl.start service '" << name << "': " << result.error();
+        }
     } else if (msg == "stop") {
         svc->Stop();
     } else if (msg == "restart") {
@@ -215,7 +211,7 @@
     }
 }
 
-static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
+static Result<Success> wait_for_coldboot_done_action(const std::vector<std::string>& args) {
     Timer t;
 
     LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
@@ -229,236 +225,24 @@
     // because any build that slow isn't likely to boot at all, and we'd
     // rather any test lab devices fail back to the bootloader.
     if (wait_for_file(COLDBOOT_DONE, 60s) < 0) {
-        LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
-        panic();
+        LOG(FATAL) << "Timed out waiting for " COLDBOOT_DONE;
     }
 
     property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration().count()));
-    return 0;
+    return Success();
 }
 
-/*
- * Writes 512 bytes of output from Hardware RNG (/dev/hw_random, backed
- * by Linux kernel's hw_random framework) into Linux RNG's via /dev/urandom.
- * Does nothing if Hardware RNG is not present.
- *
- * Since we don't yet trust the quality of Hardware RNG, these bytes are not
- * mixed into the primary pool of Linux RNG and the entropy estimate is left
- * unmodified.
- *
- * If the HW RNG device /dev/hw_random is present, we require that at least
- * 512 bytes read from it are written into Linux RNG. QA is expected to catch
- * devices/configurations where these I/O operations are blocking for a long
- * time. We do not reboot or halt on failures, as this is a best-effort
- * attempt.
- */
-static int mix_hwrng_into_linux_rng_action(const std::vector<std::string>& args)
-{
-    int result = -1;
-    int hwrandom_fd = -1;
-    int urandom_fd = -1;
-    char buf[512];
-    ssize_t chunk_size;
-    size_t total_bytes_written = 0;
-
-    hwrandom_fd = TEMP_FAILURE_RETRY(
-            open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
-    if (hwrandom_fd == -1) {
-        if (errno == ENOENT) {
-            LOG(ERROR) << "/dev/hw_random not found";
-            // It's not an error to not have a Hardware RNG.
-            result = 0;
-        } else {
-            PLOG(ERROR) << "Failed to open /dev/hw_random";
-        }
-        goto ret;
-    }
-
-    urandom_fd = TEMP_FAILURE_RETRY(
-            open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
-    if (urandom_fd == -1) {
-        PLOG(ERROR) << "Failed to open /dev/urandom";
-        goto ret;
-    }
-
-    while (total_bytes_written < sizeof(buf)) {
-        chunk_size = TEMP_FAILURE_RETRY(
-                read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
-        if (chunk_size == -1) {
-            PLOG(ERROR) << "Failed to read from /dev/hw_random";
-            goto ret;
-        } else if (chunk_size == 0) {
-            LOG(ERROR) << "Failed to read from /dev/hw_random: EOF";
-            goto ret;
-        }
-
-        chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
-        if (chunk_size == -1) {
-            PLOG(ERROR) << "Failed to write to /dev/urandom";
-            goto ret;
-        }
-        total_bytes_written += chunk_size;
-    }
-
-    LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
-    result = 0;
-
-ret:
-    if (hwrandom_fd != -1) {
-        close(hwrandom_fd);
-    }
-    if (urandom_fd != -1) {
-        close(urandom_fd);
-    }
-    return result;
-}
-
-static void security_failure() {
-    LOG(ERROR) << "Security failure...";
-    panic();
-}
-
-static bool set_highest_available_option_value(std::string path, int min, int max)
-{
-    std::ifstream inf(path, std::fstream::in);
-    if (!inf) {
-        LOG(ERROR) << "Cannot open for reading: " << path;
-        return false;
-    }
-
-    int current = max;
-    while (current >= min) {
-        // try to write out new value
-        std::string str_val = std::to_string(current);
-        std::ofstream of(path, std::fstream::out);
-        if (!of) {
-            LOG(ERROR) << "Cannot open for writing: " << path;
-            return false;
-        }
-        of << str_val << std::endl;
-        of.close();
-
-        // check to make sure it was recorded
-        inf.seekg(0);
-        std::string str_rec;
-        inf >> str_rec;
-        if (str_val.compare(str_rec) == 0) {
-            break;
-        }
-        current--;
-    }
-    inf.close();
-
-    if (current < min) {
-        LOG(ERROR) << "Unable to set minimum option value " << min << " in " << path;
-        return false;
-    }
-    return true;
-}
-
-#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
-#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
-
-/* __attribute__((unused)) due to lack of mips support: see mips block
- * in set_mmap_rnd_bits_action */
-static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
-    std::string path;
-    if (compat) {
-        path = MMAP_RND_COMPAT_PATH;
-    } else {
-        path = MMAP_RND_PATH;
-    }
-
-    return set_highest_available_option_value(path, min, start);
-}
-
-/*
- * Set /proc/sys/vm/mmap_rnd_bits and potentially
- * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
- * Returns -1 if unable to set these to an acceptable value.
- *
- * To support this sysctl, the following upstream commits are needed:
- *
- * d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
- * e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
- * 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
- * 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
- * ec9ee4acd97c drivers: char: random: add get_random_long()
- * 5ef11c35ce86 mm: ASLR: use get_random_long()
- */
-static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
-{
-    int ret = -1;
-
-    /* values are arch-dependent */
-#if defined(USER_MODE_LINUX)
-    /* uml does not support mmap_rnd_bits */
-    ret = 0;
-#elif defined(__aarch64__)
-    /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
-    if (set_mmap_rnd_bits_min(33, 24, false)
-            && set_mmap_rnd_bits_min(16, 16, true)) {
-        ret = 0;
-    }
-#elif defined(__x86_64__)
-    /* x86_64 supports 28 - 32 bits */
-    if (set_mmap_rnd_bits_min(32, 32, false)
-            && set_mmap_rnd_bits_min(16, 16, true)) {
-        ret = 0;
-    }
-#elif defined(__arm__) || defined(__i386__)
-    /* check to see if we're running on 64-bit kernel */
-    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
-    /* supported 32-bit architecture must have 16 bits set */
-    if (set_mmap_rnd_bits_min(16, 16, h64)) {
-        ret = 0;
-    }
-#elif defined(__mips__) || defined(__mips64__)
-    // TODO: add mips support b/27788820
-    ret = 0;
-#else
-    LOG(ERROR) << "Unknown architecture";
-#endif
-
-    if (ret == -1) {
-        LOG(ERROR) << "Unable to set adequate mmap entropy value!";
-        security_failure();
-    }
-    return ret;
-}
-
-#define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
-#define KPTR_RESTRICT_MINVALUE 2
-#define KPTR_RESTRICT_MAXVALUE 4
-
-/* Set kptr_restrict to the highest available level.
- *
- * Aborts if unable to set this to an acceptable value.
- */
-static int set_kptr_restrict_action(const std::vector<std::string>& args)
-{
-    std::string path = KPTR_RESTRICT_PATH;
-
-    if (!set_highest_available_option_value(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
-        LOG(ERROR) << "Unable to set adequate kptr_restrict value!";
-        security_failure();
-    }
-    return 0;
-}
-
-static int keychord_init_action(const std::vector<std::string>& args)
-{
+static Result<Success> keychord_init_action(const std::vector<std::string>& args) {
     keychord_init();
-    return 0;
+    return Success();
 }
 
-static int console_init_action(const std::vector<std::string>& args)
-{
+static Result<Success> console_init_action(const std::vector<std::string>& args) {
     std::string console = GetProperty("ro.boot.console", "");
     if (!console.empty()) {
         default_console = "/dev/" + console;
     }
-    return 0;
+    return Success();
 }
 
 static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
@@ -540,396 +324,24 @@
     if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
 }
 
-static int property_enable_triggers_action(const std::vector<std::string>& args)
-{
+static Result<Success> property_enable_triggers_action(const std::vector<std::string>& args) {
     /* Enable property triggers. */
     property_triggers_enabled = 1;
-    return 0;
+    return Success();
 }
 
-static int queue_property_triggers_action(const std::vector<std::string>& args)
-{
+static Result<Success> queue_property_triggers_action(const std::vector<std::string>& args) {
     ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
     ActionManager::GetInstance().QueueAllPropertyActions();
-    return 0;
+    return Success();
 }
 
-static void selinux_init_all_handles(void)
-{
-    sehandle = selinux_android_file_context_handle();
-    selinux_android_set_sehandle(sehandle);
-    sehandle_prop = selinux_android_prop_context_handle();
-}
-
-enum selinux_enforcing_status { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
-
-static selinux_enforcing_status selinux_status_from_cmdline() {
-    selinux_enforcing_status status = SELINUX_ENFORCING;
-
-    import_kernel_cmdline(false, [&](const std::string& key, const std::string& value, bool in_qemu) {
-        if (key == "androidboot.selinux" && value == "permissive") {
-            status = SELINUX_PERMISSIVE;
+static void global_seccomp() {
+    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+        if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+            LOG(FATAL) << "Failed to globally enable seccomp!";
         }
     });
-
-    return status;
-}
-
-static bool selinux_is_enforcing(void)
-{
-    if (ALLOW_PERMISSIVE_SELINUX) {
-        return selinux_status_from_cmdline() == SELINUX_ENFORCING;
-    }
-    return true;
-}
-
-static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
-
-    property_audit_data *d = reinterpret_cast<property_audit_data*>(data);
-
-    if (!d || !d->name || !d->cr) {
-        LOG(ERROR) << "audit_callback invoked with null data arguments!";
-        return 0;
-    }
-
-    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name,
-            d->cr->pid, d->cr->uid, d->cr->gid);
-    return 0;
-}
-
-/*
- * Forks, executes the provided program in the child, and waits for the completion in the parent.
- * Child's stderr is captured and logged using LOG(ERROR).
- *
- * Returns true if the child exited with status code 0, returns false otherwise.
- */
-static bool fork_execve_and_wait_for_completion(const char* filename, char* const argv[],
-                                                char* const envp[]) {
-    // Create a pipe used for redirecting child process's output.
-    // * pipe_fds[0] is the FD the parent will use for reading.
-    // * pipe_fds[1] is the FD the child will use for writing.
-    int pipe_fds[2];
-    if (pipe(pipe_fds) == -1) {
-        PLOG(ERROR) << "Failed to create pipe";
-        return false;
-    }
-
-    pid_t child_pid = fork();
-    if (child_pid == -1) {
-        PLOG(ERROR) << "Failed to fork for " << filename;
-        return false;
-    }
-
-    if (child_pid == 0) {
-        // fork succeeded -- this is executing in the child process
-
-        // Close the pipe FD not used by this process
-        TEMP_FAILURE_RETRY(close(pipe_fds[0]));
-
-        // Redirect stderr to the pipe FD provided by the parent
-        if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
-            PLOG(ERROR) << "Failed to redirect stderr of " << filename;
-            _exit(127);
-            return false;
-        }
-        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
-
-        if (execve(filename, argv, envp) == -1) {
-            PLOG(ERROR) << "Failed to execve " << filename;
-            return false;
-        }
-        // Unreachable because execve will have succeeded and replaced this code
-        // with child process's code.
-        _exit(127);
-        return false;
-    } else {
-        // fork succeeded -- this is executing in the original/parent process
-
-        // Close the pipe FD not used by this process
-        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
-
-        // Log the redirected output of the child process.
-        // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
-        // As a result, we're buffering all output and logging it in one go at the end of the
-        // invocation, instead of logging it as it comes in.
-        const int child_out_fd = pipe_fds[0];
-        std::string child_output;
-        if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
-            PLOG(ERROR) << "Failed to capture full output of " << filename;
-        }
-        TEMP_FAILURE_RETRY(close(child_out_fd));
-        if (!child_output.empty()) {
-            // Log captured output, line by line, because LOG expects to be invoked for each line
-            std::istringstream in(child_output);
-            std::string line;
-            while (std::getline(in, line)) {
-                LOG(ERROR) << filename << ": " << line;
-            }
-        }
-
-        // Wait for child to terminate
-        int status;
-        if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
-            PLOG(ERROR) << "Failed to wait for " << filename;
-            return false;
-        }
-
-        if (WIFEXITED(status)) {
-            int status_code = WEXITSTATUS(status);
-            if (status_code == 0) {
-                return true;
-            } else {
-                LOG(ERROR) << filename << " exited with status " << status_code;
-            }
-        } else if (WIFSIGNALED(status)) {
-            LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
-        } else if (WIFSTOPPED(status)) {
-            LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
-        } else {
-            LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
-        }
-
-        return false;
-    }
-}
-
-static bool read_first_line(const char* file, std::string* line) {
-    line->clear();
-
-    std::string contents;
-    if (!android::base::ReadFileToString(file, &contents, true /* follow symlinks */)) {
-        return false;
-    }
-    std::istringstream in(contents);
-    std::getline(in, *line);
-    return true;
-}
-
-static bool selinux_find_precompiled_split_policy(std::string* file) {
-    file->clear();
-
-    static constexpr const char precompiled_sepolicy[] = "/vendor/etc/selinux/precompiled_sepolicy";
-    if (access(precompiled_sepolicy, R_OK) == -1) {
-        return false;
-    }
-    std::string actual_plat_id;
-    if (!read_first_line("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256",
-                         &actual_plat_id)) {
-        PLOG(INFO) << "Failed to read "
-                      "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
-        return false;
-    }
-    std::string precompiled_plat_id;
-    if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat_and_mapping.sha256",
-                         &precompiled_plat_id)) {
-        PLOG(INFO) << "Failed to read "
-                      "/vendor/etc/selinux/"
-                      "precompiled_sepolicy.plat_and_mapping.sha256";
-        return false;
-    }
-    if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
-        return false;
-    }
-
-    *file = precompiled_sepolicy;
-    return true;
-}
-
-static bool selinux_get_vendor_mapping_version(std::string* plat_vers) {
-    if (!read_first_line("/vendor/etc/selinux/plat_sepolicy_vers.txt", plat_vers)) {
-        PLOG(ERROR) << "Failed to read /vendor/etc/selinux/plat_sepolicy_vers.txt";
-        return false;
-    }
-    if (plat_vers->empty()) {
-        LOG(ERROR) << "No version present in plat_sepolicy_vers.txt";
-        return false;
-    }
-    return true;
-}
-
-static constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
-
-static bool selinux_is_split_policy_device() { return access(plat_policy_cil_file, R_OK) != -1; }
-
-/*
- * Loads SELinux policy split across platform/system and non-platform/vendor files.
- *
- * Returns true upon success, false otherwise (failure cause is logged).
- */
-static bool selinux_load_split_policy() {
-    // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
-    // * platform -- policy needed due to logic contained in the system image,
-    // * non-platform -- policy needed due to logic contained in the vendor image,
-    // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
-    //   with newer versions of platform policy.
-    //
-    // secilc is invoked to compile the above three policy files into a single monolithic policy
-    // file. This file is then loaded into the kernel.
-
-    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
-    // must match the platform policy on the system image.
-    std::string precompiled_sepolicy_file;
-    if (selinux_find_precompiled_split_policy(&precompiled_sepolicy_file)) {
-        android::base::unique_fd fd(
-            open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-        if (fd != -1) {
-            if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
-                LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
-                return false;
-            }
-            return true;
-        }
-    }
-    // No suitable precompiled policy could be loaded
-
-    LOG(INFO) << "Compiling SELinux policy";
-
-    // Determine the highest policy language version supported by the kernel
-    set_selinuxmnt("/sys/fs/selinux");
-    int max_policy_version = security_policyvers();
-    if (max_policy_version == -1) {
-        PLOG(ERROR) << "Failed to determine highest policy version supported by kernel";
-        return false;
-    }
-
-    // We store the output of the compilation on /dev because this is the most convenient tmpfs
-    // storage mount available this early in the boot sequence.
-    char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
-    android::base::unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
-    if (compiled_sepolicy_fd < 0) {
-        PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
-        return false;
-    }
-
-    // Determine which mapping file to include
-    std::string vend_plat_vers;
-    if (!selinux_get_vendor_mapping_version(&vend_plat_vers)) {
-        return false;
-    }
-    std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
-    const std::string version_as_string = std::to_string(max_policy_version);
-
-    // clang-format off
-    const char* compile_args[] = {
-        "/system/bin/secilc",
-        plat_policy_cil_file,
-        "-M", "true", "-G", "-N",
-        // Target the highest policy language version supported by the kernel
-        "-c", version_as_string.c_str(),
-        mapping_file.c_str(),
-        "/vendor/etc/selinux/nonplat_sepolicy.cil",
-        "-o", compiled_sepolicy,
-        // We don't care about file_contexts output by the compiler
-        "-f", "/sys/fs/selinux/null",  // /dev/null is not yet available
-        nullptr};
-    // clang-format on
-
-    if (!fork_execve_and_wait_for_completion(compile_args[0], (char**)compile_args, (char**)ENV)) {
-        unlink(compiled_sepolicy);
-        return false;
-    }
-    unlink(compiled_sepolicy);
-
-    LOG(INFO) << "Loading compiled SELinux policy";
-    if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) {
-        LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy;
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Loads SELinux policy from a monolithic file.
- *
- * Returns true upon success, false otherwise (failure cause is logged).
- */
-static bool selinux_load_monolithic_policy() {
-    LOG(VERBOSE) << "Loading SELinux policy from monolithic file";
-    if (selinux_android_load_policy() < 0) {
-        PLOG(ERROR) << "Failed to load monolithic SELinux policy";
-        return false;
-    }
-    return true;
-}
-
-/*
- * Loads SELinux policy into the kernel.
- *
- * Returns true upon success, false otherwise (failure cause is logged).
- */
-static bool selinux_load_policy() {
-    return selinux_is_split_policy_device() ? selinux_load_split_policy()
-                                            : selinux_load_monolithic_policy();
-}
-
-static void selinux_initialize(bool in_kernel_domain) {
-    Timer t;
-
-    selinux_callback cb;
-    cb.func_log = selinux_klog_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
-    cb.func_audit = audit_callback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
-    if (in_kernel_domain) {
-        LOG(INFO) << "Loading SELinux policy";
-        if (!selinux_load_policy()) {
-            panic();
-        }
-
-        bool kernel_enforcing = (security_getenforce() == 1);
-        bool is_enforcing = selinux_is_enforcing();
-        if (kernel_enforcing != is_enforcing) {
-            if (security_setenforce(is_enforcing)) {
-                PLOG(ERROR) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
-                security_failure();
-            }
-        }
-
-        std::string err;
-        if (!WriteFile("/sys/fs/selinux/checkreqprot", "0", &err)) {
-            LOG(ERROR) << err;
-            security_failure();
-        }
-
-        // init's first stage can't set properties, so pass the time to the second stage.
-        setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
-    } else {
-        selinux_init_all_handles();
-    }
-}
-
-// The files and directories that were created before initial sepolicy load or
-// files on ramdisk need to have their security context restored to the proper
-// value. This must happen before /dev is populated by ueventd.
-static void selinux_restore_context() {
-    LOG(INFO) << "Running restorecon...";
-    selinux_android_restorecon("/dev", 0);
-    selinux_android_restorecon("/dev/kmsg", 0);
-    selinux_android_restorecon("/dev/socket", 0);
-    selinux_android_restorecon("/dev/random", 0);
-    selinux_android_restorecon("/dev/urandom", 0);
-    selinux_android_restorecon("/dev/__properties__", 0);
-
-    selinux_android_restorecon("/plat_file_contexts", 0);
-    selinux_android_restorecon("/nonplat_file_contexts", 0);
-    selinux_android_restorecon("/plat_property_contexts", 0);
-    selinux_android_restorecon("/nonplat_property_contexts", 0);
-    selinux_android_restorecon("/plat_seapp_contexts", 0);
-    selinux_android_restorecon("/nonplat_seapp_contexts", 0);
-    selinux_android_restorecon("/plat_service_contexts", 0);
-    selinux_android_restorecon("/nonplat_service_contexts", 0);
-    selinux_android_restorecon("/plat_hwservice_contexts", 0);
-    selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
-    selinux_android_restorecon("/sepolicy", 0);
-    selinux_android_restorecon("/vndservice_contexts", 0);
-
-    selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
-    selinux_android_restorecon("/dev/device-mapper", 0);
-
-    selinux_android_restorecon("/sbin/mke2fs_static", 0);
-    selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
 }
 
 // Set the UDC controller for the ConfigFS USB Gadgets.
@@ -948,7 +360,7 @@
     }
 }
 
-static void install_reboot_signal_handlers() {
+static void InstallRebootSignalHandlers() {
     // Instead of panic'ing the kernel as is the default behavior when init crashes,
     // we prefer to reboot to bootloader on development builds, as this will prevent
     // boot looping bad configurations and allow both developers and test farms to easily
@@ -956,9 +368,18 @@
     struct sigaction action;
     memset(&action, 0, sizeof(action));
     sigfillset(&action.sa_mask);
-    action.sa_handler = [](int) {
-        // panic() reboots to bootloader
-        panic();
+    action.sa_handler = [](int signal) {
+        // These signal handlers are also caught for processes forked from init, however we do not
+        // want them to trigger reboot, so we directly call _exit() for children processes here.
+        if (getpid() != 1) {
+            _exit(signal);
+        }
+
+        // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
+        // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
+        // and probably good enough given this is already an error case and only enabled for
+        // development builds.
+        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
     };
     action.sa_flags = SA_RESTART;
     sigaction(SIGABRT, &action, nullptr);
@@ -973,6 +394,41 @@
     sigaction(SIGTRAP, &action, nullptr);
 }
 
+static void HandleSigtermSignal() {
+    signalfd_siginfo siginfo;
+    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
+    if (bytes_read != sizeof(siginfo)) {
+        PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
+        return;
+    }
+
+    if (siginfo.ssi_pid != 0) {
+        // Drop any userspace SIGTERM requests.
+        LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
+        return;
+    }
+
+    LOG(INFO) << "Handling SIGTERM, shutting system down";
+    HandlePowerctlMessage("shutdown");
+}
+
+static void InstallSigtermHandler() {
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGTERM);
+
+    if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to block SIGTERM";
+    }
+
+    sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+    if (sigterm_signal_fd == -1) {
+        PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+    }
+
+    register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -983,11 +439,9 @@
     }
 
     if (REBOOT_BOOTLOADER_ON_PANIC) {
-        install_reboot_signal_handlers();
+        InstallRebootSignalHandlers();
     }
 
-    add_environment("PATH", _PATH_DEFPATH);
-
     bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
 
     if (is_first_stage) {
@@ -996,6 +450,8 @@
         // Clear the umask.
         umask(0);
 
+        clearenv();
+        setenv("PATH", _PATH_DEFPATH, 1);
         // Get the basic filesystem setup we need put together in the initramdisk
         // on / and then we'll let the rc file figure out the rest.
         mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
@@ -1010,7 +466,13 @@
         setgroups(arraysize(groups), groups);
         mount("sysfs", "/sys", "sysfs", 0, NULL);
         mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
+
         mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+
+        if constexpr (WORLD_WRITABLE_KMSG) {
+            mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
+        }
+
         mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
         mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
 
@@ -1021,20 +483,22 @@
         LOG(INFO) << "init first stage started!";
 
         if (!DoFirstStageMount()) {
-            LOG(ERROR) << "Failed to mount required partitions early ...";
-            panic();
+            LOG(FATAL) << "Failed to mount required partitions early ...";
         }
 
         SetInitAvbVersionInRecovery();
 
+        // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+        global_seccomp();
+
         // Set up SELinux, loading the SELinux policy.
-        selinux_initialize(true);
+        SelinuxSetupKernelLogging();
+        SelinuxInitialize();
 
         // We're in the kernel domain, so re-exec init to transition to the init domain now
         // that the SELinux policy has been loaded.
         if (selinux_android_restorecon("/init", 0) == -1) {
-            PLOG(ERROR) << "restorecon failed";
-            security_failure();
+            PLOG(FATAL) << "restorecon failed of /init failed";
         }
 
         setenv("INIT_SECOND_STAGE", "true", 1);
@@ -1049,8 +513,7 @@
 
         // execv() only returns if an error happened, in which case we
         // panic and never fall through this conditional.
-        PLOG(ERROR) << "execv(\"" << path << "\") failed";
-        security_failure();
+        PLOG(FATAL) << "execv(\"" << path << "\") failed";
     }
 
     // At this point we're in the second stage of init.
@@ -1091,8 +554,9 @@
     unsetenv("INIT_AVB_VERSION");
 
     // Now set up SELinux for second stage.
-    selinux_initialize(false);
-    selinux_restore_context();
+    SelinuxSetupKernelLogging();
+    SelabelInitialize();
+    SelinuxRestoreContext();
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     if (epoll_fd == -1) {
@@ -1100,7 +564,13 @@
         exit(1);
     }
 
-    signal_handler_init();
+    sigchld_handler_init();
+
+    if (!IsRebootCapable()) {
+        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+        // In that case, receiving SIGTERM will cause the system to shut down.
+        InstallSigtermHandler();
+    }
 
     property_load_boot_defaults();
     export_oem_lock_status();
@@ -1111,26 +581,9 @@
     Action::set_function_map(&function_map);
 
     ActionManager& am = ActionManager::GetInstance();
-    ServiceManager& sm = ServiceManager::GetInstance();
-    Parser& parser = Parser::GetInstance();
+    ServiceList& sm = ServiceList::GetInstance();
 
-    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
-    parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
-    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
-    std::string bootscript = GetProperty("ro.boot.init_rc", "");
-    if (bootscript.empty()) {
-        parser.ParseConfig("/init.rc");
-        parser.set_is_system_etc_init_loaded(
-                parser.ParseConfig("/system/etc/init"));
-        parser.set_is_vendor_etc_init_loaded(
-                parser.ParseConfig("/vendor/etc/init"));
-        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
-    } else {
-        parser.ParseConfig(bootscript);
-        parser.set_is_system_etc_init_loaded(true);
-        parser.set_is_vendor_etc_init_loaded(true);
-        parser.set_is_odm_etc_init_loaded(true);
-    }
+    LoadBootScripts(am, sm);
 
     // Turning this on and letting the INFO logging be discarded adds 0.2s to
     // Nexus 9 boot time, so it's disabled by default.
@@ -1141,9 +594,9 @@
     // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
     am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
-    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
-    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
+    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
+    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
+    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
@@ -1152,7 +605,7 @@
 
     // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     // wasn't ready immediately after wait_for_coldboot_done
-    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
 
     // Don't mount filesystems or start core system services in charger mode.
     std::string bootmode = GetProperty("ro.bootmode", "");
@@ -1169,16 +622,20 @@
         // By default, sleep until something happens.
         int epoll_timeout_ms = -1;
 
-        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
+        if (!(waiting_for_prop || Service::is_exec_service_running())) {
             am.ExecuteOneCommand();
         }
-        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
-            if (!shutting_down) restart_processes();
+        if (!(waiting_for_prop || Service::is_exec_service_running())) {
+            if (!shutting_down) {
+                auto next_process_restart_time = RestartProcesses();
 
-            // If there's a process that needs restarting, wake up in time for that.
-            if (process_needs_restart_at != 0) {
-                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
-                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+                // If there's a process that needs restarting, wake up in time for that.
+                if (next_process_restart_time) {
+                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
+                                           *next_process_restart_time - boot_clock::now())
+                                           .count();
+                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+                }
             }
 
             // If there's more work to do, wake up again immediately.
diff --git a/init/init.h b/init/init.h
index aaab523..b757c1d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -18,8 +18,11 @@
 #define _INIT_INIT_H
 
 #include <string>
+#include <vector>
 
-#include <selinux/label.h>
+#include "action.h"
+#include "parser.h"
+#include "service.h"
 
 namespace android {
 namespace init {
@@ -27,10 +30,10 @@
 // Note: These globals are *only* valid in init, so they should not be used in ueventd,
 // watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
 // TODO: Have an Init class and remove all globals.
-extern const char *ENV[32];
 extern std::string default_console;
-extern struct selabel_handle *sehandle;
-extern struct selabel_handle *sehandle_prop;
+extern std::vector<std::string> late_import_paths;
+
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 
 void handle_control_message(const std::string& msg, const std::string& arg);
 
@@ -38,8 +41,6 @@
 
 void register_epoll_handler(int fd, void (*fn)());
 
-int add_environment(const char* key, const char* val);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
deleted file mode 100644
index 9f7089b..0000000
--- a/init/init_parser.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2010 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 "init_parser.h"
-
-#include <dirent.h>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "parser.h"
-#include "util.h"
-
-namespace android {
-namespace init {
-
-Parser::Parser() {
-}
-
-Parser& Parser::GetInstance() {
-    static Parser instance;
-    return instance;
-}
-
-void Parser::AddSectionParser(const std::string& name,
-                              std::unique_ptr<SectionParser> parser) {
-    section_parsers_[name] = std::move(parser);
-}
-
-void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
-    line_callbacks_.emplace_back(prefix, callback);
-}
-
-void Parser::ParseData(const std::string& filename, const std::string& data) {
-    //TODO: Use a parser with const input and remove this copy
-    std::vector<char> data_copy(data.begin(), data.end());
-    data_copy.push_back('\0');
-
-    parse_state state;
-    state.line = 0;
-    state.ptr = &data_copy[0];
-    state.nexttoken = 0;
-
-    SectionParser* section_parser = nullptr;
-    std::vector<std::string> args;
-
-    for (;;) {
-        switch (next_token(&state)) {
-        case T_EOF:
-            if (section_parser) {
-                section_parser->EndSection();
-            }
-            return;
-        case T_NEWLINE:
-            state.line++;
-            if (args.empty()) {
-                break;
-            }
-            // If we have a line matching a prefix we recognize, call its callback and unset any
-            // current section parsers.  This is meant for /sys/ and /dev/ line entries for uevent.
-            for (const auto& [prefix, callback] : line_callbacks_) {
-                if (android::base::StartsWith(args[0], prefix.c_str())) {
-                    if (section_parser) section_parser->EndSection();
-
-                    std::string ret_err;
-                    if (!callback(std::move(args), &ret_err)) {
-                        LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
-                    }
-                    section_parser = nullptr;
-                    break;
-                }
-            }
-            if (section_parsers_.count(args[0])) {
-                if (section_parser) {
-                    section_parser->EndSection();
-                }
-                section_parser = section_parsers_[args[0]].get();
-                std::string ret_err;
-                if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) {
-                    LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
-                    section_parser = nullptr;
-                }
-            } else if (section_parser) {
-                std::string ret_err;
-                if (!section_parser->ParseLineSection(std::move(args), state.line, &ret_err)) {
-                    LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
-                }
-            }
-            args.clear();
-            break;
-        case T_TEXT:
-            args.emplace_back(state.text);
-            break;
-        }
-    }
-}
-
-bool Parser::ParseConfigFile(const std::string& path) {
-    LOG(INFO) << "Parsing file " << path << "...";
-    android::base::Timer t;
-    std::string data;
-    std::string err;
-    if (!ReadFile(path, &data, &err)) {
-        LOG(ERROR) << err;
-        return false;
-    }
-
-    data.push_back('\n'); // TODO: fix parse_config.
-    ParseData(path, data);
-    for (const auto& [section_name, section_parser] : section_parsers_) {
-        section_parser->EndFile();
-    }
-
-    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
-    return true;
-}
-
-bool Parser::ParseConfigDir(const std::string& path) {
-    LOG(INFO) << "Parsing directory " << path << "...";
-    std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
-    if (!config_dir) {
-        PLOG(ERROR) << "Could not import directory '" << path << "'";
-        return false;
-    }
-    dirent* current_file;
-    std::vector<std::string> files;
-    while ((current_file = readdir(config_dir.get()))) {
-        // Ignore directories and only process regular files.
-        if (current_file->d_type == DT_REG) {
-            std::string current_path =
-                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
-            files.emplace_back(current_path);
-        }
-    }
-    // Sort first so we load files in a consistent order (bug 31996208)
-    std::sort(files.begin(), files.end());
-    for (const auto& file : files) {
-        if (!ParseConfigFile(file)) {
-            LOG(ERROR) << "could not import file '" << file << "'";
-        }
-    }
-    return true;
-}
-
-bool Parser::ParseConfig(const std::string& path) {
-    if (is_dir(path.c_str())) {
-        return ParseConfigDir(path);
-    }
-    return ParseConfigFile(path);
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/init_parser.h b/init/init_parser.h
deleted file mode 100644
index c07a699..0000000
--- a/init/init_parser.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 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 _INIT_INIT_PARSER_H_
-#define _INIT_INIT_PARSER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-//  SectionParser is an interface that can parse a given 'section' in init.
-//
-//  You can implement up to 4 functions below, with ParseSection() being mandatory.
-//  The first two function return bool with false indicating a failure and has a std::string* err
-//  parameter into which an error string can be written.  It will be reported along with the
-//  filename and line number of where the error occurred.
-//
-//  1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
-//                       int line, std::string* err)
-//    This function is called when a section is first encountered.
-//
-//  2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
-//    This function is called on each subsequent line until the next section is encountered.
-//
-//  3) bool EndSection()
-//    This function is called either when a new section is found or at the end of the file.
-//    It indicates that parsing of the current section is complete and any relevant objects should
-//    be committed.
-//
-//  4) bool EndFile()
-//    This function is called at the end of the file.
-//    It indicates that the parsing has completed and any relevant objects should be committed.
-
-namespace android {
-namespace init {
-
-class SectionParser {
-  public:
-    virtual ~SectionParser() {}
-    virtual bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                              int line, std::string* err) = 0;
-    virtual bool ParseLineSection(std::vector<std::string>&&, int, std::string*) { return true; };
-    virtual void EndSection(){};
-    virtual void EndFile(){};
-};
-
-class Parser {
-  public:
-    //  LineCallback is the type for callbacks that can parse a line starting with a given prefix.
-    //
-    //  They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
-    //
-    //  Similar to ParseSection() and ParseLineSection(), this function returns bool with false
-    //  indicating a failure and has an std::string* err parameter into which an error string can
-    //  be written.
-    using LineCallback = std::function<bool(std::vector<std::string>&&, std::string*)>;
-
-    // TODO: init is the only user of this as a singleton; remove it.
-    static Parser& GetInstance();
-
-    Parser();
-
-    bool ParseConfig(const std::string& path);
-    void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
-    void AddSingleLineParser(const std::string& prefix, LineCallback callback);
-    void set_is_system_etc_init_loaded(bool loaded) { is_system_etc_init_loaded_ = loaded; }
-    void set_is_vendor_etc_init_loaded(bool loaded) { is_vendor_etc_init_loaded_ = loaded; }
-    void set_is_odm_etc_init_loaded(bool loaded) { is_odm_etc_init_loaded_ = loaded; }
-    bool is_system_etc_init_loaded() { return is_system_etc_init_loaded_; }
-    bool is_vendor_etc_init_loaded() { return is_vendor_etc_init_loaded_; }
-    bool is_odm_etc_init_loaded() { return is_odm_etc_init_loaded_; }
-
-  private:
-    void ParseData(const std::string& filename, const std::string& data);
-    bool ParseConfigFile(const std::string& path);
-    bool ParseConfigDir(const std::string& path);
-
-    std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
-    std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
-    bool is_system_etc_init_loaded_ = false;
-    bool is_vendor_etc_init_loaded_ = false;
-    bool is_odm_etc_init_loaded_ = false;
-};
-
-}  // namespace init
-}  // namespace android
-
-#endif
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
deleted file mode 100644
index 95f269a..0000000
--- a/init/init_parser_test.cpp
+++ /dev/null
@@ -1,150 +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.
- */
-
-#include "init_parser.h"
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "init.h"
-#include "service.h"
-#include "util.h"
-
-namespace android {
-namespace init {
-
-TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
-    ServiceManager& sm = ServiceManager::GetInstance();
-    std::vector<std::string> args;
-    // Nothing.
-    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-
-    // No arguments to 'exec'.
-    args.push_back("exec");
-    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-
-    // No command in "exec --".
-    args.push_back("--");
-    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-}
-
-TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) {
-    ServiceManager& sm = ServiceManager::GetInstance();
-    std::vector<std::string> args;
-    args.push_back("exec");
-    args.push_back("seclabel");
-    args.push_back("root"); // uid.
-    args.push_back("root"); // gid.
-    for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
-        args.push_back("root"); // Supplementary gid.
-    }
-    args.push_back("--");
-    args.push_back("/system/bin/id");
-    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-}
-
-static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid,
-                                           bool gid, bool supplementary_gids) {
-    ServiceManager& sm = ServiceManager::GetInstance();
-    std::vector<std::string> args;
-    args.push_back("exec");
-    if (seclabel) {
-        args.push_back("u:r:su:s0"); // seclabel
-        if (uid) {
-            args.push_back("log");      // uid
-            if (gid) {
-                args.push_back("shell");     // gid
-                if (supplementary_gids) {
-                    args.push_back("system");    // supplementary gid 0
-                    args.push_back("adb");       // supplementary gid 1
-                }
-            }
-        }
-    }
-    if (dash_dash) {
-        args.push_back("--");
-    }
-    args.push_back("/system/bin/toybox");
-    args.push_back("id");
-    Service* svc = sm.MakeExecOneshotService(args);
-    ASSERT_NE(nullptr, svc);
-
-    if (seclabel) {
-        ASSERT_EQ("u:r:su:s0", svc->seclabel());
-    } else {
-        ASSERT_EQ("", svc->seclabel());
-    }
-    if (uid) {
-        uid_t decoded_uid;
-        std::string err;
-        ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
-        ASSERT_EQ(decoded_uid, svc->uid());
-    } else {
-        ASSERT_EQ(0U, svc->uid());
-    }
-    if (gid) {
-        uid_t decoded_uid;
-        std::string err;
-        ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
-        ASSERT_EQ(decoded_uid, svc->gid());
-    } else {
-        ASSERT_EQ(0U, svc->gid());
-    }
-    if (supplementary_gids) {
-        ASSERT_EQ(2U, svc->supp_gids().size());
-        uid_t decoded_uid;
-        std::string err;
-        ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
-        ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
-        ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
-        ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
-    } else {
-        ASSERT_EQ(0U, svc->supp_gids().size());
-    }
-
-    ASSERT_EQ(static_cast<std::size_t>(2), svc->args().size());
-    ASSERT_EQ("/system/bin/toybox", svc->args()[0]);
-    ASSERT_EQ("id", svc->args()[1]);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_everything) {
-    Test_make_exec_oneshot_service(true, true, true, true, true);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid_gid) {
-    Test_make_exec_oneshot_service(true, true, true, true, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid) {
-    Test_make_exec_oneshot_service(true, true, true, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel) {
-    Test_make_exec_oneshot_service(true, true, false, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_just_command) {
-    Test_make_exec_oneshot_service(true, false, false, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_just_command_no_dash) {
-    Test_make_exec_oneshot_service(false, false, false, false, false);
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0a4071b..27659f9 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -23,8 +23,8 @@
 #include "action.h"
 #include "builtins.h"
 #include "import_parser.h"
-#include "init_parser.h"
 #include "keyword_map.h"
+#include "parser.h"
 #include "util.h"
 
 namespace android {
@@ -37,7 +37,7 @@
     void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
         Add(name, 0, 0, [function](const std::vector<std::string>&) {
             function();
-            return 0;
+            return Success();
         });
     }
 
@@ -156,10 +156,9 @@
                                "execute 3";
     // clang-format on
     // WriteFile() ensures the right mode is set
-    std::string err;
-    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script, &err));
+    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script));
 
-    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5", &err));
+    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
 
     // clang-format off
     std::string start_script = "import " + std::string(first_import.path) + "\n"
@@ -175,7 +174,7 @@
     auto execute_command = [&num_executed](const std::vector<std::string>& args) {
         EXPECT_EQ(2U, args.size());
         EXPECT_EQ(++num_executed, std::stoi(args[1]));
-        return 0;
+        return Success();
     };
 
     TestFunctionMap test_function_map;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index a0d7cc5..e686ce1 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -79,10 +79,13 @@
     // Only handle keychords if adb is enabled.
     std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
-        Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
+        Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
         if (svc) {
-            LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
-            svc->Start();
+            LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
+            if (auto result = svc->Start(); !result) {
+                LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
+                           << ": " << result.error();
+            }
         } else {
             LOG(ERROR) << "Service for keychord " << id << " not found";
         }
@@ -92,7 +95,9 @@
 }
 
 void keychord_init() {
-    ServiceManager::GetInstance().ForEachService(add_service_keycodes);
+    for (const auto& service : ServiceList::GetInstance()) {
+        add_service_keycodes(service.get());
+    }
 
     // Nothing to do if no services require keychords.
     if (!keychords) {
diff --git a/init/keyword_map.h b/init/keyword_map.h
index 481d637..c95fc73 100644
--- a/init/keyword_map.h
+++ b/init/keyword_map.h
@@ -22,6 +22,8 @@
 
 #include <android-base/stringprintf.h>
 
+#include "result.h"
+
 namespace android {
 namespace init {
 
@@ -34,20 +36,17 @@
     virtual ~KeywordMap() {
     }
 
-    const Function FindFunction(const std::vector<std::string>& args, std::string* err) const {
+    const Result<Function> FindFunction(const std::vector<std::string>& args) const {
         using android::base::StringPrintf;
 
-        if (args.empty()) {
-            *err = "keyword needed, but not provided";
-            return nullptr;
-        }
+        if (args.empty()) return Error() << "Keyword needed, but not provided";
+
         auto& keyword = args[0];
         auto num_args = args.size() - 1;
 
         auto function_info_it = map().find(keyword);
         if (function_info_it == map().end()) {
-            *err = StringPrintf("invalid keyword '%s'", keyword.c_str());
-            return nullptr;
+            return Error() << StringPrintf("Invalid keyword '%s'", keyword.c_str());
         }
 
         auto function_info = function_info_it->second;
@@ -55,22 +54,18 @@
         auto min_args = std::get<0>(function_info);
         auto max_args = std::get<1>(function_info);
         if (min_args == max_args && num_args != min_args) {
-            *err = StringPrintf("%s requires %zu argument%s",
-                                keyword.c_str(), min_args,
-                                (min_args > 1 || min_args == 0) ? "s" : "");
-            return nullptr;
+            return Error() << StringPrintf("%s requires %zu argument%s", keyword.c_str(), min_args,
+                                           (min_args > 1 || min_args == 0) ? "s" : "");
         }
 
         if (num_args < min_args || num_args > max_args) {
             if (max_args == std::numeric_limits<decltype(max_args)>::max()) {
-                *err = StringPrintf("%s requires at least %zu argument%s",
-                                    keyword.c_str(), min_args,
-                                    min_args > 1 ? "s" : "");
+                return Error() << StringPrintf("%s requires at least %zu argument%s",
+                                               keyword.c_str(), min_args, min_args > 1 ? "s" : "");
             } else {
-                *err = StringPrintf("%s requires between %zu and %zu arguments",
-                                    keyword.c_str(), min_args, max_args);
+                return Error() << StringPrintf("%s requires between %zu and %zu arguments",
+                                               keyword.c_str(), min_args, max_args);
             }
-            return nullptr;
         }
 
         return std::get<Function>(function_info);
diff --git a/init/log.cpp b/init/log.cpp
index 1830077..6198fc2 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -19,19 +19,45 @@
 #include <fcntl.h>
 #include <linux/audit.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <android-base/logging.h>
+#include <cutils/android_reboot.h>
 #include <selinux/selinux.h>
 
+#include "reboot.h"
+
 namespace android {
 namespace init {
 
+static void InitAborter(const char* abort_message) {
+    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
+    // simply abort instead of trying to reboot the system.
+    if (getpid() != 1) {
+        android::base::DefaultAborter(abort_message);
+        return;
+    }
+
+    // DoReboot() does a lot to try to shutdown the system cleanly.  If something happens to call
+    // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to
+    // reboot instead of recursing here.
+    static bool has_aborted = false;
+    if (!has_aborted) {
+        has_aborted = true;
+        // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely
+        // that we can even run the ActionQueue at this point.
+        DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
+    } else {
+        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+    }
+}
+
 void InitKernelLogging(char* argv[]) {
     // Make stdin/stdout/stderr all point to /dev/null.
     int fd = open("/sys/fs/selinux/null", O_RDWR);
     if (fd == -1) {
         int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger);
+        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
         errno = saved_errno;
         PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
     }
@@ -40,7 +66,7 @@
     dup2(fd, 2);
     if (fd > 2) close(fd);
 
-    android::base::InitLogging(argv, &android::base::KernelLogger);
+    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
 }
 
 int selinux_klog_callback(int type, const char *fmt, ...) {
diff --git a/init/parser.cpp b/init/parser.cpp
index c0fa6d9..8a4e798 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -1,123 +1,154 @@
+/*
+ * Copyright (C) 2010 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 "parser.h"
 
+#include <dirent.h>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "tokenizer.h"
+#include "util.h"
+
 namespace android {
 namespace init {
 
-int next_token(struct parse_state *state)
-{
-    char *x = state->ptr;
-    char *s;
+Parser::Parser() {}
 
-    if (state->nexttoken) {
-        int t = state->nexttoken;
-        state->nexttoken = 0;
-        return t;
-    }
+void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {
+    section_parsers_[name] = std::move(parser);
+}
+
+void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
+    line_callbacks_.emplace_back(prefix, callback);
+}
+
+void Parser::ParseData(const std::string& filename, const std::string& data) {
+    // TODO: Use a parser with const input and remove this copy
+    std::vector<char> data_copy(data.begin(), data.end());
+    data_copy.push_back('\0');
+
+    parse_state state;
+    state.line = 0;
+    state.ptr = &data_copy[0];
+    state.nexttoken = 0;
+
+    SectionParser* section_parser = nullptr;
+    std::vector<std::string> args;
 
     for (;;) {
-        switch (*x) {
-        case 0:
-            state->ptr = x;
-            return T_EOF;
-        case '\n':
-            x++;
-            state->ptr = x;
-            return T_NEWLINE;
-        case ' ':
-        case '\t':
-        case '\r':
-            x++;
-            continue;
-        case '#':
-            while (*x && (*x != '\n')) x++;
-            if (*x == '\n') {
-                state->ptr = x+1;
-                return T_NEWLINE;
-            } else {
-                state->ptr = x;
-                return T_EOF;
-            }
-        default:
-            goto text;
+        switch (next_token(&state)) {
+            case T_EOF:
+                if (section_parser) section_parser->EndSection();
+                return;
+            case T_NEWLINE:
+                state.line++;
+                if (args.empty()) break;
+                // If we have a line matching a prefix we recognize, call its callback and unset any
+                // current section parsers.  This is meant for /sys/ and /dev/ line entries for
+                // uevent.
+                for (const auto& [prefix, callback] : line_callbacks_) {
+                    if (android::base::StartsWith(args[0], prefix.c_str())) {
+                        if (section_parser) section_parser->EndSection();
+
+                        if (auto result = callback(std::move(args)); !result) {
+                            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
+                        }
+                        section_parser = nullptr;
+                        break;
+                    }
+                }
+                if (section_parsers_.count(args[0])) {
+                    if (section_parser) section_parser->EndSection();
+                    section_parser = section_parsers_[args[0]].get();
+                    if (auto result =
+                            section_parser->ParseSection(std::move(args), filename, state.line);
+                        !result) {
+                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
+                        section_parser = nullptr;
+                    }
+                } else if (section_parser) {
+                    if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
+                        !result) {
+                        LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
+                    }
+                }
+                args.clear();
+                break;
+            case T_TEXT:
+                args.emplace_back(state.text);
+                break;
         }
     }
+}
+
+bool Parser::ParseConfigFile(const std::string& path) {
+    LOG(INFO) << "Parsing file " << path << "...";
+    android::base::Timer t;
+    auto config_contents = ReadFile(path);
+    if (!config_contents) {
+        LOG(ERROR) << "Unable to read config file '" << path << "': " << config_contents.error();
+        return false;
+    }
 
-textdone:
-    state->ptr = x;
-    *s = 0;
-    return T_TEXT;
-text:
-    state->text = s = x;
-textresume:
-    for (;;) {
-        switch (*x) {
-        case 0:
-            goto textdone;
-        case ' ':
-        case '\t':
-        case '\r':
-            x++;
-            goto textdone;
-        case '\n':
-            state->nexttoken = T_NEWLINE;
-            x++;
-            goto textdone;
-        case '"':
-            x++;
-            for (;;) {
-                switch (*x) {
-                case 0:
-                        /* unterminated quoted thing */
-                    state->ptr = x;
-                    return T_EOF;
-                case '"':
-                    x++;
-                    goto textresume;
-                default:
-                    *s++ = *x++;
-                }
-            }
-            break;
-        case '\\':
-            x++;
-            switch (*x) {
-            case 0:
-                goto textdone;
-            case 'n':
-                *s++ = '\n';
-                break;
-            case 'r':
-                *s++ = '\r';
-                break;
-            case 't':
-                *s++ = '\t';
-                break;
-            case '\\':
-                *s++ = '\\';
-                break;
-            case '\r':
-                    /* \ <cr> <lf> -> line continuation */
-                if (x[1] != '\n') {
-                    x++;
-                    continue;
-                }
-            case '\n':
-                    /* \ <lf> -> line continuation */
-                state->line++;
-                x++;
-                    /* eat any extra whitespace */
-                while((*x == ' ') || (*x == '\t')) x++;
-                continue;
-            default:
-                    /* unknown escape -- just copy */
-                *s++ = *x++;
-            }
-            continue;
-        default:
-            *s++ = *x++;
+    config_contents->push_back('\n');  // TODO: fix parse_config.
+    ParseData(path, *config_contents);
+    for (const auto& [section_name, section_parser] : section_parsers_) {
+        section_parser->EndFile();
+    }
+
+    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
+    return true;
+}
+
+bool Parser::ParseConfigDir(const std::string& path) {
+    LOG(INFO) << "Parsing directory " << path << "...";
+    std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
+    if (!config_dir) {
+        PLOG(ERROR) << "Could not import directory '" << path << "'";
+        return false;
+    }
+    dirent* current_file;
+    std::vector<std::string> files;
+    while ((current_file = readdir(config_dir.get()))) {
+        // Ignore directories and only process regular files.
+        if (current_file->d_type == DT_REG) {
+            std::string current_path =
+                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
+            files.emplace_back(current_path);
         }
     }
-    return T_EOF;
+    // Sort first so we load files in a consistent order (bug 31996208)
+    std::sort(files.begin(), files.end());
+    for (const auto& file : files) {
+        if (!ParseConfigFile(file)) {
+            LOG(ERROR) << "could not import file '" << file << "'";
+        }
+    }
+    return true;
+}
+
+bool Parser::ParseConfig(const std::string& path) {
+    if (is_dir(path.c_str())) {
+        return ParseConfigDir(path);
+    }
+    return ParseConfigFile(path);
 }
 
 }  // namespace init
diff --git a/init/parser.h b/init/parser.h
index 86e4c57..4ab24a4 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -14,27 +14,79 @@
  * limitations under the License.
  */
 
-#ifndef PARSER_H_
-#define PARSER_H_
+#ifndef _INIT_PARSER_H_
+#define _INIT_PARSER_H_
 
-#define T_EOF 0
-#define T_TEXT 1
-#define T_NEWLINE 2
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "result.h"
+
+//  SectionParser is an interface that can parse a given 'section' in init.
+//
+//  You can implement up to 4 functions below, with ParseSection() being mandatory.
+//  The first two function return bool with false indicating a failure and has a std::string* err
+//  parameter into which an error string can be written.  It will be reported along with the
+//  filename and line number of where the error occurred.
+//
+//  1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
+//                       int line, std::string* err)
+//    This function is called when a section is first encountered.
+//
+//  2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
+//    This function is called on each subsequent line until the next section is encountered.
+//
+//  3) bool EndSection()
+//    This function is called either when a new section is found or at the end of the file.
+//    It indicates that parsing of the current section is complete and any relevant objects should
+//    be committed.
+//
+//  4) bool EndFile()
+//    This function is called at the end of the file.
+//    It indicates that the parsing has completed and any relevant objects should be committed.
 
 namespace android {
 namespace init {
 
-struct parse_state
-{
-    char *ptr;
-    char *text;
-    int line;
-    int nexttoken;
+class SectionParser {
+  public:
+    virtual ~SectionParser() {}
+    virtual Result<Success> ParseSection(std::vector<std::string>&& args,
+                                         const std::string& filename, int line) = 0;
+    virtual Result<Success> ParseLineSection(std::vector<std::string>&&, int) { return Success(); };
+    virtual void EndSection(){};
+    virtual void EndFile(){};
 };
 
-int next_token(struct parse_state *state);
+class Parser {
+  public:
+    //  LineCallback is the type for callbacks that can parse a line starting with a given prefix.
+    //
+    //  They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
+    //
+    //  Similar to ParseSection() and ParseLineSection(), this function returns bool with false
+    //  indicating a failure and has an std::string* err parameter into which an error string can
+    //  be written.
+    using LineCallback = std::function<Result<Success>(std::vector<std::string>&&)>;
+
+    Parser();
+
+    bool ParseConfig(const std::string& path);
+    void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
+    void AddSingleLineParser(const std::string& prefix, LineCallback callback);
+
+  private:
+    void ParseData(const std::string& filename, const std::string& data);
+    bool ParseConfigFile(const std::string& path);
+    bool ParseConfigDir(const std::string& path);
+
+    std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
+    std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
+};
 
 }  // namespace init
 }  // namespace android
 
-#endif /* PARSER_H_ */
+#endif
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
new file mode 100644
index 0000000..66fa011
--- /dev/null
+++ b/init/persistent_properties.cpp
@@ -0,0 +1,341 @@
+/*
+ * 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 "persistent_properties.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/system_properties.h>
+#include <sys/types.h>
+
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include "util.h"
+
+using android::base::ReadFdToString;
+using android::base::StartsWith;
+using android::base::WriteStringToFd;
+using android::base::unique_fd;
+
+namespace android {
+namespace init {
+
+std::string persistent_property_filename = "/data/property/persistent_properties";
+
+namespace {
+
+constexpr const uint32_t kMagic = 0x8495E0B4;
+constexpr const char kLegacyPersistentPropertyDir[] = "/data/property";
+
+Result<std::vector<std::pair<std::string, std::string>>> LoadLegacyPersistentProperties() {
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
+    if (!dir) {
+        return ErrnoError() << "Unable to open persistent property directory \""
+                            << kLegacyPersistentPropertyDir << "\"";
+    }
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties;
+    dirent* entry;
+    while ((entry = readdir(dir.get())) != nullptr) {
+        if (!StartsWith(entry->d_name, "persist.")) {
+            continue;
+        }
+        if (entry->d_type != DT_REG) {
+            continue;
+        }
+
+        unique_fd fd(openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW));
+        if (fd == -1) {
+            PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
+            continue;
+        }
+
+        struct stat sb;
+        if (fstat(fd, &sb) == -1) {
+            PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
+            continue;
+        }
+
+        // File must not be accessible to others, be owned by root/root, and
+        // not be a hard link to any other file.
+        if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 ||
+            sb.st_nlink != 1) {
+            PLOG(ERROR) << "skipping insecure property file " << entry->d_name
+                        << " (uid=" << sb.st_uid << " gid=" << sb.st_gid << " nlink=" << sb.st_nlink
+                        << " mode=" << std::oct << sb.st_mode << ")";
+            continue;
+        }
+
+        std::string value;
+        if (ReadFdToString(fd, &value)) {
+            persistent_properties.emplace_back(entry->d_name, value);
+        } else {
+            PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
+        }
+    }
+    return persistent_properties;
+}
+
+void RemoveLegacyPersistentPropertyFiles() {
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
+    if (!dir) {
+        PLOG(ERROR) << "Unable to open persistent property directory \""
+                    << kLegacyPersistentPropertyDir << "\"";
+        return;
+    }
+
+    dirent* entry;
+    while ((entry = readdir(dir.get())) != nullptr) {
+        if (!StartsWith(entry->d_name, "persist.")) {
+            continue;
+        }
+        if (entry->d_type != DT_REG) {
+            continue;
+        }
+        unlinkat(dirfd(dir.get()), entry->d_name, 0);
+    }
+}
+
+std::vector<std::pair<std::string, std::string>> LoadPersistentPropertiesFromMemory() {
+    std::vector<std::pair<std::string, std::string>> properties;
+    __system_property_foreach(
+        [](const prop_info* pi, void* cookie) {
+            __system_property_read_callback(
+                pi,
+                [](void* cookie, const char* name, const char* value, unsigned serial) {
+                    if (StartsWith(name, "persist.")) {
+                        auto properties =
+                            reinterpret_cast<std::vector<std::pair<std::string, std::string>>*>(
+                                cookie);
+                        properties->emplace_back(name, value);
+                    }
+                },
+                cookie);
+        },
+        &properties);
+    return properties;
+}
+
+class PersistentPropertyFileParser {
+  public:
+    PersistentPropertyFileParser(const std::string& contents) : contents_(contents), position_(0) {}
+    Result<std::vector<std::pair<std::string, std::string>>> Parse();
+
+  private:
+    Result<std::string> ReadString();
+    Result<uint32_t> ReadUint32();
+
+    const std::string& contents_;
+    size_t position_;
+};
+
+Result<std::vector<std::pair<std::string, std::string>>> PersistentPropertyFileParser::Parse() {
+    std::vector<std::pair<std::string, std::string>> result;
+
+    if (auto magic = ReadUint32(); magic) {
+        if (*magic != kMagic) {
+            return Error() << "Magic value '0x" << std::hex << *magic
+                           << "' does not match expected value '0x" << kMagic << "'";
+        }
+    } else {
+        return Error() << "Could not read magic value: " << magic.error();
+    }
+
+    if (auto version = ReadUint32(); version) {
+        if (*version != 1) {
+            return Error() << "Version '" << *version
+                           << "' does not match any compatible version: (1)";
+        }
+    } else {
+        return Error() << "Could not read version: " << version.error();
+    }
+
+    auto num_properties = ReadUint32();
+    if (!num_properties) {
+        return Error() << "Could not read num_properties: " << num_properties.error();
+    }
+
+    while (position_ < contents_.size()) {
+        auto key = ReadString();
+        if (!key) {
+            return Error() << "Could not read key: " << key.error();
+        }
+        if (!StartsWith(*key, "persist.")) {
+            return Error() << "Property '" << *key << "' does not starts with 'persist.'";
+        }
+        auto value = ReadString();
+        if (!value) {
+            return Error() << "Could not read value: " << value.error();
+        }
+        result.emplace_back(*key, *value);
+    }
+
+    if (result.size() != *num_properties) {
+        return Error() << "Mismatch of number of persistent properties read, " << result.size()
+                       << " and number of persistent properties expected, " << *num_properties;
+    }
+
+    return result;
+}
+
+Result<std::string> PersistentPropertyFileParser::ReadString() {
+    auto string_length = ReadUint32();
+    if (!string_length) {
+        return Error() << "Could not read size for string";
+    }
+
+    if (position_ + *string_length > contents_.size()) {
+        return Error() << "String size would cause it to overflow the input buffer";
+    }
+    auto result = std::string(contents_, position_, *string_length);
+    position_ += *string_length;
+    return result;
+}
+
+Result<uint32_t> PersistentPropertyFileParser::ReadUint32() {
+    if (position_ + 3 > contents_.size()) {
+        return Error() << "Input buffer not large enough to read uint32_t";
+    }
+    uint32_t result = *reinterpret_cast<const uint32_t*>(&contents_[position_]);
+    position_ += sizeof(uint32_t);
+    return result;
+}
+
+}  // namespace
+
+Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile() {
+    const std::string temp_filename = persistent_property_filename + ".tmp";
+    if (access(temp_filename.c_str(), F_OK) == 0) {
+        LOG(INFO)
+            << "Found temporary property file while attempting to persistent system properties"
+               " a previous persistent property write may have failed";
+        unlink(temp_filename.c_str());
+    }
+    auto file_contents = ReadFile(persistent_property_filename);
+    if (!file_contents) {
+        return Error() << "Unable to read persistent property file: " << file_contents.error();
+    }
+    auto parsed_contents = PersistentPropertyFileParser(*file_contents).Parse();
+    if (!parsed_contents) {
+        // If the file cannot be parsed, then we don't have any recovery mechanisms, so we delete
+        // it to allow for future writes to take place successfully.
+        unlink(persistent_property_filename.c_str());
+        return Error() << "Unable to parse persistent property file: " << parsed_contents.error();
+    }
+    return parsed_contents;
+}
+
+std::string GenerateFileContents(
+    const std::vector<std::pair<std::string, std::string>>& persistent_properties) {
+    std::string result;
+
+    uint32_t magic = kMagic;
+    result.append(reinterpret_cast<char*>(&magic), sizeof(uint32_t));
+
+    uint32_t version = 1;
+    result.append(reinterpret_cast<char*>(&version), sizeof(uint32_t));
+
+    uint32_t num_properties = persistent_properties.size();
+    result.append(reinterpret_cast<char*>(&num_properties), sizeof(uint32_t));
+
+    for (const auto& [key, value] : persistent_properties) {
+        uint32_t key_length = key.length();
+        result.append(reinterpret_cast<char*>(&key_length), sizeof(uint32_t));
+        result.append(key);
+        uint32_t value_length = value.length();
+        result.append(reinterpret_cast<char*>(&value_length), sizeof(uint32_t));
+        result.append(value);
+    }
+    return result;
+}
+
+Result<Success> WritePersistentPropertyFile(
+    const std::vector<std::pair<std::string, std::string>>& persistent_properties) {
+    auto file_contents = GenerateFileContents(persistent_properties);
+
+    const std::string temp_filename = persistent_property_filename + ".tmp";
+    unique_fd fd(TEMP_FAILURE_RETRY(
+        open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
+    if (fd == -1) {
+        return ErrnoError() << "Could not open temporary properties file";
+    }
+    if (!WriteStringToFd(file_contents, fd)) {
+        return ErrnoError() << "Unable to write file contents";
+    }
+    fsync(fd);
+    fd.reset();
+
+    if (rename(temp_filename.c_str(), persistent_property_filename.c_str())) {
+        int saved_errno = errno;
+        unlink(temp_filename.c_str());
+        return Error(saved_errno) << "Unable to rename persistent property file";
+    }
+    return Success();
+}
+
+// Persistent properties are not written often, so we rather not keep any data in memory and read
+// then rewrite the persistent property file for each update.
+void WritePersistentProperty(const std::string& name, const std::string& value) {
+    auto persistent_properties = LoadPersistentPropertyFile();
+    if (!persistent_properties) {
+        LOG(ERROR) << "Recovering persistent properties from memory: "
+                   << persistent_properties.error();
+        persistent_properties = LoadPersistentPropertiesFromMemory();
+    }
+    auto it = std::find_if(persistent_properties->begin(), persistent_properties->end(),
+                           [&name](const auto& entry) { return entry.first == name; });
+    if (it != persistent_properties->end()) {
+        *it = {name, value};
+    } else {
+        persistent_properties->emplace_back(name, value);
+    }
+
+    if (auto result = WritePersistentPropertyFile(*persistent_properties); !result) {
+        LOG(ERROR) << "Could not store persistent property: " << result.error();
+    }
+}
+
+std::vector<std::pair<std::string, std::string>> LoadPersistentProperties() {
+    auto persistent_properties = LoadPersistentPropertyFile();
+
+    if (!persistent_properties) {
+        LOG(ERROR) << "Could not load single persistent property file, trying legacy directory: "
+                   << persistent_properties.error();
+        persistent_properties = LoadLegacyPersistentProperties();
+        if (!persistent_properties) {
+            LOG(ERROR) << "Unable to load legacy persistent properties: "
+                       << persistent_properties.error();
+            return {};
+        }
+        if (auto result = WritePersistentPropertyFile(*persistent_properties); result) {
+            RemoveLegacyPersistentPropertyFiles();
+        } else {
+            LOG(ERROR) << "Unable to write single persistent property file: " << result.error();
+            // Fall through so that we still set the properties that we've read.
+        }
+    }
+
+    return *persistent_properties;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/persistent_properties.h b/init/persistent_properties.h
new file mode 100644
index 0000000..d84d9db
--- /dev/null
+++ b/init/persistent_properties.h
@@ -0,0 +1,42 @@
+/*
+ * 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 _INIT_PERSISTENT_PROPERTIES_H
+#define _INIT_PERSISTENT_PROPERTIES_H
+
+#include <string>
+#include <vector>
+
+#include "result.h"
+
+namespace android {
+namespace init {
+
+std::vector<std::pair<std::string, std::string>> LoadPersistentProperties();
+void WritePersistentProperty(const std::string& name, const std::string& value);
+
+// Exposed only for testing
+Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile();
+std::string GenerateFileContents(
+    const std::vector<std::pair<std::string, std::string>>& persistent_properties);
+Result<Success> WritePersistentPropertyFile(
+    const std::vector<std::pair<std::string, std::string>>& persistent_properties);
+extern std::string persistent_property_filename;
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
new file mode 100644
index 0000000..9ab5b22
--- /dev/null
+++ b/init/persistent_properties_test.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "persistent_properties.h"
+
+#include <errno.h>
+
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "util.h"
+
+using namespace std::string_literals;
+
+namespace android {
+namespace init {
+
+TEST(persistent_properties, GeneratedContents) {
+    const std::vector<std::pair<std::string, std::string>> persistent_properties = {
+        {"persist.abc", ""},
+        {"persist.def", "test_success"},
+    };
+    auto generated_contents = GenerateFileContents(persistent_properties);
+
+    // Manually serialized contents below:
+    std::string file_contents;
+    // All values below are written and read as little endian.
+    // Add magic value: 0x8495E0B4
+    file_contents += "\xB4\xE0\x95\x84"s;
+    // Add version: 1
+    file_contents += "\x01\x00\x00\x00"s;
+    // Add number of properties: 2
+    file_contents += "\x02\x00\x00\x00"s;
+
+    // Add first key: persist.abc
+    file_contents += "\x0B\x00\x00\x00persist.abc"s;
+    // Add first value: (empty string)
+    file_contents += "\x00\x00\x00\x00"s;
+
+    // Add second key: persist.def
+    file_contents += "\x0B\x00\x00\x00persist.def"s;
+    // Add second value: test_success
+    file_contents += "\x0C\x00\x00\x00test_success"s;
+
+    EXPECT_EQ(file_contents, generated_contents);
+}
+
+TEST(persistent_properties, EndToEnd) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    persistent_property_filename = tf.path;
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties = {
+        {"persist.sys.locale", "en-US"},
+        {"persist.sys.timezone", "America/Los_Angeles"},
+        {"persist.test.empty.value", ""},
+        {"persist.test.new.line", "abc\n\n\nabc"},
+        {"persist.test.numbers", "1234567890"},
+        {"persist.test.non.ascii", "\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F"},
+        // We don't currently allow for non-ascii keys for system properties, but this is a policy
+        // decision, not a technical limitation.
+        {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-key"},
+    };
+
+    ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties));
+
+    auto read_back_properties = LoadPersistentProperties();
+    EXPECT_EQ(persistent_properties, read_back_properties);
+}
+
+TEST(persistent_properties, BadMagic) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    persistent_property_filename = tf.path;
+
+    ASSERT_TRUE(WriteFile(tf.path, "ab"));
+
+    auto read_back_properties = LoadPersistentPropertyFile();
+
+    ASSERT_FALSE(read_back_properties);
+    EXPECT_EQ(
+        "Unable to parse persistent property file: Could not read magic value: Input buffer not "
+        "large enough to read uint32_t",
+        read_back_properties.error_string());
+
+    ASSERT_TRUE(WriteFile(tf.path, "\xFF\xFF\xFF\xFF"));
+
+    read_back_properties = LoadPersistentPropertyFile();
+
+    ASSERT_FALSE(read_back_properties);
+    EXPECT_EQ(
+        "Unable to parse persistent property file: Magic value '0xffffffff' does not match "
+        "expected value '0x8495e0b4'",
+        read_back_properties.error_string());
+}
+
+TEST(persistent_properties, AddProperty) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    persistent_property_filename = tf.path;
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties = {
+        {"persist.sys.timezone", "America/Los_Angeles"},
+    };
+    ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties));
+
+    WritePersistentProperty("persist.sys.locale", "pt-BR");
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties_expected = {
+        {"persist.sys.timezone", "America/Los_Angeles"},
+        {"persist.sys.locale", "pt-BR"},
+    };
+
+    auto read_back_properties = LoadPersistentProperties();
+    EXPECT_EQ(persistent_properties_expected, read_back_properties);
+}
+
+TEST(persistent_properties, UpdateProperty) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    persistent_property_filename = tf.path;
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties = {
+        {"persist.sys.locale", "en-US"},
+        {"persist.sys.timezone", "America/Los_Angeles"},
+    };
+    ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties));
+
+    WritePersistentProperty("persist.sys.locale", "pt-BR");
+
+    std::vector<std::pair<std::string, std::string>> persistent_properties_expected = {
+        {"persist.sys.locale", "pt-BR"},
+        {"persist.sys.timezone", "America/Los_Angeles"},
+    };
+
+    auto read_back_properties = LoadPersistentProperties();
+    EXPECT_EQ(persistent_properties_expected, read_back_properties);
+}
+
+TEST(persistent_properties, UpdatePropertyBadParse) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    persistent_property_filename = tf.path;
+
+    ASSERT_TRUE(WriteFile(tf.path, "ab"));
+
+    WritePersistentProperty("persist.sys.locale", "pt-BR");
+
+    auto read_back_properties = LoadPersistentProperties();
+    EXPECT_GT(read_back_properties.size(), 0U);
+
+    auto it = std::find_if(
+        read_back_properties.begin(), read_back_properties.end(), [](const auto& entry) {
+            return entry.first == "persist.sys.locale" && entry.second == "pt-BR";
+        });
+    EXPECT_FALSE(it == read_back_properties.end());
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index fd14bd6..8f145cf 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -17,7 +17,6 @@
 #include "property_service.h"
 
 #include <ctype.h>
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -46,6 +45,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <bootimg.h>
 #include <fs_mgr.h>
@@ -54,20 +54,23 @@
 #include <selinux/selinux.h>
 
 #include "init.h"
+#include "persistent_properties.h"
 #include "util.h"
 
+using android::base::StringPrintf;
 using android::base::Timer;
 
-#define PERSISTENT_PROPERTY_DIR  "/data/property"
 #define RECOVERY_MOUNT_POINT "/recovery"
 
 namespace android {
 namespace init {
 
-static int persistent_properties_loaded = 0;
+static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
 
+static struct selabel_handle* sehandle_prop;
+
 void property_init() {
     if (__system_property_area_init()) {
         LOG(ERROR) << "Failed to initialize property area";
@@ -118,29 +121,6 @@
     return check_mac_perms(ctl_name, sctx, cr);
 }
 
-static void write_persistent_property(const char *name, const char *value)
-{
-    char tempPath[PATH_MAX];
-    char path[PATH_MAX];
-    int fd;
-
-    snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
-    fd = mkstemp(tempPath);
-    if (fd < 0) {
-        PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath;
-        return;
-    }
-    write(fd, value, strlen(value));
-    fsync(fd);
-    close(fd);
-
-    snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
-    if (rename(tempPath, path)) {
-        PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path;
-        unlink(tempPath);
-    }
-}
-
 bool is_legal_property_name(const std::string& name) {
     size_t namelen = name.size();
 
@@ -202,7 +182,7 @@
     // Don't write properties to disk until after we have read all default
     // properties to prevent them from being overwritten by default values.
     if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
-        write_persistent_property(name.c_str(), value.c_str());
+        WritePersistentProperty(name, value);
     }
     property_changed(name, value);
     return PROP_SUCCESS;
@@ -440,6 +420,20 @@
     }
   } else {
     if (check_mac_perms(name, source_ctx, &cr)) {
+      // sys.powerctl is a special property that is used to make the device reboot.  We want to log
+      // any process that sets this property to be able to accurately blame the cause of a shutdown.
+      if (name == "sys.powerctl") {
+        std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+        std::string process_cmdline;
+        std::string process_log_string;
+        if (android::base::ReadFileToString(cmdline_path, &process_cmdline)) {
+          // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
+          process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+        }
+        LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+                  << process_log_string;
+      }
+
       uint32_t result = property_set(name, value);
       if (!legacy_protocol) {
         socket.SendUint32(result);
@@ -586,73 +580,18 @@
 // "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
 static bool load_properties_from_file(const char* filename, const char* filter) {
     Timer t;
-    std::string data;
-    std::string err;
-    if (!ReadFile(filename, &data, &err)) {
-        PLOG(WARNING) << "Couldn't load property file: " << err;
+    auto file_contents = ReadFile(filename);
+    if (!file_contents) {
+        PLOG(WARNING) << "Couldn't load property file '" << filename
+                      << "': " << file_contents.error();
         return false;
     }
-    data.push_back('\n');
-    load_properties(&data[0], filter);
+    file_contents->push_back('\n');
+    load_properties(file_contents->data(), filter);
     LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
     return true;
 }
 
-static void load_persistent_properties() {
-    persistent_properties_loaded = 1;
-
-    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
-    if (!dir) {
-        PLOG(ERROR) << "Unable to open persistent property directory \""
-                    << PERSISTENT_PROPERTY_DIR << "\"";
-        return;
-    }
-
-    struct dirent* entry;
-    while ((entry = readdir(dir.get())) != NULL) {
-        if (strncmp("persist.", entry->d_name, strlen("persist."))) {
-            continue;
-        }
-        if (entry->d_type != DT_REG) {
-            continue;
-        }
-
-        // Open the file and read the property value.
-        int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
-        if (fd == -1) {
-            PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
-            continue;
-        }
-
-        struct stat sb;
-        if (fstat(fd, &sb) == -1) {
-            PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
-            close(fd);
-            continue;
-        }
-
-        // File must not be accessible to others, be owned by root/root, and
-        // not be a hard link to any other file.
-        if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) {
-            PLOG(ERROR) << "skipping insecure property file " << entry->d_name
-                        << " (uid=" << sb.st_uid << " gid=" << sb.st_gid
-                        << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")";
-            close(fd);
-            continue;
-        }
-
-        char value[PROP_VALUE_MAX];
-        int length = read(fd, value, sizeof(value) - 1);
-        if (length >= 0) {
-            value[length] = 0;
-            property_set(entry->d_name, value);
-        } else {
-            PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
-        }
-        close(fd);
-    }
-}
-
 // persist.sys.usb.config values can't be combined on build-time when property
 // files are split into each partition.
 // So we need to apply the same rule of build/make/tools/post_process_props.py
@@ -695,9 +634,24 @@
  * has mounted /data.
  */
 void load_persist_props(void) {
+    // Devices with FDE have load_persist_props called twice; the first time when the temporary
+    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
+    // read persistent properties from the temporary /data partition or mark persistent properties
+    // as having been loaded during the first call, so we return in that case.
+    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+    if (crypto_state == "encrypted" && crypto_type == "block") {
+        static size_t num_calls = 0;
+        if (++num_calls == 1) return;
+    }
+
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
-    load_persistent_properties();
+    auto persistent_properties = LoadPersistentProperties();
+    for (const auto& [name, value] : persistent_properties) {
+        property_set(name, value);
+    }
+    persistent_properties_loaded = true;
     property_set("ro.persistent_properties.ready", "true");
 }
 
@@ -740,11 +694,30 @@
     load_recovery_id_prop();
 }
 
+static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
+    property_audit_data* d = reinterpret_cast<property_audit_data*>(data);
+
+    if (!d || !d->name || !d->cr) {
+        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
+        return 0;
+    }
+
+    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
+             d->cr->gid);
+    return 0;
+}
+
 void start_property_service() {
+    sehandle_prop = selinux_android_prop_context_handle();
+
+    selinux_callback cb;
+    cb.func_audit = SelinuxAuditCallback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
     property_set("ro.property_service.version", "2");
 
     property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   false, 0666, 0, 0, nullptr, sehandle);
+                                   false, 0666, 0, 0, nullptr);
     if (property_set_fd == -1) {
         PLOG(ERROR) << "start_property_service socket creation failed";
         exit(1);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 17e3576..049c952 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -48,11 +48,13 @@
 #include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
+#include <selinux/selinux.h>
 
 #include "capabilities.h"
 #include "init.h"
 #include "property_service.h"
 #include "service.h"
+#include "sigchld_handler.h"
 
 using android::base::StringPrintf;
 using android::base::Timer;
@@ -167,9 +169,7 @@
                  << stat;
 }
 
-// Determines whether the system is capable of rebooting. This is conservative,
-// so if any of the attempts to determine this fail, it will still return true.
-static bool IsRebootCapable() {
+bool IsRebootCapable() {
     if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
         PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
         return true;
@@ -189,8 +189,7 @@
     return value == CAP_SET;
 }
 
-static void __attribute__((noreturn))
-RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
     LOG(INFO) << "Reboot ending, jumping to kernel";
 
     if (!IsRebootCapable()) {
@@ -214,7 +213,7 @@
             break;
     }
     // In normal case, reboot should not return.
-    PLOG(FATAL) << "reboot call returned";
+    PLOG(ERROR) << "reboot call returned";
     abort();
 }
 
@@ -265,8 +264,6 @@
 
 static UmountStat UmountPartitions(std::chrono::milliseconds timeout) {
     Timer t;
-    UmountStat stat = UMOUNT_STAT_TIMEOUT;
-    int retry = 0;
     /* data partition needs all pending writes to be completed and all emulated partitions
      * umounted.If the current waiting is not good enough, give
      * up and leave it to e2fsck after reboot to fix it.
@@ -278,25 +275,27 @@
             return UMOUNT_STAT_ERROR;
         }
         if (block_devices.size() == 0) {
-            stat = UMOUNT_STAT_SUCCESS;
-            break;
+            return UMOUNT_STAT_SUCCESS;
         }
-        if ((timeout < t.duration()) && retry > 0) {  // try umount at least once
-            stat = UMOUNT_STAT_TIMEOUT;
-            break;
+        bool unmount_done = true;
+        if (emulated_devices.size() > 0) {
+            unmount_done = std::all_of(emulated_devices.begin(), emulated_devices.end(),
+                                       [](auto& entry) { return entry.Umount(); });
+            if (unmount_done) {
+                sync();
+            }
         }
-        if (emulated_devices.size() > 0 &&
-            std::all_of(emulated_devices.begin(), emulated_devices.end(),
-                        [](auto& entry) { return entry.Umount(); })) {
-            sync();
+        unmount_done = std::all_of(block_devices.begin(), block_devices.end(),
+                                   [](auto& entry) { return entry.Umount(); }) &&
+                       unmount_done;
+        if (unmount_done) {
+            return UMOUNT_STAT_SUCCESS;
         }
-        for (auto& entry : block_devices) {
-            entry.Umount();
+        if ((timeout < t.duration())) {  // try umount at least once
+            return UMOUNT_STAT_TIMEOUT;
         }
-        retry++;
         std::this_thread::sleep_for(100ms);
     }
-    return stat;
 }
 
 static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
@@ -346,14 +345,10 @@
     Timer t;
     LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
 
-    android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
-                                     S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
+    property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str());
+    sync();
 
-    bool is_thermal_shutdown = false;
-    if (cmd == ANDROID_RB_THERMOFF) {
-        is_thermal_shutdown = true;
-        runFsck = false;
-    }
+    bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
 
     auto shutdown_timeout = 0ms;
     if (!SHUTDOWN_ZERO_TIMEOUT) {
@@ -373,23 +368,31 @@
     const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
     const std::set<std::string> to_starts{"watchdogd"};
-    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
+    for (const auto& s : ServiceList::GetInstance()) {
         if (kill_after_apps.count(s->name())) {
             s->SetShutdownCritical();
         } else if (to_starts.count(s->name())) {
-            s->Start();
+            if (auto result = s->Start(); !result) {
+                LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
+                           << "': " << result.error();
+            }
             s->SetShutdownCritical();
         } else if (s->IsShutdownCritical()) {
-            s->Start();  // start shutdown critical service if not started
+            // Start shutdown critical service if not started.
+            if (auto result = s->Start(); !result) {
+                LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
+                           << "': " << result.error();
+            }
         }
-    });
+    }
 
-    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
-    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
+    Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
+    Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
     if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
-        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
-            s->SetShutdownCritical();  // will not check animation class separately
-        });
+        // will not check animation class separately
+        for (const auto& service : ServiceList::GetInstance()) {
+            if (service->classnames().count("animation")) service->SetShutdownCritical();
+        }
     }
 
     // optional shutdown step
@@ -398,18 +401,18 @@
         LOG(INFO) << "terminating init services";
 
         // Ask all services to terminate except shutdown critical ones.
-        ServiceManager::GetInstance().ForEachService([](Service* s) {
+        for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
             if (!s->IsShutdownCritical()) s->Terminate();
-        });
+        }
 
         int service_count = 0;
         // Only wait up to half of timeout here
         auto termination_wait_timeout = shutdown_timeout / 2;
         while (t.duration() < termination_wait_timeout) {
-            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+            ReapAnyOutstandingChildren();
 
             service_count = 0;
-            ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
+            for (const auto& s : ServiceList::GetInstance()) {
                 // Count the number of services running except shutdown critical.
                 // Exclude the console as it will ignore the SIGTERM signal
                 // and not exit.
@@ -418,7 +421,7 @@
                 if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
                     service_count++;
                 }
-            });
+            }
 
             if (service_count == 0) {
                 // All terminable services terminated. We can exit early.
@@ -434,13 +437,13 @@
 
     // minimum safety steps before restarting
     // 2. kill all services except ones that are necessary for the shutdown sequence.
-    ServiceManager::GetInstance().ForEachService([](Service* s) {
+    for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
         if (!s->IsShutdownCritical()) s->Stop();
-    });
-    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+    }
+    ReapAnyOutstandingChildren();
 
     // 3. send volume shutdown to vold
-    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
+    Service* voldService = ServiceList::GetInstance().FindService("vold");
     if (voldService != nullptr && voldService->IsRunning()) {
         ShutdownVold();
         voldService->Stop();
@@ -448,9 +451,9 @@
         LOG(INFO) << "vold not running, skipping vold shutdown";
     }
     // logcat stopped here
-    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
+    for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
         if (kill_after_apps.count(s->name())) s->Stop();
-    });
+    }
     // 4. sync, try umount, and optionally run fsck for user shutdown
     sync();
     UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
@@ -474,10 +477,15 @@
         command_invalid = true;
     } else if (cmd_params[0] == "shutdown") {
         cmd = ANDROID_RB_POWEROFF;
-        if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
-            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
-            // Run fsck once the file system is remounted in read-only mode.
-            run_fsck = true;
+        if (cmd_params.size() == 2) {
+            if (cmd_params[1] == "userrequested") {
+                // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
+                // Run fsck once the file system is remounted in read-only mode.
+                run_fsck = true;
+            } else if (cmd_params[1] == "thermal") {
+                // run_fsck is false to avoid delay
+                cmd = ANDROID_RB_THERMOFF;
+            }
         }
     } else if (cmd_params[0] == "reboot") {
         cmd = ANDROID_RB_RESTART2;
@@ -493,14 +501,11 @@
                                << err;
                 }
             }
-            // If there is an additional bootloader parameter, pass it along
-            if (cmd_params.size() == 3) {
+            // If there is an additional parameter, pass it along
+            if ((cmd_params.size() == 3) && cmd_params[2].size()) {
                 reboot_target += "," + cmd_params[2];
             }
         }
-    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
-        // run_fsck is false to avoid delay
-        cmd = ANDROID_RB_THERMOFF;
     } else {
         command_invalid = true;
     }
@@ -517,16 +522,16 @@
     auto shutdown_handler = [cmd, command, reboot_target,
                              run_fsck](const std::vector<std::string>&) {
         DoReboot(cmd, command, reboot_target, run_fsck);
-        return 0;
+        return Success();
     };
     ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
 
     // Skip wait for prop if it is in progress
     ResetWaitForProp();
 
-    // Skip wait for exec if it is in progress
-    if (ServiceManager::GetInstance().IsWaitingForExec()) {
-        ServiceManager::GetInstance().ClearExecWait();
+    // Clear EXEC flag if there is one pending
+    for (const auto& s : ServiceList::GetInstance()) {
+        s->UnSetExec();
     }
 
     return true;
diff --git a/init/reboot.h b/init/reboot.h
index e559540..1c58bd1 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,9 +22,12 @@
 namespace android {
 namespace init {
 
+// This is a wrapper around the actual reboot calls.  DoReboot() should be preferred in most cases.
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget);
+
 /* Reboot / shutdown the system.
  * cmd ANDROID_RB_* as defined in android_reboot.h
- * reason Reason string like "reboot", "userrequested"
+ * reason Reason string like "reboot", "shutdown,userrequested"
  * rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
  *              empty string.
  * runFsck Whether to run fsck after umount is done.
@@ -35,6 +38,10 @@
 // Parses and handles a setprop sys.powerctl message.
 bool HandlePowerctlMessage(const std::string& command);
 
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+bool IsRebootCapable();
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/result.h b/init/result.h
new file mode 100644
index 0000000..36c3b83
--- /dev/null
+++ b/init/result.h
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+// This file contains classes for returning a successful result along with an optional
+// arbitrarily typed return value or for returning a failure result along with an optional string
+// indicating why the function failed.
+
+// There are 3 classes that implement this functionality and one additional helper type.
+//
+// Result<T> either contains a member of type T that can be accessed using similar semantics as
+// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
+// Result<T>::error().
+//
+// ResultError is a type that contains both a std::string describing the error and a copy of errno
+// from when the error occurred.  ResultError can be used in an ostream directly to print its
+// string value.
+//
+// Success is a typedef that aids in creating Result<T> that do not contain a return value.
+// Result<Success> is the correct return type for a function that either returns successfully or
+// returns an error value.  Returning Success() from a function that returns Result<Success> is the
+// correct way to indicate that a function without a return type has completed successfully.
+//
+// A successful Result<T> is constructed implicitly from any type that can be implicitly converted
+// to T or from the constructor arguments for T.  This allows you to return a type T directly from
+// a function that returns Result<T>.
+//
+// Error and ErrnoError are used to construct a Result<T> that has failed.  The Error class takes
+// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
+// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
+// to the end of the failure string to aid in interacting with C APIs.  Alternatively, an errno
+// value can be directly specified via the Error() constructor.
+//
+// ResultError can be used in the ostream when using Error to construct a Result<T>.  In this case,
+// the string that the ResultError takes is passed through the stream normally, but the errno is
+// passed to the Result<T>.  This can be used to pass errno from a failing C function up multiple
+// callers.
+//
+// ResultError can also directly construct a Result<T>.  This is particularly useful if you have a
+// function that return Result<T> but you have a Result<U> and want to return its error.  In this
+// case, you can return the .error() from the Result<U> to construct the Result<T>.
+
+// An example of how to use these is below:
+// Result<U> CalculateResult(const T& input) {
+//   U output;
+//   if (!SomeOtherCppFunction(input, &output)) {
+//     return Error() << "SomeOtherCppFunction(" << input << ") failed";
+//   }
+//   if (!c_api_function(output)) {
+//     return ErrnoError() << "c_api_function(" << output << ") failed";
+//   }
+//   return output;
+// }
+//
+// auto output = CalculateResult(input);
+// if (!output) return Error() << "CalculateResult failed: " << output.error();
+// UseOutput(*output);
+
+#ifndef _INIT_RESULT_H
+#define _INIT_RESULT_H
+
+#include <errno.h>
+
+#include <sstream>
+#include <string>
+#include <variant>
+
+namespace android {
+namespace init {
+
+struct ResultError {
+    template <typename T>
+    ResultError(T&& error_string, int error_errno)
+        : error_string(std::forward<T>(error_string)), error_errno(error_errno) {}
+
+    std::string error_string;
+    int error_errno;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
+    os << t.error_string;
+    return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, ResultError&& t) {
+    os << std::move(t.error_string);
+    return os;
+}
+
+class Error {
+  public:
+    Error() : errno_(0), append_errno_(false) {}
+    Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
+
+    template <typename T>
+    Error&& operator<<(T&& t) {
+        ss_ << std::forward<T>(t);
+        return std::move(*this);
+    }
+
+    Error&& operator<<(const ResultError& result_error) {
+        ss_ << result_error.error_string;
+        errno_ = result_error.error_errno;
+        return std::move(*this);
+    }
+
+    Error&& operator<<(ResultError&& result_error) {
+        ss_ << std::move(result_error.error_string);
+        errno_ = result_error.error_errno;
+        return std::move(*this);
+    }
+
+    const std::string str() const {
+        std::string str = ss_.str();
+        if (append_errno_) {
+            if (str.empty()) {
+                return strerror(errno_);
+            }
+            return str + ": " + strerror(errno_);
+        }
+        return str;
+    }
+
+    int get_errno() const { return errno_; }
+
+    Error(const Error&) = delete;
+    Error(Error&&) = delete;
+    Error& operator=(const Error&) = delete;
+    Error& operator=(Error&&) = delete;
+
+  private:
+    std::stringstream ss_;
+    int errno_;
+    bool append_errno_;
+};
+
+inline Error ErrnoError() {
+    return Error(errno);
+}
+
+template <typename T>
+class Result {
+  public:
+    template <typename... U>
+    Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
+
+    Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
+    Result(const ResultError& result_error)
+        : contents_(std::in_place_index_t<1>(), result_error.error_string,
+                    result_error.error_errno) {}
+    Result(ResultError&& result_error)
+        : contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
+                    result_error.error_errno) {}
+
+    bool has_value() const { return contents_.index() == 0; }
+
+    T& value() & { return std::get<0>(contents_); }
+    const T& value() const & { return std::get<0>(contents_); }
+    T&& value() && { return std::get<0>(std::move(contents_)); }
+    const T&& value() const && { return std::get<0>(std::move(contents_)); }
+
+    const ResultError& error() const & { return std::get<1>(contents_); }
+    ResultError&& error() && { return std::get<1>(std::move(contents_)); }
+    const ResultError&& error() const && { return std::get<1>(std::move(contents_)); }
+
+    const std::string& error_string() const & { return std::get<1>(contents_).error_string; }
+    std::string&& error_string() && { return std::get<1>(std::move(contents_)).error_string; }
+    const std::string&& error_string() const && {
+        return std::get<1>(std::move(contents_)).error_string;
+    }
+
+    int error_errno() const { return std::get<1>(contents_).error_errno; }
+
+    explicit operator bool() const { return has_value(); }
+
+    T& operator*() & { return value(); }
+    const T& operator*() const & { return value(); }
+    T&& operator*() && { return std::move(value()); }
+    const T&& operator*() const && { return std::move(value()); }
+
+    T* operator->() { return &value(); }
+    const T* operator->() const { return &value(); }
+
+  private:
+    std::variant<T, ResultError> contents_;
+};
+
+using Success = std::monostate;
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/result_test.cpp b/init/result_test.cpp
new file mode 100644
index 0000000..19caaf5
--- /dev/null
+++ b/init/result_test.cpp
@@ -0,0 +1,290 @@
+/*
+ * 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 "result.h"
+
+#include "errno.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+using namespace std::string_literals;
+
+namespace android {
+namespace init {
+
+TEST(result, result_accessors) {
+    Result<std::string> result = "success";
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+
+    EXPECT_EQ("success", *result);
+    EXPECT_EQ("success", result.value());
+
+    EXPECT_EQ('s', result->data()[0]);
+}
+
+TEST(result, result_accessors_rvalue) {
+    ASSERT_TRUE(Result<std::string>("success"));
+    ASSERT_TRUE(Result<std::string>("success").has_value());
+
+    EXPECT_EQ("success", *Result<std::string>("success"));
+    EXPECT_EQ("success", Result<std::string>("success").value());
+
+    EXPECT_EQ('s', Result<std::string>("success")->data()[0]);
+}
+
+TEST(result, result_success) {
+    Result<Success> result = Success();
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+
+    EXPECT_EQ(Success(), *result);
+    EXPECT_EQ(Success(), result.value());
+}
+
+TEST(result, result_success_rvalue) {
+    // Success() doesn't actually create a Result<Success> object, but rather an object that can be
+    // implicitly constructed into a Result<Success> object.
+
+    auto MakeRvalueSuccessResult = []() -> Result<Success> { return Success(); };
+    ASSERT_TRUE(MakeRvalueSuccessResult());
+    ASSERT_TRUE(MakeRvalueSuccessResult().has_value());
+
+    EXPECT_EQ(Success(), *MakeRvalueSuccessResult());
+    EXPECT_EQ(Success(), MakeRvalueSuccessResult().value());
+}
+
+TEST(result, result_error) {
+    Result<Success> result = Error() << "failure" << 1;
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ("failure1", result.error_string());
+}
+
+TEST(result, result_error_empty) {
+    Result<Success> result = Error();
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ("", result.error_string());
+}
+
+TEST(result, result_error_rvalue) {
+    // Error() and ErrnoError() aren't actually used to create a Result<T> object.
+    // Under the hood, they are an intermediate class that can be implicitly constructed into a
+    // Result<T>.  This is needed both to create the ostream and because Error() itself, by
+    // definition will not know what the type, T, of the underlying Result<T> object that it would
+    // create is.
+
+    auto MakeRvalueErrorResult = []() -> Result<Success> { return Error() << "failure" << 1; };
+    ASSERT_FALSE(MakeRvalueErrorResult());
+    ASSERT_FALSE(MakeRvalueErrorResult().has_value());
+
+    EXPECT_EQ(0, MakeRvalueErrorResult().error_errno());
+    EXPECT_EQ("failure1", MakeRvalueErrorResult().error_string());
+}
+
+TEST(result, result_errno_error) {
+    constexpr int test_errno = 6;
+    errno = test_errno;
+    Result<Success> result = ErrnoError() << "failure" << 1;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ("failure1: "s + strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_errno_error_no_text) {
+    constexpr int test_errno = 6;
+    errno = test_errno;
+    Result<Success> result = ErrnoError();
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ(strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_error_from_other_result) {
+    auto error_text = "test error"s;
+    Result<Success> result = Error() << error_text;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_error_through_ostream) {
+    auto error_text = "test error"s;
+    Result<Success> result = Error() << error_text;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = Error() << result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_errno_error_through_ostream) {
+    auto error_text = "test error"s;
+    constexpr int test_errno = 6;
+    errno = 6;
+    Result<Success> result = ErrnoError() << error_text;
+
+    errno = 0;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = Error() << result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ(error_text + ": " + strerror(test_errno), result.error_string());
+}
+
+TEST(result, constructor_forwarding) {
+    auto result = Result<std::string>(5, 'a');
+
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+
+    EXPECT_EQ("aaaaa", *result);
+}
+
+struct ConstructorTracker {
+    static size_t constructor_called;
+    static size_t copy_constructor_called;
+    static size_t move_constructor_called;
+    static size_t copy_assignment_called;
+    static size_t move_assignment_called;
+
+    template <typename T>
+    ConstructorTracker(T&& string) : string(string) {
+        ++constructor_called;
+    }
+
+    ConstructorTracker(const ConstructorTracker& ct) {
+        ++copy_constructor_called;
+        string = ct.string;
+    }
+    ConstructorTracker(ConstructorTracker&& ct) noexcept {
+        ++move_constructor_called;
+        string = std::move(ct.string);
+    }
+    ConstructorTracker& operator=(const ConstructorTracker& ct) {
+        ++copy_assignment_called;
+        string = ct.string;
+        return *this;
+    }
+    ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept {
+        ++move_assignment_called;
+        string = std::move(ct.string);
+        return *this;
+    }
+
+    std::string string;
+};
+
+size_t ConstructorTracker::constructor_called = 0;
+size_t ConstructorTracker::copy_constructor_called = 0;
+size_t ConstructorTracker::move_constructor_called = 0;
+size_t ConstructorTracker::copy_assignment_called = 0;
+size_t ConstructorTracker::move_assignment_called = 0;
+
+Result<ConstructorTracker> ReturnConstructorTracker(const std::string& in) {
+    if (in.empty()) {
+        return "literal string";
+    }
+    if (in == "test2") {
+        return ConstructorTracker(in + in + "2");
+    }
+    ConstructorTracker result(in + " " + in);
+    return result;
+};
+
+TEST(result, no_copy_on_return) {
+    // If returning parameters that may be used to implicitly construct the type T of Result<T>,
+    // then those parameters are forwarded to the construction of Result<T>.
+
+    // If returning an prvalue or xvalue, it will be move constructed during the construction of
+    // Result<T>.
+
+    // This check ensures that that is the case, and particularly that no copy constructors
+    // are called.
+
+    auto result1 = ReturnConstructorTracker("");
+    ASSERT_TRUE(result1);
+    EXPECT_EQ("literal string", result1->string);
+    EXPECT_EQ(1U, ConstructorTracker::constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
+    EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
+
+    auto result2 = ReturnConstructorTracker("test2");
+    ASSERT_TRUE(result2);
+    EXPECT_EQ("test2test22", result2->string);
+    EXPECT_EQ(2U, ConstructorTracker::constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
+    EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
+    EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
+
+    auto result3 = ReturnConstructorTracker("test3");
+    ASSERT_TRUE(result3);
+    EXPECT_EQ("test3 test3", result3->string);
+    EXPECT_EQ(3U, ConstructorTracker::constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
+    EXPECT_EQ(2U, ConstructorTracker::move_constructor_called);
+    EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
+    EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
+}
+
+TEST(result, die_on_access_failed_result) {
+    Result<std::string> result = Error();
+    ASSERT_DEATH(*result, "");
+}
+
+TEST(result, die_on_get_error_succesful_result) {
+    Result<std::string> result = "success";
+    ASSERT_DEATH(result.error_string(), "");
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/rlimit_parser.cpp b/init/rlimit_parser.cpp
new file mode 100644
index 0000000..fe1d6a7
--- /dev/null
+++ b/init/rlimit_parser.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "rlimit_parser.h"
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+using android::base::EqualsIgnoreCase;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::StartsWith;
+
+namespace android {
+namespace init {
+
+// Builtins and service definitions both have their arguments start at 1 and finish at 3.
+Result<std::pair<int, rlimit>> ParseRlimit(const std::vector<std::string>& args) {
+    static const std::vector<std::pair<const char*, int>> text_to_resources = {
+        {"cpu", 0},       {"fsize", 1}, {"data", 2},    {"stack", 3},
+        {"core", 4},      {"rss", 5},   {"nproc", 6},   {"nofile", 7},
+        {"memlock", 8},   {"as", 9},    {"locks", 10},  {"sigpending", 11},
+        {"msgqueue", 12}, {"nice", 13}, {"rtprio", 14}, {"rttime", 15},
+    };
+
+    int resource;
+
+    if (ParseInt(args[1], &resource)) {
+        if (resource >= RLIM_NLIMITS) {
+            return Error() << "Resource '" << args[1] << "' over the maximum resource value '"
+                           << RLIM_NLIMITS << "'";
+        } else if (resource < 0) {
+            return Error() << "Resource '" << args[1] << "' below the minimum resource value '0'";
+        }
+    } else {
+        std::string resource_string;
+        if (StartsWith(args[1], "RLIM_")) {
+            resource_string = args[1].substr(5);
+        } else {
+            resource_string = args[1];
+        }
+
+        auto it = std::find_if(text_to_resources.begin(), text_to_resources.end(),
+                               [&resource_string](const auto& entry) {
+                                   return EqualsIgnoreCase(resource_string, entry.first);
+                               });
+        if (it == text_to_resources.end()) {
+            return Error() << "Could not parse resource '" << args[1] << "'";
+        }
+
+        resource = it->second;
+    }
+
+    rlimit limit;
+    if (!ParseUint(args[2], &limit.rlim_cur)) {
+        return Error() << "Could not parse soft limit '" << args[2] << "'";
+    }
+    if (!ParseUint(args[3], &limit.rlim_max)) {
+        return Error() << "Could not parse hard limit '" << args[3] << "'";
+    }
+    return {resource, limit};
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/signal_handler.h b/init/rlimit_parser.h
similarity index 70%
copy from init/signal_handler.h
copy to init/rlimit_parser.h
index f7881ab..0396463 100644
--- a/init/signal_handler.h
+++ b/init/rlimit_parser.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,13 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_RLIMIT_PARSER_H
+#define _INIT_RLIMIT_PARSER_H
+
+#include <sys/resource.h>
+
+#include <string>
+#include <vector>
+
+#include "result.h"
 
 namespace android {
 namespace init {
 
-void signal_handler_init(void);
+Result<std::pair<int, rlimit>> ParseRlimit(const std::vector<std::string>& args);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/rlimit_parser_test.cpp b/init/rlimit_parser_test.cpp
new file mode 100644
index 0000000..f3f9eb4
--- /dev/null
+++ b/init/rlimit_parser_test.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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 "rlimit_parser.h"
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+void TestRlimitSuccess(std::vector<std::string> input,
+                       const std::pair<int, rlimit>& expected_result) {
+    input.emplace(input.begin(), "");
+    ASSERT_EQ(4U, input.size());
+    auto result = ParseRlimit(input);
+
+    ASSERT_TRUE(result) << "input: " << input[1];
+    const auto& [resource, rlimit] = *result;
+    const auto& [expected_resource, expected_rlimit] = expected_result;
+    EXPECT_EQ(expected_resource, resource);
+    EXPECT_EQ(expected_rlimit.rlim_cur, rlimit.rlim_cur);
+    EXPECT_EQ(expected_rlimit.rlim_max, rlimit.rlim_max);
+}
+
+void TestRlimitFailure(std::vector<std::string> input, const std::string& expected_result) {
+    input.emplace(input.begin(), "");
+    ASSERT_EQ(4U, input.size());
+    auto result = ParseRlimit(input);
+
+    ASSERT_FALSE(result) << "input: " << input[1];
+    EXPECT_EQ(expected_result, result.error_string());
+    EXPECT_EQ(0, result.error_errno());
+}
+
+TEST(rlimit, RlimitSuccess) {
+    const std::vector<std::pair<std::vector<std::string>, std::pair<int, rlimit>>>
+        inputs_and_results = {
+            {{"cpu", "10", "10"}, {0, {10, 10}}},
+            {{"fsize", "10", "10"}, {1, {10, 10}}},
+            {{"data", "10", "10"}, {2, {10, 10}}},
+            {{"stack", "10", "10"}, {3, {10, 10}}},
+            {{"core", "10", "10"}, {4, {10, 10}}},
+            {{"rss", "10", "10"}, {5, {10, 10}}},
+            {{"nproc", "10", "10"}, {6, {10, 10}}},
+            {{"nofile", "10", "10"}, {7, {10, 10}}},
+            {{"memlock", "10", "10"}, {8, {10, 10}}},
+            {{"as", "10", "10"}, {9, {10, 10}}},
+            {{"locks", "10", "10"}, {10, {10, 10}}},
+            {{"sigpending", "10", "10"}, {11, {10, 10}}},
+            {{"msgqueue", "10", "10"}, {12, {10, 10}}},
+            {{"nice", "10", "10"}, {13, {10, 10}}},
+            {{"rtprio", "10", "10"}, {14, {10, 10}}},
+            {{"rttime", "10", "10"}, {15, {10, 10}}},
+
+            {{"RLIM_CPU", "10", "10"}, {0, {10, 10}}},
+            {{"RLIM_FSIZE", "10", "10"}, {1, {10, 10}}},
+            {{"RLIM_DATA", "10", "10"}, {2, {10, 10}}},
+            {{"RLIM_STACK", "10", "10"}, {3, {10, 10}}},
+            {{"RLIM_CORE", "10", "10"}, {4, {10, 10}}},
+            {{"RLIM_RSS", "10", "10"}, {5, {10, 10}}},
+            {{"RLIM_NPROC", "10", "10"}, {6, {10, 10}}},
+            {{"RLIM_NOFILE", "10", "10"}, {7, {10, 10}}},
+            {{"RLIM_MEMLOCK", "10", "10"}, {8, {10, 10}}},
+            {{"RLIM_AS", "10", "10"}, {9, {10, 10}}},
+            {{"RLIM_LOCKS", "10", "10"}, {10, {10, 10}}},
+            {{"RLIM_SIGPENDING", "10", "10"}, {11, {10, 10}}},
+            {{"RLIM_MSGQUEUE", "10", "10"}, {12, {10, 10}}},
+            {{"RLIM_NICE", "10", "10"}, {13, {10, 10}}},
+            {{"RLIM_RTPRIO", "10", "10"}, {14, {10, 10}}},
+            {{"RLIM_RTTIME", "10", "10"}, {15, {10, 10}}},
+
+            {{"0", "10", "10"}, {0, {10, 10}}},
+            {{"1", "10", "10"}, {1, {10, 10}}},
+            {{"2", "10", "10"}, {2, {10, 10}}},
+            {{"3", "10", "10"}, {3, {10, 10}}},
+            {{"4", "10", "10"}, {4, {10, 10}}},
+            {{"5", "10", "10"}, {5, {10, 10}}},
+            {{"6", "10", "10"}, {6, {10, 10}}},
+            {{"7", "10", "10"}, {7, {10, 10}}},
+            {{"8", "10", "10"}, {8, {10, 10}}},
+            {{"9", "10", "10"}, {9, {10, 10}}},
+            {{"10", "10", "10"}, {10, {10, 10}}},
+            {{"11", "10", "10"}, {11, {10, 10}}},
+            {{"12", "10", "10"}, {12, {10, 10}}},
+            {{"13", "10", "10"}, {13, {10, 10}}},
+            {{"14", "10", "10"}, {14, {10, 10}}},
+            {{"15", "10", "10"}, {15, {10, 10}}},
+        };
+
+    for (const auto& [input, expected_result] : inputs_and_results) {
+        TestRlimitSuccess(input, expected_result);
+    }
+}
+
+TEST(rlimit, RlimitFailure) {
+    const std::vector<std::pair<std::vector<std::string>, std::string>> inputs_and_results = {
+        {{"-4", "10", "10"}, "Resource '-4' below the minimum resource value '0'"},
+        {{"100", "10", "10"}, "Resource '100' over the maximum resource value '16'"},
+        {{"bad_string", "10", "10"}, "Could not parse resource 'bad_string'"},
+        {{"RLIM_", "10", "10"}, "Could not parse resource 'RLIM_'"},
+        {{"cpu", "abc", "10"}, "Could not parse soft limit 'abc'"},
+        {{"cpu", "10", "abc"}, "Could not parse hard limit 'abc'"},
+    };
+
+    for (const auto& [input, expected_result] : inputs_and_results) {
+        TestRlimitFailure(input, expected_result);
+    }
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/security.cpp b/init/security.cpp
new file mode 100644
index 0000000..aac8f2e
--- /dev/null
+++ b/init/security.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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 "security.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+namespace android {
+namespace init {
+
+// Writes 512 bytes of output from Hardware RNG (/dev/hw_random, backed
+// by Linux kernel's hw_random framework) into Linux RNG's via /dev/urandom.
+// Does nothing if Hardware RNG is not present.
+//
+// Since we don't yet trust the quality of Hardware RNG, these bytes are not
+// mixed into the primary pool of Linux RNG and the entropy estimate is left
+// unmodified.
+//
+// If the HW RNG device /dev/hw_random is present, we require that at least
+// 512 bytes read from it are written into Linux RNG. QA is expected to catch
+// devices/configurations where these I/O operations are blocking for a long
+// time. We do not reboot or halt on failures, as this is a best-effort
+// attempt.
+Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) {
+    unique_fd hwrandom_fd(
+        TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
+    if (hwrandom_fd == -1) {
+        if (errno == ENOENT) {
+            LOG(INFO) << "/dev/hw_random not found";
+            // It's not an error to not have a Hardware RNG.
+            return Success();
+        }
+        return ErrnoError() << "Failed to open /dev/hw_random";
+    }
+
+    unique_fd urandom_fd(
+        TEMP_FAILURE_RETRY(open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC)));
+    if (urandom_fd == -1) {
+        return ErrnoError() << "Failed to open /dev/urandom";
+    }
+
+    char buf[512];
+    size_t total_bytes_written = 0;
+    while (total_bytes_written < sizeof(buf)) {
+        ssize_t chunk_size =
+            TEMP_FAILURE_RETRY(read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
+        if (chunk_size == -1) {
+            return ErrnoError() << "Failed to read from /dev/hw_random";
+        } else if (chunk_size == 0) {
+            return Error() << "Failed to read from /dev/hw_random: EOF";
+        }
+
+        chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
+        if (chunk_size == -1) {
+            return ErrnoError() << "Failed to write to /dev/urandom";
+        }
+        total_bytes_written += chunk_size;
+    }
+
+    LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
+    return Success();
+}
+
+static bool SetHighestAvailableOptionValue(std::string path, int min, int max) {
+    std::ifstream inf(path, std::fstream::in);
+    if (!inf) {
+        LOG(ERROR) << "Cannot open for reading: " << path;
+        return false;
+    }
+
+    int current = max;
+    while (current >= min) {
+        // try to write out new value
+        std::string str_val = std::to_string(current);
+        std::ofstream of(path, std::fstream::out);
+        if (!of) {
+            LOG(ERROR) << "Cannot open for writing: " << path;
+            return false;
+        }
+        of << str_val << std::endl;
+        of.close();
+
+        // check to make sure it was recorded
+        inf.seekg(0);
+        std::string str_rec;
+        inf >> str_rec;
+        if (str_val.compare(str_rec) == 0) {
+            break;
+        }
+        current--;
+    }
+    inf.close();
+
+    if (current < min) {
+        LOG(ERROR) << "Unable to set minimum option value " << min << " in " << path;
+        return false;
+    }
+    return true;
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+// __attribute__((unused)) due to lack of mips support: see mips block in SetMmapRndBitsAction
+static bool __attribute__((unused)) SetMmapRndBitsMin(int start, int min, bool compat) {
+    std::string path;
+    if (compat) {
+        path = MMAP_RND_COMPAT_PATH;
+    } else {
+        path = MMAP_RND_PATH;
+    }
+
+    return SetHighestAvailableOptionValue(path, min, start);
+}
+
+// Set /proc/sys/vm/mmap_rnd_bits and potentially
+// /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+// Returns -1 if unable to set these to an acceptable value.
+//
+// To support this sysctl, the following upstream commits are needed:
+//
+// d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
+// e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
+// 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
+// 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
+// ec9ee4acd97c drivers: char: random: add get_random_long()
+// 5ef11c35ce86 mm: ASLR: use get_random_long()
+Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args) {
+// values are arch-dependent
+#if defined(USER_MODE_LINUX)
+    // uml does not support mmap_rnd_bits
+    return Success();
+#elif defined(__aarch64__)
+    // arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE
+    if (SetMmapRndBitsMin(33, 24, false) && SetMmapRndBitsMin(16, 16, true)) {
+        return Success();
+    }
+#elif defined(__x86_64__)
+    // x86_64 supports 28 - 32 bits
+    if (SetMmapRndBitsMin(32, 32, false) && SetMmapRndBitsMin(16, 16, true)) {
+        return Success();
+    }
+#elif defined(__arm__) || defined(__i386__)
+    // check to see if we're running on 64-bit kernel
+    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+    // supported 32-bit architecture must have 16 bits set
+    if (SetMmapRndBitsMin(16, 16, h64)) {
+        return Success();
+    }
+#elif defined(__mips__) || defined(__mips64__)
+    // TODO: add mips support b/27788820
+    return Success();
+#else
+    LOG(ERROR) << "Unknown architecture";
+#endif
+
+    LOG(FATAL) << "Unable to set adequate mmap entropy value!";
+    return Error();
+}
+
+#define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
+#define KPTR_RESTRICT_MINVALUE 2
+#define KPTR_RESTRICT_MAXVALUE 4
+
+// Set kptr_restrict to the highest available level.
+//
+// Aborts if unable to set this to an acceptable value.
+Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args) {
+    std::string path = KPTR_RESTRICT_PATH;
+
+    if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
+        LOG(FATAL) << "Unable to set adequate kptr_restrict value!";
+        return Error();
+    }
+    return Success();
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/signal_handler.h b/init/security.h
similarity index 62%
copy from init/signal_handler.h
copy to init/security.h
index f7881ab..31e5790 100644
--- a/init/signal_handler.h
+++ b/init/security.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,13 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_SECURITY_H
+#define _INIT_SECURITY_H
+
+#include <string>
+#include <vector>
+
+#include "result.h"
 
 namespace android {
 namespace init {
 
-void signal_handler_init(void);
+Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args);
+Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args);
+Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/selinux.cpp b/init/selinux.cpp
new file mode 100644
index 0000000..aefec14
--- /dev/null
+++ b/init/selinux.cpp
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ */
+
+// This file contains the functions that initialize SELinux during boot as well as helper functions
+// for SELinux operation for init.
+
+// When the system boots, there is no SEPolicy present and init is running in the kernel domain.
+// Init loads the SEPolicy from the file system, restores the context of /init based on this
+// SEPolicy, and finally exec()'s itself to run in the proper domain.
+
+// The SEPolicy on Android comes in two variants: monolithic and split.
+
+// The monolithic policy variant is for legacy non-treble devices that contain a single SEPolicy
+// file located at /sepolicy and is directly loaded into the kernel SELinux subsystem.
+
+// The split policy is for supporting treble devices.  It splits the SEPolicy across files on
+// /system/etc/selinux (the 'plat' portion of the policy) and /vendor/etc/selinux (the 'nonplat'
+// portion of the policy).  This is necessary to allow the system image to be updated independently
+// of the vendor image, while maintaining contributions from both partitions in the SEPolicy.  This
+// is especially important for VTS testing, where the SEPolicy on the Google System Image may not be
+// identical to the system image shipped on a vendor's device.
+
+// The split SEPolicy is loaded as described below:
+// 1) There is a precompiled SEPolicy located at /vendor/etc/selinux/precompiled_sepolicy.
+//    Stored along with this file is the sha256 hash of the parts of the SEPolicy on /system that
+//    were used to compile this precompiled policy.  The system partition contains a similar sha256
+//    of the parts of the SEPolicy that it currently contains.  If these two hashes match, then the
+//    system loads this precompiled_sepolicy directly.
+// 2) If these hashes do not match, then /system has been updated out of sync with /vendor and the
+//    init needs to compile the SEPolicy.  /system contains the SEPolicy compiler, secilc, and it
+//    is used by the LoadSplitPolicy() function below to compile the SEPolicy to a temp directory
+//    and load it.  That function contains even more documentation with the specific implementation
+//    details of how the SEPolicy is compiled if needed.
+
+#include "selinux.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <selinux/android.h>
+
+#include "log.h"
+#include "util.h"
+
+using android::base::Timer;
+using android::base::unique_fd;
+
+namespace android {
+namespace init {
+
+namespace {
+
+selabel_handle* sehandle = nullptr;
+
+enum EnforcingStatus { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
+
+EnforcingStatus StatusFromCmdline() {
+    EnforcingStatus status = SELINUX_ENFORCING;
+
+    import_kernel_cmdline(false,
+                          [&](const std::string& key, const std::string& value, bool in_qemu) {
+                              if (key == "androidboot.selinux" && value == "permissive") {
+                                  status = SELINUX_PERMISSIVE;
+                              }
+                          });
+
+    return status;
+}
+
+bool IsEnforcing() {
+    if (ALLOW_PERMISSIVE_SELINUX) {
+        return StatusFromCmdline() == SELINUX_ENFORCING;
+    }
+    return true;
+}
+
+// Forks, executes the provided program in the child, and waits for the completion in the parent.
+// Child's stderr is captured and logged using LOG(ERROR).
+bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) {
+    // Create a pipe used for redirecting child process's output.
+    // * pipe_fds[0] is the FD the parent will use for reading.
+    // * pipe_fds[1] is the FD the child will use for writing.
+    int pipe_fds[2];
+    if (pipe(pipe_fds) == -1) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    pid_t child_pid = fork();
+    if (child_pid == -1) {
+        PLOG(ERROR) << "Failed to fork for " << filename;
+        return false;
+    }
+
+    if (child_pid == 0) {
+        // fork succeeded -- this is executing in the child process
+
+        // Close the pipe FD not used by this process
+        TEMP_FAILURE_RETRY(close(pipe_fds[0]));
+
+        // Redirect stderr to the pipe FD provided by the parent
+        if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
+            PLOG(ERROR) << "Failed to redirect stderr of " << filename;
+            _exit(127);
+            return false;
+        }
+        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
+        if (execv(filename, argv) == -1) {
+            PLOG(ERROR) << "Failed to execve " << filename;
+            return false;
+        }
+        // Unreachable because execve will have succeeded and replaced this code
+        // with child process's code.
+        _exit(127);
+        return false;
+    } else {
+        // fork succeeded -- this is executing in the original/parent process
+
+        // Close the pipe FD not used by this process
+        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
+        // Log the redirected output of the child process.
+        // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
+        // As a result, we're buffering all output and logging it in one go at the end of the
+        // invocation, instead of logging it as it comes in.
+        const int child_out_fd = pipe_fds[0];
+        std::string child_output;
+        if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
+            PLOG(ERROR) << "Failed to capture full output of " << filename;
+        }
+        TEMP_FAILURE_RETRY(close(child_out_fd));
+        if (!child_output.empty()) {
+            // Log captured output, line by line, because LOG expects to be invoked for each line
+            std::istringstream in(child_output);
+            std::string line;
+            while (std::getline(in, line)) {
+                LOG(ERROR) << filename << ": " << line;
+            }
+        }
+
+        // Wait for child to terminate
+        int status;
+        if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
+            PLOG(ERROR) << "Failed to wait for " << filename;
+            return false;
+        }
+
+        if (WIFEXITED(status)) {
+            int status_code = WEXITSTATUS(status);
+            if (status_code == 0) {
+                return true;
+            } else {
+                LOG(ERROR) << filename << " exited with status " << status_code;
+            }
+        } else if (WIFSIGNALED(status)) {
+            LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
+        } else if (WIFSTOPPED(status)) {
+            LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
+        } else {
+            LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
+        }
+
+        return false;
+    }
+}
+
+bool ReadFirstLine(const char* file, std::string* line) {
+    line->clear();
+
+    std::string contents;
+    if (!android::base::ReadFileToString(file, &contents, true /* follow symlinks */)) {
+        return false;
+    }
+    std::istringstream in(contents);
+    std::getline(in, *line);
+    return true;
+}
+
+bool FindPrecompiledSplitPolicy(std::string* file) {
+    file->clear();
+    // If there is an odm partition, precompiled_sepolicy will be in
+    // odm/etc/selinux. Otherwise it will be in vendor/etc/selinux.
+    static constexpr const char vendor_precompiled_sepolicy[] =
+        "/vendor/etc/selinux/precompiled_sepolicy";
+    static constexpr const char odm_precompiled_sepolicy[] =
+        "/odm/etc/selinux/precompiled_sepolicy";
+    if (access(odm_precompiled_sepolicy, R_OK) == 0) {
+        *file = odm_precompiled_sepolicy;
+    } else if (access(vendor_precompiled_sepolicy, R_OK) == 0) {
+        *file = vendor_precompiled_sepolicy;
+    } else {
+        PLOG(INFO) << "No precompiled sepolicy";
+        return false;
+    }
+    std::string actual_plat_id;
+    if (!ReadFirstLine("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256", &actual_plat_id)) {
+        PLOG(INFO) << "Failed to read "
+                      "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
+        return false;
+    }
+
+    std::string precompiled_plat_id;
+    std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256";
+    if (!ReadFirstLine(precompiled_sha256.c_str(), &precompiled_plat_id)) {
+        PLOG(INFO) << "Failed to read " << precompiled_sha256;
+        file->clear();
+        return false;
+    }
+    if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
+        file->clear();
+        return false;
+    }
+    return true;
+}
+
+bool GetVendorMappingVersion(std::string* plat_vers) {
+    if (!ReadFirstLine("/vendor/etc/selinux/plat_sepolicy_vers.txt", plat_vers)) {
+        PLOG(ERROR) << "Failed to read /vendor/etc/selinux/plat_sepolicy_vers.txt";
+        return false;
+    }
+    if (plat_vers->empty()) {
+        LOG(ERROR) << "No version present in plat_sepolicy_vers.txt";
+        return false;
+    }
+    return true;
+}
+
+constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
+
+bool IsSplitPolicyDevice() {
+    return access(plat_policy_cil_file, R_OK) != -1;
+}
+
+bool LoadSplitPolicy() {
+    // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
+    // * platform -- policy needed due to logic contained in the system image,
+    // * non-platform -- policy needed due to logic contained in the vendor image,
+    // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
+    //   with newer versions of platform policy.
+    //
+    // secilc is invoked to compile the above three policy files into a single monolithic policy
+    // file. This file is then loaded into the kernel.
+
+    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
+    // must match the platform policy on the system image.
+    std::string precompiled_sepolicy_file;
+    if (FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
+        unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
+        if (fd != -1) {
+            if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
+                LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
+                return false;
+            }
+            return true;
+        }
+    }
+    // No suitable precompiled policy could be loaded
+
+    LOG(INFO) << "Compiling SELinux policy";
+
+    // Determine the highest policy language version supported by the kernel
+    set_selinuxmnt("/sys/fs/selinux");
+    int max_policy_version = security_policyvers();
+    if (max_policy_version == -1) {
+        PLOG(ERROR) << "Failed to determine highest policy version supported by kernel";
+        return false;
+    }
+
+    // We store the output of the compilation on /dev because this is the most convenient tmpfs
+    // storage mount available this early in the boot sequence.
+    char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
+    unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
+    if (compiled_sepolicy_fd < 0) {
+        PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
+        return false;
+    }
+
+    // Determine which mapping file to include
+    std::string vend_plat_vers;
+    if (!GetVendorMappingVersion(&vend_plat_vers)) {
+        return false;
+    }
+    std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
+
+    // vendor_sepolicy.cil and nonplat_declaration.cil are the new design to replace
+    // nonplat_sepolicy.cil.
+    std::string nonplat_declaration_cil_file("/vendor/etc/selinux/nonplat_declaration.cil");
+    std::string vendor_policy_cil_file("/vendor/etc/selinux/vendor_sepolicy.cil");
+
+    if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) {
+        // For backward compatibility.
+        // TODO: remove this after no device is using nonplat_sepolicy.cil.
+        vendor_policy_cil_file = "/vendor/etc/selinux/nonplat_sepolicy.cil";
+        nonplat_declaration_cil_file.clear();
+    } else if (access(nonplat_declaration_cil_file.c_str(), F_OK) == -1) {
+        LOG(ERROR) << "Missing " << nonplat_declaration_cil_file;
+        return false;
+    }
+
+    // odm_sepolicy.cil is default but optional.
+    std::string odm_policy_cil_file("/odm/etc/selinux/odm_sepolicy.cil");
+    if (access(odm_policy_cil_file.c_str(), F_OK) == -1) {
+        odm_policy_cil_file.clear();
+    }
+    const std::string version_as_string = std::to_string(max_policy_version);
+
+    // clang-format off
+    std::vector<const char*> compile_args {
+        "/system/bin/secilc",
+        plat_policy_cil_file,
+        "-M", "true", "-G", "-N",
+        // Target the highest policy language version supported by the kernel
+        "-c", version_as_string.c_str(),
+        mapping_file.c_str(),
+        "-o", compiled_sepolicy,
+        // We don't care about file_contexts output by the compiler
+        "-f", "/sys/fs/selinux/null",  // /dev/null is not yet available
+    };
+    // clang-format on
+
+    if (!nonplat_declaration_cil_file.empty()) {
+        compile_args.push_back(nonplat_declaration_cil_file.c_str());
+    }
+    if (!vendor_policy_cil_file.empty()) {
+        compile_args.push_back(vendor_policy_cil_file.c_str());
+    }
+    if (!odm_policy_cil_file.empty()) {
+        compile_args.push_back(odm_policy_cil_file.c_str());
+    }
+    compile_args.push_back(nullptr);
+
+    if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) {
+        unlink(compiled_sepolicy);
+        return false;
+    }
+    unlink(compiled_sepolicy);
+
+    LOG(INFO) << "Loading compiled SELinux policy";
+    if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) {
+        LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy;
+        return false;
+    }
+
+    return true;
+}
+
+bool LoadMonolithicPolicy() {
+    LOG(VERBOSE) << "Loading SELinux policy from monolithic file";
+    if (selinux_android_load_policy() < 0) {
+        PLOG(ERROR) << "Failed to load monolithic SELinux policy";
+        return false;
+    }
+    return true;
+}
+
+bool LoadPolicy() {
+    return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
+}
+
+}  // namespace
+
+void SelinuxInitialize() {
+    Timer t;
+
+    LOG(INFO) << "Loading SELinux policy";
+    if (!LoadPolicy()) {
+        LOG(FATAL) << "Unable to load SELinux policy";
+    }
+
+    bool kernel_enforcing = (security_getenforce() == 1);
+    bool is_enforcing = IsEnforcing();
+    if (kernel_enforcing != is_enforcing) {
+        if (security_setenforce(is_enforcing)) {
+            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
+        }
+    }
+
+    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
+        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
+    }
+
+    // init's first stage can't set properties, so pass the time to the second stage.
+    setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
+}
+
+// The files and directories that were created before initial sepolicy load or
+// files on ramdisk need to have their security context restored to the proper
+// value. This must happen before /dev is populated by ueventd.
+void SelinuxRestoreContext() {
+    LOG(INFO) << "Running restorecon...";
+    selinux_android_restorecon("/dev", 0);
+    selinux_android_restorecon("/dev/kmsg", 0);
+    if constexpr (WORLD_WRITABLE_KMSG) {
+        selinux_android_restorecon("/dev/kmsg_debug", 0);
+    }
+    selinux_android_restorecon("/dev/socket", 0);
+    selinux_android_restorecon("/dev/random", 0);
+    selinux_android_restorecon("/dev/urandom", 0);
+    selinux_android_restorecon("/dev/__properties__", 0);
+
+    selinux_android_restorecon("/plat_file_contexts", 0);
+    selinux_android_restorecon("/nonplat_file_contexts", 0);
+    selinux_android_restorecon("/plat_property_contexts", 0);
+    selinux_android_restorecon("/nonplat_property_contexts", 0);
+    selinux_android_restorecon("/plat_seapp_contexts", 0);
+    selinux_android_restorecon("/nonplat_seapp_contexts", 0);
+    selinux_android_restorecon("/plat_service_contexts", 0);
+    selinux_android_restorecon("/nonplat_service_contexts", 0);
+    selinux_android_restorecon("/plat_hwservice_contexts", 0);
+    selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
+    selinux_android_restorecon("/sepolicy", 0);
+    selinux_android_restorecon("/vndservice_contexts", 0);
+
+    selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+    selinux_android_restorecon("/dev/device-mapper", 0);
+
+    selinux_android_restorecon("/sbin/mke2fs_static", 0);
+    selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
+}
+
+// This function sets up SELinux logging to be written to kmsg, to match init's logging.
+void SelinuxSetupKernelLogging() {
+    selinux_callback cb;
+    cb.func_log = selinux_klog_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+}
+
+// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
+// its value.  selinux_android_restorecon() also needs an sehandle for file context look up.  It
+// will create and store its own copy, but selinux_android_set_sehandle() can be used to provide
+// one, thus eliminating an extra call to selinux_android_file_context_handle().
+void SelabelInitialize() {
+    sehandle = selinux_android_file_context_handle();
+    selinux_android_set_sehandle(sehandle);
+}
+
+// A C++ wrapper around selabel_lookup() using the cached sehandle.
+// If sehandle is null, this returns success with an empty context.
+bool SelabelLookupFileContext(const std::string& key, int type, std::string* result) {
+    result->clear();
+
+    if (!sehandle) return true;
+
+    char* context;
+    if (selabel_lookup(sehandle, &context, key.c_str(), type) != 0) {
+        return false;
+    }
+    *result = context;
+    free(context);
+    return true;
+}
+
+// A C++ wrapper around selabel_lookup_best_match() using the cached sehandle.
+// If sehandle is null, this returns success with an empty context.
+bool SelabelLookupFileContextBestMatch(const std::string& key,
+                                       const std::vector<std::string>& aliases, int type,
+                                       std::string* result) {
+    result->clear();
+
+    if (!sehandle) return true;
+
+    std::vector<const char*> c_aliases;
+    for (const auto& alias : aliases) {
+        c_aliases.emplace_back(alias.c_str());
+    }
+    c_aliases.emplace_back(nullptr);
+
+    char* context;
+    if (selabel_lookup_best_match(sehandle, &context, key.c_str(), &c_aliases[0], type) != 0) {
+        return false;
+    }
+    *result = context;
+    free(context);
+    return true;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/selinux.h b/init/selinux.h
new file mode 100644
index 0000000..7b880ec
--- /dev/null
+++ b/init/selinux.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _INIT_SELINUX_H
+#define _INIT_SELINUX_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace init {
+
+void SelinuxInitialize();
+void SelinuxRestoreContext();
+
+void SelinuxSetupKernelLogging();
+
+void SelabelInitialize();
+bool SelabelLookupFileContext(const std::string& key, int type, std::string* result);
+bool SelabelLookupFileContextBestMatch(const std::string& key,
+                                       const std::vector<std::string>& aliases, int type,
+                                       std::string* result);
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/service.cpp b/init/service.cpp
index fe38ee2..6f27a4b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -43,6 +43,7 @@
 
 #include "init.h"
 #include "property_service.h"
+#include "rlimit_parser.h"
 #include "util.h"
 
 using android::base::boot_clock;
@@ -57,22 +58,20 @@
 namespace android {
 namespace init {
 
-static std::string ComputeContextFromExecutable(std::string& service_name,
-                                                const std::string& service_path) {
+static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
+                                                        const std::string& service_path) {
     std::string computed_context;
 
     char* raw_con = nullptr;
     char* raw_filecon = nullptr;
 
     if (getcon(&raw_con) == -1) {
-        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get security context";
     }
     std::unique_ptr<char> mycon(raw_con);
 
     if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
-        LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get file context";
     }
     std::unique_ptr<char> filecon(raw_filecon);
 
@@ -84,12 +83,14 @@
         free(new_con);
     }
     if (rc == 0 && computed_context == mycon.get()) {
-        LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
-        return "";
+        return Error() << "File " << service_path << "(labeled \"" << filecon.get()
+                       << "\") has incorrect label or no domain transition from " << mycon.get()
+                       << " to another SELinux domain defined. Have you configured your "
+                          "service correctly? https://source.android.com/security/selinux/"
+                          "device-policy#label_new_services_and_address_denials";
     }
     if (rc < 0) {
-        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get process context";
     }
     return computed_context;
 }
@@ -147,36 +148,11 @@
     strs->push_back(nullptr);
 }
 
-ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
-}
-
-ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
-                                               const std::string& value)
-    : name(name), value(value) {
-}
+unsigned long Service::next_start_order_ = 1;
+bool Service::is_exec_service_running_ = false;
 
 Service::Service(const std::string& name, const std::vector<std::string>& args)
-    : name_(name),
-      classnames_({"default"}),
-      flags_(0),
-      pid_(0),
-      crash_count_(0),
-      uid_(0),
-      gid_(0),
-      namespace_flags_(0),
-      seclabel_(""),
-      onrestart_(false, "<Service '" + name + "' onrestart>", 0),
-      keychord_id_(0),
-      ioprio_class_(IoSchedClass_NONE),
-      ioprio_pri_(0),
-      priority_(0),
-      oom_score_adjust_(-1000),
-      swappiness_(-1),
-      soft_limit_in_bytes_(-1),
-      limit_in_bytes_(-1),
-      args_(args) {
-    onrestart_.InitSingleTrigger("onrestart");
-}
+    : Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
 
 Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
                  const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
@@ -202,6 +178,7 @@
       swappiness_(-1),
       soft_limit_in_bytes_(-1),
       limit_in_bytes_(-1),
+      start_order_(0),
       args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
@@ -217,7 +194,10 @@
 
     if (new_state == "running") {
         uint64_t start_ns = time_started_.time_since_epoch().count();
-        property_set("ro.boottime." + name_, std::to_string(start_ns));
+        std::string boottime_property = "ro.boottime." + name_;
+        if (GetProperty(boottime_property, "").empty()) {
+            property_set(boottime_property, std::to_string(start_ns));
+        }
     }
 }
 
@@ -241,6 +221,12 @@
 }
 
 void Service::SetProcessAttributes() {
+    for (const auto& rlimit : rlimits_) {
+        if (setrlimit(rlimit.first, &rlimit.second) == -1) {
+            LOG(FATAL) << StringPrintf("setrlimit(%d, {rlim_cur=%ld, rlim_max=%ld}) failed",
+                                       rlimit.first, rlimit.second.rlim_cur, rlimit.second.rlim_max);
+        }
+    }
     // Keep capabilites on uid change.
     if (capabilities_.any() && uid_) {
         // If Android is running in a container, some securebits might already
@@ -297,12 +283,13 @@
     std::for_each(descriptors_.begin(), descriptors_.end(),
                   std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
 
-    if (flags_ & SVC_TEMPORARY) {
-        return;
-    }
+    if (flags_ & SVC_EXEC) UnSetExec();
+
+    if (flags_ & SVC_TEMPORARY) return;
 
     pid_ = 0;
     flags_ &= (~SVC_RUNNING);
+    start_order_ = 0;
 
     // Oneshot processes go into the disabled state on exit,
     // except when manually restarted.
@@ -321,8 +308,7 @@
     if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
             if (++crash_count_ > 4) {
-                LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
-                panic();
+                LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
             }
         } else {
             time_crashed_ = now;
@@ -348,12 +334,12 @@
                   [] (const auto& info) { LOG(INFO) << *info; });
 }
 
-bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseCapabilities(const std::vector<std::string>& args) {
     capabilities_ = 0;
 
     if (!CapAmbientSupported()) {
-        *err = "capabilities requested but the kernel does not support ambient capabilities";
-        return false;
+        return Error()
+               << "capabilities requested but the kernel does not support ambient capabilities";
     }
 
     unsigned int last_valid_cap = GetLastValidCap();
@@ -365,74 +351,71 @@
         const std::string& arg = args[i];
         int res = LookupCap(arg);
         if (res < 0) {
-            *err = StringPrintf("invalid capability '%s'", arg.c_str());
-            return false;
+            return Error() << StringPrintf("invalid capability '%s'", arg.c_str());
         }
         unsigned int cap = static_cast<unsigned int>(res);  // |res| is >= 0.
         if (cap > last_valid_cap) {
-            *err = StringPrintf("capability '%s' not supported by the kernel", arg.c_str());
-            return false;
+            return Error() << StringPrintf("capability '%s' not supported by the kernel",
+                                           arg.c_str());
         }
         capabilities_[cap] = true;
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseClass(const std::vector<std::string>& args) {
     classnames_ = std::set<std::string>(args.begin() + 1, args.end());
-    return true;
+    return Success();
 }
 
-bool Service::ParseConsole(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseConsole(const std::vector<std::string>& args) {
     flags_ |= SVC_CONSOLE;
     console_ = args.size() > 1 ? "/dev/" + args[1] : "";
-    return true;
+    return Success();
 }
 
-bool Service::ParseCritical(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseCritical(const std::vector<std::string>& args) {
     flags_ |= SVC_CRITICAL;
-    return true;
+    return Success();
 }
 
-bool Service::ParseDisabled(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseDisabled(const std::vector<std::string>& args) {
     flags_ |= SVC_DISABLED;
     flags_ |= SVC_RC_DISABLED;
-    return true;
+    return Success();
 }
 
-bool Service::ParseGroup(const std::vector<std::string>& args, std::string* err) {
-    std::string decode_uid_err;
-    if (!DecodeUid(args[1], &gid_, &decode_uid_err)) {
-        *err = "Unable to find GID for '" + args[1] + "': " + decode_uid_err;
-        return false;
+Result<Success> Service::ParseGroup(const std::vector<std::string>& args) {
+    auto gid = DecodeUid(args[1]);
+    if (!gid) {
+        return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
     }
+    gid_ = *gid;
+
     for (std::size_t n = 2; n < args.size(); n++) {
-        gid_t gid;
-        if (!DecodeUid(args[n], &gid, &decode_uid_err)) {
-            *err = "Unable to find GID for '" + args[n] + "': " + decode_uid_err;
-            return false;
+        gid = DecodeUid(args[n]);
+        if (!gid) {
+            return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
         }
-        supp_gids_.emplace_back(gid);
+        supp_gids_.emplace_back(*gid);
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParsePriority(const std::vector<std::string>& args) {
     priority_ = 0;
     if (!ParseInt(args[1], &priority_,
                   static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
                   static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
-        *err = StringPrintf("process priority value must be range %d - %d",
-                ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
-        return false;
+        return Error() << StringPrintf("process priority value must be range %d - %d",
+                                       ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseIoprio(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
     if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
-        *err = "priority value must be range 0 - 7";
-        return false;
+        return Error() << "priority value must be range 0 - 7";
     }
 
     if (args[1] == "rt") {
@@ -442,14 +425,13 @@
     } else if (args[1] == "idle") {
         ioprio_class_ = IoSchedClass_IDLE;
     } else {
-        *err = "ioprio option usage: ioprio <rt|be|idle> <0-7>";
-        return false;
+        return Error() << "ioprio option usage: ioprio <rt|be|idle> <0-7>";
     }
 
-    return true;
+    return Success();
 }
 
-bool Service::ParseKeycodes(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseKeycodes(const std::vector<std::string>& args) {
     for (std::size_t i = 1; i < args.size(); i++) {
         int code;
         if (ParseInt(args[i], &code)) {
@@ -458,22 +440,24 @@
             LOG(WARNING) << "ignoring invalid keycode: " << args[i];
         }
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseOneshot(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseOneshot(const std::vector<std::string>& args) {
     flags_ |= SVC_ONESHOT;
-    return true;
+    return Success();
 }
 
-bool Service::ParseOnrestart(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseOnrestart(const std::vector<std::string>& args) {
     std::vector<std::string> str_args(args.begin() + 1, args.end());
     int line = onrestart_.NumCommands() + 1;
-    onrestart_.AddCommand(str_args, line, err);
-    return true;
+    if (auto result = onrestart_.AddCommand(str_args, line); !result) {
+        return Error() << "cannot add Onrestart command: " << result.error();
+    }
+    return Success();
 }
 
-bool Service::ParseNamespace(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseNamespace(const std::vector<std::string>& args) {
     for (size_t i = 1; i < args.size(); i++) {
         if (args[i] == "pid") {
             namespace_flags_ |= CLONE_NEWPID;
@@ -482,135 +466,133 @@
         } else if (args[i] == "mnt") {
             namespace_flags_ |= CLONE_NEWNS;
         } else {
-            *err = "namespace must be 'pid' or 'mnt'";
-            return false;
+            return Error() << "namespace must be 'pid' or 'mnt'";
         }
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseOomScoreAdjust(const std::vector<std::string>& args) {
     if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) {
-        *err = "oom_score_adjust value must be in range -1000 - +1000";
-        return false;
+        return Error() << "oom_score_adjust value must be in range -1000 - +1000";
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseMemcgSwappiness(const std::vector<std::string>& args) {
     if (!ParseInt(args[1], &swappiness_, 0)) {
-        *err = "swappiness value must be equal or greater than 0";
-        return false;
+        return Error() << "swappiness value must be equal or greater than 0";
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args) {
     if (!ParseInt(args[1], &limit_in_bytes_, 0)) {
-        *err = "limit_in_bytes value must be equal or greater than 0";
-        return false;
+        return Error() << "limit_in_bytes value must be equal or greater than 0";
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args) {
     if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) {
-        *err = "soft_limit_in_bytes value must be equal or greater than 0";
-        return false;
+        return Error() << "soft_limit_in_bytes value must be equal or greater than 0";
     }
-    return true;
+    return Success();
 }
 
-bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseProcessRlimit(const std::vector<std::string>& args) {
+    auto rlimit = ParseRlimit(args);
+    if (!rlimit) return rlimit.error();
+
+    rlimits_.emplace_back(*rlimit);
+    return Success();
+}
+
+Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) {
     seclabel_ = args[1];
-    return true;
+    return Success();
 }
 
-bool Service::ParseSetenv(const std::vector<std::string>& args, std::string* err) {
-    envvars_.emplace_back(args[1], args[2]);
-    return true;
+Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
+    environment_vars_.emplace_back(args[1], args[2]);
+    return Success();
 }
 
-bool Service::ParseShutdown(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseShutdown(const std::vector<std::string>& args) {
     if (args[1] == "critical") {
         flags_ |= SVC_SHUTDOWN_CRITICAL;
-        return true;
+        return Success();
     }
-    return false;
+    return Error() << "Invalid shutdown option";
 }
 
 template <typename T>
-bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::AddDescriptor(const std::vector<std::string>& args) {
     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
-    uid_t uid = 0;
-    gid_t gid = 0;
+    Result<uid_t> uid = 0;
+    Result<gid_t> gid = 0;
     std::string context = args.size() > 6 ? args[6] : "";
 
-    std::string decode_uid_err;
     if (args.size() > 4) {
-        if (!DecodeUid(args[4], &uid, &decode_uid_err)) {
-            *err = "Unable to find UID for '" + args[4] + "': " + decode_uid_err;
-            return false;
+        uid = DecodeUid(args[4]);
+        if (!uid) {
+            return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
         }
     }
 
     if (args.size() > 5) {
-        if (!DecodeUid(args[5], &gid, &decode_uid_err)) {
-            *err = "Unable to find GID for '" + args[5] + "': " + decode_uid_err;
-            return false;
+        gid = DecodeUid(args[5]);
+        if (!gid) {
+            return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
         }
     }
 
-    auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
+    auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
 
     auto old =
         std::find_if(descriptors_.begin(), descriptors_.end(),
                      [&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
 
     if (old != descriptors_.end()) {
-        *err = "duplicate descriptor " + args[1] + " " + args[2];
-        return false;
+        return Error() << "duplicate descriptor " << args[1] << " " << args[2];
     }
 
     descriptors_.emplace_back(std::move(descriptor));
-    return true;
+    return Success();
 }
 
 // name type perm [ uid gid context ]
-bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseSocket(const std::vector<std::string>& args) {
     if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
         !StartsWith(args[2], "seqpacket")) {
-        *err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
-        return false;
+        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
     }
-    return AddDescriptor<SocketInfo>(args, err);
+    return AddDescriptor<SocketInfo>(args);
 }
 
 // name type perm [ uid gid context ]
-bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseFile(const std::vector<std::string>& args) {
     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
-        *err = "file type must be 'r', 'w' or 'rw'";
-        return false;
+        return Error() << "file type must be 'r', 'w' or 'rw'";
     }
     if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
-        *err = "file name must not be relative";
-        return false;
+        return Error() << "file name must not be relative";
     }
-    return AddDescriptor<FileInfo>(args, err);
+    return AddDescriptor<FileInfo>(args);
 }
 
-bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
-    std::string decode_uid_err;
-    if (!DecodeUid(args[1], &uid_, &decode_uid_err)) {
-        *err = "Unable to find UID for '" + args[1] + "': " + decode_uid_err;
-        return false;
+Result<Success> Service::ParseUser(const std::vector<std::string>& args) {
+    auto uid = DecodeUid(args[1]);
+    if (!uid) {
+        return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
     }
-    return true;
+    uid_ = *uid;
+    return Success();
 }
 
-bool Service::ParseWritepid(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseWritepid(const std::vector<std::string>& args) {
     writepid_files_.assign(args.begin() + 1, args.end());
-    return true;
+    return Success();
 }
 
 class Service::OptionParserMap : public KeywordMap<OptionParser> {
@@ -646,6 +628,7 @@
         {"memcg.limit_in_bytes",
                         {1,     1,    &Service::ParseMemcgLimitInBytes}},
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
+        {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
         {"shutdown",    {1,     1,    &Service::ParseShutdown}},
@@ -658,30 +641,33 @@
     return option_parsers;
 }
 
-bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
+Result<Success> Service::ParseLine(const std::vector<std::string>& args) {
     static const OptionParserMap parser_map;
-    auto parser = parser_map.FindFunction(args, err);
+    auto parser = parser_map.FindFunction(args);
 
-    if (!parser) {
-        return false;
-    }
+    if (!parser) return parser.error();
 
-    return (this->*parser)(args, err);
+    return std::invoke(*parser, this, args);
 }
 
-bool Service::ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter) {
-    flags_ |= SVC_EXEC | SVC_ONESHOT;
+Result<Success> Service::ExecStart() {
+    flags_ |= SVC_ONESHOT;
 
-    exec_waiter->reset(new android::base::Timer);
-
-    if (!Start()) {
-        exec_waiter->reset();
-        return false;
+    if (auto result = Start(); !result) {
+        return result;
     }
-    return true;
+
+    flags_ |= SVC_EXEC;
+    is_exec_service_running_ = true;
+
+    LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
+              << supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
+              << ") started; waiting...";
+
+    return Success();
 }
 
-bool Service::Start() {
+Result<Success> Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -690,7 +676,8 @@
     // process of exiting, we've ensured that they will immediately restart
     // on exit, unless they are ONESHOT.
     if (flags_ & SVC_RUNNING) {
-        return false;
+        // It is not an error to try to start a service that is already running.
+        return Success();
     }
 
     bool needs_console = (flags_ & SVC_CONSOLE);
@@ -703,28 +690,27 @@
         // properly registered for the device node
         int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
         if (console_fd < 0) {
-            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
             flags_ |= SVC_DISABLED;
-            return false;
+            return ErrnoError() << "Couldn't open console '" << console_ << "'";
         }
         close(console_fd);
     }
 
     struct stat sb;
     if (stat(args_[0].c_str(), &sb) == -1) {
-        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
         flags_ |= SVC_DISABLED;
-        return false;
+        return ErrnoError() << "Cannot find '" << args_[0] << "'";
     }
 
     std::string scon;
     if (!seclabel_.empty()) {
         scon = seclabel_;
     } else {
-        scon = ComputeContextFromExecutable(name_, args_[0]);
-        if (scon == "") {
-            return false;
+        auto result = ComputeContextFromExecutable(name_, args_[0]);
+        if (!result) {
+            return result.error();
         }
+        scon = *result;
     }
 
     LOG(INFO) << "starting service '" << name_ << "'...";
@@ -745,8 +731,8 @@
             SetUpPidNamespace(name_);
         }
 
-        for (const auto& ei : envvars_) {
-            add_environment(ei.name.c_str(), ei.value.c_str());
+        for (const auto& [key, value] : environment_vars_) {
+            setenv(key.c_str(), value.c_str(), 1);
         }
 
         std::for_each(descriptors_.begin(), descriptors_.end(),
@@ -801,7 +787,7 @@
 
         std::vector<char*> strs;
         ExpandArgs(args_, &strs);
-        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
+        if (execv(strs[0], (char**)&strs[0]) < 0) {
             PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
         }
 
@@ -809,9 +795,8 @@
     }
 
     if (pid < 0) {
-        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
         pid_ = 0;
-        return false;
+        return ErrnoError() << "Failed to fork";
     }
 
     if (oom_score_adjust_ != -1000) {
@@ -825,6 +810,7 @@
     time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
+    start_order_ = next_start_order_++;
     process_cgroup_empty_ = false;
 
     errno = -createProcessGroup(uid_, pid_);
@@ -851,31 +837,25 @@
         }
     }
 
-    if ((flags_ & SVC_EXEC) != 0) {
-        LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
-                  << supp_gids_.size() << " context "
-                  << (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
-    }
-
     NotifyStateChange("running");
-    return true;
+    return Success();
 }
 
-bool Service::StartIfNotDisabled() {
+Result<Success> Service::StartIfNotDisabled() {
     if (!(flags_ & SVC_DISABLED)) {
         return Start();
     } else {
         flags_ |= SVC_DISABLED_START;
     }
-    return true;
+    return Success();
 }
 
-bool Service::Enable() {
+Result<Success> Service::Enable() {
     flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
     if (flags_ & SVC_DISABLED_START) {
         return Start();
     }
-    return true;
+    return Success();
 }
 
 void Service::Reset() {
@@ -901,26 +881,12 @@
         StopOrReset(SVC_RESTART);
     } else if (!(flags_ & SVC_RESTARTING)) {
         /* Just start the service since it's not running. */
-        Start();
+        if (auto result = Start(); !result) {
+            LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
+        }
     } /* else: Service is restarting anyways. */
 }
 
-void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
-    boot_clock::time_point now = boot_clock::now();
-    boot_clock::time_point next_start = time_started_ + 5s;
-    if (now > next_start) {
-        flags_ &= (~SVC_RESTARTING);
-        Start();
-        return;
-    }
-
-    time_t next_start_time_t = time(nullptr) +
-        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
-    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
-        *process_needs_restart_at = next_start_time_t;
-    }
-}
-
 // The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
 void Service::StopOrReset(int how) {
     // The service is still SVC_RUNNING until its process exits, but if it has
@@ -966,50 +932,18 @@
     close(fd);
 }
 
-int ServiceManager::exec_count_ = 0;
+ServiceList::ServiceList() {}
 
-ServiceManager::ServiceManager() {
-}
-
-ServiceManager& ServiceManager::GetInstance() {
-    static ServiceManager instance;
+ServiceList& ServiceList::GetInstance() {
+    static ServiceList instance;
     return instance;
 }
 
-void ServiceManager::AddService(std::unique_ptr<Service> service) {
+void ServiceList::AddService(std::unique_ptr<Service> service) {
     services_.emplace_back(std::move(service));
 }
 
-bool ServiceManager::Exec(const std::vector<std::string>& args) {
-    Service* svc = MakeExecOneshotService(args);
-    if (!svc) {
-        LOG(ERROR) << "Could not create exec service";
-        return false;
-    }
-    if (!svc->ExecStart(&exec_waiter_)) {
-        LOG(ERROR) << "Could not start exec service";
-        ServiceManager::GetInstance().RemoveService(*svc);
-        return false;
-    }
-    return true;
-}
-
-bool ServiceManager::ExecStart(const std::string& name) {
-    Service* svc = FindServiceByName(name);
-    if (!svc) {
-        LOG(ERROR) << "ExecStart(" << name << "): Service not found";
-        return false;
-    }
-    if (!svc->ExecStart(&exec_waiter_)) {
-        LOG(ERROR) << "ExecStart(" << name << "): Could not start Service";
-        return false;
-    }
-    return true;
-}
-
-bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; }
-
-Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
+std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<std::string>& args) {
     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
     // SECLABEL can be a - to denote default
     std::size_t command_arg = 1;
@@ -1030,10 +964,11 @@
     }
     std::vector<std::string> str_args(args.begin() + command_arg, args.end());
 
-    exec_count_++;
-    std::string name = "exec " + std::to_string(exec_count_) + " (" + Join(str_args, " ") + ")";
+    static size_t exec_count = 0;
+    exec_count++;
+    std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";
 
-    unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY;
+    unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
     CapSet no_capabilities;
     unsigned namespace_flags = 0;
 
@@ -1041,100 +976,50 @@
     if (command_arg > 2 && args[1] != "-") {
         seclabel = args[1];
     }
-    uid_t uid = 0;
+    Result<uid_t> uid = 0;
     if (command_arg > 3) {
-        std::string decode_uid_err;
-        if (!DecodeUid(args[2], &uid, &decode_uid_err)) {
-            LOG(ERROR) << "Unable to find UID for '" << args[2] << "': " << decode_uid_err;
+        uid = DecodeUid(args[2]);
+        if (!uid) {
+            LOG(ERROR) << "Unable to decode UID for '" << args[2] << "': " << uid.error();
             return nullptr;
         }
     }
-    gid_t gid = 0;
+    Result<gid_t> gid = 0;
     std::vector<gid_t> supp_gids;
     if (command_arg > 4) {
-        std::string decode_uid_err;
-        if (!DecodeUid(args[3], &gid, &decode_uid_err)) {
-            LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
+        gid = DecodeUid(args[3]);
+        if (!gid) {
+            LOG(ERROR) << "Unable to decode GID for '" << args[3] << "': " << gid.error();
             return nullptr;
         }
         std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
         for (size_t i = 0; i < nr_supp_gids; ++i) {
-            gid_t supp_gid;
-            if (!DecodeUid(args[4 + i], &supp_gid, &decode_uid_err)) {
-                LOG(ERROR) << "Unable to find UID for '" << args[4 + i] << "': " << decode_uid_err;
+            auto supp_gid = DecodeUid(args[4 + i]);
+            if (!supp_gid) {
+                LOG(ERROR) << "Unable to decode GID for '" << args[4 + i]
+                           << "': " << supp_gid.error();
                 return nullptr;
             }
-            supp_gids.push_back(supp_gid);
+            supp_gids.push_back(*supp_gid);
         }
     }
 
-    auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
-                                           namespace_flags, seclabel, str_args);
-    Service* svc = svc_p.get();
-    services_.emplace_back(std::move(svc_p));
-
-    return svc;
+    return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities,
+                                     namespace_flags, seclabel, str_args);
 }
 
-Service* ServiceManager::FindServiceByName(const std::string& name) const {
-    auto svc = std::find_if(services_.begin(), services_.end(),
-                            [&name] (const std::unique_ptr<Service>& s) {
-                                return name == s->name();
-                            });
-    if (svc != services_.end()) {
-        return svc->get();
+// Shutdown services in the opposite order that they were started.
+const std::vector<Service*> ServiceList::services_in_shutdown_order() const {
+    std::vector<Service*> shutdown_services;
+    for (const auto& service : services_) {
+        if (service->start_order() > 0) shutdown_services.emplace_back(service.get());
     }
-    return nullptr;
+    std::sort(shutdown_services.begin(), shutdown_services.end(),
+              [](const auto& a, const auto& b) { return a->start_order() > b->start_order(); });
+    return shutdown_services;
 }
 
-Service* ServiceManager::FindServiceByPid(pid_t pid) const {
-    auto svc = std::find_if(services_.begin(), services_.end(),
-                            [&pid] (const std::unique_ptr<Service>& s) {
-                                return s->pid() == pid;
-                            });
-    if (svc != services_.end()) {
-        return svc->get();
-    }
-    return nullptr;
-}
-
-Service* ServiceManager::FindServiceByKeychord(int keychord_id) const {
-    auto svc = std::find_if(services_.begin(), services_.end(),
-                            [&keychord_id] (const std::unique_ptr<Service>& s) {
-                                return s->keychord_id() == keychord_id;
-                            });
-
-    if (svc != services_.end()) {
-        return svc->get();
-    }
-    return nullptr;
-}
-
-void ServiceManager::ForEachService(const std::function<void(Service*)>& callback) const {
-    for (const auto& s : services_) {
-        callback(s.get());
-    }
-}
-
-void ServiceManager::ForEachServiceInClass(const std::string& classname,
-                                           void (*func)(Service* svc)) const {
-    for (const auto& s : services_) {
-        if (s->classnames().find(classname) != s->classnames().end()) {
-            func(s.get());
-        }
-    }
-}
-
-void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
-                                             void (*func)(Service* svc)) const {
-    for (const auto& s : services_) {
-        if (s->flags() & matchflags) {
-            func(s.get());
-        }
-    }
-}
-
-void ServiceManager::RemoveService(const Service& svc) {
+void ServiceList::RemoveService(const Service& svc) {
     auto svc_it = std::find_if(services_.begin(), services_.end(),
                                [&svc] (const std::unique_ptr<Service>& s) {
                                    return svc.name() == s->name();
@@ -1146,116 +1031,40 @@
     services_.erase(svc_it);
 }
 
-void ServiceManager::DumpState() const {
+void ServiceList::DumpState() const {
     for (const auto& s : services_) {
         s->DumpState();
     }
 }
 
-bool ServiceManager::ReapOneProcess() {
-    siginfo_t siginfo = {};
-    // This returns a zombie pid or informs us that there are no zombies left to be reaped.
-    // It does NOT reap the pid; that is done below.
-    if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
-        PLOG(ERROR) << "waitid failed";
-        return false;
-    }
-
-    auto pid = siginfo.si_pid;
-    if (pid == 0) return false;
-
-    // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
-    // whenever the function returns from this point forward.
-    // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
-    // want the pid to remain valid throughout that (and potentially future) usages.
-    auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
-
-    if (PropertyChildReap(pid)) {
-        return true;
-    }
-
-    Service* svc = FindServiceByPid(pid);
-
-    std::string name;
-    std::string wait_string;
-    if (svc) {
-        name = StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
-        if (svc->flags() & SVC_EXEC) {
-            wait_string = StringPrintf(" waiting took %f seconds",
-                                       exec_waiter_->duration().count() / 1000.0f);
-        }
-    } else {
-        name = StringPrintf("Untracked pid %d", pid);
-    }
-
-    auto status = siginfo.si_status;
-    if (WIFEXITED(status)) {
-        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
-    } else if (WIFSIGNALED(status)) {
-        LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
-    }
-
-    if (!svc) {
-        return true;
-    }
-
-    svc->Reap();
-
-    if (svc->flags() & SVC_EXEC) {
-        exec_waiter_.reset();
-    }
-    if (svc->flags() & SVC_TEMPORARY) {
-        RemoveService(*svc);
-    }
-
-    return true;
-}
-
-void ServiceManager::ReapAnyOutstandingChildren() {
-    while (ReapOneProcess()) {
-    }
-}
-
-void ServiceManager::ClearExecWait() {
-    // Clear EXEC flag if there is one pending
-    // And clear the wait flag
-    for (const auto& s : services_) {
-        s->UnSetExec();
-    }
-    exec_waiter_.reset();
-}
-
-bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                                 int line, std::string* err) {
+Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
+                                            const std::string& filename, int line) {
     if (args.size() < 3) {
-        *err = "services must have a name and a program";
-        return false;
+        return Error() << "services must have a name and a program";
     }
 
     const std::string& name = args[1];
     if (!IsValidName(name)) {
-        *err = StringPrintf("invalid service name '%s'", name.c_str());
-        return false;
+        return Error() << "invalid service name '" << name << "'";
     }
 
-    Service* old_service = service_manager_->FindServiceByName(name);
+    Service* old_service = service_list_->FindService(name);
     if (old_service) {
-        *err = "ignored duplicate definition of service '" + name + "'";
-        return false;
+        return Error() << "ignored duplicate definition of service '" << name << "'";
     }
 
     std::vector<std::string> str_args(args.begin() + 2, args.end());
     service_ = std::make_unique<Service>(name, str_args);
-    return true;
+    return Success();
 }
 
-bool ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
-    return service_ ? service_->ParseLine(std::move(args), err) : false;
+Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
+    return service_ ? service_->ParseLine(std::move(args)) : Success();
 }
 
 void ServiceParser::EndSection() {
     if (service_) {
-        service_manager_->AddService(std::move(service_));
+        service_list_->AddService(std::move(service_));
     }
 }
 
diff --git a/init/service.h b/init/service.h
index 62a3299..67542ca 100644
--- a/init/service.h
+++ b/init/service.h
@@ -17,6 +17,7 @@
 #ifndef _INIT_SERVICE_H
 #define _INIT_SERVICE_H
 
+#include <sys/resource.h>
 #include <sys/types.h>
 
 #include <memory>
@@ -30,8 +31,8 @@
 #include "action.h"
 #include "capabilities.h"
 #include "descriptors.h"
-#include "init_parser.h"
 #include "keyword_map.h"
+#include "parser.h"
 
 #define SVC_DISABLED 0x001        // do not autostart with class
 #define SVC_ONESHOT 0x002         // do not restart on exit
@@ -57,13 +58,6 @@
 namespace android {
 namespace init {
 
-struct ServiceEnvironmentInfo {
-    ServiceEnvironmentInfo();
-    ServiceEnvironmentInfo(const std::string& name, const std::string& value);
-    std::string name;
-    std::string value;
-};
-
 class Service {
   public:
     Service(const std::string& name, const std::vector<std::string>& args);
@@ -73,27 +67,34 @@
             unsigned namespace_flags, const std::string& seclabel,
             const std::vector<std::string>& args);
 
+    static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
+
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
-    bool ParseLine(const std::vector<std::string>& args, std::string* err);
-    bool ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter);
-    bool Start();
-    bool StartIfNotDisabled();
-    bool Enable();
+    Result<Success> ParseLine(const std::vector<std::string>& args);
+    Result<Success> ExecStart();
+    Result<Success> Start();
+    Result<Success> StartIfNotDisabled();
+    Result<Success> Enable();
     void Reset();
     void Stop();
     void Terminate();
     void Restart();
-    void RestartIfNeeded(time_t* process_needs_restart_at);
     void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
-    void UnSetExec() { flags_ &= ~SVC_EXEC; }
+    void UnSetExec() {
+        is_exec_service_running_ = false;
+        flags_ &= ~SVC_EXEC;
+    }
+
+    static bool is_exec_service_running() { return is_exec_service_running_; }
 
     const std::string& name() const { return name_; }
     const std::set<std::string>& classnames() const { return classnames_; }
     unsigned flags() const { return flags_; }
     pid_t pid() const { return pid_; }
+    android::base::boot_clock::time_point time_started() const { return time_started_; }
     int crash_count() const { return crash_count_; }
     uid_t uid() const { return uid_; }
     gid_t gid() const { return gid_; }
@@ -108,11 +109,11 @@
     int priority() const { return priority_; }
     int oom_score_adjust() const { return oom_score_adjust_; }
     bool process_cgroup_empty() const { return process_cgroup_empty_; }
+    unsigned long start_order() const { return start_order_; }
     const std::vector<std::string>& args() const { return args_; }
 
   private:
-    using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
-                                            std::string* err);
+    using OptionParser = Result<Success> (Service::*)(const std::vector<std::string>& args);
     class OptionParserMap;
 
     void NotifyStateChange(const std::string& new_state) const;
@@ -122,32 +123,36 @@
     void KillProcessGroup(int signal);
     void SetProcessAttributes();
 
-    bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
-    bool ParseClass(const std::vector<std::string>& args, std::string* err);
-    bool ParseConsole(const std::vector<std::string>& args, std::string* err);
-    bool ParseCritical(const std::vector<std::string>& args, std::string* err);
-    bool ParseDisabled(const std::vector<std::string>& args, std::string* err);
-    bool ParseGroup(const std::vector<std::string>& args, std::string* err);
-    bool ParsePriority(const std::vector<std::string>& args, std::string* err);
-    bool ParseIoprio(const std::vector<std::string>& args, std::string* err);
-    bool ParseKeycodes(const std::vector<std::string>& args, std::string* err);
-    bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
-    bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
-    bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
-    bool ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err);
-    bool ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err);
-    bool ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err);
-    bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
-    bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
-    bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
-    bool ParseShutdown(const std::vector<std::string>& args, std::string* err);
-    bool ParseSocket(const std::vector<std::string>& args, std::string* err);
-    bool ParseFile(const std::vector<std::string>& args, std::string* err);
-    bool ParseUser(const std::vector<std::string>& args, std::string* err);
-    bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
+    Result<Success> ParseCapabilities(const std::vector<std::string>& args);
+    Result<Success> ParseClass(const std::vector<std::string>& args);
+    Result<Success> ParseConsole(const std::vector<std::string>& args);
+    Result<Success> ParseCritical(const std::vector<std::string>& args);
+    Result<Success> ParseDisabled(const std::vector<std::string>& args);
+    Result<Success> ParseGroup(const std::vector<std::string>& args);
+    Result<Success> ParsePriority(const std::vector<std::string>& args);
+    Result<Success> ParseIoprio(const std::vector<std::string>& args);
+    Result<Success> ParseKeycodes(const std::vector<std::string>& args);
+    Result<Success> ParseOneshot(const std::vector<std::string>& args);
+    Result<Success> ParseOnrestart(const std::vector<std::string>& args);
+    Result<Success> ParseOomScoreAdjust(const std::vector<std::string>& args);
+    Result<Success> ParseMemcgLimitInBytes(const std::vector<std::string>& args);
+    Result<Success> ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args);
+    Result<Success> ParseMemcgSwappiness(const std::vector<std::string>& args);
+    Result<Success> ParseNamespace(const std::vector<std::string>& args);
+    Result<Success> ParseProcessRlimit(const std::vector<std::string>& args);
+    Result<Success> ParseSeclabel(const std::vector<std::string>& args);
+    Result<Success> ParseSetenv(const std::vector<std::string>& args);
+    Result<Success> ParseShutdown(const std::vector<std::string>& args);
+    Result<Success> ParseSocket(const std::vector<std::string>& args);
+    Result<Success> ParseFile(const std::vector<std::string>& args);
+    Result<Success> ParseUser(const std::vector<std::string>& args);
+    Result<Success> ParseWritepid(const std::vector<std::string>& args);
 
     template <typename T>
-    bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
+    Result<Success> AddDescriptor(const std::vector<std::string>& args);
+
+    static unsigned long next_start_order_;
+    static bool is_exec_service_running_;
 
     std::string name_;
     std::set<std::string> classnames_;
@@ -168,7 +173,7 @@
     std::string seclabel_;
 
     std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
-    std::vector<ServiceEnvironmentInfo> envvars_;
+    std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.
 
@@ -190,58 +195,58 @@
 
     bool process_cgroup_empty_ = false;
 
+    unsigned long start_order_;
+
+    std::vector<std::pair<int, rlimit>> rlimits_;
+
     std::vector<std::string> args_;
 };
 
-class ServiceManager {
+class ServiceList {
   public:
-    static ServiceManager& GetInstance();
+    static ServiceList& GetInstance();
 
     // Exposed for testing
-    ServiceManager();
+    ServiceList();
 
     void AddService(std::unique_ptr<Service> service);
-    Service* MakeExecOneshotService(const std::vector<std::string>& args);
-    bool Exec(const std::vector<std::string>& args);
-    bool ExecStart(const std::string& name);
-    bool IsWaitingForExec() const;
-    Service* FindServiceByName(const std::string& name) const;
-    Service* FindServiceByPid(pid_t pid) const;
-    Service* FindServiceByKeychord(int keychord_id) const;
-    void ForEachService(const std::function<void(Service*)>& callback) const;
-    void ForEachServiceInClass(const std::string& classname,
-                               void (*func)(Service* svc)) const;
-    void ForEachServiceWithFlags(unsigned matchflags,
-                             void (*func)(Service* svc)) const;
-    void ReapAnyOutstandingChildren();
     void RemoveService(const Service& svc);
+
+    template <typename T, typename F = decltype(&Service::name)>
+    Service* FindService(T value, F function = &Service::name) const {
+        auto svc = std::find_if(services_.begin(), services_.end(),
+                                [&function, &value](const std::unique_ptr<Service>& s) {
+                                    return std::invoke(function, s) == value;
+                                });
+        if (svc != services_.end()) {
+            return svc->get();
+        }
+        return nullptr;
+    }
+
     void DumpState() const;
-    void ClearExecWait();
+
+    auto begin() const { return services_.begin(); }
+    auto end() const { return services_.end(); }
+    const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
+    const std::vector<Service*> services_in_shutdown_order() const;
 
   private:
-    // Cleans up a child process that exited.
-    // Returns true iff a children was cleaned up.
-    bool ReapOneProcess();
-
-    static int exec_count_; // Every service needs a unique name.
-    std::unique_ptr<android::base::Timer> exec_waiter_;
-
     std::vector<std::unique_ptr<Service>> services_;
 };
 
 class ServiceParser : public SectionParser {
   public:
-    ServiceParser(ServiceManager* service_manager)
-        : service_manager_(service_manager), service_(nullptr) {}
-    bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
-                      std::string* err) override;
-    bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override;
+    ServiceParser(ServiceList* service_list) : service_list_(service_list), service_(nullptr) {}
+    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+                                 int line) override;
+    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
     void EndSection() override;
 
   private:
     bool IsValidName(const std::string& name) const;
 
-    ServiceManager* service_manager_;
+    ServiceList* service_list_;
     std::unique_ptr<Service> service_;
 };
 
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 44f28a3..98d876f 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -23,6 +23,8 @@
 
 #include <gtest/gtest.h>
 
+#include "util.h"
+
 namespace android {
 namespace init {
 
@@ -71,5 +73,120 @@
     EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
 }
 
+TEST(service, make_temporary_oneshot_service_invalid_syntax) {
+    std::vector<std::string> args;
+    // Nothing.
+    ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+
+    // No arguments to 'exec'.
+    args.push_back("exec");
+    ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+
+    // No command in "exec --".
+    args.push_back("--");
+    ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+}
+
+TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
+    std::vector<std::string> args;
+    args.push_back("exec");
+    args.push_back("seclabel");
+    args.push_back("root");  // uid.
+    args.push_back("root");  // gid.
+    for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
+        args.push_back("root");  // Supplementary gid.
+    }
+    args.push_back("--");
+    args.push_back("/system/bin/id");
+    ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+}
+
+static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
+                                                bool supplementary_gids) {
+    std::vector<std::string> args;
+    args.push_back("exec");
+    if (seclabel) {
+        args.push_back("u:r:su:s0");  // seclabel
+        if (uid) {
+            args.push_back("log");  // uid
+            if (gid) {
+                args.push_back("shell");  // gid
+                if (supplementary_gids) {
+                    args.push_back("system");  // supplementary gid 0
+                    args.push_back("adb");     // supplementary gid 1
+                }
+            }
+        }
+    }
+    if (dash_dash) {
+        args.push_back("--");
+    }
+    args.push_back("/system/bin/toybox");
+    args.push_back("id");
+    auto svc = Service::MakeTemporaryOneshotService(args);
+    ASSERT_NE(nullptr, svc);
+
+    if (seclabel) {
+        ASSERT_EQ("u:r:su:s0", svc->seclabel());
+    } else {
+        ASSERT_EQ("", svc->seclabel());
+    }
+    if (uid) {
+        auto decoded_uid = DecodeUid("log");
+        ASSERT_TRUE(decoded_uid);
+        ASSERT_EQ(*decoded_uid, svc->uid());
+    } else {
+        ASSERT_EQ(0U, svc->uid());
+    }
+    if (gid) {
+        auto decoded_uid = DecodeUid("shell");
+        ASSERT_TRUE(decoded_uid);
+        ASSERT_EQ(*decoded_uid, svc->gid());
+    } else {
+        ASSERT_EQ(0U, svc->gid());
+    }
+    if (supplementary_gids) {
+        ASSERT_EQ(2U, svc->supp_gids().size());
+
+        auto decoded_uid = DecodeUid("system");
+        ASSERT_TRUE(decoded_uid);
+        ASSERT_EQ(*decoded_uid, svc->supp_gids()[0]);
+
+        decoded_uid = DecodeUid("adb");
+        ASSERT_TRUE(decoded_uid);
+        ASSERT_EQ(*decoded_uid, svc->supp_gids()[1]);
+    } else {
+        ASSERT_EQ(0U, svc->supp_gids().size());
+    }
+
+    ASSERT_EQ(static_cast<std::size_t>(2), svc->args().size());
+    ASSERT_EQ("/system/bin/toybox", svc->args()[0]);
+    ASSERT_EQ("id", svc->args()[1]);
+}
+
+TEST(service, make_temporary_oneshot_service_with_everything) {
+    Test_make_temporary_oneshot_service(true, true, true, true, true);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid_gid) {
+    Test_make_temporary_oneshot_service(true, true, true, true, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid) {
+    Test_make_temporary_oneshot_service(true, true, true, false, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel) {
+    Test_make_temporary_oneshot_service(true, true, false, false, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_just_command) {
+    Test_make_temporary_oneshot_service(true, false, false, false, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_just_command_no_dash) {
+    Test_make_temporary_oneshot_service(false, false, false, false, false);
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
new file mode 100644
index 0000000..8fc9956
--- /dev/null
+++ b/init/sigchld_handler.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 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 "sigchld_handler.h"
+
+#include <signal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
+
+#include "init.h"
+#include "property_service.h"
+#include "service.h"
+
+using android::base::StringPrintf;
+using android::base::boot_clock;
+using android::base::make_scope_guard;
+
+namespace android {
+namespace init {
+
+static int signal_write_fd = -1;
+static int signal_read_fd = -1;
+
+static bool ReapOneProcess() {
+    siginfo_t siginfo = {};
+    // This returns a zombie pid or informs us that there are no zombies left to be reaped.
+    // It does NOT reap the pid; that is done below.
+    if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
+        PLOG(ERROR) << "waitid failed";
+        return false;
+    }
+
+    auto pid = siginfo.si_pid;
+    if (pid == 0) return false;
+
+    // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
+    // whenever the function returns from this point forward.
+    // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
+    // want the pid to remain valid throughout that (and potentially future) usages.
+    auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
+
+    if (PropertyChildReap(pid)) return true;
+
+    Service* service = ServiceList::GetInstance().FindService(pid, &Service::pid);
+
+    std::string name;
+    std::string wait_string;
+    if (service) {
+        name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
+        if (service->flags() & SVC_EXEC) {
+            auto exec_duration = boot_clock::now() - service->time_started();
+            auto exec_duration_ms =
+                std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
+            wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
+        }
+    } else {
+        name = StringPrintf("Untracked pid %d", pid);
+    }
+
+    auto status = siginfo.si_status;
+    if (WIFEXITED(status)) {
+        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
+    } else if (WIFSIGNALED(status)) {
+        LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
+    }
+
+    if (!service) return true;
+
+    service->Reap();
+
+    if (service->flags() & SVC_TEMPORARY) {
+        ServiceList::GetInstance().RemoveService(*service);
+    }
+
+    return true;
+}
+
+static void handle_signal() {
+    // Clear outstanding requests.
+    char buf[32];
+    read(signal_read_fd, buf, sizeof(buf));
+
+    ReapAnyOutstandingChildren();
+}
+
+static void SIGCHLD_handler(int) {
+    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
+        PLOG(ERROR) << "write(signal_write_fd) failed";
+    }
+}
+
+void ReapAnyOutstandingChildren() {
+    while (ReapOneProcess()) {
+    }
+}
+
+void sigchld_handler_init() {
+    // Create a signalling mechanism for SIGCHLD.
+    int s[2];
+    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
+        PLOG(ERROR) << "socketpair failed";
+        exit(1);
+    }
+
+    signal_write_fd = s[0];
+    signal_read_fd = s[1];
+
+    // Write to signal_write_fd if we catch SIGCHLD.
+    struct sigaction act;
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = SIGCHLD_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, 0);
+
+    ReapAnyOutstandingChildren();
+
+    register_epoll_handler(signal_read_fd, handle_signal);
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/signal_handler.h b/init/sigchld_handler.h
similarity index 84%
rename from init/signal_handler.h
rename to init/sigchld_handler.h
index f7881ab..c86dc8d 100644
--- a/init/signal_handler.h
+++ b/init/sigchld_handler.h
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_SIGCHLD_HANDLER_H_
+#define _INIT_SIGCHLD_HANDLER_H_
 
 namespace android {
 namespace init {
 
-void signal_handler_init(void);
+void ReapAnyOutstandingChildren();
+
+void sigchld_handler_init(void);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
deleted file mode 100644
index db1bfcf..0000000
--- a/init/signal_handler.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2010 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 <signal.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-
-#include "init.h"
-#include "service.h"
-
-namespace android {
-namespace init {
-
-static int signal_write_fd = -1;
-static int signal_read_fd = -1;
-
-static void handle_signal() {
-    // Clear outstanding requests.
-    char buf[32];
-    read(signal_read_fd, buf, sizeof(buf));
-
-    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
-}
-
-static void SIGCHLD_handler(int) {
-    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
-        PLOG(ERROR) << "write(signal_write_fd) failed";
-    }
-}
-
-void signal_handler_init() {
-    // Create a signalling mechanism for SIGCHLD.
-    int s[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
-        PLOG(ERROR) << "socketpair failed";
-        exit(1);
-    }
-
-    signal_write_fd = s[0];
-    signal_read_fd = s[1];
-
-    // Write to signal_write_fd if we catch SIGCHLD.
-    struct sigaction act;
-    memset(&act, 0, sizeof(act));
-    act.sa_handler = SIGCHLD_handler;
-    act.sa_flags = SA_NOCLDSTOP;
-    sigaction(SIGCHLD, &act, 0);
-
-    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
-
-    register_epoll_handler(signal_read_fd, handle_signal);
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/tokenizer.cpp b/init/tokenizer.cpp
new file mode 100644
index 0000000..f8d9b6b
--- /dev/null
+++ b/init/tokenizer.cpp
@@ -0,0 +1,124 @@
+#include "tokenizer.h"
+
+namespace android {
+namespace init {
+
+int next_token(struct parse_state *state)
+{
+    char *x = state->ptr;
+    char *s;
+
+    if (state->nexttoken) {
+        int t = state->nexttoken;
+        state->nexttoken = 0;
+        return t;
+    }
+
+    for (;;) {
+        switch (*x) {
+        case 0:
+            state->ptr = x;
+            return T_EOF;
+        case '\n':
+            x++;
+            state->ptr = x;
+            return T_NEWLINE;
+        case ' ':
+        case '\t':
+        case '\r':
+            x++;
+            continue;
+        case '#':
+            while (*x && (*x != '\n')) x++;
+            if (*x == '\n') {
+                state->ptr = x+1;
+                return T_NEWLINE;
+            } else {
+                state->ptr = x;
+                return T_EOF;
+            }
+        default:
+            goto text;
+        }
+    }
+
+textdone:
+    state->ptr = x;
+    *s = 0;
+    return T_TEXT;
+text:
+    state->text = s = x;
+textresume:
+    for (;;) {
+        switch (*x) {
+        case 0:
+            goto textdone;
+        case ' ':
+        case '\t':
+        case '\r':
+            x++;
+            goto textdone;
+        case '\n':
+            state->nexttoken = T_NEWLINE;
+            x++;
+            goto textdone;
+        case '"':
+            x++;
+            for (;;) {
+                switch (*x) {
+                case 0:
+                        /* unterminated quoted thing */
+                    state->ptr = x;
+                    return T_EOF;
+                case '"':
+                    x++;
+                    goto textresume;
+                default:
+                    *s++ = *x++;
+                }
+            }
+            break;
+        case '\\':
+            x++;
+            switch (*x) {
+            case 0:
+                goto textdone;
+            case 'n':
+                *s++ = '\n';
+                break;
+            case 'r':
+                *s++ = '\r';
+                break;
+            case 't':
+                *s++ = '\t';
+                break;
+            case '\\':
+                *s++ = '\\';
+                break;
+            case '\r':
+                    /* \ <cr> <lf> -> line continuation */
+                if (x[1] != '\n') {
+                    x++;
+                    continue;
+                }
+            case '\n':
+                    /* \ <lf> -> line continuation */
+                state->line++;
+                x++;
+                    /* eat any extra whitespace */
+                while((*x == ' ') || (*x == '\t')) x++;
+                continue;
+            default:
+                    /* unknown escape -- just copy */
+                *s++ = *x++;
+            }
+            continue;
+        default:
+            *s++ = *x++;
+        }
+    }
+    return T_EOF;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/signal_handler.h b/init/tokenizer.h
similarity index 74%
copy from init/signal_handler.h
copy to init/tokenizer.h
index f7881ab..72c08ef 100644
--- a/init/signal_handler.h
+++ b/init/tokenizer.h
@@ -14,13 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_TOKENIZER_H_
+#define _INIT_TOKENIZER_H_
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_NEWLINE 2
 
 namespace android {
 namespace init {
 
-void signal_handler_init(void);
+struct parse_state
+{
+    char *ptr;
+    char *text;
+    int line;
+    int nexttoken;
+};
+
+int next_token(struct parse_state *state);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index c0eae1e..1435d82 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -36,6 +36,7 @@
 #include "devices.h"
 #include "firmware_handler.h"
 #include "log.h"
+#include "selinux.h"
 #include "uevent_listener.h"
 #include "ueventd_parser.h"
 #include "util.h"
@@ -222,10 +223,10 @@
     using namespace std::placeholders;
     std::vector<SysfsPermissions> sysfs_permissions;
     std::vector<Permissions> dev_permissions;
-    parser.AddSingleLineParser(
-        "/sys/", std::bind(ParsePermissionsLine, _1, _2, &sysfs_permissions, nullptr));
+    parser.AddSingleLineParser("/sys/",
+                               std::bind(ParsePermissionsLine, _1, &sysfs_permissions, nullptr));
     parser.AddSingleLineParser("/dev/",
-                               std::bind(ParsePermissionsLine, _1, _2, nullptr, &dev_permissions));
+                               std::bind(ParsePermissionsLine, _1, nullptr, &dev_permissions));
 
     parser.ParseConfig("/ueventd.rc");
     parser.ParseConfig("/vendor/ueventd.rc");
@@ -257,9 +258,8 @@
 
     LOG(INFO) << "ueventd started!";
 
-    selinux_callback cb;
-    cb.func_log = selinux_klog_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
+    SelinuxSetupKernelLogging();
+    SelabelInitialize();
 
     DeviceHandler device_handler = CreateDeviceHandler();
     UeventListener uevent_listener;
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 02e0d42..cd7adb4 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -24,18 +24,16 @@
 namespace android {
 namespace init {
 
-bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err,
-                          std::vector<SysfsPermissions>* out_sysfs_permissions,
-                          std::vector<Permissions>* out_dev_permissions) {
+Result<Success> ParsePermissionsLine(std::vector<std::string>&& args,
+                                     std::vector<SysfsPermissions>* out_sysfs_permissions,
+                                     std::vector<Permissions>* out_dev_permissions) {
     bool is_sysfs = out_sysfs_permissions != nullptr;
     if (is_sysfs && args.size() != 5) {
-        *err = "/sys/ lines must have 5 entries";
-        return false;
+        return Error() << "/sys/ lines must have 5 entries";
     }
 
     if (!is_sysfs && args.size() != 4) {
-        *err = "/dev/ lines must have 4 entries";
-        return false;
+        return Error() << "/dev/ lines must have 4 entries";
     }
 
     auto it = args.begin();
@@ -49,23 +47,20 @@
     char* end_pointer = 0;
     mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8);
     if (end_pointer == nullptr || *end_pointer != '\0') {
-        *err = "invalid mode '" + perm_string + "'";
-        return false;
+        return Error() << "invalid mode '" << perm_string << "'";
     }
 
     std::string& uid_string = *it++;
     passwd* pwd = getpwnam(uid_string.c_str());
     if (!pwd) {
-        *err = "invalid uid '" + uid_string + "'";
-        return false;
+        return Error() << "invalid uid '" << uid_string << "'";
     }
     uid_t uid = pwd->pw_uid;
 
     std::string& gid_string = *it++;
     struct group* grp = getgrnam(gid_string.c_str());
     if (!grp) {
-        *err = "invalid gid '" + gid_string + "'";
-        return false;
+        return Error() << "invalid gid '" << gid_string << "'";
     }
     gid_t gid = grp->gr_gid;
 
@@ -74,53 +69,49 @@
     } else {
         out_dev_permissions->emplace_back(name, perm, uid, gid);
     }
-    return true;
+    return Success();
 }
 
-bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                                   int line, std::string* err) {
+Result<Success> SubsystemParser::ParseSection(std::vector<std::string>&& args,
+                                              const std::string& filename, int line) {
     if (args.size() != 2) {
-        *err = "subsystems must have exactly one name";
-        return false;
+        return Error() << "subsystems must have exactly one name";
     }
 
     if (std::find(subsystems_->begin(), subsystems_->end(), args[1]) != subsystems_->end()) {
-        *err = "ignoring duplicate subsystem entry";
-        return false;
+        return Error() << "ignoring duplicate subsystem entry";
     }
 
-    subsystem_.name_ = args[1];
+    subsystem_ = Subsystem(std::move(args[1]));
 
-    return true;
+    return Success();
 }
 
-bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) {
+Result<Success> SubsystemParser::ParseDevName(std::vector<std::string>&& args) {
     if (args[1] == "uevent_devname") {
         subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
-        return true;
+        return Success();
     }
     if (args[1] == "uevent_devpath") {
         subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
-        return true;
+        return Success();
     }
 
-    *err = "invalid devname '" + args[1] + "'";
-    return false;
+    return Error() << "invalid devname '" << args[1] << "'";
 }
 
-bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) {
+Result<Success> SubsystemParser::ParseDirName(std::vector<std::string>&& args) {
     if (args[1].front() != '/') {
-        *err = "dirname '" + args[1] + " ' does not start with '/'";
-        return false;
+        return Error() << "dirname '" << args[1] << " ' does not start with '/'";
     }
 
     subsystem_.dir_name_ = args[1];
-    return true;
+    return Success();
 }
 
-bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
-    using OptionParser =
-        bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err);
+Result<Success> SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line) {
+    using OptionParser = Result<Success> (SubsystemParser::*)(std::vector<std::string> && args);
+
     static class OptionParserMap : public KeywordMap<OptionParser> {
       private:
         const Map& map() const override {
@@ -134,13 +125,11 @@
         }
     } parser_map;
 
-    auto parser = parser_map.FindFunction(args, err);
+    auto parser = parser_map.FindFunction(args);
 
-    if (!parser) {
-        return false;
-    }
+    if (!parser) return Error() << parser.error();
 
-    return (this->*parser)(std::move(args), err);
+    return std::invoke(*parser, this, std::move(args));
 }
 
 void SubsystemParser::EndSection() {
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 592df63..18d1027 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -21,7 +21,7 @@
 #include <vector>
 
 #include "devices.h"
-#include "init_parser.h"
+#include "parser.h"
 
 namespace android {
 namespace init {
@@ -29,22 +29,22 @@
 class SubsystemParser : public SectionParser {
   public:
     SubsystemParser(std::vector<Subsystem>* subsystems) : subsystems_(subsystems) {}
-    bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
-                      std::string* err) override;
-    bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override;
+    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+                                 int line) override;
+    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
     void EndSection() override;
 
   private:
-    bool ParseDevName(std::vector<std::string>&& args, std::string* err);
-    bool ParseDirName(std::vector<std::string>&& args, std::string* err);
+    Result<Success> ParseDevName(std::vector<std::string>&& args);
+    Result<Success> ParseDirName(std::vector<std::string>&& args);
 
     Subsystem subsystem_;
     std::vector<Subsystem>* subsystems_;
 };
 
-bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err,
-                          std::vector<SysfsPermissions>* out_sysfs_permissions,
-                          std::vector<Permissions>* out_dev_permissions);
+Result<Success> ParsePermissionsLine(std::vector<std::string>&& args,
+                                     std::vector<SysfsPermissions>* out_sysfs_permissions,
+                                     std::vector<Permissions>* out_dev_permissions);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
index 4d9a1fa..7290051 100644
--- a/init/ueventd_test.cpp
+++ b/init/ueventd_test.cpp
@@ -19,6 +19,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <atomic>
+#include <chrono>
 #include <string>
 #include <thread>
 #include <vector>
@@ -27,8 +29,11 @@
 #include <android-base/scopeguard.h>
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
 #include <selinux/selinux.h>
 
+using namespace std::chrono_literals;
 using namespace std::string_literals;
 
 template <typename T, typename F>
@@ -120,3 +125,80 @@
         freecon(file_context);
     }
 }
+
+TEST(ueventd, selabel_lookup_MultiThreaded) {
+    if (getuid() != 0) {
+        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+        return;
+    }
+
+    // Test parameters
+    constexpr auto num_threads = 10;
+    constexpr auto run_time = 200ms;
+
+    std::unique_ptr<selabel_handle, decltype(&selabel_close)> sehandle(
+        selinux_android_file_context_handle(), &selabel_close);
+
+    ASSERT_TRUE(sehandle);
+
+    struct {
+        const char* file;
+        int mode;
+        std::string expected_context;
+    } files_and_modes[] = {
+        {"/dev/zero", 020666, ""},
+        {"/dev/null", 020666, ""},
+        {"/dev/random", 020666, ""},
+        {"/dev/urandom", 020666, ""},
+    };
+
+    // Precondition, ensure that we can lookup all of these from a single thread, and store the
+    // expected context for each.
+    for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
+        char* secontext;
+        ASSERT_EQ(0, selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
+                                    files_and_modes[i].mode));
+        files_and_modes[i].expected_context = secontext;
+        freecon(secontext);
+    }
+
+    // Now that we know we can access them, and what their context should be, run in parallel.
+    std::atomic_bool stopped = false;
+    std::atomic_uint num_api_failures = 0;
+    std::atomic_uint num_context_check_failures = 0;
+    std::atomic_uint num_successes = 0;
+
+    auto thread_function = [&]() {
+        while (!stopped) {
+            for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
+                char* secontext;
+                int result = selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
+                                            files_and_modes[i].mode);
+                if (result != 0) {
+                    num_api_failures++;
+                } else {
+                    if (files_and_modes[i].expected_context != secontext) {
+                        num_context_check_failures++;
+                    } else {
+                        num_successes++;
+                    }
+                    freecon(secontext);
+                }
+            }
+        }
+    };
+
+    std::vector<std::thread> threads;
+    std::generate_n(back_inserter(threads), num_threads,
+                    [&]() { return std::thread(thread_function); });
+
+    std::this_thread::sleep_for(run_time);
+    stopped = true;
+    for (auto& thread : threads) {
+        thread.join();
+    }
+
+    EXPECT_EQ(0U, num_api_failures);
+    EXPECT_EQ(0U, num_context_check_failures);
+    EXPECT_GT(num_successes, 0U);
+}
diff --git a/init/util.cpp b/init/util.cpp
index fdcb22d..a19a6f3 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -42,6 +42,7 @@
 #include <selinux/android.h>
 
 #include "reboot.h"
+#include "selinux.h"
 
 #ifdef _INIT_INIT_H
 #error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
@@ -56,30 +57,20 @@
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
 
 // DecodeUid() - decodes and returns the given string, which can be either the
-// numeric or name representation, into the integer uid or gid. Returns
-// UINT_MAX on error.
-bool DecodeUid(const std::string& name, uid_t* uid, std::string* err) {
-    *uid = UINT_MAX;
-    *err = "";
-
+// numeric or name representation, into the integer uid or gid.
+Result<uid_t> DecodeUid(const std::string& name) {
     if (isalpha(name[0])) {
         passwd* pwd = getpwnam(name.c_str());
-        if (!pwd) {
-            *err = "getpwnam failed: "s + strerror(errno);
-            return false;
-        }
-        *uid = pwd->pw_uid;
-        return true;
+        if (!pwd) return ErrnoError() << "getpwnam failed";
+
+        return pwd->pw_uid;
     }
 
     errno = 0;
     uid_t result = static_cast<uid_t>(strtoul(name.c_str(), 0, 0));
-    if (errno) {
-        *err = "strtoul failed: "s + strerror(errno);
-        return false;
-    }
-    *uid = result;
-    return true;
+    if (errno) return ErrnoError() << "strtoul failed";
+
+    return result;
 }
 
 /*
@@ -89,7 +80,7 @@
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
 int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon, selabel_handle* sehandle) {
+                 const char* socketcon) {
     if (socketcon) {
         if (setsockcreatecon(socketcon) == -1) {
             PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -116,11 +107,9 @@
         return -1;
     }
 
-    char *filecon = NULL;
-    if (sehandle) {
-        if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
-            setfscreatecon(filecon);
-        }
+    std::string secontext;
+    if (SelabelLookupFileContext(addr.sun_path, S_IFSOCK, &secontext) && !secontext.empty()) {
+        setfscreatecon(secontext.c_str());
     }
 
     if (passcred) {
@@ -134,8 +123,9 @@
     int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
     int savederrno = errno;
 
-    setfscreatecon(NULL);
-    freecon(filecon);
+    if (!secontext.empty()) {
+        setfscreatecon(nullptr);
+    }
 
     if (ret) {
         errno = savederrno;
@@ -164,75 +154,68 @@
     return -1;
 }
 
-bool ReadFile(const std::string& path, std::string* content, std::string* err) {
-    content->clear();
-    *err = "";
-
+Result<std::string> ReadFile(const std::string& path) {
     android::base::unique_fd fd(
         TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
     if (fd == -1) {
-        *err = "Unable to open '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "open() failed";
     }
 
     // For security reasons, disallow world-writable
     // or group-writable files.
     struct stat sb;
     if (fstat(fd, &sb) == -1) {
-        *err = "fstat failed for '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "fstat failed()";
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
-        *err = "Skipping insecure file '" + path + "'";
-        return false;
+        return Error() << "Skipping insecure file";
     }
 
-    if (!android::base::ReadFdToString(fd, content)) {
-        *err = "Unable to read '" + path + "': " + strerror(errno);
-        return false;
+    std::string content;
+    if (!android::base::ReadFdToString(fd, &content)) {
+        return ErrnoError() << "Unable to read file contents";
     }
-    return true;
+    return content;
 }
 
-bool WriteFile(const std::string& path, const std::string& content, std::string* err) {
-    *err = "";
-
+Result<Success> WriteFile(const std::string& path, const std::string& content) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
         open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
     if (fd == -1) {
-        *err = "Unable to open '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "open() failed";
     }
     if (!android::base::WriteStringToFd(content, fd)) {
-        *err = "Unable to write to '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "Unable to write file contents";
     }
-    return true;
+    return Success();
 }
 
-int mkdir_recursive(const std::string& path, mode_t mode, selabel_handle* sehandle) {
+bool mkdir_recursive(const std::string& path, mode_t mode) {
     std::string::size_type slash = 0;
     while ((slash = path.find('/', slash + 1)) != std::string::npos) {
         auto directory = path.substr(0, slash);
         struct stat info;
         if (stat(directory.c_str(), &info) != 0) {
-            auto ret = make_dir(directory.c_str(), mode, sehandle);
-            if (ret && errno != EEXIST) return ret;
+            auto ret = make_dir(directory, mode);
+            if (!ret && errno != EEXIST) return false;
         }
     }
-    auto ret = make_dir(path.c_str(), mode, sehandle);
-    if (ret && errno != EEXIST) return ret;
-    return 0;
+    auto ret = make_dir(path, mode);
+    if (!ret && errno != EEXIST) return false;
+    return true;
 }
 
 int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
-    boot_clock::time_point timeout_time = boot_clock::now() + timeout;
-    while (boot_clock::now() < timeout_time) {
+    android::base::Timer t;
+    while (t.duration() < timeout) {
         struct stat sb;
-        if (stat(filename, &sb) != -1) return 0;
-
+        if (stat(filename, &sb) != -1) {
+            LOG(INFO) << "wait for '" << filename << "' took " << t;
+            return 0;
+        }
         std::this_thread::sleep_for(10ms);
     }
+    LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
     return -1;
 }
 
@@ -249,26 +232,21 @@
     }
 }
 
-int make_dir(const char* path, mode_t mode, selabel_handle* sehandle) {
-    int rc;
-
-    char *secontext = NULL;
-
-    if (sehandle) {
-        selabel_lookup(sehandle, &secontext, path, mode);
-        setfscreatecon(secontext);
+bool make_dir(const std::string& path, mode_t mode) {
+    std::string secontext;
+    if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
+        setfscreatecon(secontext.c_str());
     }
 
-    rc = mkdir(path, mode);
+    int rc = mkdir(path.c_str(), mode);
 
-    if (secontext) {
+    if (!secontext.empty()) {
         int save_errno = errno;
-        freecon(secontext);
-        setfscreatecon(NULL);
+        setfscreatecon(nullptr);
         errno = save_errno;
     }
 
-    return rc;
+    return rc == 0;
 }
 
 /*
@@ -370,12 +348,6 @@
     return true;
 }
 
-void panic() {
-    LOG(ERROR) << "panic: rebooting to bootloader";
-    // Do not queue "shutdown" trigger since we want to shutdown immediately
-    DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
-}
-
 static std::string init_android_dt_dir() {
     // Use the standard procfs-based path by default
     std::string android_dt_dir = kDefaultAndroidDtDir;
diff --git a/init/util.h b/init/util.h
index 29c10cb..2cfcf6c 100644
--- a/init/util.h
+++ b/init/util.h
@@ -28,6 +28,8 @@
 #include <android-base/chrono_utils.h>
 #include <selinux/label.h>
 
+#include "result.h"
+
 #define COLDBOOT_DONE "/dev/.coldboot_done"
 
 using android::base::boot_clock;
@@ -37,24 +39,22 @@
 namespace init {
 
 int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon, selabel_handle* sehandle);
+                 const char* socketcon);
 
-bool ReadFile(const std::string& path, std::string* content, std::string* err);
-bool WriteFile(const std::string& path, const std::string& content, std::string* err);
+Result<std::string> ReadFile(const std::string& path);
+Result<Success> WriteFile(const std::string& path, const std::string& content);
 
-bool DecodeUid(const std::string& name, uid_t* uid, std::string* err);
+Result<uid_t> DecodeUid(const std::string& name);
 
-int mkdir_recursive(const std::string& pathname, mode_t mode, selabel_handle* sehandle);
+bool mkdir_recursive(const std::string& pathname, mode_t mode);
 int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
 void import_kernel_cmdline(bool in_qemu,
                            const std::function<void(const std::string&, const std::string&, bool)>&);
-int make_dir(const char* path, mode_t mode, selabel_handle* sehandle);
+bool make_dir(const std::string& path, mode_t mode);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
 
-void panic() __attribute__((__noreturn__));
-
 // Returns the platform's Android DT directory as specified in the kernel cmdline.
 // If the platform does not configure a custom DT path, returns the standard one (based in procfs).
 const std::string& get_android_dt_dir();
diff --git a/init/util_test.cpp b/init/util_test.cpp
index c16ab74..3ae53a4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -30,61 +30,51 @@
 namespace init {
 
 TEST(util, ReadFile_ENOENT) {
-    std::string s("hello");
-    std::string err;
     errno = 0;
-    EXPECT_FALSE(ReadFile("/proc/does-not-exist", &s, &err));
-    EXPECT_EQ("Unable to open '/proc/does-not-exist': No such file or directory", err);
+    auto file_contents = ReadFile("/proc/does-not-exist");
     EXPECT_EQ(ENOENT, errno);
-    EXPECT_EQ("", s);  // s was cleared.
+    ASSERT_FALSE(file_contents);
+    EXPECT_EQ("open() failed: No such file or directory", file_contents.error_string());
 }
 
 TEST(util, ReadFileGroupWriteable) {
     std::string s("hello");
     TemporaryFile tf;
-    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
-    EXPECT_EQ("", err);
+    EXPECT_TRUE(WriteFile(tf.path, s)) << strerror(errno);
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
-    EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
-    EXPECT_EQ("", s);  // s was cleared.
+    auto file_contents = ReadFile(tf.path);
+    ASSERT_FALSE(file_contents) << strerror(errno);
+    EXPECT_EQ("Skipping insecure file", file_contents.error_string());
 }
 
 TEST(util, ReadFileWorldWiteable) {
     std::string s("hello");
     TemporaryFile tf;
-    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
-    EXPECT_EQ("", err);
+    EXPECT_TRUE(WriteFile(tf.path, s)) << strerror(errno);
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
-    EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
-    EXPECT_EQ("", s);  // s was cleared.
+    auto file_contents = ReadFile(tf.path);
+    ASSERT_FALSE(file_contents) << strerror(errno);
+    EXPECT_EQ("Skipping insecure file", file_contents.error_string());
 }
 
 TEST(util, ReadFileSymbolicLink) {
-    std::string s("hello");
     errno = 0;
     // lrwxrwxrwx 1 root root 13 1970-01-01 00:00 charger -> /sbin/healthd
-    std::string err;
-    EXPECT_FALSE(ReadFile("/charger", &s, &err));
-    EXPECT_EQ("Unable to open '/charger': Too many symbolic links encountered", err);
+    auto file_contents = ReadFile("/charger");
     EXPECT_EQ(ELOOP, errno);
-    EXPECT_EQ("", s);  // s was cleared.
+    ASSERT_FALSE(file_contents);
+    EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error_string());
 }
 
 TEST(util, ReadFileSuccess) {
-    std::string s("hello");
-    std::string err;
-    EXPECT_TRUE(ReadFile("/proc/version", &s, &err));
-    EXPECT_EQ("", err);
-    EXPECT_GT(s.length(), 6U);
-    EXPECT_EQ('\n', s[s.length() - 1]);
-    s[5] = 0;
-    EXPECT_STREQ("Linux", s.c_str());
+    auto file_contents = ReadFile("/proc/version");
+    ASSERT_TRUE(file_contents);
+    EXPECT_GT(file_contents->length(), 6U);
+    EXPECT_EQ('\n', file_contents->at(file_contents->length() - 1));
+    (*file_contents)[5] = 0;
+    EXPECT_STREQ("Linux", file_contents->c_str());
 }
 
 TEST(util, WriteFileBinary) {
@@ -95,29 +85,23 @@
     ASSERT_EQ(10u, contents.size());
 
     TemporaryFile tf;
-    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, contents, &err)) << strerror(errno);
-    EXPECT_EQ("", err);
+    EXPECT_TRUE(WriteFile(tf.path, contents)) << strerror(errno);
 
-    std::string read_back_contents;
-    EXPECT_TRUE(ReadFile(tf.path, &read_back_contents, &err)) << strerror(errno);
-    EXPECT_EQ("", err);
-    EXPECT_EQ(contents, read_back_contents);
-    EXPECT_EQ(10u, read_back_contents.size());
+    auto read_back_contents = ReadFile(tf.path);
+    ASSERT_TRUE(read_back_contents) << strerror(errno);
+    EXPECT_EQ(contents, *read_back_contents);
+    EXPECT_EQ(10u, read_back_contents->size());
 }
 
 TEST(util, WriteFileNotExist) {
     std::string s("hello");
-    std::string s2("hello");
     TemporaryDir test_dir;
     std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
-    std::string err;
-    EXPECT_TRUE(WriteFile(path, s, &err));
-    EXPECT_EQ("", err);
-    EXPECT_TRUE(ReadFile(path, &s2, &err));
-    EXPECT_EQ("", err);
-    EXPECT_EQ(s, s2);
+    EXPECT_TRUE(WriteFile(path, s));
+    auto file_contents = ReadFile(path);
+    ASSERT_TRUE(file_contents);
+    EXPECT_EQ(s, *file_contents);
     struct stat sb;
     int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
     EXPECT_NE(-1, fd);
@@ -127,37 +111,30 @@
 }
 
 TEST(util, WriteFileExist) {
-    std::string s2("");
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    std::string err;
-    EXPECT_TRUE(WriteFile(tf.path, "1hello1", &err)) << strerror(errno);
-    EXPECT_EQ("", err);
-    EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
-    EXPECT_EQ("", err);
-    EXPECT_STREQ("1hello1", s2.c_str());
-    EXPECT_TRUE(WriteFile(tf.path, "2ll2", &err));
-    EXPECT_EQ("", err);
-    EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
-    EXPECT_EQ("", err);
-    EXPECT_STREQ("2ll2", s2.c_str());
+    EXPECT_TRUE(WriteFile(tf.path, "1hello1")) << strerror(errno);
+    auto file_contents = ReadFile(tf.path);
+    ASSERT_TRUE(file_contents);
+    EXPECT_EQ("1hello1", *file_contents);
+    EXPECT_TRUE(WriteFile(tf.path, "2ll2"));
+    file_contents = ReadFile(tf.path);
+    ASSERT_TRUE(file_contents);
+    EXPECT_EQ("2ll2", *file_contents);
 }
 
 TEST(util, DecodeUid) {
-    uid_t decoded_uid;
-    std::string err;
+    auto decoded_uid = DecodeUid("root");
+    EXPECT_TRUE(decoded_uid);
+    EXPECT_EQ(0U, *decoded_uid);
 
-    EXPECT_TRUE(DecodeUid("root", &decoded_uid, &err));
-    EXPECT_EQ("", err);
-    EXPECT_EQ(0U, decoded_uid);
+    decoded_uid = DecodeUid("toot");
+    EXPECT_FALSE(decoded_uid);
+    EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error_string());
 
-    EXPECT_FALSE(DecodeUid("toot", &decoded_uid, &err));
-    EXPECT_EQ("getpwnam failed: No such file or directory", err);
-    EXPECT_EQ(UINT_MAX, decoded_uid);
-
-    EXPECT_TRUE(DecodeUid("123", &decoded_uid, &err));
-    EXPECT_EQ("", err);
-    EXPECT_EQ(123U, decoded_uid);
+    decoded_uid = DecodeUid("123");
+    EXPECT_TRUE(decoded_uid);
+    EXPECT_EQ(123U, *decoded_uid);
 }
 
 TEST(util, is_dir) {
@@ -170,7 +147,7 @@
 TEST(util, mkdir_recursive) {
     TemporaryDir test_dir;
     std::string path = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
-    EXPECT_EQ(0, mkdir_recursive(path, 0755, nullptr));
+    EXPECT_TRUE(mkdir_recursive(path, 0755));
     std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
     EXPECT_TRUE(is_dir(path1.c_str()));
     std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
@@ -182,7 +159,7 @@
 TEST(util, mkdir_recursive_extra_slashes) {
     TemporaryDir test_dir;
     std::string path = android::base::StringPrintf("%s/three////directories/deep//", test_dir.path);
-    EXPECT_EQ(0, mkdir_recursive(path, 0755, nullptr));
+    EXPECT_TRUE(mkdir_recursive(path, 0755));
     std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
     EXPECT_TRUE(is_dir(path1.c_str()));
     std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index b0ac5c4..29ffe32 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -8,7 +8,6 @@
         "-Wall",
         "-Werror",
     ],
-    clang: true
 }
 
 cc_library_shared {
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
new file mode 100644
index 0000000..9a637ac
--- /dev/null
+++ b/libasyncio/Android.bp
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+
+libasyncio_cppflags = [
+    "-Wall",
+    "-Wextra",
+    "-Werror",
+]
+
+cc_library {
+    name: "libasyncio",
+    vendor_available: true,
+    host_supported: true,
+    srcs: [
+        "AsyncIO.cpp",
+    ],
+    cppflags: libasyncio_cppflags,
+
+    export_include_dirs: ["include"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libasyncio/AsyncIO.cpp b/libasyncio/AsyncIO.cpp
new file mode 100644
index 0000000..7430bc8
--- /dev/null
+++ b/libasyncio/AsyncIO.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 <asyncio/AsyncIO.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int io_setup(unsigned nr, aio_context_t* ctxp) {
+    memset(ctxp, 0, sizeof(*ctxp));
+    return syscall(__NR_io_setup, nr, ctxp);
+}
+
+int io_destroy(aio_context_t ctx) {
+    return syscall(__NR_io_destroy, ctx);
+}
+
+int io_submit(aio_context_t ctx, long nr, iocb** iocbpp) {
+    return syscall(__NR_io_submit, ctx, nr, iocbpp);
+}
+
+int io_getevents(aio_context_t ctx, long min_nr, long max_nr, io_event* events, timespec* timeout) {
+    return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
+}
+
+int io_cancel(aio_context_t ctx, iocb* iocbp, io_event* result) {
+    return syscall(__NR_io_cancel, ctx, iocbp, result);
+}
+
+void io_prep(iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read) {
+    memset(iocb, 0, sizeof(*iocb));
+    iocb->aio_fildes = fd;
+    iocb->aio_lio_opcode = read ? IOCB_CMD_PREAD : IOCB_CMD_PWRITE;
+    iocb->aio_reqprio = 0;
+    iocb->aio_buf = reinterpret_cast<uint64_t>(buf);
+    iocb->aio_nbytes = count;
+    iocb->aio_offset = offset;
+}
diff --git a/libasyncio/include/asyncio/AsyncIO.h b/libasyncio/include/asyncio/AsyncIO.h
new file mode 100644
index 0000000..e3fb93a
--- /dev/null
+++ b/libasyncio/include/asyncio/AsyncIO.h
@@ -0,0 +1,47 @@
+/*
+ * 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 _ASYNCIO_H
+#define _ASYNCIO_H
+
+#include <cstring>
+#include <cstdint>
+#include <linux/aio_abi.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Provides kernel aio operations.
+ */
+
+int io_setup(unsigned nr, aio_context_t* ctxp);
+int io_destroy(aio_context_t ctx);
+int io_submit(aio_context_t ctx, long nr, iocb** iocbpp);
+int io_getevents(aio_context_t ctx, long min_nr, long max_nr, io_event* events, timespec* timeout);
+int io_cancel(aio_context_t ctx, iocb*, io_event* result);
+void io_prep(iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif  // ASYNCIO_H
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 7eefc95..e889bdd 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -53,6 +53,8 @@
     "UnwindCurrent.cpp",
     "UnwindMap.cpp",
     "UnwindPtrace.cpp",
+    "UnwindStack.cpp",
+    "UnwindStackMap.cpp",
 ]
 
 cc_library_headers {
@@ -88,6 +90,7 @@
                 "libbase",
                 "liblog",
                 "libunwind",
+                "libunwindstack",
             ],
 
             static_libs: ["libcutils"],
@@ -101,6 +104,7 @@
                 "libbase",
                 "liblog",
                 "libunwind",
+                "libunwindstack",
             ],
 
             static_libs: ["libcutils"],
@@ -112,6 +116,7 @@
                 "libbase",
                 "liblog",
                 "libunwind",
+                "libunwindstack",
             ],
 
             static_libs: ["libasync_safe", "libcutils"],
@@ -134,11 +139,13 @@
         linux: {
             shared_libs: [
                 "libunwind",
+                "libunwindstack",
             ],
         },
         android: {
             shared_libs: [
                 "libunwind",
+                "libunwindstack",
             ],
         },
     }
@@ -165,6 +172,7 @@
     shared_libs = [
         "libbase",
         "libunwind",
+        "libunwindstack",
         "libziparchive",
     ],
 }
@@ -196,6 +204,7 @@
         "libcutils",
         "liblog",
         "libunwind",
+        "libunwindstack",
     ],
 
     group_static_libs: true,
@@ -234,4 +243,25 @@
             static_libs: ["libutils"],
         },
     },
+
+    data: [
+        "testdata/arm/*",
+        "testdata/arm64/*",
+        "testdata/x86/*",
+        "testdata/x86_64/*",
+    ],
+}
+
+cc_benchmark {
+    name: "backtrace_benchmarks",
+    defaults: ["libbacktrace_common"],
+
+    srcs: [
+        "backtrace_benchmarks.cpp",
+    ],
+
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+    ],
 }
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
new file mode 100644
index 0000000..61812ab
--- /dev/null
+++ b/libbacktrace/UnwindStack.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE 1
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include <memory>
+#include <string>
+
+#if !defined(__ANDROID__)
+#include <cutils/threads.h>
+#endif
+
+#include <backtrace/Backtrace.h>
+#include <demangle.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+
+#include "BacktraceLog.h"
+#include "UnwindStack.h"
+#include "UnwindStackMap.h"
+
+static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
+
+  // Get the map for this
+  unwindstack::MapInfo* map_info = maps->Find(pc);
+  if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
+    return "";
+  }
+
+  UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
+  unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
+
+  std::string name;
+  uint64_t func_offset;
+  if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
+    return "";
+  }
+  *offset = func_offset;
+  return name;
+}
+
+static bool IsUnwindLibrary(const std::string& map_name) {
+  const std::string library(basename(map_name.c_str()));
+  return library == "libunwindstack.so" || library == "libbacktrace.so";
+}
+
+static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
+                   std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
+  UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
+  unwindstack::Maps* maps = stack_map->stack_maps();
+  bool adjust_rel_pc = false;
+  size_t num_frames = 0;
+  frames->clear();
+  while (num_frames < MAX_BACKTRACE_FRAMES) {
+    if (regs->pc() == 0) {
+      break;
+    }
+    unwindstack::MapInfo* map_info = maps->Find(regs->pc());
+    if (map_info == nullptr) {
+      break;
+    }
+
+    unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
+    uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
+
+    bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
+    if (num_ignore_frames == 0 && !skip_frame) {
+      uint64_t adjusted_rel_pc = rel_pc;
+      if (adjust_rel_pc) {
+        adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
+      }
+      frames->resize(num_frames + 1);
+      backtrace_frame_data_t* frame = &frames->at(num_frames);
+      frame->num = num_frames;
+      // This will point to the adjusted absolute pc. regs->pc() is
+      // unaltered.
+      frame->pc = map_info->start + adjusted_rel_pc;
+      frame->sp = regs->sp();
+      frame->rel_pc = adjusted_rel_pc;
+      frame->stack_size = 0;
+
+      frame->map.start = map_info->start;
+      frame->map.end = map_info->end;
+      frame->map.offset = map_info->offset;
+      frame->map.load_bias = elf->GetLoadBias();
+      frame->map.flags = map_info->flags;
+      frame->map.name = map_info->name;
+
+      uint64_t func_offset = 0;
+      if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
+        frame->func_name = demangle(frame->func_name.c_str());
+      } else {
+        frame->func_name = "";
+      }
+      frame->func_offset = func_offset;
+      if (num_frames > 0) {
+        // Set the stack size for the previous frame.
+        backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
+        prev->stack_size = frame->sp - prev->sp;
+      }
+      num_frames++;
+    } else if (!skip_frame && num_ignore_frames > 0) {
+      num_ignore_frames--;
+    }
+    adjust_rel_pc = true;
+
+    // Do not unwind through a device map.
+    if (map_info->flags & PROT_DEVICE_MAP) {
+      break;
+    }
+    unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
+    if (sp_info->flags & PROT_DEVICE_MAP) {
+      break;
+    }
+
+    if (!elf->Step(rel_pc + map_info->elf_offset, regs, stack_map->process_memory().get())) {
+      break;
+    }
+  }
+
+  return true;
+}
+
+UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktraceCurrent(pid, tid, map) {}
+
+std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  return ::GetFunctionName(GetMap(), pc, offset);
+}
+
+bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+  std::unique_ptr<unwindstack::Regs> regs;
+  if (ucontext == nullptr) {
+    regs.reset(unwindstack::Regs::CreateFromLocal());
+    // Fill in the registers from this function. Do it here to avoid
+    // one extra function call appearing in the unwind.
+    unwindstack::RegsGetLocal(regs.get());
+  } else {
+    regs.reset(
+        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
+  }
+
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
+  return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+}
+
+UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktracePtrace(pid, tid, map) {}
+
+std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  return ::GetFunctionName(GetMap(), pc, offset);
+}
+
+bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
+  std::unique_ptr<unwindstack::Regs> regs;
+  if (context == nullptr) {
+    regs.reset(unwindstack::Regs::RemoteGet(Tid()));
+  } else {
+    regs.reset(
+        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
+  }
+
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
+  return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+}
+
+Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
+  if (pid == BACKTRACE_CURRENT_PROCESS) {
+    pid = getpid();
+    if (tid == BACKTRACE_CURRENT_THREAD) {
+      tid = gettid();
+    }
+  } else if (tid == BACKTRACE_CURRENT_THREAD) {
+    tid = pid;
+  }
+
+  if (map == nullptr) {
+// This would cause the wrong type of map object to be created, so disallow.
+#if defined(__ANDROID__)
+    __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
+              "Backtrace::CreateNew() must be called with a real map pointer.");
+#else
+    BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
+    abort();
+#endif
+  }
+
+  if (pid == getpid()) {
+    return new UnwindStackCurrent(pid, tid, map);
+  } else {
+    return new UnwindStackPtrace(pid, tid, map);
+  }
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
new file mode 100644
index 0000000..be9ef63
--- /dev/null
+++ b/libbacktrace/UnwindStack.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 _LIBBACKTRACE_UNWIND_STACK_H
+#define _LIBBACKTRACE_UNWIND_STACK_H
+
+#include <stdint.h>
+
+#include <string>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Memory.h>
+
+#include "BacktraceCurrent.h"
+#include "BacktracePtrace.h"
+
+class UnwindStackCurrent : public BacktraceCurrent {
+ public:
+  UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
+  virtual ~UnwindStackCurrent() = default;
+
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+
+  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
+};
+
+class UnwindStackPtrace : public BacktracePtrace {
+ public:
+  UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
+  virtual ~UnwindStackPtrace() = default;
+
+  bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
+
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+};
+
+#endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
new file mode 100644
index 0000000..d4a2444
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+
+#include "UnwindStackMap.h"
+
+//-------------------------------------------------------------------------
+UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
+
+bool UnwindStackMap::Build() {
+  if (pid_ == 0) {
+    pid_ = getpid();
+    stack_maps_.reset(new unwindstack::LocalMaps);
+  } else {
+    stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
+  }
+
+  // Create the process memory object.
+  process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_);
+
+  if (!stack_maps_->Parse()) {
+    return false;
+  }
+
+  // Iterate through the maps and fill in the backtrace_map_t structure.
+  for (auto& map_info : *stack_maps_) {
+    backtrace_map_t map;
+    map.start = map_info.start;
+    map.end = map_info.end;
+    map.offset = map_info.offset;
+    // Set to -1 so that it is demand loaded.
+    map.load_bias = static_cast<uintptr_t>(-1);
+    map.flags = map_info.flags;
+    map.name = map_info.name;
+
+    maps_.push_back(map);
+  }
+
+  return true;
+}
+
+void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+  BacktraceMap::FillIn(addr, map);
+  if (map->load_bias != static_cast<uintptr_t>(-1)) {
+    return;
+  }
+
+  // Fill in the load_bias.
+  unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
+  if (map_info == nullptr) {
+    return;
+  }
+  unwindstack::Elf* elf = map_info->GetElf(process_memory_, true);
+  map->load_bias = elf->GetLoadBias();
+}
+
+//-------------------------------------------------------------------------
+// BacktraceMap create function.
+//-------------------------------------------------------------------------
+BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
+  BacktraceMap* map;
+
+  if (uncached) {
+    // Force use of the base class to parse the maps when this call is made.
+    map = new BacktraceMap(pid);
+  } else if (pid == getpid()) {
+    map = new UnwindStackMap(0);
+  } else {
+    map = new UnwindStackMap(pid);
+  }
+  if (!map->Build()) {
+    delete map;
+    return nullptr;
+  }
+  return map;
+}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
new file mode 100644
index 0000000..b93b340
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.h
@@ -0,0 +1,46 @@
+/*
+ * 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 _LIBBACKTRACE_UNWINDSTACK_MAP_H
+#define _LIBBACKTRACE_UNWINDSTACK_MAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <memory>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Maps.h>
+
+class UnwindStackMap : public BacktraceMap {
+ public:
+  explicit UnwindStackMap(pid_t pid);
+  ~UnwindStackMap() = default;
+
+  bool Build() override;
+
+  void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+
+  unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
+
+  const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
+
+ protected:
+  std::unique_ptr<unwindstack::Maps> stack_maps_;
+  std::shared_ptr<unwindstack::Memory> process_memory_;
+};
+
+#endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
new file mode 100644
index 0000000..30c2a55
--- /dev/null
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/file.h>
+
+#include <benchmark/benchmark.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+// Definitions of prctl arguments to set a vma name in Android kernels.
+#define ANDROID_PR_SET_VMA 0x53564d41
+#define ANDROID_PR_SET_VMA_ANON_NAME 0
+
+constexpr size_t kNumMaps = 2000;
+constexpr size_t kNumIterations = 1000;
+
+static bool CountMaps(pid_t pid, size_t* num_maps) {
+  // Minimize the calls that might allocate memory. If too much memory
+  // gets allocated, then this routine will add extra maps and the next
+  // call will fail to get the same number of maps as before.
+  int fd =
+      open((std::string("/proc/") + std::to_string(pid) + "/maps").c_str(), O_RDONLY | O_CLOEXEC);
+  if (fd == -1) {
+    fprintf(stderr, "Cannot open map file for pid %d: %s\n", pid, strerror(errno));
+    return false;
+  }
+  *num_maps = 0;
+  while (true) {
+    char buffer[2048];
+    ssize_t bytes = read(fd, buffer, sizeof(buffer));
+    if (bytes <= 0) {
+      break;
+    }
+    // Count the '\n'.
+    for (size_t i = 0; i < static_cast<size_t>(bytes); i++) {
+      if (buffer[i] == '\n') {
+        ++*num_maps;
+      }
+    }
+  }
+
+  close(fd);
+  return true;
+}
+
+static void CreateMap(benchmark::State& state, BacktraceMap* (*map_func)(pid_t, bool)) {
+  state.PauseTiming();
+  // Create a remote process so that the map data is exactly the same.
+  // Also, so that we can create a set number of maps.
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    size_t num_maps;
+    if (!CountMaps(getpid(), &num_maps)) {
+      exit(1);
+    }
+    // Create uniquely named maps.
+    std::vector<void*> maps;
+    for (size_t i = num_maps; i < kNumMaps; i++) {
+      int flags = PROT_READ | PROT_WRITE;
+      // Alternate page type to make sure a map entry is added for each call.
+      if ((i % 2) == 0) {
+        flags |= PROT_EXEC;
+      }
+      void* memory = mmap(nullptr, PAGE_SIZE, flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (memory == MAP_FAILED) {
+        fprintf(stderr, "Failed to create map: %s\n", strerror(errno));
+        exit(1);
+      }
+      memset(memory, 0x1, PAGE_SIZE);
+      if (prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, memory, PAGE_SIZE, "test_map") ==
+          -1) {
+        fprintf(stderr, "Failed: %s\n", strerror(errno));
+      }
+      maps.push_back(memory);
+    }
+
+    if (!CountMaps(getpid(), &num_maps)) {
+      exit(1);
+    }
+
+    if (num_maps != kNumMaps) {
+      fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected.\n", num_maps, kNumMaps);
+      std::string str;
+      android::base::ReadFileToString("/proc/self/maps", &str);
+      fprintf(stderr, "%s\n", str.c_str());
+      exit(1);
+    }
+
+    // Wait for an hour at most.
+    sleep(3600);
+    exit(1);
+  } else if (pid < 0) {
+    fprintf(stderr, "Fork failed: %s\n", strerror(errno));
+    return;
+  }
+
+  size_t num_maps = 0;
+  for (size_t i = 0; i < 2000; i++) {
+    if (CountMaps(pid, &num_maps) && num_maps == kNumMaps) {
+      break;
+    }
+    usleep(1000);
+  }
+  if (num_maps != kNumMaps) {
+    fprintf(stderr, "Timed out waiting for the number of maps available: %zu\n", num_maps);
+    return;
+  }
+
+  state.ResumeTiming();
+  while (state.KeepRunning()) {
+    for (size_t i = 0; i < static_cast<size_t>(state.range(0)); i++) {
+      BacktraceMap* map = map_func(pid, false);
+      if (map == nullptr) {
+        fprintf(stderr, "Failed to create map\n");
+        return;
+      }
+      delete map;
+    }
+  }
+  state.PauseTiming();
+
+  kill(pid, SIGKILL);
+  waitpid(pid, nullptr, 0);
+}
+
+static void BM_create_map(benchmark::State& state) {
+  CreateMap(state, BacktraceMap::Create);
+}
+BENCHMARK(BM_create_map)->Arg(kNumIterations);
+
+static void BM_create_map_new(benchmark::State& state) {
+  CreateMap(state, BacktraceMap::CreateNew);
+}
+BENCHMARK(BM_create_map_new)->Arg(kNumIterations);
+
+BENCHMARK_MAIN();
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 16b1d79..0a1f33d 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/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <backtrace/Backtrace.h>
@@ -129,6 +130,10 @@
   return nullptr;
 }
 
+std::string GetTestPath(std::string path) {
+  return android::base::GetExecutableDirectory() + "/testdata/" + ABI_STRING + '/' + path;
+}
+
 // This test is disable because it is for generating test data.
 TEST(libbacktrace, DISABLED_generate_offline_testdata) {
   // Create a thread to generate the needed stack and registers information.
@@ -206,20 +211,6 @@
   return "";
 }
 
-static std::string GetArch() {
-#if defined(__arm__)
-  return "arm";
-#elif defined(__aarch64__)
-  return "aarch64";
-#elif defined(__i386__)
-  return "x86";
-#elif defined(__x86_64__)
-  return "x86_64";
-#else
-  return "";
-#endif
-}
-
 struct OfflineTestData {
   int pid;
   int tid;
@@ -280,20 +271,15 @@
   return true;
 }
 
-static void BacktraceOfflineTest(const std::string& testlib_name) {
-  const std::string arch = GetArch();
-  if (arch.empty()) {
-    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
-    return;
-  }
-  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
-  struct stat st;
-  if (stat(testlib_path.c_str(), &st) == -1) {
-    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+static void BacktraceOfflineTest(const char* arch, const std::string& testlib_name) {
+  // TODO: For now, we can only run this on the same arch as the library arch.
+  if (std::string(ABI_STRING) != arch) {
+    GTEST_LOG_(INFO) << "Ignoring arch " << arch << " for lib " << testlib_name;
     return;
   }
 
-  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+  const std::string testlib_path(GetTestPath(testlib_name));
+  const std::string offline_testdata_path(GetTestPath("offline_testdata"));
   OfflineTestData testdata;
   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
@@ -339,35 +325,40 @@
                                                       testdata.symbols));
 }
 
+// For now, these tests can only run on the given architectures.
 TEST(libbacktrace, offline_eh_frame) {
-  BacktraceOfflineTest("libbacktrace_test_eh_frame.so");
+  BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
+  BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
 }
 
 TEST(libbacktrace, offline_debug_frame) {
-  BacktraceOfflineTest("libbacktrace_test_debug_frame.so");
+  BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
+  BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
 }
 
 TEST(libbacktrace, offline_gnu_debugdata) {
-  BacktraceOfflineTest("libbacktrace_test_gnu_debugdata.so");
+  BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
+  BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
 }
 
 TEST(libbacktrace, offline_arm_exidx) {
-  BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
+  BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
 }
 
 // This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
 // overlap with each other, which appears in /system/lib/libart.so.
 TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
-  const std::string arch = GetArch();
-  if (arch.empty() || arch != "arm") {
-    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+  // TODO: For now, only run on the given arch.
+  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 = "testdata/" + arch + "/libart.so";
+  const std::string testlib_path(GetTestPath("libart.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 = "testdata/" + arch + "/offline_testdata_for_libart";
+  const std::string offline_testdata_path(GetTestPath("offline_testdata_for_libart"));
   OfflineTestData testdata;
   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 1ec6a45..9fe2d1c 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -304,8 +304,10 @@
   ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
 }
 
-static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*),
-                           void (*VerifyFunc)(Backtrace*)) {
+static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
+                           void (*VerifyFunc)(Backtrace*),
+                           Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
+                           BacktraceMap* (*map_func)(pid_t, bool)) {
   pid_t ptrace_tid;
   if (tid < 0) {
     ptrace_tid = pid;
@@ -322,10 +324,8 @@
       WaitForStop(ptrace_tid);
 
       std::unique_ptr<BacktraceMap> map;
-      if (share_map) {
-        map.reset(BacktraceMap::Create(pid));
-      }
-      std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+      map.reset(map_func(pid, false));
+      std::unique_ptr<Backtrace> backtrace(back_func(pid, tid, map.get()));
       ASSERT_TRUE(backtrace.get() != nullptr);
       ASSERT_TRUE(backtrace->Unwind(0));
       ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
@@ -349,21 +349,22 @@
     ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
+                 Backtrace::Create, BacktraceMap::Create);
 
   kill(pid, SIGKILL);
   int status;
   ASSERT_EQ(waitpid(pid, &status, 0), pid);
 }
 
-TEST(libbacktrace, ptrace_trace_shared_map) {
+TEST(libbacktrace, ptrace_trace_new) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
-
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, true, ReadyLevelBacktrace, VerifyLevelDump);
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
+                 Backtrace::CreateNew, BacktraceMap::CreateNew);
 
   kill(pid, SIGKILL);
   int status;
@@ -376,7 +377,22 @@
     ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
     _exit(1);
   }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
+                 BacktraceMap::Create);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+TEST(libbacktrace, ptrace_max_trace_new) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
+    _exit(1);
+  }
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump,
+                 Backtrace::CreateNew, BacktraceMap::CreateNew);
 
   kill(pid, SIGKILL);
   int status;
@@ -403,7 +419,22 @@
     ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
-  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
+                 Backtrace::Create, BacktraceMap::Create);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+TEST(libbacktrace, ptrace_ignore_frames_new) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+    _exit(1);
+  }
+  VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
+                 Backtrace::CreateNew, BacktraceMap::CreateNew);
 
   kill(pid, SIGKILL);
   int status;
@@ -466,7 +497,47 @@
     if (pid == *it) {
       continue;
     }
-    VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump);
+    VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::Create,
+                   BacktraceMap::Create);
+  }
+
+  FinishRemoteProcess(pid);
+}
+
+TEST(libbacktrace, ptrace_threads_new) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
+      pthread_attr_t attr;
+      pthread_attr_init(&attr);
+      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+      pthread_t thread;
+      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
+    }
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+    _exit(1);
+  }
+
+  // Check to see that all of the threads are running before unwinding.
+  std::vector<pid_t> threads;
+  uint64_t start = NanoTime();
+  do {
+    usleep(US_PER_MSEC);
+    threads.clear();
+    GetThreads(pid, &threads);
+  } while ((threads.size() != NUM_PTRACE_THREADS + 1) && ((NanoTime() - start) <= 5 * NS_PER_SEC));
+  ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+  WaitForStop(pid);
+  for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
+    // Skip the current forked process, we only care about the threads.
+    if (pid == *it) {
+      continue;
+    }
+    VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::CreateNew,
+                   BacktraceMap::CreateNew);
   }
 
   FinishRemoteProcess(pid);
@@ -1579,7 +1650,7 @@
   munmap(device_map, DEVICE_MAP_SIZE);
 }
 
-TEST(libbacktrace, unwind_disallow_device_map_remote) {
+TEST(libbacktrace, unwind_disallow_device_map_remote_new) {
   void* device_map;
   SetupDeviceMap(&device_map);
 
@@ -1588,13 +1659,11 @@
   CreateRemoteProcess(&pid);
 
   // Now create an unwind object.
-  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::CreateNew(pid));
+  ASSERT_TRUE(map.get() != nullptr);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateNew(pid, pid, map.get()));
 
-  // TODO: Currently unwind from context doesn't work on remote
-  // unwind. Keep this test because the new unwinder should support
-  // this eventually, or we can delete this test.
-  // properly with unwind from context.
-  // UnwindFromDevice(backtrace.get(), device_map);
+  UnwindFromDevice(backtrace.get(), device_map);
 
   FinishRemoteProcess(pid);
 
@@ -1633,7 +1702,9 @@
     ;
 }
 
-static void UnwindThroughSignal(bool use_action) {
+static void UnwindThroughSignal(bool use_action,
+                                Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
+                                BacktraceMap* (*map_func)(pid_t, bool)) {
   volatile int value = 0;
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -1659,7 +1730,8 @@
 
     WaitForStop(pid);
 
-    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+    std::unique_ptr<BacktraceMap> map(map_func(pid, false));
+    std::unique_ptr<Backtrace> backtrace(back_func(pid, pid, map.get()));
 
     size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)),
                                         reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
@@ -1677,6 +1749,7 @@
   // Wait for the process to get to the signal handler loop.
   Backtrace::const_iterator frame_iter;
   start = NanoTime();
+  std::unique_ptr<BacktraceMap> map;
   std::unique_ptr<Backtrace> backtrace;
   while (true) {
     usleep(1000);
@@ -1685,7 +1758,9 @@
 
     WaitForStop(pid);
 
-    backtrace.reset(Backtrace::Create(pid, pid));
+    map.reset(map_func(pid, false));
+    ASSERT_TRUE(map.get() != nullptr);
+    backtrace.reset(back_func(pid, pid, map.get()));
     ASSERT_TRUE(backtrace->Unwind(0));
     bool found = false;
     for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) {
@@ -1742,11 +1817,19 @@
 }
 
 TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
-  UnwindThroughSignal(false);
+  UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
+}
+
+TEST(libbacktrace, unwind_remote_through_signal_using_handler_new) {
+  UnwindThroughSignal(false, Backtrace::CreateNew, BacktraceMap::CreateNew);
 }
 
 TEST(libbacktrace, unwind_remote_through_signal_using_action) {
-  UnwindThroughSignal(true);
+  UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
+}
+
+TEST(libbacktrace, unwind_remote_through_signal_using_action_new) {
+  UnwindThroughSignal(true, Backtrace::CreateNew, BacktraceMap::CreateNew);
 }
 
 #if defined(ENABLE_PSS_TESTS)
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index b919e81..d67ea50 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -90,6 +90,8 @@
   // If map is NULL, then create the map and manage it internally.
   // If map is not NULL, the map is still owned by the caller.
   static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
+  // Same as above, but uses a different underlying unwinder.
+  static Backtrace* CreateNew(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
 
   // Create an offline Backtrace object that can be used to do an unwind without a process
   // that is still running. If cache_file is set to true, then elf information will be cached
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 02a50f7..963c34b 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -52,6 +52,8 @@
   // Passing a map created with uncached set to true to Backtrace::Create()
   // is unsupported.
   static BacktraceMap* Create(pid_t pid, bool uncached = false);
+  // Same as above, but is compatible with the new unwinder.
+  static BacktraceMap* CreateNew(pid_t pid, bool uncached = false);
 
   static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
 
diff --git a/libbacktrace/include/backtrace/backtrace_constants.h b/libbacktrace/include/backtrace/backtrace_constants.h
index f8c1575..373a1e5 100644
--- a/libbacktrace/include/backtrace/backtrace_constants.h
+++ b/libbacktrace/include/backtrace/backtrace_constants.h
@@ -20,10 +20,10 @@
 // When the pid to be traced is set to this value, then trace the current
 // process. If the tid value is not BACKTRACE_NO_TID, then the specified
 // thread from the current process will be traced.
-#define BACKTRACE_CURRENT_PROCESS -1
+#define BACKTRACE_CURRENT_PROCESS (-1)
 // When the tid to be traced is set to this value, then trace the specified
 // current thread of the specified pid.
-#define BACKTRACE_CURRENT_THREAD -1
+#define BACKTRACE_CURRENT_THREAD (-1)
 
 #define MAX_BACKTRACE_FRAMES 64
 
diff --git a/libbacktrace/testdata/arm/offline_testdata b/libbacktrace/testdata/arm/offline_testdata
index 43d305a..6acea29 100644
--- a/libbacktrace/testdata/arm/offline_testdata
+++ b/libbacktrace/testdata/arm/offline_testdata
@@ -1,98 +1,98 @@
 pid: 32232 tid: 32233
-map: start: aad19000 end: aad6c000 offset: 0 load_base: 0 flags: 5 name: /data/backtrace_test32
-map: start: aad6c000 end: aad6e000 offset: 52000 load_base: 0 flags: 1 name: /data/backtrace_test32
-map: start: aad6e000 end: aad6f000 offset: 54000 load_base: 0 flags: 3 name: /data/backtrace_test32
-map: start: e7380000 end: e7400000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e745f000 end: e7463000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libnetd_client.so
-map: start: e7463000 end: e7464000 offset: 3000 load_base: 0 flags: 1 name: /system/lib/libnetd_client.so
-map: start: e7464000 end: e7465000 offset: 4000 load_base: 0 flags: 3 name: /system/lib/libnetd_client.so
-map: start: e7480000 end: e7500000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e7558000 end: e756c000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libunwind.so
-map: start: e756c000 end: e756d000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e756d000 end: e756e000 offset: 14000 load_base: 0 flags: 1 name: /system/lib/libunwind.so
-map: start: e756e000 end: e756f000 offset: 15000 load_base: 0 flags: 3 name: /system/lib/libunwind.so
-map: start: e756f000 end: e75b5000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e75d4000 end: e75e1000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libbase.so
-map: start: e75e1000 end: e75e2000 offset: c000 load_base: 0 flags: 1 name: /system/lib/libbase.so
-map: start: e75e2000 end: e75e3000 offset: d000 load_base: 0 flags: 3 name: /system/lib/libbase.so
-map: start: e7600000 end: e7616000 offset: 0 load_base: 0 flags: 5 name: /system/lib/liblzma.so
-map: start: e7616000 end: e7617000 offset: 15000 load_base: 0 flags: 1 name: /system/lib/liblzma.so
-map: start: e7617000 end: e7618000 offset: 16000 load_base: 0 flags: 3 name: /system/lib/liblzma.so
-map: start: e7618000 end: e761d000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e7647000 end: e7656000 offset: 0 load_base: 0 flags: 5 name: /system/lib/liblog.so
-map: start: e7656000 end: e7657000 offset: e000 load_base: 0 flags: 1 name: /system/lib/liblog.so
-map: start: e7657000 end: e7658000 offset: f000 load_base: 0 flags: 3 name: /system/lib/liblog.so
-map: start: e7681000 end: e76a2000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libm.so
-map: start: e76a2000 end: e76a3000 offset: 20000 load_base: 0 flags: 1 name: /system/lib/libm.so
-map: start: e76a3000 end: e76a4000 offset: 21000 load_base: 0 flags: 3 name: /system/lib/libm.so
-map: start: e76eb000 end: e76ee000 offset: 0 load_base: 0 flags: 5 name: /data/libbacktrace_test.so
-map: start: e76ee000 end: e76ef000 offset: 2000 load_base: 0 flags: 1 name: /data/libbacktrace_test.so
-map: start: e76ef000 end: e76f0000 offset: 3000 load_base: 0 flags: 3 name: /data/libbacktrace_test.so
-map: start: e7712000 end: e771f000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libbacktrace.so
-map: start: e771f000 end: e7720000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e7720000 end: e7721000 offset: d000 load_base: 0 flags: 1 name: /system/lib/libbacktrace.so
-map: start: e7721000 end: e7722000 offset: e000 load_base: 0 flags: 3 name: /system/lib/libbacktrace.so
-map: start: e7761000 end: e7778000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libutils.so
-map: start: e7778000 end: e7779000 offset: 16000 load_base: 0 flags: 1 name: /system/lib/libutils.so
-map: start: e7779000 end: e777a000 offset: 17000 load_base: 0 flags: 3 name: /system/lib/libutils.so
-map: start: e77a5000 end: e782d000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libc.so
-map: start: e782d000 end: e7831000 offset: 87000 load_base: 0 flags: 1 name: /system/lib/libc.so
-map: start: e7831000 end: e7833000 offset: 8b000 load_base: 0 flags: 3 name: /system/lib/libc.so
-map: start: e7833000 end: e7834000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e7834000 end: e7835000 offset: 0 load_base: 0 flags: 1 name: [anon:.bss]
-map: start: e7835000 end: e783b000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e7845000 end: e8437000 offset: 0 load_base: 2b000 flags: 5 name: /system/lib/libLLVM.so
-map: start: e8437000 end: e8438000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e8438000 end: e848a000 offset: bf2000 load_base: 0 flags: 1 name: /system/lib/libLLVM.so
-map: start: e848a000 end: e848b000 offset: c44000 load_base: 0 flags: 3 name: /system/lib/libLLVM.so
-map: start: e848b000 end: e84a1000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e84eb000 end: e84f7000 offset: 0 load_base: 0 flags: 5 name: /system/lib/libcutils.so
-map: start: e84f7000 end: e84f8000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e84f8000 end: e84f9000 offset: c000 load_base: 0 flags: 1 name: /system/lib/libcutils.so
-map: start: e84f9000 end: e84fa000 offset: d000 load_base: 0 flags: 3 name: /system/lib/libcutils.so
-map: start: e852e000 end: e85b3000 offset: 0 load_base: 2000 flags: 5 name: /system/lib/libc++.so
-map: start: e85b3000 end: e85b4000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e85b4000 end: e85b8000 offset: 85000 load_base: 0 flags: 1 name: /system/lib/libc++.so
-map: start: e85b8000 end: e85b9000 offset: 89000 load_base: 0 flags: 3 name: /system/lib/libc++.so
-map: start: e85b9000 end: e85ba000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: e85ce000 end: e85cf000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
-map: start: e85e4000 end: e85e5000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e8607000 end: e8608000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e8680000 end: e8700000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e870d000 end: e8719000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: e8719000 end: e871b000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
-map: start: e871b000 end: e873b000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
-map: start: e873b000 end: e875b000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: e875b000 end: e875c000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e875c000 end: e875d000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
-map: start: e875d000 end: e875e000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
-map: start: e875e000 end: e875f000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e875f000 end: e877f000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
-map: start: e877f000 end: e879f000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: e879f000 end: e87a0000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a0000 end: e87a1000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87a1000 end: e87a2000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a2000 end: e87a3000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e87a3000 end: e87a4000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: e87a4000 end: e87a5000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: e87a5000 end: e87a6000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_lob]
-map: start: e87a6000 end: e87a7000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e87a7000 end: e87a8000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a8000 end: e87a9000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87a9000 end: e87aa000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87aa000 end: e87ab000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87ab000 end: e87ac000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
-map: start: e87ac000 end: e87ad000 offset: 0 load_base: 0 flags: 0 name: [anon:thread signal stack guard page]
-map: start: e87ad000 end: e87af000 offset: 0 load_base: 0 flags: 3 name: [anon:thread signal stack]
-map: start: e87af000 end: e87b0000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
-map: start: e87b0000 end: e880d000 offset: 0 load_base: 0 flags: 5 name: /system/bin/linker
-map: start: e880d000 end: e880f000 offset: 5c000 load_base: 0 flags: 1 name: /system/bin/linker
-map: start: e880f000 end: e8810000 offset: 5e000 load_base: 0 flags: 3 name: /system/bin/linker
-map: start: e8810000 end: e8812000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: e8812000 end: e8813000 offset: 0 load_base: 0 flags: 1 name: 
-map: start: e8813000 end: e8815000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: ff886000 end: ff8a9000 offset: 0 load_base: 0 flags: 3 name: [stack]
-map: start: ffff0000 end: ffff1000 offset: 0 load_base: 0 flags: 5 name: [vectors]
+map: start: aad19000 end: aad6c000 offset: 0 load_bias: 0 flags: 5 name: /data/backtrace_test32
+map: start: aad6c000 end: aad6e000 offset: 52000 load_bias: 0 flags: 1 name: /data/backtrace_test32
+map: start: aad6e000 end: aad6f000 offset: 54000 load_bias: 0 flags: 3 name: /data/backtrace_test32
+map: start: e7380000 end: e7400000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e745f000 end: e7463000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libnetd_client.so
+map: start: e7463000 end: e7464000 offset: 3000 load_bias: 0 flags: 1 name: /system/lib/libnetd_client.so
+map: start: e7464000 end: e7465000 offset: 4000 load_bias: 0 flags: 3 name: /system/lib/libnetd_client.so
+map: start: e7480000 end: e7500000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e7558000 end: e756c000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libunwind.so
+map: start: e756c000 end: e756d000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e756d000 end: e756e000 offset: 14000 load_bias: 0 flags: 1 name: /system/lib/libunwind.so
+map: start: e756e000 end: e756f000 offset: 15000 load_bias: 0 flags: 3 name: /system/lib/libunwind.so
+map: start: e756f000 end: e75b5000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e75d4000 end: e75e1000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libbase.so
+map: start: e75e1000 end: e75e2000 offset: c000 load_bias: 0 flags: 1 name: /system/lib/libbase.so
+map: start: e75e2000 end: e75e3000 offset: d000 load_bias: 0 flags: 3 name: /system/lib/libbase.so
+map: start: e7600000 end: e7616000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/liblzma.so
+map: start: e7616000 end: e7617000 offset: 15000 load_bias: 0 flags: 1 name: /system/lib/liblzma.so
+map: start: e7617000 end: e7618000 offset: 16000 load_bias: 0 flags: 3 name: /system/lib/liblzma.so
+map: start: e7618000 end: e761d000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e7647000 end: e7656000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/liblog.so
+map: start: e7656000 end: e7657000 offset: e000 load_bias: 0 flags: 1 name: /system/lib/liblog.so
+map: start: e7657000 end: e7658000 offset: f000 load_bias: 0 flags: 3 name: /system/lib/liblog.so
+map: start: e7681000 end: e76a2000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libm.so
+map: start: e76a2000 end: e76a3000 offset: 20000 load_bias: 0 flags: 1 name: /system/lib/libm.so
+map: start: e76a3000 end: e76a4000 offset: 21000 load_bias: 0 flags: 3 name: /system/lib/libm.so
+map: start: e76eb000 end: e76ee000 offset: 0 load_bias: 0 flags: 5 name: /data/libbacktrace_test.so
+map: start: e76ee000 end: e76ef000 offset: 2000 load_bias: 0 flags: 1 name: /data/libbacktrace_test.so
+map: start: e76ef000 end: e76f0000 offset: 3000 load_bias: 0 flags: 3 name: /data/libbacktrace_test.so
+map: start: e7712000 end: e771f000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libbacktrace.so
+map: start: e771f000 end: e7720000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e7720000 end: e7721000 offset: d000 load_bias: 0 flags: 1 name: /system/lib/libbacktrace.so
+map: start: e7721000 end: e7722000 offset: e000 load_bias: 0 flags: 3 name: /system/lib/libbacktrace.so
+map: start: e7761000 end: e7778000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libutils.so
+map: start: e7778000 end: e7779000 offset: 16000 load_bias: 0 flags: 1 name: /system/lib/libutils.so
+map: start: e7779000 end: e777a000 offset: 17000 load_bias: 0 flags: 3 name: /system/lib/libutils.so
+map: start: e77a5000 end: e782d000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libc.so
+map: start: e782d000 end: e7831000 offset: 87000 load_bias: 0 flags: 1 name: /system/lib/libc.so
+map: start: e7831000 end: e7833000 offset: 8b000 load_bias: 0 flags: 3 name: /system/lib/libc.so
+map: start: e7833000 end: e7834000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e7834000 end: e7835000 offset: 0 load_bias: 0 flags: 1 name: [anon:.bss]
+map: start: e7835000 end: e783b000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e7845000 end: e8437000 offset: 0 load_bias: 2b000 flags: 5 name: /system/lib/libLLVM.so
+map: start: e8437000 end: e8438000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e8438000 end: e848a000 offset: bf2000 load_bias: 0 flags: 1 name: /system/lib/libLLVM.so
+map: start: e848a000 end: e848b000 offset: c44000 load_bias: 0 flags: 3 name: /system/lib/libLLVM.so
+map: start: e848b000 end: e84a1000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e84eb000 end: e84f7000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libcutils.so
+map: start: e84f7000 end: e84f8000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e84f8000 end: e84f9000 offset: c000 load_bias: 0 flags: 1 name: /system/lib/libcutils.so
+map: start: e84f9000 end: e84fa000 offset: d000 load_bias: 0 flags: 3 name: /system/lib/libcutils.so
+map: start: e852e000 end: e85b3000 offset: 0 load_bias: 2000 flags: 5 name: /system/lib/libc++.so
+map: start: e85b3000 end: e85b4000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e85b4000 end: e85b8000 offset: 85000 load_bias: 0 flags: 1 name: /system/lib/libc++.so
+map: start: e85b8000 end: e85b9000 offset: 89000 load_bias: 0 flags: 3 name: /system/lib/libc++.so
+map: start: e85b9000 end: e85ba000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: e85ce000 end: e85cf000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
+map: start: e85e4000 end: e85e5000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e8607000 end: e8608000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e8680000 end: e8700000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
+map: start: e870d000 end: e8719000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: e8719000 end: e871b000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
+map: start: e871b000 end: e873b000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
+map: start: e873b000 end: e875b000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: e875b000 end: e875c000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e875c000 end: e875d000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
+map: start: e875d000 end: e875e000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
+map: start: e875e000 end: e875f000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e875f000 end: e877f000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
+map: start: e877f000 end: e879f000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: e879f000 end: e87a0000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a0000 end: e87a1000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87a1000 end: e87a2000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a2000 end: e87a3000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e87a3000 end: e87a4000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: e87a4000 end: e87a5000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: e87a5000 end: e87a6000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_lob]
+map: start: e87a6000 end: e87a7000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: e87a7000 end: e87a8000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87a8000 end: e87a9000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87a9000 end: e87aa000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: e87aa000 end: e87ab000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: e87ab000 end: e87ac000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
+map: start: e87ac000 end: e87ad000 offset: 0 load_bias: 0 flags: 0 name: [anon:thread signal stack guard page]
+map: start: e87ad000 end: e87af000 offset: 0 load_bias: 0 flags: 3 name: [anon:thread signal stack]
+map: start: e87af000 end: e87b0000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
+map: start: e87b0000 end: e880d000 offset: 0 load_bias: 0 flags: 5 name: /system/bin/linker
+map: start: e880d000 end: e880f000 offset: 5c000 load_bias: 0 flags: 1 name: /system/bin/linker
+map: start: e880f000 end: e8810000 offset: 5e000 load_bias: 0 flags: 3 name: /system/bin/linker
+map: start: e8810000 end: e8812000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: e8812000 end: e8813000 offset: 0 load_bias: 0 flags: 1 name: 
+map: start: e8813000 end: e8815000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: ff886000 end: ff8a9000 offset: 0 load_bias: 0 flags: 3 name: [stack]
+map: start: ffff0000 end: ffff1000 offset: 0 load_bias: 0 flags: 5 name: [vectors]
 registers: 64 34868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee7
 stack: start: e8715000 end: e8719000 size: 16384 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc8871e87dba6ee734868affdc8871e8dc8871e85dba6ee7070000000e000000150000001c000000dc8871e85dba6ee71c000000150000000e00000007000000100000000c0000000800000004000000ddb86ee75dba6ee7dc8871e804000000080000000c00000010000000dc8871e85dba6ee7100000000c000000080000000400000008000000060000000400000002000000288871e835b96ee75dba6ee7dc8871e802000000040000000600000008000000dc8871e85dba6ee70800000006000000040000000200000004000000030000000200000001000000708871e88db96ee75dba6ee7dc8871e801000000020000000300000004000000dc8871e85dba6ee70400000003000000020000000100000004000000208971e8208971e878000000e87d00003dba6ee75dba6ee7dc8871e878000000c5807ce7fc7183e734868aff78868aff78868aff34868aff34868aff78868affe0879437208971e84154d2aa0020000034868aff34868aff34868aff78000000c9b87ee7b1b87ee7a3f47be7288971e8b1b87ee7208971e800000000f83481e800000000e97d0000e87d000000000000005071e82039000000100000000000000000000000000000000000002354d2aa34868aff00000000002071e801000000000000000000000000000000708971e8208971e8000000000000000000000000e0879437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: e76eb835 name: unknown_start
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
index 63f6a07..03e1df5 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libart
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -1,10 +1,10 @@
 pid: 32232 tid: 32233
 registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
-map: start: e9380000 end: e9766000 offset: 0 load_base: b000 flags: 5 name: /system/lib/libart.so
+map: start: e9380000 end: e9766000 offset: 0 load_bias: b000 flags: 5 name: /system/lib/libart.so
 stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
 function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
 function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
 function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
 function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
 function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
-function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
\ No newline at end of file
+function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
diff --git a/libbacktrace/testdata/aarch64/libbacktrace_test_eh_frame.so b/libbacktrace/testdata/arm64/libbacktrace_test_eh_frame.so
similarity index 100%
rename from libbacktrace/testdata/aarch64/libbacktrace_test_eh_frame.so
rename to libbacktrace/testdata/arm64/libbacktrace_test_eh_frame.so
Binary files differ
diff --git a/libbacktrace/testdata/aarch64/offline_testdata b/libbacktrace/testdata/arm64/offline_testdata
similarity index 88%
rename from libbacktrace/testdata/aarch64/offline_testdata
rename to libbacktrace/testdata/arm64/offline_testdata
index ba44e09..75a2f12 100644
--- a/libbacktrace/testdata/aarch64/offline_testdata
+++ b/libbacktrace/testdata/arm64/offline_testdata
@@ -1,100 +1,100 @@
 pid: 32438 tid: 32439
-map: start: 557066e000 end: 55706ee000 offset: 0 load_base: 0 flags: 5 name: /data/backtrace_test64
-map: start: 55706ef000 end: 55706f2000 offset: 80000 load_base: 0 flags: 1 name: /data/backtrace_test64
-map: start: 55706f2000 end: 55706f3000 offset: 83000 load_base: 0 flags: 3 name: /data/backtrace_test64
-map: start: 7014200000 end: 7014600000 offset: 0 load_base: 0 flags: 3 name: [anon:libc_malloc]
-map: start: 701464c000 end: 701465c000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libcutils.so
-map: start: 701465c000 end: 701465d000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 701465d000 end: 701465e000 offset: 10000 load_base: 0 flags: 1 name: /system/lib64/libcutils.so
-map: start: 701465e000 end: 701465f000 offset: 11000 load_base: 0 flags: 3 name: /system/lib64/libcutils.so
-map: start: 7014691000 end: 70146b5000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/liblzma.so
-map: start: 70146b5000 end: 70146b6000 offset: 23000 load_base: 0 flags: 1 name: /system/lib64/liblzma.so
-map: start: 70146b6000 end: 70146b7000 offset: 24000 load_base: 0 flags: 3 name: /system/lib64/liblzma.so
-map: start: 70146b7000 end: 70146bc000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 70146c9000 end: 70158b5000 offset: 0 load_base: af000 flags: 5 name: /system/lib64/libLLVM.so
-map: start: 70158b5000 end: 701596b000 offset: 11eb000 load_base: 0 flags: 1 name: /system/lib64/libLLVM.so
-map: start: 701596b000 end: 701596c000 offset: 12a1000 load_base: 0 flags: 3 name: /system/lib64/libLLVM.so
-map: start: 701596c000 end: 701599f000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 70159c2000 end: 70159f9000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libm.so
-map: start: 70159f9000 end: 70159fa000 offset: 36000 load_base: 0 flags: 1 name: /system/lib64/libm.so
-map: start: 70159fa000 end: 70159fb000 offset: 37000 load_base: 0 flags: 3 name: /system/lib64/libm.so
-map: start: 7015a1e000 end: 7015a2e000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libbacktrace.so
-map: start: 7015a2e000 end: 7015a2f000 offset: f000 load_base: 0 flags: 1 name: /system/lib64/libbacktrace.so
-map: start: 7015a2f000 end: 7015a30000 offset: 10000 load_base: 0 flags: 3 name: /system/lib64/libbacktrace.so
-map: start: 7015a5e000 end: 7015a7d000 offset: 0 load_base: 1000 flags: 5 name: /system/lib64/libutils.so
-map: start: 7015a7d000 end: 7015a7e000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 7015a7e000 end: 7015a7f000 offset: 1f000 load_base: 0 flags: 1 name: /system/lib64/libutils.so
-map: start: 7015a7f000 end: 7015a80000 offset: 20000 load_base: 0 flags: 3 name: /system/lib64/libutils.so
-map: start: 7015a99000 end: 7015b6d000 offset: 0 load_base: 9000 flags: 5 name: /system/lib64/libc++.so
-map: start: 7015b6d000 end: 7015b6e000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 7015b6e000 end: 7015b76000 offset: d4000 load_base: 0 flags: 1 name: /system/lib64/libc++.so
-map: start: 7015b76000 end: 7015b77000 offset: dc000 load_base: 0 flags: 3 name: /system/lib64/libc++.so
-map: start: 7015b77000 end: 7015b7a000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 7015b81000 end: 7015b92000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/liblog.so
-map: start: 7015b92000 end: 7015b93000 offset: 10000 load_base: 0 flags: 1 name: /system/lib64/liblog.so
-map: start: 7015b93000 end: 7015b94000 offset: 11000 load_base: 0 flags: 3 name: /system/lib64/liblog.so
-map: start: 7015be3000 end: 7015ca3000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libc.so
-map: start: 7015ca3000 end: 7015ca9000 offset: bf000 load_base: 0 flags: 1 name: /system/lib64/libc.so
-map: start: 7015ca9000 end: 7015cab000 offset: c5000 load_base: 0 flags: 3 name: /system/lib64/libc.so
-map: start: 7015cab000 end: 7015cac000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 7015cac000 end: 7015cad000 offset: 0 load_base: 0 flags: 1 name: [anon:.bss]
-map: start: 7015cad000 end: 7015cb4000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 7015cf5000 end: 7015cf6000 offset: 0 load_base: 0 flags: 5 name: /data/libbacktrace_test.so
-map: start: 7015cf6000 end: 7015cf7000 offset: 0 load_base: 0 flags: 1 name: /data/libbacktrace_test.so
-map: start: 7015cf7000 end: 7015cf8000 offset: 1000 load_base: 0 flags: 3 name: /data/libbacktrace_test.so
-map: start: 7015d1f000 end: 7015d39000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libunwind.so
-map: start: 7015d39000 end: 7015d3a000 offset: 19000 load_base: 0 flags: 1 name: /system/lib64/libunwind.so
-map: start: 7015d3a000 end: 7015d3b000 offset: 1a000 load_base: 0 flags: 3 name: /system/lib64/libunwind.so
-map: start: 7015d3b000 end: 7015da4000 offset: 0 load_base: 0 flags: 3 name: [anon:.bss]
-map: start: 7015de8000 end: 7015df7000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libbase.so
-map: start: 7015df7000 end: 7015df8000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 7015df8000 end: 7015df9000 offset: f000 load_base: 0 flags: 1 name: /system/lib64/libbase.so
-map: start: 7015df9000 end: 7015dfa000 offset: 10000 load_base: 0 flags: 3 name: /system/lib64/libbase.so
-map: start: 7015e35000 end: 7015e36000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
-map: start: 7015e4f000 end: 7015e50000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015f11000 end: 7015f13000 offset: 0 load_base: 0 flags: 5 name: /system/lib64/libnetd_client.so
-map: start: 7015f13000 end: 7015f14000 offset: 1000 load_base: 0 flags: 1 name: /system/lib64/libnetd_client.so
-map: start: 7015f14000 end: 7015f15000 offset: 2000 load_base: 0 flags: 3 name: /system/lib64/libnetd_client.so
-map: start: 7015f6c000 end: 7015f79000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7015f79000 end: 7015f99000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
-map: start: 7015f99000 end: 7015f9a000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015f9a000 end: 7015f9b000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015fa6000 end: 7015fa7000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fa8000 end: 7015fa9000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7015faf000 end: 7015fcf000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: 7015fcf000 end: 7015fd0000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fd0000 end: 7015fd1000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015fd1000 end: 7015fd2000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fd4000 end: 7015fd7000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7015fd7000 end: 7015fdb000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
-map: start: 7015fdb000 end: 7015fdc000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc]
-map: start: 7015fdc000 end: 7015fdd000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7015fdd000 end: 7015fde000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7015fde000 end: 7015ffe000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
-map: start: 7015ffe000 end: 701601e000 offset: 0 load_base: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: 701601e000 end: 701601f000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 701601f000 end: 7016020000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 7016020000 end: 7016021000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7016021000 end: 7016022000 offset: 0 load_base: 0 flags: 0 name: 
-map: start: 7016022000 end: 7016023000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_lob]
-map: start: 7016023000 end: 7016025000 offset: 0 load_base: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7016025000 end: 7016026000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7016026000 end: 7016027000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7016027000 end: 7016028000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7016028000 end: 7016029000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
-map: start: 7016029000 end: 701602a000 offset: 0 load_base: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 701602a000 end: 701602b000 offset: 0 load_base: 0 flags: 1 name: [anon:atexit handlers]
-map: start: 701602b000 end: 701602c000 offset: 0 load_base: 0 flags: 0 name: [anon:thread signal stack guard page]
-map: start: 701602c000 end: 7016030000 offset: 0 load_base: 0 flags: 3 name: [anon:thread signal stack]
-map: start: 7016030000 end: 7016031000 offset: 0 load_base: 0 flags: 3 name: [anon:arc4random data]
-map: start: 7016031000 end: 7016033000 offset: 0 load_base: 0 flags: 5 name: [vdso]
-map: start: 7016033000 end: 70160dd000 offset: 0 load_base: 0 flags: 5 name: /system/bin/linker64
-map: start: 70160dd000 end: 70160e0000 offset: a9000 load_base: 0 flags: 1 name: /system/bin/linker64
-map: start: 70160e0000 end: 70160e1000 offset: ac000 load_base: 0 flags: 3 name: /system/bin/linker64
-map: start: 70160e1000 end: 70160e4000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 70160e4000 end: 70160e5000 offset: 0 load_base: 0 flags: 1 name: 
-map: start: 70160e5000 end: 70160e8000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_base: 0 flags: 3 name: [stack]
+map: start: 557066e000 end: 55706ee000 offset: 0 load_bias: 0 flags: 5 name: /data/backtrace_test64
+map: start: 55706ef000 end: 55706f2000 offset: 80000 load_bias: 0 flags: 1 name: /data/backtrace_test64
+map: start: 55706f2000 end: 55706f3000 offset: 83000 load_bias: 0 flags: 3 name: /data/backtrace_test64
+map: start: 7014200000 end: 7014600000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
+map: start: 701464c000 end: 701465c000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libcutils.so
+map: start: 701465c000 end: 701465d000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 701465d000 end: 701465e000 offset: 10000 load_bias: 0 flags: 1 name: /system/lib64/libcutils.so
+map: start: 701465e000 end: 701465f000 offset: 11000 load_bias: 0 flags: 3 name: /system/lib64/libcutils.so
+map: start: 7014691000 end: 70146b5000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/liblzma.so
+map: start: 70146b5000 end: 70146b6000 offset: 23000 load_bias: 0 flags: 1 name: /system/lib64/liblzma.so
+map: start: 70146b6000 end: 70146b7000 offset: 24000 load_bias: 0 flags: 3 name: /system/lib64/liblzma.so
+map: start: 70146b7000 end: 70146bc000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 70146c9000 end: 70158b5000 offset: 0 load_bias: af000 flags: 5 name: /system/lib64/libLLVM.so
+map: start: 70158b5000 end: 701596b000 offset: 11eb000 load_bias: 0 flags: 1 name: /system/lib64/libLLVM.so
+map: start: 701596b000 end: 701596c000 offset: 12a1000 load_bias: 0 flags: 3 name: /system/lib64/libLLVM.so
+map: start: 701596c000 end: 701599f000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 70159c2000 end: 70159f9000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libm.so
+map: start: 70159f9000 end: 70159fa000 offset: 36000 load_bias: 0 flags: 1 name: /system/lib64/libm.so
+map: start: 70159fa000 end: 70159fb000 offset: 37000 load_bias: 0 flags: 3 name: /system/lib64/libm.so
+map: start: 7015a1e000 end: 7015a2e000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libbacktrace.so
+map: start: 7015a2e000 end: 7015a2f000 offset: f000 load_bias: 0 flags: 1 name: /system/lib64/libbacktrace.so
+map: start: 7015a2f000 end: 7015a30000 offset: 10000 load_bias: 0 flags: 3 name: /system/lib64/libbacktrace.so
+map: start: 7015a5e000 end: 7015a7d000 offset: 0 load_bias: 1000 flags: 5 name: /system/lib64/libutils.so
+map: start: 7015a7d000 end: 7015a7e000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 7015a7e000 end: 7015a7f000 offset: 1f000 load_bias: 0 flags: 1 name: /system/lib64/libutils.so
+map: start: 7015a7f000 end: 7015a80000 offset: 20000 load_bias: 0 flags: 3 name: /system/lib64/libutils.so
+map: start: 7015a99000 end: 7015b6d000 offset: 0 load_bias: 9000 flags: 5 name: /system/lib64/libc++.so
+map: start: 7015b6d000 end: 7015b6e000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 7015b6e000 end: 7015b76000 offset: d4000 load_bias: 0 flags: 1 name: /system/lib64/libc++.so
+map: start: 7015b76000 end: 7015b77000 offset: dc000 load_bias: 0 flags: 3 name: /system/lib64/libc++.so
+map: start: 7015b77000 end: 7015b7a000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 7015b81000 end: 7015b92000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/liblog.so
+map: start: 7015b92000 end: 7015b93000 offset: 10000 load_bias: 0 flags: 1 name: /system/lib64/liblog.so
+map: start: 7015b93000 end: 7015b94000 offset: 11000 load_bias: 0 flags: 3 name: /system/lib64/liblog.so
+map: start: 7015be3000 end: 7015ca3000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libc.so
+map: start: 7015ca3000 end: 7015ca9000 offset: bf000 load_bias: 0 flags: 1 name: /system/lib64/libc.so
+map: start: 7015ca9000 end: 7015cab000 offset: c5000 load_bias: 0 flags: 3 name: /system/lib64/libc.so
+map: start: 7015cab000 end: 7015cac000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 7015cac000 end: 7015cad000 offset: 0 load_bias: 0 flags: 1 name: [anon:.bss]
+map: start: 7015cad000 end: 7015cb4000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 7015cf5000 end: 7015cf6000 offset: 0 load_bias: 0 flags: 5 name: /data/libbacktrace_test.so
+map: start: 7015cf6000 end: 7015cf7000 offset: 0 load_bias: 0 flags: 1 name: /data/libbacktrace_test.so
+map: start: 7015cf7000 end: 7015cf8000 offset: 1000 load_bias: 0 flags: 3 name: /data/libbacktrace_test.so
+map: start: 7015d1f000 end: 7015d39000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libunwind.so
+map: start: 7015d39000 end: 7015d3a000 offset: 19000 load_bias: 0 flags: 1 name: /system/lib64/libunwind.so
+map: start: 7015d3a000 end: 7015d3b000 offset: 1a000 load_bias: 0 flags: 3 name: /system/lib64/libunwind.so
+map: start: 7015d3b000 end: 7015da4000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
+map: start: 7015de8000 end: 7015df7000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libbase.so
+map: start: 7015df7000 end: 7015df8000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 7015df8000 end: 7015df9000 offset: f000 load_bias: 0 flags: 1 name: /system/lib64/libbase.so
+map: start: 7015df9000 end: 7015dfa000 offset: 10000 load_bias: 0 flags: 3 name: /system/lib64/libbase.so
+map: start: 7015e35000 end: 7015e36000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
+map: start: 7015e4f000 end: 7015e50000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015f11000 end: 7015f13000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libnetd_client.so
+map: start: 7015f13000 end: 7015f14000 offset: 1000 load_bias: 0 flags: 1 name: /system/lib64/libnetd_client.so
+map: start: 7015f14000 end: 7015f15000 offset: 2000 load_bias: 0 flags: 3 name: /system/lib64/libnetd_client.so
+map: start: 7015f6c000 end: 7015f79000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7015f79000 end: 7015f99000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
+map: start: 7015f99000 end: 7015f9a000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015f9a000 end: 7015f9b000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015fa6000 end: 7015fa7000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fa8000 end: 7015fa9000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7015faf000 end: 7015fcf000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: 7015fcf000 end: 7015fd0000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fd0000 end: 7015fd1000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7015fd1000 end: 7015fd2000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7015fd4000 end: 7015fd7000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7015fd7000 end: 7015fdb000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
+map: start: 7015fdb000 end: 7015fdc000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
+map: start: 7015fdc000 end: 7015fdd000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7015fdd000 end: 7015fde000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7015fde000 end: 7015ffe000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
+map: start: 7015ffe000 end: 701601e000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
+map: start: 701601e000 end: 701601f000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 701601f000 end: 7016020000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 7016020000 end: 7016021000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7016021000 end: 7016022000 offset: 0 load_bias: 0 flags: 0 name: 
+map: start: 7016022000 end: 7016023000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_lob]
+map: start: 7016023000 end: 7016025000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
+map: start: 7016025000 end: 7016026000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7016026000 end: 7016027000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
+map: start: 7016027000 end: 7016028000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 7016028000 end: 7016029000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
+map: start: 7016029000 end: 701602a000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
+map: start: 701602a000 end: 701602b000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
+map: start: 701602b000 end: 701602c000 offset: 0 load_bias: 0 flags: 0 name: [anon:thread signal stack guard page]
+map: start: 701602c000 end: 7016030000 offset: 0 load_bias: 0 flags: 3 name: [anon:thread signal stack]
+map: start: 7016030000 end: 7016031000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
+map: start: 7016031000 end: 7016033000 offset: 0 load_bias: 0 flags: 5 name: [vdso]
+map: start: 7016033000 end: 70160dd000 offset: 0 load_bias: 0 flags: 5 name: /system/bin/linker64
+map: start: 70160dd000 end: 70160e0000 offset: a9000 load_bias: 0 flags: 1 name: /system/bin/linker64
+map: start: 70160e0000 end: 70160e1000 offset: ac000 load_bias: 0 flags: 3 name: /system/bin/linker64
+map: start: 70160e1000 end: 70160e4000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 70160e4000 end: 70160e5000 offset: 0 load_bias: 0 flags: 1 name: 
+map: start: 70160e5000 end: 70160e8000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_bias: 0 flags: 3 name: [stack]
 registers: 4560 679a0b1670000000f3eb6d705500000090f56e7055000000000000000000000000206f705500000014e0677055000000d038bed87f0000004cde67705500000041000000000000001900000000000000c00f241470000000d3aec914588f4bcd0400000000000000e493af157000000090f56e7055000000060000000000000023c00b1670000000b1d1fd15700000003039bed87f000000c898041670000000304cbed87f000000b8130e1670000000303cbed87f000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000003003167000000001000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000033000000000000000300000000000000003303167000000008330316700000000000000006000000f8320316700000005839bed87f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000c84cbed87f000000e84cbed87f000000984dbed87f00000078170e167000000002fd0000000000001400000000000000ff8100000100000000000000000000000000000000000000000000000000000078145700000000000010000000000000902b000000000000bdd04058000000000000000000000000bdd04058000000000000000000000000ccb58a560000000042487408000000000000000000000000cc57041670000000004704167000000010c0fd157000000010c0fd157000000090c0fd15700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000002f48bed87f000000d3aec914588f4bcd2045bed87f0000002045bed87f0000002f48bed87f00000001000000000000002f000080000000005045bed87f0000000045bed87f000000c0a0c315700000006045bed87f0000006045bed87f000000010000000000000001000000000000000344bed87f00000001000000100000009c3fbed87f0000009b3fbed87f0000000344bed87f0000009a3fbed87f0000000100000000000000953fbed87f0000004344bed80100000001000000010000002c48bed87f0000000444bed87f0000004344bed80100000000000000000000000100000000000000b03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd000000000100000000000000000000000100000000000000f03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03fbed87f0000000000000000000000000000000000000000000000000000000000000000000000d3aec914588f4bcd08226f70550000000000000000000000000000000000000000000000000000001048bed87f0000008047bed87f0000006047bed87f000000e0ffffff80ffffff03000000000000000000000000000000891d6e7055000000d3aec914588f4bcd5047bed87f0000005047bed87f000000861d6e705500000003000000000000002f00008000000000f0a6ca15700000004047bed87f000000c0a0c31570000000891d6e7055000000d3aec914000000000100000000000000a047bed800000000f9006e70550000000100000000000000dc41bed87f000000db41bed87f0000004346bed87f000000da41bed87f0000000100000000000000d541bed87f00000001000000010000000100000001000000861d6e70550000004446bed87f0000002c42bed80300000000000000000000000100000000000000f041bed87f0000009b1e6e700100000000000000000000000000000000000000d3aec914588f4bcd8e1e6e70550000000d000000000000002f00008000000000f0a6ca15700000003048bed87f000000c0a0c31570000000661e6e700100000000000000000000002f000000000000001000000000000000e21e6e7055000000d3aec914588f4bcdb048bed87f000000b048bed87f000000e21e6e70550000002f000000000000002f00008000000000f0a6ca1570000000a048bed87f000000c0a0c315700000008e1e6e7055000000000000000000000022000000000000000000000000000000205827147000000022000000000000003c43bed87f0000003b43bed87f000000a347bed87f0000003a43bed87f00000001000000000000003543bed87f000000f048bed8010000000100000001000000dd1e6e7055000000a447bed87f0000008c43bed82f000000000000000000000001000000000000005043bed87f000000861d6e700300000000000000000000000000000000000000d3aec914588f4bcd721e6e7055000000f447bed87f000000981123141800000000000000000000000100000000000000a043bed87f000000861d6e70030000000000000000000000d042bed87f0000000000000000000000981123147000000098112314700000009811231470000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000504abed87f000000b049bed87f0000008049bed87f00000000000000000000004043bed87f0000000000000000000000991123147000000000000000000000008e1e6e70550000000d00000000000000a04abed87f000000000000000000000000000000000000000000000000000000504abed87f000000e049bed87f000000a049bed87f000000c8ffffff80ffffff591e6e70550000000d0000000000000098112314700000000000000000000000df1e6e7055000000010000000000000020582714700000002200000000000000f049bed87f000000c8ffffff80ffffff9811231470000000980023147000000098112314700000009811231470000000741e6e7055000000060000000000000009f12914700000000c00000000000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b149bed87f000000b149bed87f000000f049be317f000000f049bed87f000000f049bed87f000000b149bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000f149bed87f000000f049bed87f000000d3aec914588f4bcdfcb58a56000000006cbb687055000000160000000000000098112314700000009911231470000000991123147000000098112314700000009911231470000000fcb58a5600000000010000000000000000000000000000000100000000000000604a050000000000e845bed87f0000006048bed87f000000a046bed87f00000017000000000000002c48bed87f0000009046bed87f000000ac73c515700000009911231470000000d3aec914588f4bcd1048bed87f0000008047bed87f0000006047bed87f000000e8ffffff80ffffffffffffffffffffff99112314700000006148bed87f000000981123141500000008020000ffffffff6048bed87f000000160000000000000058112314700000001700000000000000a849bed87f0000000000000000000000284abed87f0000001700000000000000284abed87f000000284abed87f000000d249bed87f00000001000000000000009a112314700000001600000000000000284abed87f000000ffffffffffffffff284abed87f000000284abed87f000000284abed87f000000284abed87f0000001700000000000000ffffffffffffffff284abed87f000000284abed87f000000ff49bed87f000000284abed87f00000000000000000000000000000000000000d049bed87f000000d049bed87f000000004abed87f000000d049bed87f0000000100000000000000d049bed87f000000d049bed87f000000d049bed87f00000017000000000000000100000000000000ffffffffffffffff991123147000000001000000000000003448bed87f0000009911231470000000b0ca687055000000ffffffffffffffff010000000000000099112314700000007047bed87f000000d3aec914588f4bcdfcb58a56000000000100000000000000000000000000000050226f70550000000000000000000000b44b05000000000000102a1470000000861d6e70550000000300000000000000f0a6ca1570000000a047bed87f0000006c79c31570000000f048bed87f0000008048bed87f0000004048bed87f000000c8ffffff80ffffff0000000000000000d3aec914588f4bcdf849bed87f000000f0a6ca15700000000200000000000000085b0e1670000000e048bed87f0000002c6fc515700000009048bed87f000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a89912314700000000000000000000000e9216f70550000008991231470000000e449bed87f0000008991231470000000000000000000000000000000000000008891231470000000899123147000000089912314700000008891231470000000170000000000000088912314700000008891231470000000d3aec914588f4bcd899123147000000016000000000000000000000000000000e9216f705500000088912314700000008891231470000000889123147000000088912314700000008891231470000000f0a6ca15700000000049bed87f0000006c79c31570000000889123147000000088912314700000008891231470000000889123147000000088912314700000008891231470000000889123147000000089912314700000008991231470000000085b0e1670000000404abed87f0000002c6fc51570000000c80a6f7055000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a3b3325736d001b5b6d002c20776865726520002573203d202573000a526570650000000000000000000000000000000000000000000000008891231470000000000000000000000088912314700000008891231470000000889123147000000088912314700000000000000000000000889123147000000088912314700000008891231470000000470000000000000000502a1470000000d3aec914588f4bcdf05727147000000000b2221470000000604abed87f0000005c716c7055000000fcb58a56000000007c706c7055000000fcb58a5600000000ea4b050000000000
 stack: start: 7015fd3000 end: 7015fd7000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000004038bed87f000000b863fd1570000000b863fd1570000000b863fd1570000000ec59cf15700000001c000000150000000e000000070000003063fd15700000001c58cf1570000000b863fd1570000000ec59cf1570000000100000000c00000008000000040000006063fd15700000007c58cf1570000000b863fd1570000000ec59cf1570000000080000000600000004000000020000009063fd1570000000dc58cf1570000000b863fd1570000000ec59cf157000000004000000030000000200000001000000d063fd1570000000c459cf15700000000100000000000000144abed87f0000004038bed87f0000004038bed87f000000144abed87f000000d3aec914588f4bcd1064fd157000000074fd6770550000004038bed87f0000004038bed87f000000ec84c41570000000e484c41570000000c484c4157000000000000000000000004064fd15700000004015c01570000000b67e0000000000000000000000000000705a0e1670000000185b0e167000000000000000000000000000000000000000705a0e16700000000000000000000000b77e0000b67e000000000000550000000030fd157000000050340000000000000010000000000000000000000000000000b222147000000000102a14700000000000000000000000000000000000000040fd6770550000004038bed87f000000000000000000000000a0fa1570000000010000000000000000000000000000000000000000000000e864fd15700000005064fd1570000000000000000000000000000000000000000000000000000000d3aec914588f4bcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: 7015cf5760 name: unknown_start
diff --git a/libbacktrace/testdata/x86/offline_testdata b/libbacktrace/testdata/x86/offline_testdata
index 3e4e06c..e8b7a99 100644
--- a/libbacktrace/testdata/x86/offline_testdata
+++ b/libbacktrace/testdata/x86/offline_testdata
@@ -1,75 +1,75 @@
 pid: 34545 tid: 34546
-map: start: f705a000 end: f705c000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f705c000 end: f707f000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f707f000 end: f7080000 offset: 22000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f7080000 end: f7081000 offset: 23000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f7081000 end: f7088000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7088000 end: f7230000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7230000 end: f7231000 offset: 1a8000 load_base: 0 flags: 0 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7231000 end: f7233000 offset: 1a8000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7233000 end: f7234000 offset: 1aa000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7234000 end: f7237000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7237000 end: f727b000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727b000 end: f727c000 offset: 43000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727c000 end: f727d000 offset: 44000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727d000 end: f7299000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libgcc_s.so.1
-map: start: f7299000 end: f729a000 offset: 1b000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libgcc_s.so.1
-map: start: f729a000 end: f72b8000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72b8000 end: f72b9000 offset: 1e000 load_base: 0 flags: 0 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72b9000 end: f72bb000 offset: 1e000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72bb000 end: f72bc000 offset: 20000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72bc000 end: f72bd000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f72bd000 end: f72e0000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e0000 end: f72e1000 offset: 22000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e1000 end: f72e2000 offset: 23000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e2000 end: f72e5000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e5000 end: f72e6000 offset: 2000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e6000 end: f72e7000 offset: 3000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e7000 end: f72ee000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72ee000 end: f72ef000 offset: 6000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72ef000 end: f72f0000 offset: 7000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72f0000 end: f7308000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f7308000 end: f7309000 offset: 18000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f7309000 end: f730a000 offset: 19000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f730a000 end: f730c000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f732f000 end: f7331000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7331000 end: f7425000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f7425000 end: f7426000 offset: f4000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f7426000 end: f742a000 offset: f4000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f742a000 end: f742b000 offset: f8000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f742b000 end: f742d000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f742d000 end: f7446000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7446000 end: f7447000 offset: 18000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7447000 end: f7448000 offset: 19000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7448000 end: f7457000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7457000 end: f745c000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745c000 end: f745d000 offset: 4000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745d000 end: f745e000 offset: 5000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745e000 end: f7467000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7467000 end: f7468000 offset: 9000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7468000 end: f7469000 offset: 9000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7469000 end: f746a000 offset: a000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f746a000 end: f7477000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7477000 end: f7478000 offset: c000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7478000 end: f7479000 offset: d000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7479000 end: f7489000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f7489000 end: f748a000 offset: f000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f748a000 end: f748b000 offset: 10000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f748b000 end: f748c000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f748c000 end: f748d000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748d000 end: f748e000 offset: 0 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748e000 end: f748f000 offset: 1000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748f000 end: f7491000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7491000 end: f74b1000 offset: 0 load_base: 0 flags: 5 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b1000 end: f74b2000 offset: 1f000 load_base: 0 flags: 1 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b2000 end: f74b3000 offset: 20000 load_base: 0 flags: 3 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b3000 end: f77c6000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77c6000 end: f77c7000 offset: 0 load_base: ffffe000 flags: 5 name: [vdso]
-map: start: f77c7000 end: f77d4000 offset: 313000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77d4000 end: f77d5000 offset: 320000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77d5000 end: f77d6000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: f7ec6000 end: f7ee7000 offset: 0 load_base: 0 flags: 3 name: [heap]
-map: start: ffe4e000 end: ffe70000 offset: 0 load_base: 0 flags: 3 name: [stack]
+map: start: f705a000 end: f705c000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f705c000 end: f707f000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f707f000 end: f7080000 offset: 22000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f7080000 end: f7081000 offset: 23000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
+map: start: f7081000 end: f7088000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7088000 end: f7230000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7230000 end: f7231000 offset: 1a8000 load_bias: 0 flags: 0 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7231000 end: f7233000 offset: 1a8000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7233000 end: f7234000 offset: 1aa000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libc-2.19.so
+map: start: f7234000 end: f7237000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7237000 end: f727b000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727b000 end: f727c000 offset: 43000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727c000 end: f727d000 offset: 44000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libm-2.19.so
+map: start: f727d000 end: f7299000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libgcc_s.so.1
+map: start: f7299000 end: f729a000 offset: 1b000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libgcc_s.so.1
+map: start: f729a000 end: f72b8000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72b8000 end: f72b9000 offset: 1e000 load_bias: 0 flags: 0 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72b9000 end: f72bb000 offset: 1e000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72bb000 end: f72bc000 offset: 20000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libtinfo.so.5.9
+map: start: f72bc000 end: f72bd000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f72bd000 end: f72e0000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e0000 end: f72e1000 offset: 22000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e1000 end: f72e2000 offset: 23000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libncurses.so.5.9
+map: start: f72e2000 end: f72e5000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e5000 end: f72e6000 offset: 2000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e6000 end: f72e7000 offset: 3000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libdl-2.19.so
+map: start: f72e7000 end: f72ee000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72ee000 end: f72ef000 offset: 6000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72ef000 end: f72f0000 offset: 7000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/librt-2.19.so
+map: start: f72f0000 end: f7308000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f7308000 end: f7309000 offset: 18000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f7309000 end: f730a000 offset: 19000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libpthread-2.19.so
+map: start: f730a000 end: f730c000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f732f000 end: f7331000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7331000 end: f7425000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f7425000 end: f7426000 offset: f4000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f7426000 end: f742a000 offset: f4000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f742a000 end: f742b000 offset: f8000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
+map: start: f742b000 end: f742d000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f742d000 end: f7446000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7446000 end: f7447000 offset: 18000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7447000 end: f7448000 offset: 19000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
+map: start: f7448000 end: f7457000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7457000 end: f745c000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745c000 end: f745d000 offset: 4000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745d000 end: f745e000 offset: 5000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
+map: start: f745e000 end: f7467000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7467000 end: f7468000 offset: 9000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7468000 end: f7469000 offset: 9000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f7469000 end: f746a000 offset: a000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
+map: start: f746a000 end: f7477000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7477000 end: f7478000 offset: c000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7478000 end: f7479000 offset: d000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
+map: start: f7479000 end: f7489000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f7489000 end: f748a000 offset: f000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f748a000 end: f748b000 offset: 10000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
+map: start: f748b000 end: f748c000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f748c000 end: f748d000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748d000 end: f748e000 offset: 0 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748e000 end: f748f000 offset: 1000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
+map: start: f748f000 end: f7491000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7491000 end: f74b1000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b1000 end: f74b2000 offset: 1f000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b2000 end: f74b3000 offset: 20000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/ld-2.19.so
+map: start: f74b3000 end: f77c6000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77c6000 end: f77c7000 offset: 0 load_bias: ffffe000 flags: 5 name: [vdso]
+map: start: f77c7000 end: f77d4000 offset: 313000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77d4000 end: f77d5000 offset: 320000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
+map: start: f77d5000 end: f77d6000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: f7ec6000 end: f7ee7000 offset: 0 load_bias: 0 flags: 3 name: [heap]
+map: start: ffe4e000 end: ffe70000 offset: 0 load_bias: 0 flags: 3 name: [stack]
 registers: 348 00000000abdae6fff83b7df704000000a6ec77f7abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000008c8decf78c8decf7ceca48f7a8dae6ff8d8decf70a0000000000000014dae6ff8c8decf78c8decf78c8decf78c8decf78c8decf7a9dae6ff06000000c03a23f78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78d8decf78d8decf7c03a23f7543b23f7000033f75f5f0ff7c03a23f7503423f77000000098000000020000000f2700006c0000000e00000080000000000000008c8decf7000000008c8decf77f03ffff0000ffffffffffff0000000000000000000000000000ffff040000000f27000008000000003023f78d8decf7f069ec000046bdaa308decf715537df7f83b7df78c8decf74c1c71f78c8decf715537df70000000000000000f069ecf7f83b7df75064ecf792e671f7f069ecf7
 stack: start: f732c000 end: f7330000 size: 16384 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d9d49f761b009f71e382ff7000000000000000000000000000000000000000002000000f6372ff704c82bf70000000000204bf7f0a908f7ceca48f728d9e6fff4a449f70000000020f332f720f332f7d0df48f7f8f132f794c748f720f332f70c144205978142a8d4be08f7d0df48f720f332f7a0ca48f71c000000150000000e000000070000001c000000a0ca48f7d0df48f748f232f739c848f7070000000e000000150000001c000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7100000000c000000080000000400000010000000a0ca48f7d0df48f798f232f7c9c848f704000000080000000c00000010000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f70800000006000000040000000200000008000000a0ca48f7d0df48f7e8f232f759c948f702000000040000000600000008000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7040000000300000002000000010000000046bdaa00000000d0df48f738f332f77cca48f701000000020000000300000004000000a0ca48f720f332f700000000f83b7df7696d4df7d0df48f788dae6ff28d9e6ff28d9e6ff88dae6ff58f332f70046bdaa40fb32f7f83b7df758f332f78d6d4df728d9e6ff88dae6fff83b7df728d9e6ff28d9e6ff009030f728f432f7726f2ff728d9e6ff40fb32f740fb32f740fb32f790f332f700000000000000000000000000000000000000000000000000000000009030f740fb32f7000f3d0028f432f703b12c75032f144e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a06e2ff700000000000f3d00000000008e3f17f740fb32f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03823f7c4fd32f700000000e0341df7e02e1df7e03d1df70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040fb32f7188eecf740fb32f70100000030647cf70046bdaa28658876000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060a705f7a4b130f7f2860000f1860000b0fb32f7ecffffff000000000000000090f332f7000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccfb32f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c2638cfa7f3e1d0000000000000000000000000000000000406d4df728d9e6ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c032f7004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: f748c740 name: unknown_start
diff --git a/libbacktrace/testdata/x86_64/offline_testdata b/libbacktrace/testdata/x86_64/offline_testdata
index baf6450..f8d0dc0 100644
--- a/libbacktrace/testdata/x86_64/offline_testdata
+++ b/libbacktrace/testdata/x86_64/offline_testdata
@@ -1,86 +1,86 @@
 pid: 25683 tid: 25692
-map: start: 7fd5aa784000 end: 7fd5aa93e000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aa93e000 end: 7fd5aab3e000 offset: 1ba000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab3e000 end: 7fd5aab42000 offset: 1ba000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab42000 end: 7fd5aab44000 offset: 1be000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab44000 end: 7fd5aab49000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5aab49000 end: 7fd5aac4e000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aac4e000 end: 7fd5aae4d000 offset: 105000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4d000 end: 7fd5aae4e000 offset: 104000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4e000 end: 7fd5aae4f000 offset: 105000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4f000 end: 7fd5aae65000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5aae65000 end: 7fd5ab064000 offset: 16000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5ab064000 end: 7fd5ab065000 offset: 15000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5ab065000 end: 7fd5ab08a000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab08a000 end: 7fd5ab289000 offset: 25000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab289000 end: 7fd5ab28d000 offset: 24000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab28d000 end: 7fd5ab28e000 offset: 28000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab28e000 end: 7fd5ab2b0000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab2b0000 end: 7fd5ab4af000 offset: 22000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4af000 end: 7fd5ab4b0000 offset: 21000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4b0000 end: 7fd5ab4b1000 offset: 22000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4b1000 end: 7fd5ab4b4000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab4b4000 end: 7fd5ab6b3000 offset: 3000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b3000 end: 7fd5ab6b4000 offset: 2000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b4000 end: 7fd5ab6b5000 offset: 3000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b5000 end: 7fd5ab6bc000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab6bc000 end: 7fd5ab8bb000 offset: 7000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bb000 end: 7fd5ab8bc000 offset: 6000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bc000 end: 7fd5ab8bd000 offset: 7000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bd000 end: 7fd5ab8d6000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5ab8d6000 end: 7fd5abad5000 offset: 19000 load_base: 0 flags: 0 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad5000 end: 7fd5abad6000 offset: 18000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad6000 end: 7fd5abad7000 offset: 19000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad7000 end: 7fd5abadb000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abadb000 end: 7fd5abafe000 offset: 0 load_base: 0 flags: 5 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abb17000 end: 7fd5abb1a000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abb1a000 end: 7fd5abb40000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb40000 end: 7fd5abb41000 offset: 25000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb41000 end: 7fd5abb42000 offset: 26000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb42000 end: 7fd5abb4b000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abb6a000 end: 7fd5abb70000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abb70000 end: 7fd5abc62000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc62000 end: 7fd5abc63000 offset: f2000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc63000 end: 7fd5abc6b000 offset: f2000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc6b000 end: 7fd5abc6c000 offset: fa000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc6c000 end: 7fd5abc70000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abc70000 end: 7fd5abc8d000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8d000 end: 7fd5abc8e000 offset: 1c000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8e000 end: 7fd5abc8f000 offset: 1d000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8f000 end: 7fd5abcb8000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abcb8000 end: 7fd5abcbe000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcbe000 end: 7fd5abcbf000 offset: 6000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcbf000 end: 7fd5abcc0000 offset: 6000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcc0000 end: 7fd5abcc1000 offset: 7000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcc1000 end: 7fd5abcc2000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abcc2000 end: 7fd5abccd000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abccd000 end: 7fd5abcce000 offset: b000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abcce000 end: 7fd5abccf000 offset: b000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abccf000 end: 7fd5abcd0000 offset: c000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abcd0000 end: 7fd5abcdf000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abcdf000 end: 7fd5abce0000 offset: f000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce0000 end: 7fd5abce1000 offset: f000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce1000 end: 7fd5abce2000 offset: 10000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce2000 end: 7fd5abcf5000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf5000 end: 7fd5abcf6000 offset: 12000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf6000 end: 7fd5abcf7000 offset: 13000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf7000 end: 7fd5abcf8000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcf8000 end: 7fd5abcf9000 offset: 1000 load_base: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcf9000 end: 7fd5abcfa000 offset: 1000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcfa000 end: 7fd5abcfb000 offset: 2000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcfb000 end: 7fd5abcfd000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abcfd000 end: 7fd5abcfe000 offset: 22000 load_base: 0 flags: 1 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abcfe000 end: 7fd5abcff000 offset: 23000 load_base: 0 flags: 3 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abcff000 end: 7fd5abd00000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5abd00000 end: 7fd5ac053000 offset: 0 load_base: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac053000 end: 7fd5ac054000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5ac054000 end: 7fd5ac06f000 offset: 353000 load_base: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac06f000 end: 7fd5ac070000 offset: 36e000 load_base: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac070000 end: 7fd5ac071000 offset: 0 load_base: 0 flags: 3 name: 
-map: start: 7fd5ad54e000 end: 7fd5ad56f000 offset: 0 load_base: 0 flags: 3 name: [heap]
-map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_base: 0 flags: 3 name: [stack]
-map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_base: ffffffffff700000 flags: 5 name: [vdso]
-map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_base: 0 flags: 5 name: [vsyscall]
+map: start: 7fd5aa784000 end: 7fd5aa93e000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aa93e000 end: 7fd5aab3e000 offset: 1ba000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab3e000 end: 7fd5aab42000 offset: 1ba000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab42000 end: 7fd5aab44000 offset: 1be000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libc-2.19.so
+map: start: 7fd5aab44000 end: 7fd5aab49000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5aab49000 end: 7fd5aac4e000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aac4e000 end: 7fd5aae4d000 offset: 105000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4d000 end: 7fd5aae4e000 offset: 104000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4e000 end: 7fd5aae4f000 offset: 105000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libm-2.19.so
+map: start: 7fd5aae4f000 end: 7fd5aae65000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5aae65000 end: 7fd5ab064000 offset: 16000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5ab064000 end: 7fd5ab065000 offset: 15000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
+map: start: 7fd5ab065000 end: 7fd5ab08a000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab08a000 end: 7fd5ab289000 offset: 25000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab289000 end: 7fd5ab28d000 offset: 24000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab28d000 end: 7fd5ab28e000 offset: 28000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
+map: start: 7fd5ab28e000 end: 7fd5ab2b0000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab2b0000 end: 7fd5ab4af000 offset: 22000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4af000 end: 7fd5ab4b0000 offset: 21000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4b0000 end: 7fd5ab4b1000 offset: 22000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
+map: start: 7fd5ab4b1000 end: 7fd5ab4b4000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab4b4000 end: 7fd5ab6b3000 offset: 3000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b3000 end: 7fd5ab6b4000 offset: 2000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b4000 end: 7fd5ab6b5000 offset: 3000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libdl-2.19.so
+map: start: 7fd5ab6b5000 end: 7fd5ab6bc000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab6bc000 end: 7fd5ab8bb000 offset: 7000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bb000 end: 7fd5ab8bc000 offset: 6000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bc000 end: 7fd5ab8bd000 offset: 7000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/librt-2.19.so
+map: start: 7fd5ab8bd000 end: 7fd5ab8d6000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5ab8d6000 end: 7fd5abad5000 offset: 19000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad5000 end: 7fd5abad6000 offset: 18000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad6000 end: 7fd5abad7000 offset: 19000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
+map: start: 7fd5abad7000 end: 7fd5abadb000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abadb000 end: 7fd5abafe000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abb17000 end: 7fd5abb1a000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abb1a000 end: 7fd5abb40000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb40000 end: 7fd5abb41000 offset: 25000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb41000 end: 7fd5abb42000 offset: 26000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
+map: start: 7fd5abb42000 end: 7fd5abb4b000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abb6a000 end: 7fd5abb70000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abb70000 end: 7fd5abc62000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc62000 end: 7fd5abc63000 offset: f2000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc63000 end: 7fd5abc6b000 offset: f2000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc6b000 end: 7fd5abc6c000 offset: fa000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
+map: start: 7fd5abc6c000 end: 7fd5abc70000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abc70000 end: 7fd5abc8d000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8d000 end: 7fd5abc8e000 offset: 1c000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8e000 end: 7fd5abc8f000 offset: 1d000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
+map: start: 7fd5abc8f000 end: 7fd5abcb8000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abcb8000 end: 7fd5abcbe000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcbe000 end: 7fd5abcbf000 offset: 6000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcbf000 end: 7fd5abcc0000 offset: 6000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcc0000 end: 7fd5abcc1000 offset: 7000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
+map: start: 7fd5abcc1000 end: 7fd5abcc2000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abcc2000 end: 7fd5abccd000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abccd000 end: 7fd5abcce000 offset: b000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abcce000 end: 7fd5abccf000 offset: b000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abccf000 end: 7fd5abcd0000 offset: c000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
+map: start: 7fd5abcd0000 end: 7fd5abcdf000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abcdf000 end: 7fd5abce0000 offset: f000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce0000 end: 7fd5abce1000 offset: f000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce1000 end: 7fd5abce2000 offset: 10000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
+map: start: 7fd5abce2000 end: 7fd5abcf5000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf5000 end: 7fd5abcf6000 offset: 12000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf6000 end: 7fd5abcf7000 offset: 13000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
+map: start: 7fd5abcf7000 end: 7fd5abcf8000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcf8000 end: 7fd5abcf9000 offset: 1000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcf9000 end: 7fd5abcfa000 offset: 1000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcfa000 end: 7fd5abcfb000 offset: 2000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
+map: start: 7fd5abcfb000 end: 7fd5abcfd000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abcfd000 end: 7fd5abcfe000 offset: 22000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abcfe000 end: 7fd5abcff000 offset: 23000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/ld-2.19.so
+map: start: 7fd5abcff000 end: 7fd5abd00000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5abd00000 end: 7fd5ac053000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac053000 end: 7fd5ac054000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5ac054000 end: 7fd5ac06f000 offset: 353000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac06f000 end: 7fd5ac070000 offset: 36e000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
+map: start: 7fd5ac070000 end: 7fd5ac071000 offset: 0 load_bias: 0 flags: 3 name: 
+map: start: 7fd5ad54e000 end: 7fd5ad56f000 offset: 0 load_bias: 0 flags: 3 name: [heap]
+map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_bias: 0 flags: 3 name: [stack]
+map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_bias: ffffffffff700000 flags: 5 name: [vdso]
+map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_bias: 0 flags: 5 name: [vsyscall]
 registers: 936 010000000000000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f0000b92455add57f0000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000a0b180f4fc7f000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f000078b480f4fc7f000078b480f4fc7f00007f03ffff0000ffffffffffff000000000000000000000000801f0000fc7f000078b480f4fc7f000060b280f4fc7f000000006a80f3f73cf110b480f4fc7f0000de66d6abd57f00000000000000000000000000000000000000006a80f3f73cf128b480f4fc7f0000782455add57f0000fd96d6abd57f0000092555add57f0000000000000000000057b480f4fc7f0000092555add57f000060b480f4fc7f00006994d6abd57f0000b0e0c6abd57f000071b280f4fc7f000070b280f4fc7f0000256c640000000000a8b180f4fc7f000090b480f4fc7f0000082555add57f0000092555add57f0000092555add57f0000082555add57f00001700000000000000082555add57f0000082555add57f0000f93cfcabd57f0000092555add57f000016000000000000000000000000000000090c07acd57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f000010b380f4fc7f000078b480f4fc7f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000092555add57f0000092555add57f0000b92455add57f000028b480f4fc7f0000c800000000000000014c7f0b0380ffff0d000000fc7f0000030000000000000033000000d57f000000b480f4fc7f00000000000000000000a0e154ad5b000000000000000000000000000000000000006e000000770000000000000000000000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f00006027b4aad57f0000c800000000000000a0e154add57f0000c0e354add57f0000092555add57f000000006a80f3f73cf1e0e054add57f0000e0e554add57f0000d14df6abd57f0000
 stack: start: 7fd5abb6b000 end: 7fd5abb6f000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c4eaeabd57f00000000000000000000978142a8000000000f0000000000000012000000000000003888b4abd57f0000e657aeabd57f00000000000000000000a0dcb6abd57f0000307d78aad57f0000b0ddb6abd57f000028d978aad57f0000060aa10200000000a0ddb6abd57f0000000000000000000000000000000000002091b1abd57f0000e094b4abd57f000017008cabd57f0000c84d79aad57f000028e28babd57f00000000000005000000d503000001000000000000000000000068deb6abd57f000040deb6abd57f00002091b1abd57f00000100000000000000e0f3c6abd57f000088f0c6abd57f00006159aeabd57f000000000000000000002091b1abd57f000005000000000000000000000000000000010000000000000088f0c6abd57f00000000000000000000d07bcfabd57f00000000000000000000000000000000000098deb6abd57f000098deb6abd57f0000b0ddb6abd57f00006179cfabd57f000098deb6abd57f0000b07bcfabd57f00001c000000150000000e00000007000000f0ddb6abd57f0000e179cfabd57f00000000000000000000150000001c00000098deb6abd57f0000b07bcfabd57f0000100000000c000000080000000400000030deb6abd57f0000417acfabd57f000000000000000000000c0000001000000098deb6abd57f0000b07bcfabd57f00000800000006000000040000000200000070deb6abd57f0000a17acfabd57f00000000000000000000060000000800000098deb6abd57f0000b07bcfabd57f000004000000030000000200000001000000b0deb6abd57f0000817bcfabd57f0000000000000000000074b480f4fc7f0000c8b080f4fc7f0000c8b080f4fc7f000074b480f4fc7f000000006a80f3f73cf1d0deb6abd57f00002a52d5abd57f0000c8b080f4fc7f0000c8b080f4fc7f0000000000000000000084518cabd57f0000000000000000000000e7b6abd57f000000e7b6abd57f00008f990b1e3bad5a6700000000000000000000000000000000c0e354add57f000000e7b6abd57f00008f99cba356faf1988f9991bc23faf1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f00007de387aad57f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006030b4aad57f0000b8edb6abd57f00000000000000000000000000000000000080b88eaad57f0000000000000000000080b28eaad57f0000000000000000000080c18eaad57f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f0000402555add57f000000e7b6abd57f00000100000000000000000000000000000000006a80f3f73cf1058f9d56adb3c7cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407ab1abd57f000030a3adabd57f00005c64000053640000e0e9b6abd57f0000e0e9b6abd57f0000e0ffffffffffffff00000000000000000000000000000000f0deb6abd57f00000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010eab6abd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c46ad90f52391d00000000000000000000000000000000000000000000000000f051d5abd57f0000c8b080f4fc7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b6abd57f000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: 7fd5abcf7930 name: unknown_start
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index d00ff5f..cfe8d29 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -161,8 +161,6 @@
         "-Wall",
         "-Wextra",
     ],
-
-    clang: true,
 }
 
 subdirs = ["tests"]
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index a33e45f..996d89d 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -35,11 +35,11 @@
             restart_cmd = "shutdown";
             break;
         case ANDROID_RB_THERMOFF:
-            restart_cmd = "thermal-shutdown";
+            restart_cmd = "shutdown,thermal";
             break;
     }
     if (!restart_cmd) return -1;
-    if (arg) {
+    if (arg && arg[0]) {
         ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
     } else {
         ret = asprintf(&prop_value, "%s", restart_cmd);
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 716567a..a903adb 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -29,8 +29,8 @@
 /* Properties */
 #define ANDROID_RB_PROPERTY "sys.powerctl"
 
-/* Android reboot reason stored in this file */
-#define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason"
+/* Android reboot reason stored in this property */
+#define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
 
 /* Reboot or shutdown the system.
  * This call uses ANDROID_RB_PROPERTY to request reboot to init process.
diff --git a/libcutils/include/cutils/list.h b/libcutils/include/cutils/list.h
index 4ba2cfd..dfdc53b 100644
--- a/libcutils/include/cutils/list.h
+++ b/libcutils/include/cutils/list.h
@@ -34,20 +34,20 @@
 
 #define list_declare(name) \
     struct listnode name = { \
-        .next = &name, \
-        .prev = &name, \
+        .next = &(name), \
+        .prev = &(name), \
     }
 
 #define list_for_each(node, list) \
-    for (node = (list)->next; node != (list); node = node->next)
+    for ((node) = (list)->next; (node) != (list); (node) = (node)->next)
 
 #define list_for_each_reverse(node, list) \
-    for (node = (list)->prev; node != (list); node = node->prev)
+    for ((node) = (list)->prev; (node) != (list); (node) = (node)->prev)
 
 #define list_for_each_safe(node, n, list) \
-    for (node = (list)->next, n = node->next; \
-         node != (list); \
-         node = n, n = node->next)
+    for ((node) = (list)->next, (n) = (node)->next; \
+         (node) != (list); \
+         (node) = (n), (n) = (node)->next)
 
 static inline void list_init(struct listnode *node)
 {
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index abe6dd6..10f5bc0 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -25,8 +25,8 @@
 
 /* Declare a char array for use with native_handle_init */
 #define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
-    alignas(native_handle_t) char name[                            \
-      sizeof(native_handle_t) + sizeof(int) * (maxFds + maxInts)]
+    alignas(native_handle_t) char (name)[                            \
+      sizeof(native_handle_t) + sizeof(int) * ((maxFds) + (maxInts))]
 
 typedef struct native_handle
 {
diff --git a/libcutils/include/cutils/properties.h b/libcutils/include/cutils/properties.h
index b45f58f..d2e0871 100644
--- a/libcutils/include/cutils/properties.h
+++ b/libcutils/include/cutils/properties.h
@@ -43,12 +43,7 @@
 ** If the property read fails or returns an empty value, the default
 ** value is used (if nonnull).
 */
-int property_get(const char *key, char *value, const char *default_value)
-/* Sometimes we use not-Bionic with this, so we need this check. */
-#if defined(__BIONIC_FORTIFY)
-        __overloadable __RENAME_CLANG(property_get)
-#endif
-        ;
+int property_get(const char* key, char* value, const char* default_value);
 
 /* property_get_bool: returns the value of key coerced into a
 ** boolean. If the property is not set, then the default value is returned.
@@ -119,27 +114,15 @@
 
 #if defined(__clang__)
 
-/* Some projects use -Weverything; enable_if is clang-specific.
-** FIXME: This is marked used because we'll otherwise get complaints about an
-** unused static function. This is more robust than marking it unused, since
-** -Wused-but-marked-unused is a thing that will complain if this function is
-** actually used, thus making FORTIFY noisier when an error happens. It's going
-** to go away anyway during our FORTIFY cleanup.
-**/
+/* Some projects use -Weverything; diagnose_if is clang-specific. */
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wgcc-compat"
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-int property_get(const char *key, char *value, const char *default_value)
-        __overloadable
-        __enable_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos(value) < PROPERTY_VALUE_MAX, __property_get_err_str)
-        __errorattr(__property_get_err_str)
-        __attribute__((used));
+int property_get(const char* key, char* value, const char* default_value)
+    __clang_error_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+                         __bos(value) < PROPERTY_VALUE_MAX,
+                     __property_get_err_str);
 #pragma clang diagnostic pop
 
-/* No object size? No FORTIFY.
-*/
-
 #else /* defined(__clang__) */
 
 extern int __property_get_real(const char *, char *, const char *)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index d4ba019..55ece54 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -120,6 +120,8 @@
 #define AID_ESE 1060             /* embedded secure element (eSE) subsystem */
 #define AID_OTA_UPDATE 1061      /* resource tracking UID for OTA updates */
 #define AID_AUTOMOTIVE_EVS 1062  /* Automotive rear and surround view system */
+#define AID_LOWPAN 1063          /* LoWPAN subsystem */
+#define AID_HSM 1064             /* hardware security module subsystem */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/socket_network_client_unix.c b/libcutils/socket_network_client_unix.c
index 37851b1..1b87c49 100644
--- a/libcutils/socket_network_client_unix.c
+++ b/libcutils/socket_network_client_unix.c
@@ -63,7 +63,7 @@
     for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
         // The Mac doesn't have SOCK_NONBLOCK.
         int s = socket(addr->ai_family, type, addr->ai_protocol);
-        if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
+        if (s == -1 || toggle_O_NONBLOCK(s) == -1) break;
 
         int rc = connect(s, addr->ai_addr, addr->ai_addrlen);
         if (rc == 0) {
diff --git a/libcutils/trace-container.c b/libcutils/trace-container.c
new file mode 100644
index 0000000..03e91b1
--- /dev/null
+++ b/libcutils/trace-container.c
@@ -0,0 +1,231 @@
+/*
+ * 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 "trace-dev.inc"
+
+#include <cutils/sockets.h>
+#include <sys/stat.h>
+#include <time.h>
+
+/**
+ * For tracing in container, tags are written into a socket
+ * instead of ftrace. Additional data is appended so we need extra space.
+ */
+#define CONTAINER_ATRACE_MESSAGE_LENGTH (ATRACE_MESSAGE_LENGTH + 512)
+
+static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
+
+// Variables used for tracing in container with socket.
+// Note that we need to manually close and reopen socket when Zygote is forking. This requires
+// writing and closing sockets on multiple threads. A rwlock is used for avoiding concurrent
+// operation on the file descriptor.
+static bool             atrace_use_container_sock    = false;
+static int              atrace_container_sock_fd     = -1;
+static pthread_mutex_t  atrace_enabling_mutex        = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t atrace_container_sock_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+static bool atrace_init_container_sock()
+{
+    pthread_rwlock_wrlock(&atrace_container_sock_rwlock);
+    atrace_container_sock_fd =
+        socket_local_client("trace", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
+    if (atrace_container_sock_fd < 0) {
+        ALOGE("Error opening container trace socket: %s (%d)", strerror(errno), errno);
+    }
+    pthread_rwlock_unlock(&atrace_container_sock_rwlock);
+    return atrace_container_sock_fd != -1;
+}
+
+static void atrace_close_container_sock()
+{
+    pthread_rwlock_wrlock(&atrace_container_sock_rwlock);
+    if (atrace_container_sock_fd != -1) close(atrace_container_sock_fd);
+    atrace_container_sock_fd = -1;
+    pthread_rwlock_unlock(&atrace_container_sock_rwlock);
+}
+
+// Set whether tracing is enabled in this process.  This is used to prevent
+// the Zygote process from tracing.  We need to close the socket in the container when tracing is
+// disabled, and reopen it again after Zygote forking.
+void atrace_set_tracing_enabled(bool enabled)
+{
+    pthread_mutex_lock(&atrace_enabling_mutex);
+    if (atrace_use_container_sock) {
+        bool already_enabled = atomic_load_explicit(&atrace_is_enabled, memory_order_acquire);
+        if (enabled && !already_enabled) {
+            // Trace was disabled previously. Re-initialize container socket.
+            atrace_init_container_sock();
+        } else if (!enabled && already_enabled) {
+            // Trace was enabled previously. Close container socket.
+            atrace_close_container_sock();
+        }
+    }
+    atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
+    pthread_mutex_unlock(&atrace_enabling_mutex);
+    atrace_update_tags();
+}
+
+static void atrace_init_once()
+{
+    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+    if (atrace_marker_fd < 0) {
+        // We're in container, ftrace may be disabled. In such case, we use the
+        // socket to write trace event.
+
+        // Protect the initialization of container socket from
+        // atrace_set_tracing_enabled.
+        pthread_mutex_lock(&atrace_enabling_mutex);
+        atrace_use_container_sock = true;
+        bool success = false;
+        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+            success = atrace_init_container_sock();
+        }
+        pthread_mutex_unlock(&atrace_enabling_mutex);
+
+        if (!success) {
+            atrace_enabled_tags = 0;
+            goto done;
+        }
+    }
+    atrace_enabled_tags = atrace_get_property();
+
+done:
+    atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
+}
+
+void atrace_setup()
+{
+    pthread_once(&atrace_once_control, atrace_init_once);
+}
+
+static inline uint64_t gettime(clockid_t clk_id)
+{
+    struct timespec ts;
+    clock_gettime(clk_id, &ts);
+    return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}
+
+// Write trace events to container trace file. Note that we need to amend tid and time information
+// here comparing to normal ftrace, where those informations are added by kernel.
+#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value) { \
+    char buf[CONTAINER_ATRACE_MESSAGE_LENGTH]; \
+    int pid = getpid(); \
+    int tid = gettid(); \
+    uint64_t ts = gettime(CLOCK_MONOTONIC); \
+    uint64_t tts = gettime(CLOCK_THREAD_CPUTIME_ID); \
+    int len = snprintf( \
+            buf, sizeof(buf), \
+            ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s" value_format, \
+            pid, tid, ts, tts, name, value); \
+    if (len >= (int) sizeof(buf)) { \
+        int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
+        /* Truncate the name to make the message fit. */ \
+        if (name_len > 0) { \
+            ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+            len = snprintf( \
+                    buf, sizeof(buf), \
+                    ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s" value_format, \
+                    pid, tid, ts, tts, name_len, name, value); \
+        } else { \
+            /* Data is still too long. Drop it. */ \
+            ALOGW("Data is too long in %s: %s\n", __FUNCTION__, name); \
+            len = 0; \
+        } \
+    } \
+    if (len > 0) { \
+        write(atrace_container_sock_fd, buf, len); \
+    } \
+}
+
+#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, name, value) { \
+    pthread_rwlock_rdlock(&atrace_container_sock_rwlock); \
+    if (atrace_container_sock_fd != -1) { \
+       WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value); \
+    } \
+    pthread_rwlock_unlock(&atrace_container_sock_rwlock); \
+}
+
+void atrace_begin_body(const char* name)
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("B", "|", "%s", name, "");
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("B|%d|", "%s", name, "");
+}
+
+void atrace_end_body()
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "");
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("E|%d", "%s", "", "");
+}
+
+void atrace_async_begin_body(const char* name, int32_t cookie)
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("S", "|", "|%d", name, cookie);
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
+}
+
+void atrace_async_end_body(const char* name, int32_t cookie)
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("F", "|", "|%d", name, cookie);
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
+}
+
+void atrace_int_body(const char* name, int32_t value)
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, name, value);
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("C|%d|", "|%" PRId32, name, value);
+}
+
+void atrace_int64_body(const char* name, int64_t value)
+{
+    if (CC_LIKELY(atrace_use_container_sock)) {
+        WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, name, value);
+        return;
+    }
+
+    if (atrace_marker_fd < 0) return;
+
+    WRITE_MSG("C|%d|", "|%" PRId64, name, value);
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index d45e5a9..4468e83 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -14,47 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "cutils-trace"
+#include "trace-dev.inc"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pthread.h>
-#include <stdatomic.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <cutils/compiler.h>
-#include <cutils/properties.h>
-#include <cutils/trace.h>
-#include <log/log.h>
-#include <log/log_properties.h>
-
-/**
- * Maximum size of a message that can be logged to the trace buffer.
- * Note this message includes a tag, the pid, and the string given as the name.
- * Names should be kept short to get the most use of the trace buffer.
- */
-#define ATRACE_MESSAGE_LENGTH 1024
-
-atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(false);
-int                     atrace_marker_fd     = -1;
-uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
-static bool             atrace_is_debuggable = false;
-static atomic_bool      atrace_is_enabled    = ATOMIC_VAR_INIT(true);
-static pthread_once_t   atrace_once_control  = PTHREAD_ONCE_INIT;
-static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
-
-// Set whether this process is debuggable, which determines whether
-// application-level tracing is allowed when the ro.debuggable system property
-// is not set to '1'.
-void atrace_set_debuggable(bool debuggable)
-{
-    atrace_is_debuggable = debuggable;
-    atrace_update_tags();
-}
+static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
 
 // Set whether tracing is enabled in this process.  This is used to prevent
 // the Zygote process from tracing.
@@ -64,101 +26,6 @@
     atrace_update_tags();
 }
 
-// Check whether the given command line matches one of the comma-separated
-// values listed in the app_cmdlines property.
-static bool atrace_is_cmdline_match(const char* cmdline)
-{
-    int count = property_get_int32("debug.atrace.app_number", 0);
-
-    char buf[PROPERTY_KEY_MAX];
-    char value[PROPERTY_VALUE_MAX];
-
-    for (int i = 0; i < count; i++) {
-        snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
-        property_get(buf, value, "");
-        if (strcmp(value, cmdline) == 0) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-// Determine whether application-level tracing is enabled for this process.
-static bool atrace_is_app_tracing_enabled()
-{
-    bool sys_debuggable = __android_log_is_debuggable();
-    bool result = false;
-
-    if (sys_debuggable || atrace_is_debuggable) {
-        // Check whether tracing is enabled for this process.
-        FILE * file = fopen("/proc/self/cmdline", "re");
-        if (file) {
-            char cmdline[4096];
-            if (fgets(cmdline, sizeof(cmdline), file)) {
-                result = atrace_is_cmdline_match(cmdline);
-            } else {
-                ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
-            }
-            fclose(file);
-        } else {
-            ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
-                    errno);
-        }
-    }
-
-    return result;
-}
-
-// Read the sysprop and return the value tags should be set to
-static uint64_t atrace_get_property()
-{
-    char value[PROPERTY_VALUE_MAX];
-    char *endptr;
-    uint64_t tags;
-
-    property_get("debug.atrace.tags.enableflags", value, "0");
-    errno = 0;
-    tags = strtoull(value, &endptr, 0);
-    if (value[0] == '\0' || *endptr != '\0') {
-        ALOGE("Error parsing trace property: Not a number: %s", value);
-        return 0;
-    } else if (errno == ERANGE || tags == ULLONG_MAX) {
-        ALOGE("Error parsing trace property: Number too large: %s", value);
-        return 0;
-    }
-
-    // Only set the "app" tag if this process was selected for app-level debug
-    // tracing.
-    if (atrace_is_app_tracing_enabled()) {
-        tags |= ATRACE_TAG_APP;
-    } else {
-        tags &= ~ATRACE_TAG_APP;
-    }
-
-    return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
-}
-
-// Update tags if tracing is ready. Useful as a sysprop change callback.
-void atrace_update_tags()
-{
-    uint64_t tags;
-    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
-        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
-            tags = atrace_get_property();
-            pthread_mutex_lock(&atrace_tags_mutex);
-            atrace_enabled_tags = tags;
-            pthread_mutex_unlock(&atrace_tags_mutex);
-        } else {
-            // Tracing is disabled for this process, so we simply don't
-            // initialize the tags.
-            pthread_mutex_lock(&atrace_tags_mutex);
-            atrace_enabled_tags = ATRACE_TAG_NOT_READY;
-            pthread_mutex_unlock(&atrace_tags_mutex);
-        }
-    }
-}
-
 static void atrace_init_once()
 {
     atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
@@ -181,54 +48,30 @@
 
 void atrace_begin_body(const char* name)
 {
-    char buf[ATRACE_MESSAGE_LENGTH];
-
-    int len = snprintf(buf, sizeof(buf), "B|%d|%s", getpid(), name);
-    if (len >= (int) sizeof(buf)) {
-        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name);
-        len = sizeof(buf) - 1;
-    }
-    write(atrace_marker_fd, buf, len);
+    WRITE_MSG("B|%d|", "%s", name, "");
 }
 
 void atrace_end_body()
 {
-    char c = 'E';
-    write(atrace_marker_fd, &c, 1);
-}
-
-#define WRITE_MSG(format_begin, format_end, pid, name, value) { \
-    char buf[ATRACE_MESSAGE_LENGTH]; \
-    int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
-        name, value); \
-    if (len >= (int) sizeof(buf)) { \
-        /* Given the sizeof(buf), and all of the current format buffers, \
-         * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
-        int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
-        /* Truncate the name to make the message fit. */ \
-        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
-        len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
-            name_len, name, value); \
-    } \
-    write(atrace_marker_fd, buf, len); \
+    WRITE_MSG("E|%d", "%s", "", "");
 }
 
 void atrace_async_begin_body(const char* name, int32_t cookie)
 {
-    WRITE_MSG("S|%d|", "|%" PRId32, getpid(), name, cookie);
+    WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
 }
 
 void atrace_async_end_body(const char* name, int32_t cookie)
 {
-    WRITE_MSG("F|%d|", "|%" PRId32, getpid(), name, cookie);
+    WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
 }
 
 void atrace_int_body(const char* name, int32_t value)
 {
-    WRITE_MSG("C|%d|", "|%" PRId32, getpid(), name, value);
+    WRITE_MSG("C|%d|", "|%" PRId32, name, value);
 }
 
 void atrace_int64_body(const char* name, int64_t value)
 {
-    WRITE_MSG("C|%d|", "|%" PRId64, getpid(), name, value);
+    WRITE_MSG("C|%d|", "|%" PRId64, name, value);
 }
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
new file mode 100644
index 0000000..f32330a
--- /dev/null
+++ b/libcutils/trace-dev.inc
@@ -0,0 +1,173 @@
+/*
+ * 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 __TRACE_DEV_INC
+#define __TRACE_DEV_INC
+
+#define LOG_TAG "cutils-trace"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <cutils/trace.h>
+#include <log/log.h>
+#include <log/log_properties.h>
+
+/**
+ * Maximum size of a message that can be logged to the trace buffer.
+ * Note this message includes a tag, the pid, and the string given as the name.
+ * Names should be kept short to get the most use of the trace buffer.
+ */
+#define ATRACE_MESSAGE_LENGTH 1024
+
+atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(false);
+int                     atrace_marker_fd     = -1;
+uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
+static bool             atrace_is_debuggable = false;
+static atomic_bool      atrace_is_enabled    = ATOMIC_VAR_INIT(true);
+static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
+
+// Set whether this process is debuggable, which determines whether
+// application-level tracing is allowed when the ro.debuggable system property
+// is not set to '1'.
+void atrace_set_debuggable(bool debuggable)
+{
+    atrace_is_debuggable = debuggable;
+    atrace_update_tags();
+}
+
+// Check whether the given command line matches one of the comma-separated
+// values listed in the app_cmdlines property.
+static bool atrace_is_cmdline_match(const char* cmdline)
+{
+    int count = property_get_int32("debug.atrace.app_number", 0);
+
+    char buf[PROPERTY_KEY_MAX];
+    char value[PROPERTY_VALUE_MAX];
+
+    for (int i = 0; i < count; i++) {
+        snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
+        property_get(buf, value, "");
+        if (strcmp(value, cmdline) == 0) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Determine whether application-level tracing is enabled for this process.
+static bool atrace_is_app_tracing_enabled()
+{
+    bool sys_debuggable = __android_log_is_debuggable();
+    bool result = false;
+
+    if (sys_debuggable || atrace_is_debuggable) {
+        // Check whether tracing is enabled for this process.
+        FILE * file = fopen("/proc/self/cmdline", "re");
+        if (file) {
+            char cmdline[4096];
+            if (fgets(cmdline, sizeof(cmdline), file)) {
+                result = atrace_is_cmdline_match(cmdline);
+            } else {
+                ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+            }
+            fclose(file);
+        } else {
+            ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+                    errno);
+        }
+    }
+
+    return result;
+}
+
+// Read the sysprop and return the value tags should be set to
+static uint64_t atrace_get_property()
+{
+    char value[PROPERTY_VALUE_MAX];
+    char *endptr;
+    uint64_t tags;
+
+    property_get("debug.atrace.tags.enableflags", value, "0");
+    errno = 0;
+    tags = strtoull(value, &endptr, 0);
+    if (value[0] == '\0' || *endptr != '\0') {
+        ALOGE("Error parsing trace property: Not a number: %s", value);
+        return 0;
+    } else if (errno == ERANGE || tags == ULLONG_MAX) {
+        ALOGE("Error parsing trace property: Number too large: %s", value);
+        return 0;
+    }
+
+    // Only set the "app" tag if this process was selected for app-level debug
+    // tracing.
+    if (atrace_is_app_tracing_enabled()) {
+        tags |= ATRACE_TAG_APP;
+    } else {
+        tags &= ~ATRACE_TAG_APP;
+    }
+
+    return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
+}
+
+// Update tags if tracing is ready. Useful as a sysprop change callback.
+void atrace_update_tags()
+{
+    uint64_t tags;
+    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+            tags = atrace_get_property();
+            pthread_mutex_lock(&atrace_tags_mutex);
+            atrace_enabled_tags = tags;
+            pthread_mutex_unlock(&atrace_tags_mutex);
+        } else {
+            // Tracing is disabled for this process, so we simply don't
+            // initialize the tags.
+            pthread_mutex_lock(&atrace_tags_mutex);
+            atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+            pthread_mutex_unlock(&atrace_tags_mutex);
+        }
+    }
+}
+
+#define WRITE_MSG(format_begin, format_end, name, value) { \
+    char buf[ATRACE_MESSAGE_LENGTH]; \
+    int pid = getpid(); \
+    int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
+        name, value); \
+    if (len >= (int) sizeof(buf)) { \
+        /* Given the sizeof(buf), and all of the current format buffers, \
+         * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
+        int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
+        /* Truncate the name to make the message fit. */ \
+        ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+        len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
+            name_len, name, value); \
+    } \
+    write(atrace_marker_fd, buf, len); \
+}
+
+#endif  // __TRACE_DEV_INC
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
index 4428848..b3fcb3b 100644
--- a/libion/tests/Android.bp
+++ b/libion/tests/Android.bp
@@ -16,7 +16,6 @@
 
 cc_test {
     name: "ion-unit-tests",
-    clang: true,
     cflags: [
         "-g",
         "-Wall",
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 68c2e9a..339a06d 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -354,11 +354,11 @@
 
 #if LOG_NDEBUG /* Production */
 #define android_testLog(prio, tag)                                           \
-  (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+  (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
                                  ANDROID_LOG_DEBUG) != 0)
 #else
 #define android_testLog(prio, tag)                                           \
-  (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+  (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
                                  ANDROID_LOG_VERBOSE) != 0)
 #endif
 
diff --git a/liblog/local_logger.c b/liblog/local_logger.c
index 522867d..563cb3f 100644
--- a/liblog/local_logger.c
+++ b/liblog/local_logger.c
@@ -222,6 +222,7 @@
       log->last[logId] = node->prev;
     }
     list_remove(node);
+    LOG_ALWAYS_FATAL_IF(node == log->last[logId], "corrupted list");
     free(e);
   }
   /* add entry to list */
diff --git a/liblog/logprint.c b/liblog/logprint.c
index b62f8b4..a2839bf 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -250,6 +250,7 @@
   while (!list_empty(&convertHead)) {
     struct listnode* node = list_head(&convertHead);
     list_remove(node);
+    LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list");
     free(node);
   }
 }
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 46ec5ef..e2d5aeb 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -105,7 +105,7 @@
 }
 
 #if (defined(__ANDROID__) && defined(USING_LOGGER_DEFAULT))
-static std::string popenToString(std::string command) {
+static std::string popenToString(const std::string& command) {
   std::string ret;
 
   FILE* fp = popen(command.c_str(), "r");
@@ -129,17 +129,17 @@
 static bool isLogdwActive() {
   std::string logdwSignature =
       popenToString("grep /dev/socket/logdw /proc/net/unix");
-  size_t beginning = logdwSignature.find(" ");
+  size_t beginning = logdwSignature.find(' ');
   if (beginning == std::string::npos) return true;
-  beginning = logdwSignature.find(" ", beginning + 1);
+  beginning = logdwSignature.find(' ', beginning + 1);
   if (beginning == std::string::npos) return true;
-  size_t end = logdwSignature.find(" ", beginning + 1);
+  size_t end = logdwSignature.find(' ', beginning + 1);
   if (end == std::string::npos) return true;
-  end = logdwSignature.find(" ", end + 1);
+  end = logdwSignature.find(' ', end + 1);
   if (end == std::string::npos) return true;
-  end = logdwSignature.find(" ", end + 1);
+  end = logdwSignature.find(' ', end + 1);
   if (end == std::string::npos) return true;
-  end = logdwSignature.find(" ", end + 1);
+  end = logdwSignature.find(' ', end + 1);
   if (end == std::string::npos) return true;
   std::string allLogdwEndpoints = popenToString(
       "grep ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
@@ -159,7 +159,7 @@
 
   // NB: fgrep with multiple strings is broken in Android
   for (beginning = 0;
-       (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+       (end = allLogdwEndpoints.find('\n', beginning)) != std::string::npos;
        beginning = end + 1) {
     if (myPidFds.find(allLogdwEndpoints.substr(beginning, end - beginning)) !=
         std::string::npos)
@@ -3170,7 +3170,7 @@
   return (offset != std::string::npos) &&
          ((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
           std::string::npos) &&
-         (content.find_first_not_of("0", offset) != offset);
+         (content.find_first_not_of('0', offset) != offset);
 }
 
 // must not be: '<needle:> 0 kB'
@@ -3239,7 +3239,7 @@
   filename = android::base::StringPrintf("/proc/%d/comm", pid);
   android::base::ReadFileToString(filename, &content);
   content = android::base::StringPrintf(
-      "%d:%s", pid, content.substr(0, content.find("\n")).c_str());
+      "%d:%s", pid, content.substr(0, content.find('\n')).c_str());
 
   EXPECT_TRUE(IsOk(shared_ok, content));
   EXPECT_TRUE(IsOk(private_ok, content));
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
index c56fa8b..9fb5a2c 100644
--- a/liblog/tests/log_id_test.cpp
+++ b/liblog/tests/log_id_test.cpp
@@ -89,12 +89,12 @@
     ASSERT_EQ(0, pthread_create(&t[i], NULL, ConcurrentPrintFn,
                                 reinterpret_cast<void*>(i)));
   }
-  int ret = 0;
+  int ret = 1;
   for (i = 0; i < NUM_CONCURRENT; i++) {
     void* result;
     ASSERT_EQ(0, pthread_join(t[i], &result));
     int this_result = reinterpret_cast<uintptr_t>(result);
-    if ((0 == ret) && (0 != this_result)) {
+    if ((0 < ret) && (ret != this_result)) {
       ret = this_result;
     }
   }
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 826a576..8b76a65 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -6,7 +6,6 @@
         "-Wextra",
         "-Werror",
     ],
-    clang: true,
     shared_libs: [
         "libbase",
     ],
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index 5e062fd..24fdc7f 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -479,23 +479,6 @@
   return oss.str();
 }
 
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
 std::string UnreachableMemoryInfo::ToString(bool log_contents) const {
   std::ostringstream oss;
   oss << "  " << leak_bytes << " bytes in ";
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index 26a041a..c692d1f 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -7,7 +7,6 @@
 cc_defaults {
     name: "metricslogger_defaults",
 
-    clang: true,
     host_supported: true,
 
     export_include_dirs: ["include"],
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 1cea4cd..b3c42f0 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -11,8 +11,7 @@
 
     host_supported: true,
     srcs: ["native_bridge.cc"],
-    shared_libs: ["liblog"],
-    clang: true,
+    shared_libs: ["liblog", "libbase"],
 
     export_include_dirs=["include"],
 
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 02b4fe7..e24307a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -28,6 +28,7 @@
 
 #include <cstring>
 
+#include <android-base/macros.h>
 #include <log/log.h>
 
 namespace android {
@@ -243,29 +244,12 @@
   }
 }
 
-#if defined(__arm__)
-static const char* kRuntimeISA = "arm";
-#elif defined(__aarch64__)
-static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const char* kRuntimeISA = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const char* kRuntimeISA = "mips64";
-#elif defined(__i386__)
-static const char* kRuntimeISA = "x86";
-#elif defined(__x86_64__)
-static const char* kRuntimeISA = "x86_64";
-#else
-static const char* kRuntimeISA = "unknown";
-#endif
-
-
 bool NeedsNativeBridge(const char* instruction_set) {
   if (instruction_set == nullptr) {
     ALOGE("Null instruction set in NeedsNativeBridge.");
     return false;
   }
-  return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
+  return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0;
 }
 
 #ifdef __APPLE__
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 70b3fcc..b3861e0 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -29,12 +29,12 @@
 
 shared_libraries := \
     liblog \
+    libbase \
     libnativebridge \
     libnativebridge-dummy
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_CLANG := true) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -43,7 +43,6 @@
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_CLANG := true) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
index 2067ed2..c8ff743 100644
--- a/libnativebridge/tests/NeedsNativeBridge_test.cpp
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -16,34 +16,20 @@
 
 #include "NativeBridgeTest.h"
 
+#include <android-base/macros.h>
+
 namespace android {
 
 static const char* kISAs[] = { "arm", "arm64", "mips", "mips64", "x86", "x86_64", "random", "64arm",
                                "64_x86", "64_x86_64", "", "reallylongstringabcd", nullptr };
 
-#if defined(__arm__)
-static const char* kRuntimeISA = "arm";
-#elif defined(__aarch64__)
-static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const char* kRuntimeISA = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const char* kRuntimeISA = "mips64";
-#elif defined(__i386__)
-static const char* kRuntimeISA = "x86";
-#elif defined(__x86_64__)
-static const char* kRuntimeISA = "x86_64";
-#else
-static const char* kRuntimeISA = "unknown";
-#endif
-
 TEST_F(NativeBridgeTest, NeedsNativeBridge) {
-    EXPECT_EQ(false, NeedsNativeBridge(kRuntimeISA));
+  EXPECT_EQ(false, NeedsNativeBridge(ABI_STRING));
 
-    const size_t kISACount = sizeof(kISAs)/sizeof(kISAs[0]);
-    for (size_t i = 0; i < kISACount; i++) {
-        EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], kRuntimeISA) != 0,
-                  NeedsNativeBridge(kISAs[i]));
+  const size_t kISACount = sizeof(kISAs) / sizeof(kISAs[0]);
+  for (size_t i = 0; i < kISACount; i++) {
+    EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], ABI_STRING) != 0,
+              NeedsNativeBridge(kISAs[i]));
     }
 }
 
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index c1133fb..13f9744 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -19,7 +19,6 @@
             host_ldlibs: ["-ldl"],
         },
     },
-    clang: true,
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 70ff528..a9fec7d 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -6,7 +6,6 @@
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
diff --git a/libsync/Android.bp b/libsync/Android.bp
index ce9e84a..3fae5e6 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -57,5 +57,4 @@
         "-Wno-missing-field-initializers",
         "-Wno-sign-compare",
     ],
-    clang: true,
 }
diff --git a/libsync/sync.c b/libsync/sync.c
index 0950082..6b187fa 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -277,7 +277,6 @@
     info = calloc(1, sizeof(struct sync_file_info) +
                      num_fences * sizeof(struct sync_fence_info));
     if (!info) {
-        free(legacy_info);
         return NULL;
     }
     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 04c4cfa..32ba692 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -30,19 +30,15 @@
             enabled: false,
         },
     },
-
-    arch: {
-        mips: {
-            enabled: false,
-        },
-        mips64: {
-            enabled: false,
-        },
-    },
 }
 
 cc_library {
     name: "libunwindstack",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     defaults: ["libunwindstack_flags"],
     export_include_dirs: ["include"],
 
@@ -65,6 +61,13 @@
         "Symbols.cpp",
     ],
 
+    target: {
+        // Always disable optimizations for host to make it easier to debug.
+        linux: {
+            cflags: ["-O0", "-g"],
+        },
+    },
+
     arch: {
         x86: {
             srcs: ["AsmGetRegsX86.S"],
@@ -105,7 +108,6 @@
         "tests/ElfTest.cpp",
         "tests/ElfTestUtils.cpp",
         "tests/LogFake.cpp",
-        "tests/MapInfoCreateMemoryTest.cpp",
         "tests/MapInfoGetElfTest.cpp",
         "tests/MapsTest.cpp",
         "tests/MemoryBufferTest.cpp",
diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrame.cpp
index d0b35c3..db8f558 100644
--- a/libunwindstack/DwarfEhFrame.cpp
+++ b/libunwindstack/DwarfEhFrame.cpp
@@ -100,7 +100,7 @@
     fde_info_.erase(index);
     return nullptr;
   }
-  info->pc = value;
+  info->pc = value + 4;
   return info;
 }
 
@@ -175,7 +175,7 @@
       last_error_ = DWARF_ERROR_MEMORY_INVALID;
       return false;
     }
-    info->pc = value;
+    info->pc = value + 4;
 
     if (pc < info->pc) {
       if (prev_info == nullptr) {
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index b6e0412..901f492 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -235,7 +235,7 @@
       return false;
   }
 
-  return AdjustEncodedValue(encoding & 0xf0, value);
+  return AdjustEncodedValue(encoding & 0x70, value);
 }
 
 // Instantiate all of the needed template functions.
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 4fc7c67..4f7476d 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -124,6 +124,28 @@
   return true;
 }
 
+void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
+  if (!IsValidElf(memory)) {
+    *valid = false;
+    return;
+  }
+  *size = 0;
+  *valid = true;
+
+  // Now read the section header information.
+  uint8_t class_type;
+  if (!memory->Read(EI_CLASS, &class_type, 1)) {
+    return;
+  }
+  if (class_type == ELFCLASS32) {
+    ElfInterface32::GetMaxSize(memory, size);
+  } else if (class_type == ELFCLASS64) {
+    ElfInterface64::GetMaxSize(memory, size);
+  } else {
+    *valid = false;
+  }
+}
+
 ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
   if (!IsValidElf(memory)) {
     return nullptr;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 75abc85..be4f88a 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -370,6 +370,22 @@
   return false;
 }
 
+// This is an estimation of the size of the elf file using the location
+// of the section headers and size. This assumes that the section headers
+// are at the end of the elf file. If the elf has a load bias, the size
+// will be too large, but this is acceptable.
+template <typename EhdrType>
+void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
+  EhdrType ehdr;
+  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
+    return;
+  }
+  if (ehdr.e_shnum == 0) {
+    return;
+  }
+  *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
+}
+
 // Instantiate all of the needed template functions.
 template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
 template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
@@ -391,4 +407,7 @@
 template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
                                                                    uint64_t*);
 
+template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
+template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
+
 }  // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index d0e1216..96f2cb4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -27,60 +28,88 @@
 
 namespace unwindstack {
 
-Memory* MapInfo::CreateMemory(pid_t pid) {
+Memory* MapInfo::GetFileMemory() {
+  std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
+  if (offset == 0) {
+    if (memory->Init(name, 0)) {
+      return memory.release();
+    }
+    return nullptr;
+  }
+
+  // There are two possibilities when the offset is non-zero.
+  // - There is an elf file embedded in a file.
+  // - The whole file is an elf file, and the offset needs to be saved.
+  //
+  // Map in just the part of the file for the map. If this is not
+  // a valid elf, then reinit as if the whole file is an elf file.
+  // If the offset is a valid elf, then determine the size of the map
+  // and reinit to that size. This is needed because the dynamic linker
+  // only maps in a portion of the original elf, and never the symbol
+  // file data.
+  uint64_t map_size = end - start;
+  if (!memory->Init(name, offset, map_size)) {
+    return nullptr;
+  }
+
+  bool valid;
+  uint64_t max_size;
+  Elf::GetInfo(memory.get(), &valid, &max_size);
+  if (!valid) {
+    // Init as if the whole file is an elf.
+    if (memory->Init(name, 0)) {
+      elf_offset = offset;
+      return memory.release();
+    }
+    return nullptr;
+  }
+
+  if (max_size > map_size) {
+    if (memory->Init(name, offset, max_size)) {
+      return memory.release();
+    }
+    // Try to reinit using the default map_size.
+    if (memory->Init(name, offset, map_size)) {
+      return memory.release();
+    }
+    return nullptr;
+  }
+  return memory.release();
+}
+
+Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
   if (end <= start) {
     return nullptr;
   }
 
   elf_offset = 0;
 
+  // Fail on device maps.
+  if (flags & MAPS_FLAGS_DEVICE_MAP) {
+    return nullptr;
+  }
+
   // First try and use the file associated with the info.
   if (!name.empty()) {
-    // Fail on device maps.
-    if (flags & MAPS_FLAGS_DEVICE_MAP) {
-      return nullptr;
-    }
-
-    std::unique_ptr<MemoryFileAtOffset> file_memory(new MemoryFileAtOffset);
-    uint64_t map_size;
-    if (offset != 0) {
-      // Only map in a piece of the file.
-      map_size = end - start;
-    } else {
-      map_size = UINT64_MAX;
-    }
-    if (file_memory->Init(name, offset, map_size)) {
-      // It's possible that a non-zero offset might not be pointing to
-      // valid elf data. Check if this is a valid elf, and if not assume
-      // that this was meant to incorporate the entire file.
-      if (offset != 0 && !Elf::IsValidElf(file_memory.get())) {
-        // Don't bother checking the validity that will happen on the elf init.
-        if (file_memory->Init(name, 0)) {
-          elf_offset = offset;
-          return file_memory.release();
-        }
-        // Fall through if the init fails.
-      } else {
-        return file_memory.release();
-      }
+    Memory* memory = GetFileMemory();
+    if (memory != nullptr) {
+      return memory;
     }
   }
 
-  Memory* memory = nullptr;
-  if (pid == getpid()) {
-    memory = new MemoryLocal();
-  } else {
-    memory = new MemoryRemote(pid);
+  // If the map isn't readable, don't bother trying to read from process memory.
+  if (!(flags & PROT_READ)) {
+    return nullptr;
   }
-  return new MemoryRange(memory, start, end);
+  return new MemoryRange(process_memory, start, end);
 }
 
-Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) {
+Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
   if (elf) {
     return elf;
   }
 
-  elf = new Elf(CreateMemory(pid));
+  elf = new Elf(CreateMemory(process_memory));
   if (elf->Init() && init_gnu_debugdata) {
     elf->InitGnuDebugdata();
   }
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 8a90423..5e1c0a2 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -25,6 +25,7 @@
 
 #include <android-base/unique_fd.h>
 
+#include <cctype>
 #include <memory>
 #include <string>
 #include <vector>
@@ -55,63 +56,151 @@
   return nullptr;
 }
 
-bool Maps::ParseLine(const char* line, MapInfo* map_info) {
-  char permissions[5];
-  int name_pos;
-  // Linux /proc/<pid>/maps lines:
+// Assumes that line does not end in '\n'.
+static bool InternalParseLine(const char* line, MapInfo* map_info) {
+  // Do not use a sscanf implementation since it is not performant.
+
+  // Example linux /proc/<pid>/maps lines:
   // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
-  if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*x:%*x %*d %n", &map_info->start,
-             &map_info->end, permissions, &map_info->offset, &name_pos) != 4) {
+  char* str;
+  const char* old_str = line;
+  map_info->start = strtoul(old_str, &str, 16);
+  if (old_str == str || *str++ != '-') {
     return false;
   }
-  map_info->flags = PROT_NONE;
-  if (permissions[0] == 'r') {
+
+  old_str = str;
+  map_info->end = strtoul(old_str, &str, 16);
+  if (old_str == str || !std::isspace(*str++)) {
+    return false;
+  }
+
+  while (std::isspace(*str)) {
+    str++;
+  }
+
+  // Parse permissions data.
+  if (*str == '\0') {
+    return false;
+  }
+  map_info->flags = 0;
+  if (*str == 'r') {
     map_info->flags |= PROT_READ;
+  } else if (*str != '-') {
+    return false;
   }
-  if (permissions[1] == 'w') {
+  str++;
+  if (*str == 'w') {
     map_info->flags |= PROT_WRITE;
+  } else if (*str != '-') {
+    return false;
   }
-  if (permissions[2] == 'x') {
+  str++;
+  if (*str == 'x') {
     map_info->flags |= PROT_EXEC;
+  } else if (*str != '-') {
+    return false;
+  }
+  str++;
+  if (*str != 'p' && *str != 's') {
+    return false;
+  }
+  str++;
+
+  if (!std::isspace(*str++)) {
+    return false;
   }
 
-  if (line[name_pos] != '\0') {
-    map_info->name = &line[name_pos];
-    size_t length = map_info->name.length() - 1;
-    if (map_info->name[length] == '\n') {
-      map_info->name.erase(length);
-    }
-
-    // Mark a device map in /dev/and not in /dev/ashmem/ specially.
-    if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
-      map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
-    }
+  old_str = str;
+  map_info->offset = strtoul(old_str, &str, 16);
+  if (old_str == str || !std::isspace(*str)) {
+    return false;
   }
 
+  // Ignore the 00:00 values.
+  old_str = str;
+  (void)strtoul(old_str, &str, 16);
+  if (old_str == str || *str++ != ':') {
+    return false;
+  }
+  if (std::isspace(*str)) {
+    return false;
+  }
+
+  // Skip the inode.
+  old_str = str;
+  (void)strtoul(str, &str, 16);
+  if (old_str == str || !std::isspace(*str++)) {
+    return false;
+  }
+
+  // Skip decimal digit.
+  old_str = str;
+  (void)strtoul(old_str, &str, 10);
+  if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
+    return false;
+  }
+
+  while (std::isspace(*str)) {
+    str++;
+  }
+  if (*str == '\0') {
+    map_info->name = str;
+    return true;
+  }
+
+  // Save the name data.
+  map_info->name = str;
+
+  // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+  if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
+    map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+  }
   return true;
 }
 
 bool Maps::Parse() {
-  std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
-  if (!fp) {
+  int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
+  if (fd == -1) {
     return false;
   }
 
-  bool valid = true;
-  char* line = nullptr;
-  size_t line_len;
-  while (getline(&line, &line_len, fp.get()) > 0) {
-    MapInfo map_info;
-    if (!ParseLine(line, &map_info)) {
-      valid = false;
+  bool return_value = true;
+  char buffer[2048];
+  size_t leftover = 0;
+  while (true) {
+    ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
+    if (bytes == -1) {
+      return_value = false;
       break;
     }
+    if (bytes == 0) {
+      break;
+    }
+    bytes += leftover;
+    char* line = buffer;
+    while (bytes > 0) {
+      char* newline = static_cast<char*>(memchr(line, '\n', bytes));
+      if (newline == nullptr) {
+        memmove(buffer, line, bytes);
+        break;
+      }
+      *newline = '\0';
 
-    maps_.push_back(map_info);
+      MapInfo map_info;
+      if (!InternalParseLine(line, &map_info)) {
+        return_value = false;
+        break;
+      }
+      maps_.push_back(map_info);
+
+      bytes -= newline - line + 1;
+      line = newline + 1;
+    }
+    leftover = bytes;
   }
-  free(line);
-
-  return valid;
+  close(fd);
+  return return_value;
 }
 
 Maps::~Maps() {
@@ -129,12 +218,12 @@
     if (end_of_line == nullptr) {
       line = start_of_line;
     } else {
-      end_of_line++;
       line = std::string(start_of_line, end_of_line - start_of_line);
+      end_of_line++;
     }
 
     MapInfo map_info;
-    if (!ParseLine(line.c_str(), &map_info)) {
+    if (!InternalParseLine(line.c_str(), &map_info)) {
       return false;
     }
     maps_.push_back(map_info);
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 8c36055..32753df 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -52,6 +52,13 @@
   return false;
 }
 
+std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
+  if (pid == getpid()) {
+    return std::shared_ptr<Memory>(new MemoryLocal());
+  }
+  return std::shared_ptr<Memory>(new MemoryRemote(pid));
+}
+
 bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
   uint64_t last_read_byte;
   if (__builtin_add_overflow(size, addr, &last_read_byte)) {
@@ -249,7 +256,7 @@
   return true;
 }
 
-MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
+MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end)
     : memory_(memory), begin_(begin), length_(end - begin) {
   CHECK(end > begin);
 }
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index dea7b87..4d09c1b 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -56,6 +56,10 @@
 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;
@@ -90,6 +94,10 @@
 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;
@@ -109,6 +117,10 @@
 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;
@@ -128,6 +140,10 @@
 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;
@@ -212,7 +228,7 @@
 
 // This function assumes that reg_data is already aligned to a 64 bit value.
 // If not this could crash with an unaligned access.
-Regs* Regs::RemoteGet(pid_t pid, uint32_t* machine_type) {
+Regs* Regs::RemoteGet(pid_t pid) {
   // Make the buffer large enough to contain the largest registers type.
   std::vector<uint64_t> buffer(MAX_USER_REGS_SIZE / sizeof(uint64_t));
   struct iovec io;
@@ -225,16 +241,12 @@
 
   switch (io.iov_len) {
   case sizeof(x86_user_regs):
-    *machine_type = EM_386;
     return ReadX86(buffer.data());
   case sizeof(x86_64_user_regs):
-    *machine_type = EM_X86_64;
     return ReadX86_64(buffer.data());
   case sizeof(arm_user_regs):
-    *machine_type = EM_ARM;
     return ReadArm(buffer.data());
   case sizeof(arm64_user_regs):
-    *machine_type = EM_AARCH64;
     return ReadArm64(buffer.data());
   }
   return nullptr;
@@ -320,7 +332,7 @@
   return nullptr;
 }
 
-uint32_t Regs::GetMachineType() {
+uint32_t Regs::CurrentMachineType() {
 #if defined(__arm__)
   return EM_ARM;
 #elif defined(__aarch64__)
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index a97ca2b..26485ae 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -106,7 +106,7 @@
   DwarfMemory memory_;
   DwarfError last_error_;
 
-  uint64_t fde_count_;
+  uint64_t fde_count_ = 0;
   std::unordered_map<uint64_t, DwarfFde> fde_entries_;
   std::unordered_map<uint64_t, DwarfCie> cie_entries_;
   std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index d89a746..4e7eb34 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -70,6 +70,8 @@
 
   static bool IsValidElf(Memory* memory);
 
+  static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
+
  protected:
   bool valid_ = false;
   std::unique_ptr<ElfInterface> interface_;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 5cac0d3..142a625 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -102,6 +102,9 @@
 
   virtual bool HandleType(uint64_t, uint32_t) { return false; }
 
+  template <typename EhdrType>
+  static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
+
   Memory* memory_;
   std::unordered_map<uint64_t, LoadInfo> pt_loads_;
   uint64_t load_bias_ = 0;
@@ -146,6 +149,10 @@
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
     return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
   }
+
+  static void GetMaxSize(Memory* memory, uint64_t* size) {
+    GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
+  }
 };
 
 class ElfInterface64 : public ElfInterface {
@@ -166,6 +173,10 @@
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
     return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
   }
+
+  static void GetMaxSize(Memory* memory, uint64_t* size) {
+    GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
+  }
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 2a97dde..f108766 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -40,8 +40,13 @@
   // instead of a portion of the file.
   uint64_t elf_offset;
 
-  Memory* CreateMemory(pid_t pid);
-  Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
+  // This function guarantees it will never return nullptr.
+  Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
+
+ private:
+  Memory* GetFileMemory();
+
+  Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 0b02739..22122a9 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -38,8 +38,6 @@
 
   MapInfo* Find(uint64_t pc);
 
-  bool ParseLine(const char* line, MapInfo* map_info);
-
   virtual bool Parse();
 
   virtual const std::string GetMapsFile() const { return ""; }
@@ -54,6 +52,11 @@
 
   size_t Total() { return maps_.size(); }
 
+  MapInfo* Get(size_t index) {
+    if (index >= maps_.size()) return nullptr;
+    return &maps_[index];
+  }
+
  protected:
   std::vector<MapInfo> maps_;
 };
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 0c05266..183b899 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 <memory>
 #include <string>
 #include <vector>
 
@@ -31,6 +32,8 @@
   Memory() = default;
   virtual ~Memory() = default;
 
+  static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+
   virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
 
   virtual bool Read(uint64_t addr, void* dst, size_t size) = 0;
@@ -125,13 +128,13 @@
 
 class MemoryRange : public Memory {
  public:
-  MemoryRange(Memory* memory, uint64_t begin, uint64_t end);
-  virtual ~MemoryRange() { delete memory_; }
+  MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end);
+  virtual ~MemoryRange() = default;
 
   bool Read(uint64_t addr, void* dst, size_t size) override;
 
  private:
-  Memory* memory_;
+  std::shared_ptr<Memory> memory_;
   uint64_t begin_;
   uint64_t length_;
 };
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 78e2c0d..ed4d38a 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -49,6 +49,8 @@
       : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {}
   virtual ~Regs() = default;
 
+  virtual uint32_t MachineType() = 0;
+
   virtual void* RawData() = 0;
   virtual uint64_t pc() = 0;
   virtual uint64_t sp() = 0;
@@ -64,8 +66,8 @@
   uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
-  static uint32_t GetMachineType();
-  static Regs* RemoteGet(pid_t pid, uint32_t* machine_type);
+  static uint32_t CurrentMachineType();
+  static Regs* RemoteGet(pid_t pid);
   static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext);
   static Regs* CreateFromLocal();
 
@@ -105,6 +107,8 @@
   RegsArm();
   virtual ~RegsArm() = default;
 
+  virtual uint32_t MachineType() override final;
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
@@ -117,6 +121,8 @@
   RegsArm64();
   virtual ~RegsArm64() = default;
 
+  virtual uint32_t MachineType() override final;
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
@@ -129,6 +135,8 @@
   RegsX86();
   virtual ~RegsX86() = default;
 
+  virtual uint32_t MachineType() override final;
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
@@ -143,6 +151,8 @@
   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;
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index ffec213..d1461d8 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -97,6 +97,11 @@
   regs->SetFromRaw();
 }
 
+#elif defined(__mips__)
+
+// Stub to allow mips to build.
+void RegsGetLocal(Regs*) {}
+
 #endif
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index e9501e3..07159b0 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -124,7 +124,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x1380U, info->pc);
+  EXPECT_EQ(0x1384U, info->pc);
   EXPECT_EQ(0x1540U, info->offset);
 }
 
@@ -139,7 +139,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x3340U, info->pc);
+  EXPECT_EQ(0x3344U, info->pc);
   EXPECT_EQ(0x3500U, info->offset);
 }
 
@@ -153,7 +153,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x340U, info->pc);
+  EXPECT_EQ(0x344U, info->pc);
   EXPECT_EQ(0x500U, info->offset);
 
   // Clear the memory so that this will fail if it doesn't read cached data.
@@ -161,7 +161,7 @@
 
   info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x340U, info->pc);
+  EXPECT_EQ(0x344U, info->pc);
   EXPECT_EQ(0x500U, info->offset);
 }
 
@@ -220,18 +220,18 @@
 
   // Verify that if entries is zero, that it fails.
   uint64_t fde_offset;
-  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x340, &fde_offset));
+  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
   this->eh_frame_->TestSetCurEntriesOffset(0x1040);
 
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x340, &fde_offset));
+  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
   EXPECT_EQ(0x500U, fde_offset);
 
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x440, &fde_offset));
+  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
   EXPECT_EQ(0x600U, fde_offset);
 
   // Expect that the data is cached so no more memory reads will occur.
   this->memory_.Clear();
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x440, &fde_offset));
+  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
   EXPECT_EQ(0x600U, fde_offset);
 }
 
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index 08fe7cf..f12d2fe 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -52,6 +52,8 @@
   void ReadEncodedValue_non_zero_adjust();
   template <typename AddressType>
   void ReadEncodedValue_overflow();
+  template <typename AddressType>
+  void ReadEncodedValue_high_bit_set();
 
   MemoryFake memory_;
   std::unique_ptr<DwarfMemory> dwarf_mem_;
@@ -435,6 +437,26 @@
   ReadEncodedValue_overflow<uint64_t>();
 }
 
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_high_bit_set() {
+  uint64_t value;
+  memory_.SetData32(0, 0x15234);
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
+
+  dwarf_mem_->set_func_offset(0x60000);
+  dwarf_mem_->set_cur_offset(0);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
+  ASSERT_EQ(0x75234U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint32_t) {
+  ReadEncodedValue_high_bit_set<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint64_t) {
+  ReadEncodedValue_high_bit_set<uint64_t>();
+}
+
 TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
   uint64_t value = 0x1234;
   ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 9e45e78..d2aad49 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -34,49 +34,78 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 
+#include "MemoryFake.h"
+
 namespace unwindstack {
 
 class MapInfoCreateMemoryTest : public ::testing::Test {
  protected:
+  template <typename Ehdr, typename Shdr>
+  static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) {
+    std::vector<uint8_t> buffer(20000);
+    memset(buffer.data(), 0, buffer.size());
+
+    Ehdr ehdr;
+    memset(&ehdr, 0, sizeof(ehdr));
+    memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
+    ehdr.e_ident[EI_CLASS] = class_type;
+    ehdr.e_shoff = sh_offset;
+    ehdr.e_shentsize = sizeof(Shdr) + 100;
+    ehdr.e_shnum = 4;
+    memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr));
+
+    ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size()));
+  }
+
   static void SetUpTestCase() {
     std::vector<uint8_t> buffer(1024);
+    memset(buffer.data(), 0, buffer.size());
     memcpy(buffer.data(), ELFMAG, SELFMAG);
-    for (size_t i = SELFMAG; i < buffer.size(); i++) {
-      buffer[i] = i / 256 + 1;
-    }
+    buffer[EI_CLASS] = ELFCLASS32;
     ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-    for (size_t i = 0; i < 0x100; i++) {
-      buffer[i] = i / 256 + 1;
-    }
+    memset(buffer.data(), 0, buffer.size());
     memcpy(&buffer[0x100], ELFMAG, SELFMAG);
-    for (size_t i = 0x100 + SELFMAG; i < buffer.size(); i++) {
-      buffer[i] = i / 256 + 1;
-    }
+    buffer[0x100 + EI_CLASS] = ELFCLASS64;
     ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
+
+    InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
+    InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
   }
 
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+  }
+
+  MemoryFake* memory_;
+  std::shared_ptr<Memory> process_memory_;
+
   static TemporaryFile elf_;
 
   static TemporaryFile elf_at_100_;
+
+  static TemporaryFile elf32_at_map_;
+  static TemporaryFile elf64_at_map_;
 };
 TemporaryFile MapInfoCreateMemoryTest::elf_;
 TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
+TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
+TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
 
 TEST_F(MapInfoCreateMemoryTest, end_le_start) {
   MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
 
-  std::unique_ptr<Memory> memory;
-  memory.reset(info.CreateMemory(getpid()));
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
 
   info.end = 0xff;
-  memory.reset(info.CreateMemory(getpid()));
+  memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
 
   // Make sure this test is valid.
   info.end = 0x101;
-  memory.reset(info.CreateMemory(getpid()));
+  memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
 }
 
@@ -85,7 +114,7 @@
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
   MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
 
-  std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0x100U, info.elf_offset);
 
@@ -93,8 +122,9 @@
   std::vector<uint8_t> buffer(1024);
   ASSERT_TRUE(memory->Read(0, buffer.data(), 1024));
   ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
-  for (size_t i = SELFMAG; i < buffer.size(); i++) {
-    ASSERT_EQ(i / 256 + 1, buffer[i]) << "Failed at byte " << i;
+  ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]);
+  for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
+    ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
   ASSERT_FALSE(memory->Read(1024, buffer.data(), 1));
@@ -105,7 +135,7 @@
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
   MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
 
-  std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
 
@@ -113,13 +143,50 @@
   std::vector<uint8_t> buffer(0x100);
   ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100));
   ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
-  for (size_t i = SELFMAG; i < buffer.size(); i++) {
-    ASSERT_EQ(2, buffer[i]) << "Failed at byte " << i;
+  ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]);
+  for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
+    ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
   ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1));
 }
 
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used. Further verify that if the
+// embedded elf is bigger than the initial map, the new object is larger
+// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
+  MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path};
+
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0U, info.elf_offset);
+
+  // Verify the memory is a valid elf.
+  uint8_t e_ident[SELFMAG + 1];
+  ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
+  ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
+
+  // Read past the end of what would normally be the size of the map.
+  ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
+}
+
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
+  MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path};
+
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0U, info.elf_offset);
+
+  // Verify the memory is a valid elf.
+  uint8_t e_ident[SELFMAG + 1];
+  ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
+  ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
+
+  // Read past the end of what would normally be the size of the map.
+  ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
+}
+
 // Verify that device file names will never result in Memory object creation.
 TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
   // Set up some memory so that a valid local memory object would
@@ -129,81 +196,38 @@
   info.start = reinterpret_cast<uint64_t>(buffer.data());
   info.end = info.start + buffer.size();
   info.offset = 0;
-  std::unique_ptr<Memory> memory;
 
   info.flags = 0x8000;
   info.name = "/dev/something";
-  memory.reset(info.CreateMemory(getpid()));
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
 }
 
-TEST_F(MapInfoCreateMemoryTest, local_memory) {
-  // Set up some memory for a valid local memory object.
+TEST_F(MapInfoCreateMemoryTest, process_memory) {
+  MapInfo info;
+  info.start = 0x2000;
+  info.end = 0x3000;
+  info.offset = 0;
+
+  // Verify that the the process_memory object is used, so seed it
+  // with memory.
   std::vector<uint8_t> buffer(1024);
   for (size_t i = 0; i < buffer.size(); i++) {
     buffer[i] = i % 256;
   }
+  memory_->SetMemory(info.start, buffer.data(), buffer.size());
 
-  MapInfo info;
-  info.start = reinterpret_cast<uint64_t>(buffer.data());
-  info.end = info.start + buffer.size();
-  info.offset = 0;
-
-  std::unique_ptr<Memory> memory;
-  memory.reset(info.CreateMemory(getpid()));
+  std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
 
-  std::vector<uint8_t> read_buffer(1024);
-  ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
-  for (size_t i = 0; i < read_buffer.size(); i++) {
-    ASSERT_EQ(i % 256, read_buffer[i]) << "Failed at byte " << i;
+  memset(buffer.data(), 0, buffer.size());
+  ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size()));
+  for (size_t i = 0; i < buffer.size(); i++) {
+    ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
-}
-
-TEST_F(MapInfoCreateMemoryTest, remote_memory) {
-  std::vector<uint8_t> buffer(1024);
-  memset(buffer.data(), 0xa, buffer.size());
-
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    while (true)
-      ;
-    exit(1);
-  }
-  ASSERT_LT(0, pid);
-
-  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) != -1);
-  uint64_t iterations = 0;
-  siginfo_t si;
-  while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
-    usleep(30);
-    iterations++;
-    ASSERT_LT(iterations, 500000000ULL);
-  }
-
-  MapInfo info;
-  info.start = reinterpret_cast<uint64_t>(buffer.data());
-  info.end = info.start + buffer.size();
-  info.offset = 0;
-
-  std::unique_ptr<Memory> memory;
-  memory.reset(info.CreateMemory(pid));
-  ASSERT_TRUE(memory.get() != nullptr);
-  // Set the local memory to a different value to guarantee we are reading
-  // from the remote process.
-  memset(buffer.data(), 0x1, buffer.size());
-  std::vector<uint8_t> read_buffer(1024);
-  ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
-  for (size_t i = 0; i < read_buffer.size(); i++) {
-    ASSERT_EQ(0xaU, read_buffer[i]) << "Failed at byte " << i;
-  }
-
-  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
+  // Try to read outside of the map size.
+  ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index abfa172..0b70d13 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -32,43 +32,57 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 
 #include "ElfTestUtils.h"
+#include "MemoryFake.h"
 
 namespace unwindstack {
 
 class MapInfoGetElfTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-    ASSERT_NE(MAP_FAILED, map_);
-
-    uint64_t start = reinterpret_cast<uint64_t>(map_);
-    info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""});
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
   }
 
-  void TearDown() override { munmap(map_, kMapSize); }
+  template <typename Ehdr, typename Shdr>
+  static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) {
+    memset(ehdr, 0, sizeof(*ehdr));
+    memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+    ehdr->e_ident[EI_CLASS] = class_type;
+    ehdr->e_machine = machine_type;
+    ehdr->e_shoff = sh_offset;
+    ehdr->e_shentsize = sizeof(Shdr) + 100;
+    ehdr->e_shnum = 4;
+  }
 
   const size_t kMapSize = 4096;
 
-  void* map_ = nullptr;
-  std::unique_ptr<MapInfo> info_;
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_;
+
+  TemporaryFile elf_;
 };
 
 TEST_F(MapInfoGetElfTest, invalid) {
+  MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""};
+
   // The map is empty, but this should still create an invalid elf object.
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_FALSE(elf->valid());
 }
 
 TEST_F(MapInfoGetElfTest, valid32) {
+  MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""};
+
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
-  memcpy(map_, &ehdr, sizeof(ehdr));
+  memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -76,11 +90,13 @@
 }
 
 TEST_F(MapInfoGetElfTest, valid64) {
+  MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""};
+
   Elf64_Ehdr ehdr;
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
-  memcpy(map_, &ehdr, sizeof(ehdr));
+  memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -88,12 +104,14 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
-  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
-      ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) {
-        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
-      });
+  MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(0x4000 + offset, ptr, size);
+                                               });
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -102,12 +120,14 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
-  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
-      ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) {
-        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
-      });
+  MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(0x6000 + offset, ptr, size);
+                                               });
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -116,12 +136,14 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
-  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
-      ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) {
-        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
-      });
+  MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""};
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(0x2000 + offset, ptr, size);
+                                               });
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -130,12 +152,14 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
-  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
-      ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) {
-        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
-      });
+  MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
 
-  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(0x5000 + offset, ptr, size);
+                                               });
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
   ASSERT_TRUE(elf.get() != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -143,4 +167,195 @@
   EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
 }
 
+TEST_F(MapInfoGetElfTest, end_le_start) {
+  MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path};
+
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_FALSE(elf->valid());
+
+  info.elf = nullptr;
+  info.end = 0xfff;
+  elf.reset(info.GetElf(process_memory_, false));
+  ASSERT_FALSE(elf->valid());
+
+  // Make sure this test is valid.
+  info.elf = nullptr;
+  info.end = 0x2000;
+  elf.reset(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+}
+
+// Verify that if the offset is non-zero but there is no elf at the offset,
+// that the full file is used.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
+  MapInfo info{
+      .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path};
+
+  std::vector<uint8_t> buffer(0x1000);
+  memset(buffer.data(), 0, buffer.size());
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memcpy(buffer.data(), &ehdr, sizeof(ehdr));
+  ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+  ASSERT_TRUE(elf->memory() != nullptr);
+  ASSERT_EQ(0x100U, info.elf_offset);
+
+  // Read the entire file.
+  memset(buffer.data(), 0, buffer.size());
+  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size()));
+  ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+  for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
+    ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
+  }
+
+  ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1));
+}
+
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
+  MapInfo info{
+      .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path};
+
+  std::vector<uint8_t> buffer(0x4000);
+  memset(buffer.data(), 0, buffer.size());
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+  ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+  ASSERT_TRUE(elf->memory() != nullptr);
+  ASSERT_EQ(0U, info.elf_offset);
+
+  // Read the valid part of the file.
+  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+  for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
+    ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
+  }
+
+  ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used. Further verify that if the
+// embedded elf is bigger than the initial map, the new object is larger
+// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
+  MapInfo info{
+      .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+
+  std::vector<uint8_t> buffer(0x4000);
+  memset(buffer.data(), 0, buffer.size());
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+  ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+  ASSERT_TRUE(elf->memory() != nullptr);
+  ASSERT_EQ(0U, info.elf_offset);
+
+  // Verify the memory is a valid elf.
+  memset(buffer.data(), 0, buffer.size());
+  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+
+  // Read past the end of what would normally be the size of the map.
+  ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
+  MapInfo info{
+      .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+
+  std::vector<uint8_t> buffer(0x4000);
+  memset(buffer.data(), 0, buffer.size());
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+  ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+  ASSERT_TRUE(elf->memory() != nullptr);
+  ASSERT_EQ(0U, info.elf_offset);
+
+  // Verify the memory is a valid elf.
+  memset(buffer.data(), 0, buffer.size());
+  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+
+  // Read past the end of what would normally be the size of the map.
+  ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
+  MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""};
+
+  // Create valid elf data in process memory only.
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_FALSE(elf->valid());
+
+  info.elf = nullptr;
+  info.flags = PROT_READ;
+  elf.reset(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+}
+
+TEST_F(MapInfoGetElfTest, check_device_maps) {
+  MapInfo info{.start = 0x7000,
+               .end = 0x8000,
+               .offset = 0x1000,
+               .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP,
+               .name = "/dev/something"};
+
+  // Create valid elf data in process memory for this to verify that only
+  // the name is causing invalid elf data.
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
+
+  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  ASSERT_FALSE(elf->valid());
+
+  // Set the name to nothing to verify that it still fails.
+  info.elf = nullptr;
+  info.name = "";
+  elf.reset(info.GetElf(process_memory_, false));
+  ASSERT_FALSE(elf->valid());
+
+  // Change the flags and verify the elf is valid now.
+  info.elf = nullptr;
+  info.flags = PROT_READ;
+  elf.reset(info.GetElf(process_memory_, false));
+  ASSERT_TRUE(elf->valid());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 9430cf3..2d15a4e 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <inttypes.h>
 #include <sys/mman.h>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
@@ -24,13 +26,116 @@
 
 namespace unwindstack {
 
+static void VerifyLine(std::string line, MapInfo* info) {
+  BufferMaps maps(line.c_str());
+
+  if (info == nullptr) {
+    ASSERT_FALSE(maps.Parse()) << "Failed on: " + line;
+  } else {
+    ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
+    MapInfo* element = maps.Get(0);
+    ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
+    *info = *element;
+  }
+}
+
+TEST(MapsTest, verify_parse_line) {
+  MapInfo info;
+
+  VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
+  EXPECT_EQ(1U, info.start);
+  EXPECT_EQ(2U, info.end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+  EXPECT_EQ(3U, info.offset);
+  EXPECT_EQ("", info.name);
+
+  VerifyLine("0a-0b ---s 0c 0d:0e 06 /fake/name\n", &info);
+  EXPECT_EQ(0xaU, info.start);
+  EXPECT_EQ(0xbU, info.end);
+  EXPECT_EQ(0U, info.flags);
+  EXPECT_EQ(0xcU, info.offset);
+  EXPECT_EQ("/fake/name", info.name);
+
+  VerifyLine("01-02   rwxp   03    04:05    06    /fake/name/again\n", &info);
+  EXPECT_EQ(1U, info.start);
+  EXPECT_EQ(2U, info.end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+  EXPECT_EQ(3U, info.offset);
+  EXPECT_EQ("/fake/name/again", info.name);
+
+  VerifyLine("-00 rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00- rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 00 :00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 00 00:00 \n", nullptr);
+  VerifyLine("x-00 rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00 -00 rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00-00x rwxp 00 00:00 0\n", nullptr);
+  VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
+  VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
+  VerifyLine("00-00 rwp 00 00:00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 0000:00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 00 00 :00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 00 00: 00 0\n", nullptr);
+  VerifyLine("00-00 rwxp 00 00:000\n", nullptr);
+  VerifyLine("00-00 rwxp 00 00:00 0/fake\n", nullptr);
+  VerifyLine("00-00 xxxx 00 00:00 0 /fake\n", nullptr);
+  VerifyLine("00-00 ywxp 00 00:00 0 /fake\n", nullptr);
+  VerifyLine("00-00 ryxp 00 00:00 0 /fake\n", nullptr);
+  VerifyLine("00-00 rwyp 00 00:00 0 /fake\n", nullptr);
+  VerifyLine("00-00 rwx- 00 00:00 0 /fake\n", nullptr);
+  VerifyLine("0\n", nullptr);
+  VerifyLine("00\n", nullptr);
+  VerifyLine("00-\n", nullptr);
+  VerifyLine("00-0\n", nullptr);
+  VerifyLine("00-00\n", nullptr);
+  VerifyLine("00-00 \n", nullptr);
+  VerifyLine("00-00 -\n", nullptr);
+  VerifyLine("00-00 r\n", nullptr);
+  VerifyLine("00-00 --\n", nullptr);
+  VerifyLine("00-00 rw\n", nullptr);
+  VerifyLine("00-00 ---\n", nullptr);
+  VerifyLine("00-00 rwx\n", nullptr);
+  VerifyLine("00-00 ---s\n", nullptr);
+  VerifyLine("00-00 ---p\n", nullptr);
+  VerifyLine("00-00 ---s 0\n", nullptr);
+  VerifyLine("00-00 ---p 0 \n", nullptr);
+  VerifyLine("00-00 ---p 0 0\n", nullptr);
+  VerifyLine("00-00 ---p 0 0:\n", nullptr);
+  VerifyLine("00-00 ---p 0 0:0\n", nullptr);
+  VerifyLine("00-00 ---p 0 0:0 \n", nullptr);
+
+  // Line to verify that the parser will detect a completely malformed line
+  // properly.
+  VerifyLine("7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n",
+             nullptr);
+}
+
+TEST(MapsTest, verify_large_values) {
+  MapInfo info;
+#if defined(__LP64__)
+  VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
+  EXPECT_EQ(0xfabcdef012345678UL, info.start);
+  EXPECT_EQ(0xf12345678abcdef8UL, info.end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+  EXPECT_EQ(0xf0b0d0f010305070UL, info.offset);
+#else
+  VerifyLine("f2345678-fabcdef8 rwxp f0305070 00:00 0\n", &info);
+  EXPECT_EQ(0xf2345678UL, info.start);
+  EXPECT_EQ(0xfabcdef8UL, info.end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+  EXPECT_EQ(0xf0305070UL, info.offset);
+#endif
+}
+
 TEST(MapsTest, parse_permissions) {
   BufferMaps maps(
-      "1000-2000 ---- 00000000 00:00 0\n"
-      "2000-3000 r--- 00000000 00:00 0\n"
-      "3000-4000 -w-- 00000000 00:00 0\n"
-      "4000-5000 --x- 00000000 00:00 0\n"
-      "5000-6000 rwx- 00000000 00:00 0\n");
+      "1000-2000 ---s 00000000 00:00 0\n"
+      "2000-3000 r--s 00000000 00:00 0\n"
+      "3000-4000 -w-s 00000000 00:00 0\n"
+      "4000-5000 --xp 00000000 00:00 0\n"
+      "5000-6000 rwxp 00000000 00:00 0\n");
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(5U, maps.Total());
@@ -70,28 +175,28 @@
 
 TEST(MapsTest, parse_name) {
   BufferMaps maps(
-      "720b29b000-720b29e000 rw-p 00000000 00:00 0\n"
-      "720b29e000-720b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
-      "720b29f000-720b2a0000 rw-p 00000000 00:00 0");
+      "7b29b000-7b29e000 rw-p 00000000 00:00 0\n"
+      "7b29e000-7b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+      "7b29f000-7b2a0000 rw-p 00000000 00:00 0");
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
   auto it = maps.begin();
   ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x720b29b000U, it->start);
-  ASSERT_EQ(0x720b29e000U, it->end);
+  ASSERT_EQ(0x7b29b000U, it->start);
+  ASSERT_EQ(0x7b29e000U, it->end);
   ASSERT_EQ(0U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
   ++it;
   ASSERT_EQ("/system/lib/fake.so", it->name);
-  ASSERT_EQ(0x720b29e000U, it->start);
-  ASSERT_EQ(0x720b29f000U, it->end);
+  ASSERT_EQ(0x7b29e000U, it->start);
+  ASSERT_EQ(0x7b29f000U, it->end);
   ASSERT_EQ(0U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
   ++it;
   ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x720b29f000U, it->start);
-  ASSERT_EQ(0x720b2a0000U, it->end);
+  ASSERT_EQ(0x7b29f000U, it->start);
+  ASSERT_EQ(0x7b2a0000U, it->end);
   ASSERT_EQ(0U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
   ++it;
@@ -149,9 +254,9 @@
   ASSERT_TRUE(tf.fd != -1);
 
   ASSERT_TRUE(
-      android::base::WriteStringToFile("720b29b000-720b29e000 r-xp a0000000 00:00 0   /fake.so\n"
-                                       "720b2b0000-720b2e0000 r-xp b0000000 00:00 0   /fake2.so\n"
-                                       "720b2e0000-720b2f0000 r-xp c0000000 00:00 0   /fake3.so\n",
+      android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0   /fake.so\n"
+                                       "7b2b0000-7b2e0000 r-xp b0000000 00:00 0   /fake2.so\n"
+                                       "7b2e0000-7b2f0000 r-xp c0000000 00:00 0   /fake3.so\n",
                                        tf.path, 0660, getuid(), getgid()));
 
   FileMaps maps(tf.path);
@@ -159,20 +264,20 @@
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
   auto it = maps.begin();
-  ASSERT_EQ(0x720b29b000U, it->start);
-  ASSERT_EQ(0x720b29e000U, it->end);
+  ASSERT_EQ(0x7b29b000U, it->start);
+  ASSERT_EQ(0x7b29e000U, it->end);
   ASSERT_EQ(0xa0000000U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
   ASSERT_EQ("/fake.so", it->name);
   ++it;
-  ASSERT_EQ(0x720b2b0000U, it->start);
-  ASSERT_EQ(0x720b2e0000U, it->end);
+  ASSERT_EQ(0x7b2b0000U, it->start);
+  ASSERT_EQ(0x7b2e0000U, it->end);
   ASSERT_EQ(0xb0000000U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
   ASSERT_EQ("/fake2.so", it->name);
   ++it;
-  ASSERT_EQ(0x720b2e0000U, it->start);
-  ASSERT_EQ(0x720b2f0000U, it->end);
+  ASSERT_EQ(0x7b2e0000U, it->start);
+  ASSERT_EQ(0x7b2f0000U, it->end);
   ASSERT_EQ(0xc0000000U, it->offset);
   ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
   ASSERT_EQ("/fake3.so", it->name);
@@ -180,6 +285,163 @@
   ASSERT_EQ(it, maps.end());
 }
 
+TEST(MapsTest, file_no_map_name) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0\n"
+                                       "7b2b0000-7b2e0000 r-xp b0000000 00:00 0   /fake2.so\n"
+                                       "7b2e0000-7b2f0000 r-xp c0000000 00:00 0 \n",
+                                       tf.path, 0660, getuid(), getgid()));
+
+  FileMaps maps(tf.path);
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(3U, maps.Total());
+  auto it = maps.begin();
+  ASSERT_EQ(0x7b29b000U, it->start);
+  ASSERT_EQ(0x7b29e000U, it->end);
+  ASSERT_EQ(0xa0000000U, it->offset);
+  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+  ASSERT_EQ("", it->name);
+  ++it;
+  ASSERT_EQ(0x7b2b0000U, it->start);
+  ASSERT_EQ(0x7b2e0000U, it->end);
+  ASSERT_EQ(0xb0000000U, it->offset);
+  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+  ASSERT_EQ("/fake2.so", it->name);
+  ++it;
+  ASSERT_EQ(0x7b2e0000U, it->start);
+  ASSERT_EQ(0x7b2f0000U, it->end);
+  ASSERT_EQ(0xc0000000U, it->offset);
+  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+  ASSERT_EQ("", it->name);
+  ++it;
+  ASSERT_EQ(it, maps.end());
+}
+
+// Verify that a file that crosses a buffer is parsed correctly.
+static std::string CreateEntry(size_t index) {
+  return android::base::StringPrintf("%08zx-%08zx rwxp 0000 00:00 0\n", index * 4096,
+                                     (index + 1) * 4096);
+}
+
+TEST(MapsTest, file_buffer_cross) {
+  constexpr size_t kBufferSize = 2048;
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  // Compute how many to add in the first buffer.
+  size_t entry_len = CreateEntry(0).size();
+  size_t index;
+  std::string file_data;
+  for (index = 0; index < kBufferSize / entry_len; index++) {
+    file_data += CreateEntry(index);
+  }
+  // Add a long name to make sure that the first buffer does not contain a
+  // complete line.
+  // Remove the last newline.
+  size_t extra = 0;
+  size_t leftover = kBufferSize % entry_len;
+  size_t overlap1_index = 0;
+  std::string overlap1_name;
+  if (leftover == 0) {
+    // Exact match, add a long name to cross over the value.
+    overlap1_name = "/fake/name/is/long/on/purpose";
+    file_data.erase(file_data.size() - 1);
+    file_data += ' ' + overlap1_name + '\n';
+    extra = entry_len + overlap1_name.size() + 1;
+    overlap1_index = index;
+  }
+
+  // Compute how many need to go in to hit the buffer boundary exactly.
+  size_t bytes_left_in_buffer = kBufferSize - extra;
+  size_t entries_to_add = bytes_left_in_buffer / entry_len + index;
+  for (; index < entries_to_add; index++) {
+    file_data += CreateEntry(index);
+  }
+
+  // Now figure out how many bytes to add to get exactly to the buffer boundary.
+  leftover = bytes_left_in_buffer % entry_len;
+  std::string overlap2_name;
+  size_t overlap2_index = 0;
+  if (leftover != 0) {
+    file_data.erase(file_data.size() - 1);
+    file_data += ' ';
+    overlap2_name = std::string(leftover - 1, 'x');
+    file_data += overlap2_name + '\n';
+    overlap2_index = index - 1;
+  }
+
+  // Now add a few entries on the next page.
+  for (size_t start = index; index < start + 10; index++) {
+    file_data += CreateEntry(index);
+  }
+
+  ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
+
+  FileMaps maps(tf.path);
+  ASSERT_TRUE(maps.Parse());
+  EXPECT_EQ(index, maps.Total());
+  // Verify all of the maps.
+  for (size_t i = 0; i < index; i++) {
+    MapInfo* info = maps.Get(i);
+    ASSERT_TRUE(info != nullptr) << "Failed verifying index " + std::to_string(i);
+    EXPECT_EQ(i * 4096, info->start) << "Failed verifying index " + std::to_string(i);
+    EXPECT_EQ((i + 1) * 4096, info->end) << "Failed verifying index " + std::to_string(i);
+    EXPECT_EQ(0U, info->offset) << "Failed verifying index " + std::to_string(i);
+    if (overlap1_index != 0 && i == overlap1_index) {
+      EXPECT_EQ(overlap1_name, info->name) << "Failed verifying overlap1 name " + std::to_string(i);
+    } else if (overlap2_index != 0 && i == overlap2_index) {
+      EXPECT_EQ(overlap2_name, info->name) << "Failed verifying overlap2 name " + std::to_string(i);
+    } else {
+      EXPECT_EQ("", info->name) << "Failed verifying index " + std::to_string(i);
+    }
+  }
+}
+
+TEST(MapsTest, file_should_fail) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+      "7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n", tf.path,
+      0660, getuid(), getgid()));
+
+  FileMaps maps(tf.path);
+
+  ASSERT_FALSE(maps.Parse());
+}
+
+// Create a maps file that is extremely large.
+TEST(MapsTest, large_file) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  std::string file_data;
+  uint64_t start = 0x700000;
+  for (size_t i = 0; i < 5000; i++) {
+    file_data +=
+        android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r-xp 1000 00:0 0 /fake%zu.so\n",
+                                    start + i * 4096, start + (i + 1) * 4096, i);
+  }
+
+  ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
+
+  FileMaps maps(tf.path);
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(5000U, maps.Total());
+  for (size_t i = 0; i < 5000; i++) {
+    MapInfo* info = maps.Get(i);
+    ASSERT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
+    ASSERT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
+    std::string name = "/fake" + std::to_string(i) + ".so";
+    ASSERT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
+  }
+}
+
 TEST(MapsTest, find) {
   BufferMaps maps(
       "1000-2000 r--p 00000010 00:00 0 /system/lib/fake1.so\n"
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 6d1366c..680fae9 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -31,10 +31,11 @@
 TEST(MemoryRangeTest, read) {
   std::vector<uint8_t> src(1024);
   memset(src.data(), 0x4c, 1024);
-  MemoryFake* memory = new MemoryFake;
-  memory->SetMemory(9001, src);
+  MemoryFake* memory_fake = new MemoryFake;
+  std::shared_ptr<Memory> process_memory(memory_fake);
+  memory_fake->SetMemory(9001, src);
 
-  MemoryRange range(memory, 9001, 9001 + src.size());
+  MemoryRange range(process_memory, 9001, 9001 + src.size());
 
   std::vector<uint8_t> dst(1024);
   ASSERT_TRUE(range.Read(0, dst.data(), src.size()));
@@ -46,10 +47,11 @@
 TEST(MemoryRangeTest, read_near_limit) {
   std::vector<uint8_t> src(4096);
   memset(src.data(), 0x4c, 4096);
-  MemoryFake* memory = new MemoryFake;
-  memory->SetMemory(1000, src);
+  MemoryFake* memory_fake = new MemoryFake;
+  std::shared_ptr<Memory> process_memory(memory_fake);
+  memory_fake->SetMemory(1000, src);
 
-  MemoryRange range(memory, 1000, 2024);
+  MemoryRange range(process_memory, 1000, 2024);
 
   std::vector<uint8_t> dst(1024);
   ASSERT_TRUE(range.Read(1020, dst.data(), 4));
@@ -69,7 +71,8 @@
 TEST(MemoryRangeTest, read_overflow) {
   std::vector<uint8_t> buffer(100);
 
-  std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200));
+  std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
+  std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200));
   ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
 }
 
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index f8965b2..a66d0c5 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -22,7 +22,6 @@
 #include <sys/mman.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
 
 #include <vector>
@@ -34,32 +33,18 @@
 #include <unwindstack/Memory.h>
 
 #include "MemoryFake.h"
+#include "TestUtils.h"
 
 namespace unwindstack {
 
 class MemoryRemoteTest : public ::testing::Test {
  protected:
-  static uint64_t NanoTime() {
-    struct timespec t = { 0, 0 };
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
-  }
-
   static bool Attach(pid_t pid) {
     if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
       return false;
     }
 
-    uint64_t start = NanoTime();
-    siginfo_t si;
-    while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
-      if ((NanoTime() - start) > 10 * NS_PER_SEC) {
-        printf("%d: Failed to stop after 10 seconds.\n", pid);
-        return false;
-      }
-      usleep(30);
-    }
-    return true;
+    return TestQuiescePid(pid);
   }
 
   static bool Detach(pid_t pid) {
@@ -79,6 +64,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -91,9 +77,6 @@
   }
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_fail) {
@@ -111,6 +94,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -132,9 +116,6 @@
   ASSERT_EQ(0, munmap(src, pagesize));
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_overflow) {
@@ -152,6 +133,7 @@
     exit(1);
   }
   ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
 
   ASSERT_TRUE(Attach(pid));
 
@@ -162,9 +144,6 @@
   ASSERT_FALSE(remote.Read(0, dst.data(), 100));
 
   ASSERT_TRUE(Detach(pid));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 6669d7d..c76ecaa 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -31,6 +31,8 @@
       : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsFake() = default;
 
+  uint32_t MachineType() override { return 0; }
+
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
   void SetFromRaw() override {}
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index e6de56a..f549a50 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -58,6 +58,8 @@
       : RegsImpl<TypeParam>(total_regs, regs_sp, return_loc) {}
   virtual ~RegsTestImpl() = default;
 
+  uint32_t MachineType() override { return 0; }
+
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
   void SetFromRaw() override {}
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
new file mode 100644
index 0000000..8c31aa6
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.h
@@ -0,0 +1,55 @@
+/*
+ * 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_TESTS_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+namespace unwindstack {
+
+class TestScopedPidReaper {
+ public:
+  TestScopedPidReaper(pid_t pid) : pid_(pid) {}
+  ~TestScopedPidReaper() {
+    kill(pid_, SIGKILL);
+    waitpid(pid_, nullptr, 0);
+  }
+
+ private:
+  pid_t pid_;
+};
+
+inline bool TestQuiescePid(pid_t pid) {
+  siginfo_t si;
+  bool ready = false;
+  // Wait for up to 5 seconds.
+  for (size_t i = 0; i < 5000; i++) {
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+      ready = true;
+      break;
+    }
+    usleep(1000);
+  }
+  return ready;
+}
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 3c69e2a..a4f920a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -15,10 +15,9 @@
  */
 
 #include <errno.h>
-#include <string.h>
-
 #include <signal.h>
 #include <stdint.h>
+#include <string.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 #include <unistd.h>
@@ -39,14 +38,24 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 
+#include "TestUtils.h"
+
 namespace unwindstack {
 
-static std::atomic_bool g_ready(false);
-static volatile bool g_ready_for_remote = false;
-static volatile bool g_signal_ready_for_remote = false;
-static std::atomic_bool g_finish(false);
+static std::atomic_bool g_ready;
+static volatile bool g_ready_for_remote;
+static volatile bool g_signal_ready_for_remote;
+static std::atomic_bool g_finish;
 static std::atomic_uintptr_t g_ucontext;
 
+static void ResetGlobals() {
+  g_ready = false;
+  g_ready_for_remote = false;
+  g_signal_ready_for_remote = false;
+  g_finish = false;
+  g_ucontext = 0;
+}
+
 static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
 
 static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
@@ -85,10 +94,11 @@
          function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
 }
 
-static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
+static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs,
                          std::vector<const char*>& function_names) {
   size_t function_name_index = 0;
 
+  auto process_memory = Memory::CreateProcessMemory(pid);
   std::stringstream unwind_stream;
   unwind_stream << std::hex;
   for (size_t frame_num = 0; frame_num < 64; frame_num++) {
@@ -96,7 +106,7 @@
     MapInfo* map_info = maps->Find(regs->pc());
     ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
 
-    Elf* elf = map_info->GetElf(pid, true);
+    Elf* elf = map_info->GetElf(process_memory, true);
     uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
     uint64_t adjusted_rel_pc = rel_pc;
     if (frame_num != 0) {
@@ -122,7 +132,7 @@
       unwind_stream << " " << name;
     }
     unwind_stream << "\n";
-    ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory))
+    ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get()))
         << ErrorMsg(function_names, function_name_index, unwind_stream);
   }
   ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream);
@@ -137,9 +147,8 @@
     ASSERT_TRUE(maps.Parse());
     std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
     RegsGetLocal(regs.get());
-    MemoryLocal memory;
 
-    VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
+    VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
   } else {
     g_ready_for_remote = true;
     g_ready = true;
@@ -156,48 +165,52 @@
   MiddleFunction(local);
 }
 
-TEST(UnwindTest, local) {
+class UnwindTest : public ::testing::Test {
+ public:
+  void SetUp() override { ResetGlobals(); }
+};
+
+TEST_F(UnwindTest, local) {
   OuterFunction(true);
 }
 
 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
   *completed = false;
   // Need to sleep before attempting first ptrace. Without this, on the
-  // host it becomes impossible to attach and ptrace set errno to EPERM.
+  // host it becomes impossible to attach and ptrace sets errno to EPERM.
   usleep(1000);
-  for (size_t i = 0; i < 100; i++) {
-    ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
-    for (size_t j = 0; j < 100; j++) {
-      siginfo_t si;
-      if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
-        MemoryRemote memory(pid);
-        // Read the remote value to see if we are ready.
-        bool value;
-        if (memory.Read(addr, &value, sizeof(value)) && value) {
-          *completed = true;
-          break;
-        }
+  for (size_t i = 0; i < 1000; i++) {
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+      ASSERT_TRUE(TestQuiescePid(pid))
+          << "Waiting for process to quiesce failed: " << strerror(errno);
+
+      MemoryRemote memory(pid);
+      // Read the remote value to see if we are ready.
+      bool value;
+      if (memory.Read(addr, &value, sizeof(value)) && value) {
+        *completed = true;
       }
-      usleep(1000);
+      if (!*completed || !leave_attached) {
+        ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+      }
+      if (*completed) {
+        break;
+      }
+    } else {
+      ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno);
     }
-    if (leave_attached && *completed) {
-      break;
-    }
-    ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-    if (*completed) {
-      break;
-    }
-    usleep(1000);
+    usleep(5000);
   }
 }
 
-TEST(UnwindTest, remote) {
+TEST_F(UnwindTest, remote) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     OuterFunction(false);
     exit(0);
   }
   ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
 
   bool completed;
   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
@@ -205,20 +218,16 @@
 
   RemoteMaps maps(pid);
   ASSERT_TRUE(maps.Parse());
-  MemoryRemote memory(pid);
-  uint32_t machine_type;
-  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
   ASSERT_TRUE(regs.get() != nullptr);
 
-  VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
+  VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
 
-  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
-TEST(UnwindTest, from_context) {
+TEST_F(UnwindTest, from_context) {
   std::atomic_int tid(0);
   std::thread thread([&]() {
     tid = syscall(__NR_gettid);
@@ -254,10 +263,9 @@
 
   LocalMaps maps;
   ASSERT_TRUE(maps.Parse());
-  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::GetMachineType(), ucontext));
-  MemoryLocal memory;
+  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
 
-  VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
+  VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
 
   ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
 
@@ -266,10 +274,6 @@
 }
 
 static void RemoteThroughSignal(unsigned int sa_flags) {
-  g_ready = false;
-  g_signal_ready_for_remote = false;
-  g_finish = false;
-
   pid_t pid;
   if ((pid = fork()) == 0) {
     struct sigaction act, oldact;
@@ -282,6 +286,7 @@
     exit(0);
   }
   ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
 
   bool completed;
   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
@@ -292,24 +297,20 @@
 
   RemoteMaps maps(pid);
   ASSERT_TRUE(maps.Parse());
-  MemoryRemote memory(pid);
-  uint32_t machine_type;
-  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
   ASSERT_TRUE(regs.get() != nullptr);
 
-  VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
+  VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
 
-  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
-  kill(pid, SIGKILL);
-  ASSERT_EQ(pid, wait(nullptr));
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
-TEST(UnwindTest, remote_through_signal) {
+TEST_F(UnwindTest, remote_through_signal) {
   RemoteThroughSignal(0);
 }
 
-TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+TEST_F(UnwindTest, remote_through_signal_sa_siginfo) {
   RemoteThroughSignal(SA_SIGINFO);
 }
 
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 642105a..3614198 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -62,8 +62,7 @@
     return;
   }
 
-  uint32_t machine_type;
-  unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid, &machine_type);
+  unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
   if (regs == nullptr) {
     printf("Unable to get remote reg data\n");
     return;
@@ -71,7 +70,7 @@
 
   bool bits32 = true;
   printf("ABI: ");
-  switch (machine_type) {
+  switch (regs->MachineType()) {
     case EM_ARM:
       printf("arm");
       break;
@@ -92,7 +91,7 @@
   }
   printf("\n");
 
-  unwindstack::MemoryRemote remote_memory(pid);
+  auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
   for (size_t frame_num = 0; frame_num < 64; frame_num++) {
     if (regs->pc() == 0) {
       break;
@@ -103,7 +102,7 @@
       break;
     }
 
-    unwindstack::Elf* elf = map_info->GetElf(pid, true);
+    unwindstack::Elf* elf = map_info->GetElf(process_memory, true);
 
     uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
     uint64_t adjusted_rel_pc = rel_pc;
@@ -136,7 +135,7 @@
     }
     printf("\n");
 
-    if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) {
+    if (!elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) {
       break;
     }
   }
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index b757c1e..dc9ae5a 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -28,8 +28,11 @@
 #include <unwindstack/Memory.h>
 
 int main(int argc, char** argv) {
-  if (argc != 2) {
-    printf("Need to pass the name of an elf file to the program.\n");
+  if (argc != 2 && argc != 3) {
+    printf("Usage: unwind_symbols <ELF_FILE> [<FUNC_ADDRESS>]\n");
+    printf("  Dump all function symbols in ELF_FILE. If FUNC_ADDRESS is\n");
+    printf("  specified, then get the function at that address.\n");
+    printf("  FUNC_ADDRESS must be a hex number.\n");
     return 1;
   }
 
@@ -43,6 +46,16 @@
     return 1;
   }
 
+  uint64_t func_addr;
+  if (argc == 3) {
+    char* name;
+    func_addr = strtoull(argv[2], &name, 16);
+    if (*name != '\0') {
+      printf("%s is not a hex number.\n", argv[2]);
+      return 1;
+    }
+  }
+
   // Send all log messages to stdout.
   unwindstack::log_to_stdout(true);
 
@@ -76,9 +89,24 @@
       return 1;
   }
 
-  // This is a crude way to get the symbols in order.
   std::string name;
   uint64_t load_bias = elf.interface()->load_bias();
+  if (argc == 3) {
+    std::string cur_name;
+    uint64_t func_offset;
+    if (!elf.GetFunctionName(func_addr, &cur_name, &func_offset)) {
+      printf("No known function at 0x%" PRIx64 "\n", func_addr);
+      return 1;
+    }
+    printf("<0x%" PRIx64 ">", func_addr - func_offset);
+    if (func_offset != 0) {
+      printf("+%" PRId64, func_offset);
+    }
+    printf(": %s\n", cur_name.c_str());
+    return 0;
+  }
+
+  // This is a crude way to get the symbols in order.
   for (const auto& entry : elf.interface()->pt_loads()) {
     uint64_t start = entry.second.offset + load_bias;
     uint64_t end = entry.second.table_size + load_bias;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index a779a8c..6e9bddf 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -149,8 +149,6 @@
             enabled: true,
         },
     },
-
-    clang: true,
 }
 
 // Include subdirectory makefiles
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index d106185..af6076c 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -28,6 +28,53 @@
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 
+// Enable thread safety attributes only with clang.
+// The attributes can be safely erased when compiling with other compilers.
+#if defined(__clang__) && (!defined(SWIG))
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+    THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -44,24 +91,24 @@
  * The mutex must be unlocked by the thread that locked it.  They are not
  * recursive, i.e. the same thread can't lock it multiple times.
  */
-class Mutex {
-public:
+class CAPABILITY("mutex") Mutex {
+  public:
     enum {
         PRIVATE = 0,
         SHARED = 1
     };
 
-                Mutex();
-    explicit    Mutex(const char* name);
-    explicit    Mutex(int type, const char* name = NULL);
-                ~Mutex();
+    Mutex();
+    explicit Mutex(const char* name);
+    explicit Mutex(int type, const char* name = NULL);
+    ~Mutex();
 
     // lock or unlock the mutex
-    status_t    lock();
-    void        unlock();
+    status_t lock() ACQUIRE();
+    void unlock() RELEASE();
 
     // lock if possible; returns 0 on success, error otherwise
-    status_t    tryLock();
+    status_t tryLock() TRY_ACQUIRE(true);
 
 #if defined(__ANDROID__)
     // Lock the mutex, but don't wait longer than timeoutNs (relative time).
@@ -75,32 +122,36 @@
     // which is subject to NTP adjustments, and includes time during suspend,
     // so a timeout may occur even though no processes could run.
     // Not holding a partial wakelock may lead to a system suspend.
-    status_t    timedLock(nsecs_t timeoutNs);
+    status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(true);
 #endif
 
     // Manages the mutex automatically. It'll be locked when Autolock is
     // constructed and released when Autolock goes out of scope.
-    class Autolock {
-    public:
-        inline explicit Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
-        inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
-        inline ~Autolock() { mLock.unlock(); }
-    private:
+    class SCOPED_CAPABILITY Autolock {
+      public:
+        inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex) { mLock.lock(); }
+        inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex) { mLock.lock(); }
+        inline ~Autolock() RELEASE() { mLock.unlock(); }
+
+      private:
         Mutex& mLock;
+        // Cannot be copied or moved - declarations only
+        Autolock(const Autolock&);
+        Autolock& operator=(const Autolock&);
     };
 
-private:
+  private:
     friend class Condition;
 
     // A mutex cannot be copied
-                Mutex(const Mutex&);
-    Mutex&      operator = (const Mutex&);
+    Mutex(const Mutex&);
+    Mutex& operator=(const Mutex&);
 
 #if !defined(_WIN32)
     pthread_mutex_t mMutex;
 #else
-    void    _init();
-    void*   mState;
+    void _init();
+    void* mState;
 #endif
 };
 
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index bdb2332..9afedd4 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -85,7 +85,7 @@
 #define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)                 \
     template<> ::android::Mutex  \
         (::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE);  \
-    template<> TYPE* ::android::Singleton< TYPE >::sInstance(0);  \
+    template<> TYPE* ::android::Singleton< TYPE >::sInstance(0);  /* NOLINT */ \
     template class ::android::Singleton< TYPE >;
 
 
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index f6433a8..cb3d338 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -67,7 +67,6 @@
 
     inline  const char16_t*     string() const;
 
-//TODO(b/35363681): remove
 private:
     static inline std::string   std_string(const String16& str);
 public:
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index f5f9219..1f3e5d8 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -67,7 +67,6 @@
     inline  const char*         c_str() const;
     inline  const char*         string() const;
 
-// TODO(b/35363681): remove
 private:
     static inline std::string   std_string(const String8& str);
 public:
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 7b62c24..0869175 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -23,6 +23,7 @@
     srcs: [
         "BitSet_test.cpp",
         "LruCache_test.cpp",
+        "Mutex_test.cpp",
         "Singleton_test.cpp",
         "String8_test.cpp",
         "StrongPointer_test.cpp",
@@ -71,6 +72,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wthread-safety",
     ],
 }
 
diff --git a/init/signal_handler.h b/libutils/tests/Mutex_test.cpp
similarity index 62%
copy from init/signal_handler.h
copy to libutils/tests/Mutex_test.cpp
index f7881ab..8a1805f 100644
--- a/init/signal_handler.h
+++ b/libutils/tests/Mutex_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,15 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#include <utils/Mutex.h>
 
-namespace android {
-namespace init {
+#include <gtest/gtest.h>
 
-void signal_handler_init(void);
+static android::Mutex mLock;
+static int i GUARDED_BY(mLock);
 
-}  // namespace init
-}  // namespace android
+void modifyLockedVariable() REQUIRES(mLock) {
+    i = 1;
+}
 
-#endif
+TEST(Mutex, compile) {
+    android::Mutex::Autolock _l(mLock);
+    i = 0;
+    modifyLockedVariable();
+}
\ No newline at end of file
diff --git a/libziparchive/include/ziparchive/zip_archive_stream_entry.h b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
index a40b799..b4766f8 100644
--- a/libziparchive/include/ziparchive/zip_archive_stream_entry.h
+++ b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
@@ -40,7 +40,8 @@
 
   ZipArchiveHandle handle_;
 
-  uint32_t crc32_;
+  off64_t offset_ = 0;
+  uint32_t crc32_ = 0u;
 };
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 4559b32..1be4061 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -451,13 +451,20 @@
 
 static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
-  if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
+  off64_t offset = entry->offset;
+  if (entry->method != kCompressStored) {
+    offset += entry->compressed_length;
+  } else {
+    offset += entry->uncompressed_length;
+  }
+
+  if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) {
     return kIoError;
   }
 
   const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
-  const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
-  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
+  const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset);
 
   // Validate that the values in the data descriptor match those in the central
   // directory.
@@ -915,7 +922,9 @@
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
+      off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+      // Make sure to read at offset to ensure concurrent access to the fd.
+      if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
         ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
         return kIoError;
       }
@@ -978,12 +987,15 @@
   uint64_t crc = 0;
   while (count < length) {
     uint32_t remaining = length - count;
+    off64_t offset = entry->offset + count;
 
-    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
-    // value.
+    // Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
     const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
-    if (!mapped_zip.ReadData(buf.data(), block_size)) {
-      ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
+
+    // Make sure to read at offset to ensure concurrent access to the fd.
+    if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
+      ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s",
+            block_size, static_cast<int64_t>(offset), strerror(errno));
       return kIoError;
     }
 
@@ -1002,12 +1014,6 @@
 int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
-  off64_t data_offset = entry->offset;
-
-  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
-    ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
-    return kIoError;
-  }
 
   // this should default to kUnknownCompressionMethod.
   int32_t return_value = -1;
@@ -1127,52 +1133,21 @@
   }
 }
 
-bool MappedZipFile::SeekToOffset(off64_t offset) {
-  if (has_fd_) {
-    if (lseek64(fd_, offset, SEEK_SET) != offset) {
-      ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
-      return false;
-    }
-    return true;
-  } else {
-    if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
-      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_);
-      return false;
-    }
-
-    read_pos_ = offset;
-    return true;
-  }
-}
-
-bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
-  if (has_fd_) {
-    if (!android::base::ReadFully(fd_, buffer, read_amount)) {
-      ALOGE("Zip: read from %d failed\n", fd_);
-      return false;
-    }
-  } else {
-    memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
-    read_pos_ += read_amount;
-  }
-  return true;
-}
-
 // Attempts to read |len| bytes into |buf| at offset |off|.
 bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
-#if !defined(_WIN32)
   if (has_fd_) {
-    if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+    if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
       ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
       return false;
     }
-    return true;
+  } else {
+    if (off < 0 || off > static_cast<off64_t>(data_length_)) {
+      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_);
+      return false;
+    }
+    memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len);
   }
-#endif
-  if (!SeekToOffset(off)) {
-    return false;
-  }
-  return ReadData(buf, len);
+  return true;
 }
 
 void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 840f1af..174aa3f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -93,14 +93,10 @@
 class MappedZipFile {
  public:
   explicit MappedZipFile(const int fd)
-      : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {}
+      : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
 
   explicit MappedZipFile(void* address, size_t length)
-      : has_fd_(false),
-        fd_(-1),
-        base_ptr_(address),
-        data_length_(static_cast<off64_t>(length)),
-        read_pos_(0) {}
+      : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
 
   bool HasFd() const { return has_fd_; }
 
@@ -110,10 +106,6 @@
 
   off64_t GetFileLength() const;
 
-  bool SeekToOffset(off64_t offset);
-
-  bool ReadData(uint8_t* buffer, size_t read_amount);
-
   bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
 
  private:
@@ -127,8 +119,6 @@
 
   void* const base_ptr_;
   const off64_t data_length_;
-  // read_pos_ is the offset to the base_ptr_ where we read data from.
-  size_t read_pos_;
 };
 
 class CentralDirectory {
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 50352ef..9ec89b1 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -38,13 +38,8 @@
 static constexpr size_t kBufSize = 65535;
 
 bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
-  off64_t data_offset = entry.offset;
-  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
-    ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
-    return false;
-  }
   crc32_ = entry.crc32;
+  offset_ = entry.offset;
   return true;
 }
 
@@ -61,11 +56,11 @@
  protected:
   bool Init(const ZipEntry& entry) override;
 
-  uint32_t length_;
+  uint32_t length_ = 0u;
 
  private:
   std::vector<uint8_t> data_;
-  uint32_t computed_crc32_;
+  uint32_t computed_crc32_ = 0u;
 };
 
 bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
@@ -89,7 +84,7 @@
   size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   errno = 0;
-  if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
+  if (!archive->mapped_zip.ReadAtOffset(data_.data(), bytes, offset_)) {
     if (errno != 0) {
       ALOGE("Error reading from archive fd: %s", strerror(errno));
     } else {
@@ -104,6 +99,7 @@
   }
   computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
   length_ -= bytes;
+  offset_ += bytes;
   return &data_;
 }
 
@@ -129,9 +125,9 @@
   z_stream z_stream_;
   std::vector<uint8_t> in_;
   std::vector<uint8_t> out_;
-  uint32_t uncompressed_length_;
-  uint32_t compressed_length_;
-  uint32_t computed_crc32_;
+  uint32_t uncompressed_length_ = 0u;
+  uint32_t compressed_length_ = 0u;
+  uint32_t computed_crc32_ = 0u;
 };
 
 // This method is using libz macros with old-style-casts
@@ -210,7 +206,7 @@
       size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
       ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
       errno = 0;
-      if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
+      if (!archive->mapped_zip.ReadAtOffset(in_.data(), bytes, offset_)) {
         if (errno != 0) {
           ALOGE("Error reading from archive fd: %s", strerror(errno));
         } else {
@@ -220,6 +216,7 @@
       }
 
       compressed_length_ -= bytes;
+      offset_ += bytes;
       z_stream_.next_in = in_.data();
       z_stream_.avail_in = bytes;
     }
diff --git a/logcat/Android.bp b/logcat/Android.bp
new file mode 100644
index 0000000..729c8ff
--- /dev/null
+++ b/logcat/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2006-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.
+//
+
+cc_defaults {
+    name: "logcat_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libpcrecpp",
+    ],
+    logtags: ["event.logtags"],
+}
+
+cc_library {
+    name: "liblogcat",
+
+    defaults: ["logcat_defaults"],
+    srcs: [
+        "logcat.cpp",
+        "getopt_long.cpp",
+        "logcat_system.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_binary {
+    name: "logcat",
+
+    defaults: ["logcat_defaults"],
+    shared_libs: ["liblogcat"],
+    srcs: [
+        "logcat_main.cpp",
+    ],
+}
+
+cc_binary {
+    name: "logcatd",
+
+    defaults: ["logcat_defaults"],
+    shared_libs: ["liblogcat"],
+    srcs: [
+        "logcatd_main.cpp",
+    ],
+}
+
+cc_prebuilt_binary {
+    name: "logpersist.start",
+    srcs: ["logpersist"],
+    init_rc: ["logcatd.rc"],
+    symlinks: ["logpersist.stop", "logpersist.cat"],
+    strip: {
+        none: true,
+    }
+}
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 4e11ca9..a716993 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -2,48 +2,4 @@
 
 LOCAL_PATH := $(call my-dir)
 
-logcatLibs := liblog libbase libcutils libpcrecpp
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logcat
-LOCAL_SRC_FILES := logcat_main.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblogcat $(logcatLibs)
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logcatd
-LOCAL_MODULE_TAGS := debug
-LOCAL_SRC_FILES := logcatd_main.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblogcat $(logcatLibs)
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := liblogcat
-LOCAL_SRC_FILES := logcat.cpp getopt_long.cpp logcat_system.cpp
-LOCAL_SHARED_LIBRARIES := $(logcatLibs)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logpersist.start
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_INIT_RC := logcatd.rc
-LOCAL_MODULE_PATH := $(bin_dir)
-LOCAL_SRC_FILES := logpersist
-ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
-LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
-include $(BUILD_PREBUILT)
-
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f64196f..3d56472 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1019,7 +1019,6 @@
                 break;
 
             case 'm': {
-                char* end = nullptr;
                 if (!getSizeTArg(optctx.optarg, &context->maxCount)) {
                     logcat_panic(context, HELP_FALSE,
                                  "-%c \"%s\" isn't an "
@@ -1182,7 +1181,6 @@
                 std::unique_ptr<char, void (*)(void*)> formats(
                     strdup(optctx.optarg), free);
                 char* arg = formats.get();
-                unsigned idMask = 0;
                 char* sv = nullptr;  // protect against -ENOMEM above
                 while (!!(arg = strtok_r(arg, delimiters, &sv))) {
                     err = setLogFormat(context, arg);
@@ -1256,7 +1254,7 @@
                         // example: "qemu_pipe,pipe:logcat"
                         // upon opening of /dev/qemu_pipe, the "pipe:logcat"
                         // string with trailing '\0' should be written to the fd
-                        size_t pos = devname.find(",");
+                        size_t pos = devname.find(',');
                         if (pos != std::string::npos) {
                             pipePurpose = devname.substr(pos + 1);
                             devname = devname.substr(0, pos);
@@ -1733,7 +1731,7 @@
     pthread_attr_setschedparam(&attr, &param);
     pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
     if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
-        int save_errno = errno;
+        save_errno = errno;
         goto pthread_attr_exit;
     }
 
@@ -1773,7 +1771,7 @@
     context->retval = EXIT_SUCCESS;
     if (pthread_create(&context->thr, &attr,
                        (void*(*)(void*))__logcat, context)) {
-        int save_errno = errno;
+        save_errno = errno;
         goto argv_exit;
     }
     pthread_attr_destroy(&attr);
diff --git a/logcat/tests/liblogcat_test.cpp b/logcat/tests/liblogcat_test.cpp
index 9e9a2c2..c8a00da 100644
--- a/logcat/tests/liblogcat_test.cpp
+++ b/logcat/tests/liblogcat_test.cpp
@@ -17,8 +17,8 @@
 #include <log/logcat.h>
 
 #define logcat_define(context) android_logcat_context context
-#define logcat_popen(context, command) android_logcat_popen(&context, command)
-#define logcat_pclose(context, fp) android_logcat_pclose(&context, fp)
+#define logcat_popen(context, command) android_logcat_popen(&(context), command)
+#define logcat_pclose(context, fp) android_logcat_pclose(&(context), fp)
 #define logcat_system(command) android_logcat_system(command)
 #define logcat liblogcat
 
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ee38d1c..cfcbaa5 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,7 +25,11 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <fstream>
+#include <sstream>
+
 #include <android-base/macros.h>
+#include <log/log_properties.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -138,6 +142,71 @@
     return true;
 }
 
+static inline bool hasMetadata(char* str, int str_len) {
+    // need to check and see if str already contains bug metadata from
+    // possibility of stuttering if log audit crashes and then reloads kernel
+    // messages. Kernel denials that contain metadata will either end in
+    // "b/[0-9]+$" or "b/[0-9]+  duplicate messages suppressed$" which will put
+    // a '/' character at either 9 or 39 indices away from the end of the str.
+    return str_len >= 39 &&
+           (str[str_len - 9] == '/' || str[str_len - 39] == '/');
+}
+
+std::map<std::string, std::string> LogAudit::populateDenialMap() {
+    std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
+    std::string line;
+    // allocate a map for the static map pointer in logParse to keep track of,
+    // this function only runs once
+    std::map<std::string, std::string> denial_to_bug;
+    if (bug_file.good()) {
+        std::string scontext;
+        std::string tcontext;
+        std::string tclass;
+        std::string bug_num;
+        while (std::getline(bug_file, line)) {
+            std::stringstream split_line(line);
+            split_line >> scontext >> tcontext >> tclass >> bug_num;
+            denial_to_bug.emplace(scontext + tcontext + tclass, bug_num);
+        }
+    }
+    return denial_to_bug;
+}
+
+std::string LogAudit::denialParse(const std::string& denial, char terminator,
+                                  const std::string& search_term) {
+    size_t start_index = denial.find(search_term);
+    if (start_index != std::string::npos) {
+        start_index += search_term.length();
+        return denial.substr(
+            start_index, denial.find(terminator, start_index) - start_index);
+    }
+    return "";
+}
+
+void LogAudit::logParse(const std::string& string, std::string* bug_num) {
+    if (!__android_log_is_debuggable()) {
+        bug_num->assign("");
+        return;
+    }
+    static std::map<std::string, std::string> denial_to_bug =
+        populateDenialMap();
+    std::string scontext = denialParse(string, ':', "scontext=u:object_r:");
+    std::string tcontext = denialParse(string, ':', "tcontext=u:object_r:");
+    std::string tclass = denialParse(string, ' ', "tclass=");
+    if (scontext.empty()) {
+        scontext = denialParse(string, ':', "scontext=u:r:");
+    }
+    if (tcontext.empty()) {
+        tcontext = denialParse(string, ':', "tcontext=u:r:");
+    }
+    auto search = denial_to_bug.find(scontext + tcontext + tclass);
+    if (search != denial_to_bug.end()) {
+        bug_num->assign(" b/" + search->second);
+    } else {
+        bug_num->assign("");
+    }
+}
+
 int LogAudit::logPrint(const char* fmt, ...) {
     if (fmt == NULL) {
         return -EINVAL;
@@ -153,7 +222,6 @@
     if (rc < 0) {
         return rc;
     }
-
     char* cp;
     // Work around kernels missing
     // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
@@ -165,10 +233,10 @@
     while ((cp = strstr(str, "  "))) {
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
-
     bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
+    static std::string bug_metadata;
     if ((fdDmesg >= 0) && initialized) {
-        struct iovec iov[3];
+        struct iovec iov[4];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
         static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
         static const char newline[] = "\n";
@@ -197,19 +265,20 @@
             }
             if (!skip) {
                 static const char resume[] = " duplicate messages suppressed\n";
-
                 iov[0].iov_base = last_info ? const_cast<char*>(log_info)
                                             : const_cast<char*>(log_warning);
                 iov[0].iov_len =
                     last_info ? sizeof(log_info) : sizeof(log_warning);
                 iov[1].iov_base = last_str;
                 iov[1].iov_len = strlen(last_str);
+                iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
+                iov[2].iov_len = bug_metadata.length();
                 if (count > 1) {
-                    iov[2].iov_base = const_cast<char*>(resume);
-                    iov[2].iov_len = strlen(resume);
+                    iov[3].iov_base = const_cast<char*>(resume);
+                    iov[3].iov_len = strlen(resume);
                 } else {
-                    iov[2].iov_base = const_cast<char*>(newline);
-                    iov[2].iov_len = strlen(newline);
+                    iov[3].iov_base = const_cast<char*>(newline);
+                    iov[3].iov_len = strlen(newline);
                 }
 
                 writev(fdDmesg, iov, arraysize(iov));
@@ -223,13 +292,16 @@
             last_info = info;
         }
         if (count == 0) {
+            logParse(str, &bug_metadata);
             iov[0].iov_base = info ? const_cast<char*>(log_info)
                                    : const_cast<char*>(log_warning);
             iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
             iov[1].iov_base = str;
             iov[1].iov_len = strlen(str);
-            iov[2].iov_base = const_cast<char*>(newline);
-            iov[2].iov_len = strlen(newline);
+            iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
+            iov[2].iov_len = bug_metadata.length();
+            iov[3].iov_base = const_cast<char*>(newline);
+            iov[3].iov_len = strlen(newline);
 
             writev(fdDmesg, iov, arraysize(iov));
         }
@@ -285,24 +357,32 @@
 
     // log to events
 
-    size_t l = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
-    size_t n = l + sizeof(android_log_event_string_t);
+    size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
+    if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
+        logParse(str, &bug_metadata);
+    str_len = (str_len + bug_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
+                  ? str_len + bug_metadata.length()
+                  : LOGGER_ENTRY_MAX_PAYLOAD;
+    size_t message_len = str_len + sizeof(android_log_event_string_t);
 
     bool notify = false;
 
     if (events) {  // begin scope for event buffer
-        uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
+        uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
 
         android_log_event_string_t* event =
             reinterpret_cast<android_log_event_string_t*>(buffer);
         event->header.tag = htole32(AUDITD_LOG_TAG);
         event->type = EVENT_TYPE_STRING;
-        event->length = htole32(l);
-        memcpy(event->data, str, l);
+        event->length = htole32(message_len);
+        memcpy(event->data, str, str_len - bug_metadata.length());
+        memcpy(event->data + str_len - bug_metadata.length(),
+               bug_metadata.c_str(), bug_metadata.length());
 
-        rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
-                         reinterpret_cast<char*>(event),
-                         (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
+        rc = logbuf->log(
+            LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
+            (message_len <= USHRT_MAX) ? (unsigned short)message_len
+                                       : USHRT_MAX);
         if (rc >= 0) {
             notify = true;
         }
@@ -333,28 +413,31 @@
     const char* ecomm = strchr(comm, '"');
     if (ecomm) {
         ++ecomm;
-        l = ecomm - comm;
+        str_len = ecomm - comm;
     } else {
-        l = strlen(comm) + 1;
+        str_len = strlen(comm) + 1;
         ecomm = "";
     }
-    size_t b = estr - str;
-    if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
-        b = LOGGER_ENTRY_MAX_PAYLOAD;
+    size_t prefix_len = estr - str;
+    if (prefix_len > LOGGER_ENTRY_MAX_PAYLOAD) {
+        prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
     }
-    size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
-    n = b + e + l + 2;
+    size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
+    message_len = str_len + prefix_len + suffix_len + bug_metadata.length() + 2;
 
     if (main) {  // begin scope for main buffer
-        char newstr[n];
+        char newstr[message_len];
 
         *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
-        strlcpy(newstr + 1, comm, l);
-        strncpy(newstr + 1 + l, str, b);
-        strncpy(newstr + 1 + l + b, ecomm, e);
+        strlcpy(newstr + 1, comm, str_len);
+        strncpy(newstr + 1 + str_len, str, prefix_len);
+        strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
+        strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
+                bug_metadata.c_str(), bug_metadata.length());
 
         rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
-                         (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
+                         (message_len <= USHRT_MAX) ? (unsigned short)message_len
+                                                    : USHRT_MAX);
 
         if (rc >= 0) {
             notify = true;
@@ -368,7 +451,7 @@
     if (notify) {
         reader->notifyNewLog();
         if (rc < 0) {
-            rc = n;
+            rc = message_len;
         }
     }
 
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 5947819..2bd02d4 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -17,6 +17,7 @@
 #ifndef _LOGD_LOG_AUDIT_H__
 #define _LOGD_LOG_AUDIT_H__
 
+#include <map>
 #include <queue>
 
 #include <sysutils/SocketListener.h>
@@ -50,6 +51,10 @@
 
    private:
     static int getLogSocket();
+    std::map<std::string, std::string> populateDenialMap();
+    std::string denialParse(const std::string& denial, char terminator,
+                            const std::string& search_term);
+    void logParse(const std::string& string, std::string* bug_num);
     int logPrint(const char* fmt, ...)
         __attribute__((__format__(__printf__, 2, 3)));
 };
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 4397b14..8ee5ea1 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -646,16 +646,20 @@
                 recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
         }
 
-        alarm_timeout =
-            alarm((old_alarm <= 0) ? old_alarm
-                                   : (old_alarm > (1 + 3 - alarm_wrap))
-                                         ? old_alarm - 3 + alarm_wrap
-                                         : 2);
+        if (old_alarm > 0) {
+            unsigned int time_spent = 3 - alarm_wrap;
+            if (old_alarm > time_spent + 1) {
+                old_alarm -= time_spent;
+            } else {
+                old_alarm = 2;
+            }
+        }
+        alarm_timeout = alarm(old_alarm);
         sigaction(SIGALRM, &old_sigaction, nullptr);
 
         close(fd);
 
-        if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
+        if (content_wrap && alarm_wrap && content_timeout && alarm_timeout) {
             break;
         }
     }
@@ -710,8 +714,8 @@
     // A few tries to get it right just in case wrap kicks in due to
     // content providers being active during the test.
     int i = 5;
-    log_time now(android_log_clockid());
-    now.tv_sec -= 30;  // reach back a moderate period of time
+    log_time start(android_log_clockid());
+    start.tv_sec -= 30;  // reach back a moderate period of time
 
     while (--i) {
         int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
@@ -726,7 +730,7 @@
         std::string ask = android::base::StringPrintf(
             "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
             ".%09" PRIu32,
-            now.tv_sec, now.tv_nsec);
+            start.tv_sec, start.tv_nsec);
 
         struct sigaction ignore, old_sigaction;
         memset(&ignore, 0, sizeof(ignore));
@@ -756,11 +760,15 @@
                 recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
         }
 
-        alarm_timeout =
-            alarm((old_alarm <= 0) ? old_alarm
-                                   : (old_alarm > (1 + 3 - alarm_wrap))
-                                         ? old_alarm - 3 + alarm_wrap
-                                         : 2);
+        if (old_alarm > 0) {
+            unsigned int time_spent = 3 - alarm_wrap;
+            if (old_alarm > time_spent + 1) {
+                old_alarm -= time_spent;
+            } else {
+                old_alarm = 2;
+            }
+        }
+        alarm_timeout = alarm(old_alarm);
         sigaction(SIGALRM, &old_sigaction, nullptr);
 
         close(fd);
@@ -773,23 +781,23 @@
         // active _or_ inactive during the test.
         if (content_timeout) {
             log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
-            if (msg < now) {
+            if (msg < start) {
                 fprintf(stderr, "%u.%09u < %u.%09u\n", msg_timeout.entry.sec,
-                        msg_timeout.entry.nsec, (unsigned)now.tv_sec,
-                        (unsigned)now.tv_nsec);
+                        msg_timeout.entry.nsec, (unsigned)start.tv_sec,
+                        (unsigned)start.tv_nsec);
                 _exit(-1);
             }
-            if (msg > now) {
-                now = msg;
-                now.tv_sec += 30;
-                msg = log_time(android_log_clockid());
-                if (now > msg) {
-                    now = msg;
-                    --now.tv_sec;
+            if (msg > start) {
+                start = msg;
+                start.tv_sec += 30;
+                log_time now = log_time(android_log_clockid());
+                if (start > now) {
+                    start = now;
+                    --start.tv_sec;
                 }
             }
         } else {
-            now.tv_sec -= 120;  // inactive, reach further back!
+            start.tv_sec -= 120;  // inactive, reach further back!
         }
     }
 
@@ -802,8 +810,8 @@
     }
 
     if (content_wrap || !content_timeout) {
-        fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n", now.tv_sec,
-                now.tv_nsec);
+        fprintf(stderr, "start=%" PRIu32 ".%09" PRIu32 "\n", start.tv_sec,
+                start.tv_nsec);
     }
 
     EXPECT_TRUE(written);
diff --git a/rootdir/asan.options b/rootdir/asan.options
index d728f12..a264d2d 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -5,3 +5,4 @@
 detect_container_overflow=0
 abort_on_error=1
 include_if_exists=/system/asan.options.%b
+include_if_exists=/data/asan/system/asan.options.%b
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 5482085..e20b95d 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,3 +1,4 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
 libandroid.so
 libaaudio.so
 libc.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 45b4bc2..3c46094 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,3 +1,4 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
 libandroid.so
 libaaudio.so
 libc.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2a73335..6533823 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -245,7 +245,10 @@
     export DOWNLOAD_CACHE /data/cache
 
     # set RLIMIT_NICE to allow priorities from 19 to -20
-    setrlimit 13 40 40
+    setrlimit nice 40 40
+
+    # Allow up to 32K FDs per process
+    setrlimit nofile 32768 32768
 
     # This allows the ledtrig-transient properties to be created here so
     # that they can be chown'd to system:system later on boot
@@ -437,7 +440,6 @@
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/trace 0700 root root
-    mkdir /data/misc/reboot 0700 system system
     # profile file layout
     mkdir /data/misc/profiles 0771 system system
     mkdir /data/misc/profiles/cur 0771 system system
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 0c58574..5b4dc58 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -8,6 +8,5 @@
 LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
 
 LOCAL_SANITIZE := integer
-LOCAL_CLANG := true
 
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index c342cf8..343a903 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -249,7 +249,9 @@
     global.root.uid = AID_ROOT;
     global.root.under_android = false;
 
-    strcpy(global.source_path, source_path);
+    // Clang static analyzer think strcpy potentially overwrites other fields
+    // in global. Use snprintf() to mute the false warning.
+    snprintf(global.source_path, sizeof(global.source_path), "%s", source_path);
 
     if (multi_user) {
         global.root.perm = PERM_PRE_ROOT;
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/keymaster_ipc.h
index b38eb05..d63757b 100644
--- a/trusty/keymaster/keymaster_ipc.h
+++ b/trusty/keymaster/keymaster_ipc.h
@@ -24,7 +24,8 @@
 // Commands
 enum keymaster_command : uint32_t {
     KEYMASTER_RESP_BIT              = 1,
-    KEYMASTER_REQ_SHIFT             = 1,
+    KEYMASTER_STOP_BIT              = 2,
+    KEYMASTER_REQ_SHIFT             = 2,
 
     KM_GENERATE_KEY                 = (0 << KEYMASTER_REQ_SHIFT),
     KM_BEGIN_OPERATION              = (1 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index 5f16fd0..55a03bd 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -36,7 +36,8 @@
 #include "trusty_keymaster_device.h"
 #include "trusty_keymaster_ipc.h"
 
-const uint32_t RECV_BUF_SIZE = PAGE_SIZE;
+// Maximum size of message from Trusty is 8K (for RSA attestation key and chain)
+const uint32_t RECV_BUF_SIZE = 2*PAGE_SIZE;
 const uint32_t SEND_BUF_SIZE = (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
 
 const size_t kMaximumAttestationChallengeLength = 128;
@@ -176,14 +177,14 @@
     }
 
     AuthorizationSet params_copy(*params);
-    ConfigureRequest request;
+    ConfigureRequest request(message_version_);
     if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) ||
         !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) {
         ALOGD("Configuration parameters must contain OS version and patch level");
         return KM_ERROR_INVALID_ARGUMENT;
     }
 
-    ConfigureResponse response;
+    ConfigureResponse response(message_version_);
     keymaster_error_t err = Send(KM_CONFIGURE, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -199,9 +200,9 @@
         return error_;
     }
 
-    AddEntropyRequest request;
+    AddEntropyRequest request(message_version_);
     request.random_data.Reinitialize(data, data_length);
-    AddEntropyResponse response;
+    AddEntropyResponse response(message_version_);
     return Send(KM_ADD_RNG_ENTROPY, request, &response);
 }
 
@@ -260,11 +261,11 @@
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
     }
 
-    GetKeyCharacteristicsRequest request;
+    GetKeyCharacteristicsRequest request(message_version_);
     request.SetKeyMaterial(*key_blob);
     AddClientAndAppData(client_id, app_data, &request);
 
-    GetKeyCharacteristicsResponse response;
+    GetKeyCharacteristicsResponse response(message_version_);
     keymaster_error_t err = Send(KM_GET_KEY_CHARACTERISTICS, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -378,7 +379,7 @@
     cert_chain->entry_count = 0;
     cert_chain->entries = nullptr;
 
-    AttestKeyRequest request;
+    AttestKeyRequest request(message_version_);
     request.SetKeyMaterial(*key_to_attest);
     request.attest_params.Reinitialize(*attest_params);
 
@@ -390,7 +391,7 @@
         return KM_ERROR_INVALID_INPUT_LENGTH;
     }
 
-    AttestKeyResponse response;
+    AttestKeyResponse response(message_version_);
     keymaster_error_t err = Send(KM_ATTEST_KEY, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -438,11 +439,11 @@
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
     }
 
-    UpgradeKeyRequest request;
+    UpgradeKeyRequest request(message_version_);
     request.SetKeyMaterial(*key_to_upgrade);
     request.upgrade_params.Reinitialize(*upgrade_params);
 
-    UpgradeKeyResponse response;
+    UpgradeKeyResponse response(message_version_);
     keymaster_error_t err = Send(KM_UPGRADE_KEY, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -479,12 +480,12 @@
         *out_params = {};
     }
 
-    BeginOperationRequest request;
+    BeginOperationRequest request(message_version_);
     request.purpose = purpose;
     request.SetKeyMaterial(*key);
     request.additional_params.Reinitialize(*in_params);
 
-    BeginOperationResponse response;
+    BeginOperationResponse response(message_version_);
     keymaster_error_t err = Send(KM_BEGIN_OPERATION, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -527,7 +528,7 @@
         *output = {};
     }
 
-    UpdateOperationRequest request;
+    UpdateOperationRequest request(message_version_);
     request.op_handle = operation_handle;
     if (in_params) {
         request.additional_params.Reinitialize(*in_params);
@@ -537,7 +538,7 @@
         request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size));
     }
 
-    UpdateOperationResponse response;
+    UpdateOperationResponse response(message_version_);
     keymaster_error_t err = Send(KM_UPDATE_OPERATION, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -576,7 +577,9 @@
         return error_;
     }
     if (input && input->data_length > kMaximumFinishInputLength) {
-        return KM_ERROR_INVALID_ARGUMENT;
+        ALOGE("%zu-byte input to finish; only %zu bytes allowed",
+              input->data_length, kMaximumFinishInputLength);
+        return KM_ERROR_INVALID_INPUT_LENGTH;
     }
 
     if (out_params) {
@@ -586,7 +589,7 @@
         *output = {};
     }
 
-    FinishOperationRequest request;
+    FinishOperationRequest request(message_version_);
     request.op_handle = operation_handle;
     if (signature && signature->data && signature->data_length > 0) {
         request.signature.Reinitialize(signature->data, signature->data_length);
@@ -598,7 +601,7 @@
         request.additional_params.Reinitialize(*in_params);
     }
 
-    FinishOperationResponse response;
+    FinishOperationResponse response(message_version_);
     keymaster_error_t err = Send(KM_FINISH_OPERATION, request, &response);
     if (err != KM_ERROR_OK) {
         return err;
@@ -631,9 +634,9 @@
         return error_;
     }
 
-    AbortOperationRequest request;
+    AbortOperationRequest request(message_version_);
     request.op_handle = operation_handle;
-    AbortOperationResponse response;
+    AbortOperationResponse response(message_version_);
     return Send(KM_ABORT_OPERATION, request, &response);
 }
 
@@ -768,6 +771,9 @@
     ALOGV("Sending %d byte request\n", (int)req.SerializedSize());
     int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
     if (rc < 0) {
+        // Reset the connection on tipc error
+        trusty_keymaster_disconnect();
+        trusty_keymaster_connect();
         ALOGE("tipc error: %d\n", rc);
         // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
         return translate_error(rc);
@@ -775,8 +781,7 @@
         ALOGV("Received %d byte response\n", rsp_size);
     }
 
-    const keymaster_message* msg = (keymaster_message*)recv_buf;
-    const uint8_t* p = msg->payload;
+    const uint8_t* p = recv_buf;
     if (!rsp->Deserialize(&p, p + rsp_size)) {
         ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
         return KM_ERROR_UNKNOWN_ERROR;
diff --git a/trusty/keymaster/trusty_keymaster_ipc.cpp b/trusty/keymaster/trusty_keymaster_ipc.cpp
index cdc2778..fbd0eb3 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/trusty_keymaster_ipc.cpp
@@ -21,8 +21,11 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
+#include <algorithm>
+
 #include <log/log.h>
 #include <trusty/tipc.h>
 
@@ -31,7 +34,7 @@
 
 #define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
 
-static int handle_ = 0;
+static int handle_ = -1;
 
 int trusty_keymaster_connect() {
     int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
@@ -45,7 +48,7 @@
 
 int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
                           uint32_t* out_size) {
-    if (handle_ == 0) {
+    if (handle_ < 0) {
         ALOGE("not connected\n");
         return -EINVAL;
     }
@@ -62,32 +65,43 @@
         ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
         return -errno;
     }
+    size_t out_max_size = *out_size;
+    *out_size = 0;
+    struct iovec iov[2];
+    struct keymaster_message header;
+    iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
+    while (true) {
+        iov[1] = {
+            .iov_base = out + *out_size,
+            .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH, out_max_size - *out_size)};
+        rc = readv(handle_, iov, 2);
+        if (rc < 0) {
+            ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
+                  strerror(errno));
+            return -errno;
+        }
 
-    rc = read(handle_, out, *out_size);
-    if (rc < 0) {
-        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
-              strerror(errno));
-        return -errno;
+        if ((size_t)rc < sizeof(struct keymaster_message)) {
+            ALOGE("invalid response size (%d)\n", (int)rc);
+            return -EINVAL;
+        }
+
+        if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
+            ALOGE("invalid command (%d)", header.cmd);
+            return -EINVAL;
+        }
+        *out_size += ((size_t)rc - sizeof(struct keymaster_message));
+        if (header.cmd & KEYMASTER_STOP_BIT) {
+            break;
+        }
     }
 
-    if ((size_t)rc < sizeof(struct keymaster_message)) {
-        ALOGE("invalid response size (%d)\n", (int)rc);
-        return -EINVAL;
-    }
-
-    msg = (struct keymaster_message*)out;
-
-    if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
-        ALOGE("invalid command (%d)", msg->cmd);
-        return -EINVAL;
-    }
-
-    *out_size = ((size_t)rc) - sizeof(struct keymaster_message);
     return rc;
 }
 
 void trusty_keymaster_disconnect() {
-    if (handle_ != 0) {
+    if (handle_ >= 0) {
         tipc_close(handle_);
     }
+    handle_ = -1;
 }
diff --git a/trusty/storage/tests/Android.bp b/trusty/storage/tests/Android.bp
index 1b003e9..536c3ca 100644
--- a/trusty/storage/tests/Android.bp
+++ b/trusty/storage/tests/Android.bp
@@ -22,7 +22,6 @@
         "-g",
         "-Wall",
         "-Werror",
-        "-std=gnu++11",
         "-Wno-missing-field-initializers",
     ],