Implement system namespace for vendor process
am: 24c29f1be4

Change-Id: Ie5358aea408aaf817a1f0a76bf6907051cb207e4
diff --git a/adb/Android.mk b/adb/Android.mk
index d5b069a..87a02b6 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
@@ -122,7 +121,6 @@
 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 \
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..88e13b6 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -56,6 +56,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 +150,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 +160,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 +218,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..f63ac08 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -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..758f24a 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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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")))
         .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..9f23473 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;
         }
 
@@ -1589,7 +1611,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 +1707,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 +1774,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 +1841,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 +1860,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 +1876,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 +1932,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 +2057,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 +2083,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 +2120,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/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/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/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/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..7d17cd9 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -106,6 +106,7 @@
         "libdebuggerd",
         "libbacktrace",
         "libunwind",
+        "libunwindstack",
         "liblzma",
         "libcutils",
     ],
@@ -171,6 +172,7 @@
     static_libs: [
         "libbacktrace",
         "libunwind",
+        "libunwindstack",
         "liblzma",
         "libbase",
         "libcutils",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 4b1e51d..3513980 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -79,9 +79,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 +347,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 +431,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/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h
index 79743b6..45740df 100644
--- a/debuggerd/libdebuggerd/include/tombstone.h
+++ b/debuggerd/libdebuggerd/include/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/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0113131..b809ed4 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -495,8 +495,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 +557,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 +582,8 @@
   }
 
   log->current_tid = log->crashed_tid;
+
+  return matches;
 }
 
 // Reads the contents of the specified log device, filters out the entries
@@ -657,9 +717,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 +729,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 +740,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,6 +754,14 @@
   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
@@ -745,16 +817,16 @@
   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..7f450e6 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -22,16 +22,22 @@
 #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/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..b1f0279 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -67,10 +67,13 @@
         "devices.cpp",
         "firmware_handler.cpp",
         "import_parser.cpp",
-        "init_parser.cpp",
         "log.cpp",
         "parser.cpp",
+        "property_service.cpp",
+        "security.cpp",
+        "selinux.cpp",
         "service.cpp",
+        "tokenizer.cpp",
         "uevent_listener.cpp",
         "ueventd_parser.cpp",
         "util.cpp",
@@ -81,7 +84,12 @@
         "libselinux",
         "liblog",
         "libprocessgroup",
+        "libfs_mgr",
     ],
+    include_dirs: [
+        "system/core/mkbootimg",
+    ],
+
 }
 
 /*
@@ -105,15 +113,11 @@
         "init.cpp",
         "init_first_stage.cpp",
         "keychords.cpp",
-        "property_service.cpp",
         "reboot.cpp",
         "signal_handler.cpp",
         "ueventd.cpp",
         "watchdogd.cpp",
     ],
-    include_dirs: [
-        "system/core/mkbootimg"
-    ],
     static_libs: [
         "libinit",
         "libbootloader_message",
@@ -153,9 +157,9 @@
     defaults: ["init_defaults"],
     srcs: [
         "devices_test.cpp",
-        "init_parser_test.cpp",
         "init_test.cpp",
         "property_service_test.cpp",
+        "result_test.cpp",
         "service_test.cpp",
         "ueventd_test.cpp",
         "util_test.cpp",
@@ -163,9 +167,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..3886ed5 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
 
@@ -49,15 +51,12 @@
     init.cpp \
     init_first_stage.cpp \
     keychords.cpp \
-    property_service.cpp \
     reboot.cpp \
     signal_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 +74,7 @@
     libcutils \
     libbase \
     libc \
+    libseccomp_policy \
     libselinux \
     liblog \
     libcrypto_utils \
@@ -97,5 +97,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..0ea00fb 100644
--- a/init/README.md
+++ b/init/README.md
@@ -447,6 +447,9 @@
 `rmdir <path>`
 > Calls rmdir(2) on the given path.
 
+`readahead <file|dir>`
+> Calls readahead(2) on the file or files within given directory.
+
 `setprop <name> <value>`
 > Set system property _name_ to _value_. Properties are expanded
   within _value_.
diff --git a/init/action.cpp b/init/action.cpp
index 4ec5f17..f687074 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,74 @@
 
 void Action::ExecuteCommand(const Command& command) const {
     android::base::Timer t;
-    int result = command.InvokeFunc();
-
+    auto result = command.InvokeFunc();
     auto duration = t.duration();
+
     // Any action longer than 50ms will be warned to user as slow operation
     if (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());
     }
 }
 
-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 +253,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 +323,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..020ca79 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>
@@ -57,7 +60,7 @@
 #include "action.h"
 #include "bootchart.h"
 #include "init.h"
-#include "init_parser.h"
+#include "parser.h"
 #include "property_service.h"
 #include "reboot.h"
 #include "service.h"
@@ -66,6 +69,8 @@
 
 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 +78,122 @@
 
 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";
+
+    if (!svc->Enable()) return Error() << "Could not enable service";
+
+    return Success();
 }
 
-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;
+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";
     }
-    return 0;
+    if (!service->ExecStart()) {
+        return Error() << "Could not start exec service";
+    }
+
+    ServiceList::GetInstance().AddService(std::move(service));
+    return Success();
 }
 
-static int do_ifup(const std::vector<std::string>& args) {
-    return __ifupdown(args[1].c_str(), 1);
+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 (!service->ExecStart()) {
+        return Error() << "Could not start Service";
+    }
+
+    return Success();
 }
 
-static int do_insmod(const std::vector<std::string>& args) {
+static Result<Success> do_export(const std::vector<std::string>& args) {
+    if (!add_environment(args[1].c_str(), args[2].c_str())) {
+        return Error();
+    }
+    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 +204,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 +264,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 +303,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 +318,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 +373,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 +397,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 +415,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 +434,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 +447,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 +481,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 +514,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 +539,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 +553,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 +570,103 @@
     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;
+static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
     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);
+    if (!android::base::ParseInt(args[1], &resource)) {
+        return Error() << "unable to parse resource, " << args[1];
     }
-    LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
-    return -1;
+
+    struct rlimit limit;
+    if (!android::base::ParseUint(args[2], &limit.rlim_cur)) {
+        return Error() << "unable to parse rlim_cur, " << args[2];
+    }
+    if (!android::base::ParseUint(args[3], &limit.rlim_max)) {
+        return Error() << "unable to parse rlim_max, " << args[3];
+    }
+
+    if (setrlimit(resource, &limit) == -1) {
+        return ErrnoError() << "setrlimit failed";
+    }
+    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;
-    }
-    if (!svc->Start())
-        return -1;
-    return 0;
+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 (!svc->Start()) return Error() << "failed to start service";
+    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) {
+        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,113 @@
     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> do_readahead(const std::vector<std::string>& args) {
+    struct stat sb;
+
+    if (stat(args[1].c_str(), &sb)) {
+        return ErrnoError() << "Error opening " << args[1];
     }
-    if (!WriteFile(args[2], data, &err)) {
-        LOG(ERROR) << err;
-        return -1;
+
+    // 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) {
+        android::base::Timer t;
+        if (S_ISREG(sb.st_mode)) {
+            android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(args[1].c_str(), O_RDONLY)));
+            if (fd == -1) {
+                PLOG(ERROR) << "Error opening file: " << args[1];
+                _exit(EXIT_FAILURE);
+            }
+            if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+                PLOG(ERROR) << "Error readahead file: " << args[1];
+                _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) {
+                    android::base::unique_fd fd(
+                        TEMP_FAILURE_RETRY(open(ftsent->fts_accpath, O_RDONLY)));
+                    if (fd == -1) {
+                        PLOG(ERROR) << "Error opening file: " << args[1];
+                        continue;
+                    }
+                    if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+                        PLOG(ERROR) << "Unable to readahead on file: " << ftsent->fts_accpath;
+                    }
+                }
+            }
+        }
+        LOG(INFO) << "Readahead " << args[1] << " took " << t;
+        _exit(0);
+    } else if (pid < 0) {
+        return ErrnoError() << "Fork failed";
     }
-    return 0;
+    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_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 +796,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 +821,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 +832,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 +867,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 +968,7 @@
         {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
         {"umount",                  {1,     1,    do_umount}},
+        {"readahead",               {1,     1,    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..cc5b948 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -86,8 +86,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..d0afac1 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -16,26 +16,17 @@
 
 #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/sysmacros.h>
 #include <sys/types.h>
-#include <sys/un.h>
-#include <sys/wait.h>
 #include <unistd.h>
 
 #include <android-base/chrono_utils.h>
@@ -43,27 +34,23 @@
 #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 "security.h"
+#include "selinux.h"
 #include "signal_handler.h"
 #include "ueventd.h"
 #include "util.h"
@@ -78,15 +65,11 @@
 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];
 
@@ -97,11 +80,43 @@
 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;
@@ -189,16 +204,25 @@
     }
 }
 
-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) {
+            s->Start();
+        } 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;
@@ -215,7 +239,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 +253,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 +352,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.
@@ -957,8 +397,11 @@
     memset(&action, 0, sizeof(action));
     sigfillset(&action.sa_mask);
     action.sa_handler = [](int) {
-        // panic() reboots to bootloader
-        panic();
+        // 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);
@@ -1010,7 +453,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 +470,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 +500,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 +541,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) {
@@ -1111,26 +562,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 +575,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 +586,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 +603,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..50a7c83 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 {
@@ -29,8 +32,10 @@
 // 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);
 
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..2ef0ce7 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -79,7 +79,7 @@
     // 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();
@@ -92,7 +92,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..391bc1f 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -21,17 +21,35 @@
 #include <string.h>
 
 #include <android-base/logging.h>
+#include <cutils/android_reboot.h>
 #include <selinux/selinux.h>
 
+#include "reboot.h"
+
 namespace android {
 namespace init {
 
+static void RebootAborter(const char* abort_message) {
+    // 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, RebootAborter);
         errno = saved_errno;
         PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
     }
@@ -40,7 +58,7 @@
     dup2(fd, 2);
     if (fd > 2) close(fd);
 
-    android::base::InitLogging(argv, &android::base::KernelLogger);
+    android::base::InitLogging(argv, &android::base::KernelLogger, RebootAborter);
 }
 
 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/property_service.cpp b/init/property_service.cpp
index fd14bd6..bbfb047 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -68,6 +68,8 @@
 
 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";
@@ -586,14 +588,14 @@
 // "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;
 }
@@ -740,11 +742,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..5bae4bc 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 "signal_handler.h"
 
 using android::base::StringPrintf;
 using android::base::Timer;
@@ -189,8 +191,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 +215,7 @@
             break;
     }
     // In normal case, reboot should not return.
-    PLOG(FATAL) << "reboot call returned";
+    PLOG(ERROR) << "reboot call returned";
     abort();
 }
 
@@ -265,8 +266,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 +277,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"); }
@@ -373,7 +374,7 @@
     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())) {
@@ -382,14 +383,15 @@
         } else if (s->IsShutdownCritical()) {
             s->Start();  // start shutdown critical service if not started
         }
-    });
+    }
 
-    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 +400,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 +420,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 +436,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 +450,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());
@@ -517,16 +519,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..8586556 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,6 +22,9 @@
 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"
diff --git a/init/result.h b/init/result.h
new file mode 100644
index 0000000..64fa69f
--- /dev/null
+++ b/init/result.h
@@ -0,0 +1,142 @@
+/*
+ * 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 std::string describing an error, which can be accessed via
+// Result<T>::error().
+//
+// 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.  Each of these classes
+// take an ostream as an input and are implicitly cast to a Result<T> containing that failure.
+// ErrnoError() additionally appends ": " + strerror(errno) to the end of the failure string to aid
+// in interacting with C APIs.
+
+// 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 {
+
+class Error {
+  public:
+    Error() : append_errno_(0) {}
+
+    template <typename T>
+    Error&& operator<<(T&& t) {
+        ss_ << std::forward<T>(t);
+        return std::move(*this);
+    }
+
+    const std::string str() const {
+        if (append_errno_) {
+            return ss_.str() + ": " + strerror(append_errno_);
+        }
+        return ss_.str();
+    }
+
+    Error(const Error&) = delete;
+    Error(Error&&) = delete;
+    Error& operator=(const Error&) = delete;
+    Error& operator=(Error&&) = delete;
+
+  protected:
+    Error(int append_errno) : append_errno_(append_errno) {}
+
+  private:
+    std::stringstream ss_;
+    int append_errno_;
+};
+
+class ErrnoError : public Error {
+  public:
+    ErrnoError() : 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&& fb) : contents_(std::in_place_index_t<1>(), fb.str()) {}
+
+    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 std::string& error() const & { return std::get<1>(contents_); }
+    std::string&& error() && { return std::get<1>(std::move(contents_)); }
+    const std::string&& error() const && { return std::get<1>(std::move(contents_)); }
+
+    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, std::string> 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..ca65013
--- /dev/null
+++ b/init/result_test.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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("failure1", result.error());
+}
+
+TEST(result, result_error_empty) {
+    Result<Success> result = Error();
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ("", result.error());
+}
+
+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("failure1", MakeRvalueErrorResult().error());
+}
+
+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("failure1: "s + strerror(test_errno), result.error());
+}
+
+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(), "");
+}
+
+}  // 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/security.h b/init/security.h
new file mode 100644
index 0000000..31e5790
--- /dev/null
+++ b/init/security.h
@@ -0,0 +1,35 @@
+/*
+ * 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_SECURITY_H
+#define _INIT_SECURITY_H
+
+#include <string>
+#include <vector>
+
+#include "result.h"
+
+namespace android {
+namespace init {
+
+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
+
+#endif
diff --git a/init/selinux.cpp b/init/selinux.cpp
new file mode 100644
index 0000000..3c4b8f5
--- /dev/null
+++ b/init/selinux.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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 <paths.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]));
+
+        const char* envp[] = {_PATH_DEFPATH, nullptr};
+        if (execve(filename, argv, (char**)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;
+    }
+}
+
+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();
+
+    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 (!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;
+    if (!ReadFirstLine("/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;
+}
+
+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");
+    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 (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args)) {
+        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..6ab60e3 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,28 +155,11 @@
     : 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 +185,7 @@
       swappiness_(-1),
       soft_limit_in_bytes_(-1),
       limit_in_bytes_(-1),
+      start_order_(0),
       args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
@@ -217,7 +201,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));
+        }
     }
 }
 
@@ -297,12 +284,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 +309,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 +335,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 +352,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 +426,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 +441,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 +467,125 @@
         } 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::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) {
+Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
     envvars_.emplace_back(args[1], args[2]);
-    return true;
+    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> {
@@ -658,26 +633,29 @@
     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 Error() << 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;
-
-    exec_waiter->reset(new android::base::Timer);
+bool Service::ExecStart() {
+    flags_ |= SVC_ONESHOT;
 
     if (!Start()) {
-        exec_waiter->reset();
         return false;
     }
+
+    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 true;
 }
 
@@ -825,6 +803,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,12 +830,6 @@
         }
     }
 
-    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;
 }
@@ -905,22 +878,6 @@
     } /* 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 +923,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 +955,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 +967,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 +1022,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..fe85129 100644
--- a/init/service.h
+++ b/init/service.h
@@ -30,8 +30,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
@@ -73,9 +73,11 @@
             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);
+    Result<Success> ParseLine(const std::vector<std::string>& args);
+    bool ExecStart();
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
@@ -83,17 +85,22 @@
     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 +115,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 +129,35 @@
     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> 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_;
@@ -190,58 +200,56 @@
 
     bool process_cgroup_empty_ = false;
 
+    unsigned long start_order_;
+
     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/signal_handler.cpp b/init/signal_handler.cpp
index db1bfcf..9e49c48 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -14,29 +14,94 @@
  * limitations under the License.
  */
 
+#include "signal_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));
 
-    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+    ReapAnyOutstandingChildren();
 }
 
 static void SIGCHLD_handler(int) {
@@ -45,6 +110,11 @@
     }
 }
 
+void ReapAnyOutstandingChildren() {
+    while (ReapOneProcess()) {
+    }
+}
+
 void signal_handler_init() {
     // Create a signalling mechanism for SIGCHLD.
     int s[2];
@@ -63,7 +133,7 @@
     act.sa_flags = SA_NOCLDSTOP;
     sigaction(SIGCHLD, &act, 0);
 
-    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+    ReapAnyOutstandingChildren();
 
     register_epoll_handler(signal_read_fd, handle_signal);
 }
diff --git a/init/signal_handler.h b/init/signal_handler.h
index f7881ab..9362be5 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -20,6 +20,8 @@
 namespace android {
 namespace init {
 
+void ReapAnyOutstandingChildren();
+
 void signal_handler_init(void);
 
 }  // namespace init
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/tokenizer.h b/init/tokenizer.h
new file mode 100644
index 0000000..72c08ef
--- /dev/null
+++ b/init/tokenizer.h
@@ -0,0 +1,40 @@
+/*
+ * 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_TOKENIZER_H_
+#define _INIT_TOKENIZER_H_
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_NEWLINE 2
+
+namespace android {
+namespace init {
+
+struct parse_state
+{
+    char *ptr;
+    char *text;
+    int line;
+    int nexttoken;
+};
+
+int next_token(struct parse_state *state);
+
+}  // namespace init
+}  // namespace android
+
+#endif
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..9112c3f 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,65 +154,55 @@
     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) {
@@ -249,26 +229,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 +345,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..007d10e 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());
 }
 
 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());
 }
 
 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());
 }
 
 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());
 }
 
 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());
 
-    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/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 7eefc95..02e0487 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,
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
new file mode 100644
index 0000000..e79bca3
--- /dev/null
+++ b/libbacktrace/UnwindStack.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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(pid_t pid, 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 "";
+  }
+
+  unwindstack::Elf* elf = map_info->GetElf(pid, 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(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
+                   BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
+                   size_t num_ignore_frames) {
+  unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_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(pid, 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, memory)) {
+      break;
+    }
+  }
+
+  return true;
+}
+
+UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}
+
+std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  return ::GetFunctionName(Pid(), 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::GetMachineType(), ucontext));
+  }
+
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
+  return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
+}
+
+UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}
+
+std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  return ::GetFunctionName(Pid(), GetMap(), pc, offset);
+}
+
+bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
+  std::unique_ptr<unwindstack::Regs> regs;
+  if (context == nullptr) {
+    uint32_t machine_type;
+    regs.reset(unwindstack::Regs::RemoteGet(Tid(), &machine_type));
+  } else {
+    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), context));
+  }
+
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
+  return ::Unwind(Pid(), memory_.get(), 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..32d1f51
--- /dev/null
+++ b/libbacktrace/UnwindStack.h
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+ private:
+  std::unique_ptr<unwindstack::Memory> memory_;
+};
+
+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);
+
+ private:
+  std::unique_ptr<unwindstack::Memory> memory_;
+};
+
+#endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
new file mode 100644
index 0000000..ba9fd87
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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_));
+  }
+
+  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(pid_, 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..7885b74
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <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(); }
+
+ protected:
+  std::unique_ptr<unwindstack::Maps> stack_maps_;
+};
+
+#endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
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/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/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/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/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/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..8b48a87 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -12,7 +12,6 @@
     host_supported: true,
     srcs: ["native_bridge.cc"],
     shared_libs: ["liblog"],
-    clang: true,
 
     export_include_dirs=["include"],
 
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 70b3fcc..c1e65ff 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -34,7 +34,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=%))) \
@@ -43,7 +42,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/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/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 04c4cfa..b4a6cba 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"],
 
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/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/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 2a97dde..1854767 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -41,6 +41,7 @@
   uint64_t elf_offset;
 
   Memory* CreateMemory(pid_t pid);
+  // This function guarantees it will never return nullptr.
   Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
 };
 
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/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/libutils/tests/Mutex_test.cpp b/libutils/tests/Mutex_test.cpp
new file mode 100644
index 0000000..8a1805f
--- /dev/null
+++ b/libutils/tests/Mutex_test.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 <utils/Mutex.h>
+
+#include <gtest/gtest.h>
+
+static android::Mutex mLock;
+static int i GUARDED_BY(mLock);
+
+void modifyLockedVariable() REQUIRES(mLock) {
+    i = 1;
+}
+
+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/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/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/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..54b251e 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/trusty_keymaster_ipc.cpp
@@ -23,6 +23,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <algorithm>
+
 #include <log/log.h>
 #include <trusty/tipc.h>
 
@@ -31,7 +33,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 +47,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 +64,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 3eff3f2..1e4fced 100644
--- a/trusty/storage/tests/Android.bp
+++ b/trusty/storage/tests/Android.bp
@@ -21,7 +21,6 @@
         "-g",
         "-Wall",
         "-Werror",
-        "-std=gnu++11",
         "-Wno-missing-field-initializers",
     ],