Merge "Fixed a typo in the version name" into rvc-dev
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index ff97a6f..87937fb 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -528,14 +528,16 @@
             }
 
             if (id.direction == TransferDirection::READ) {
-                HandleRead(id, event.res);
+                if (!HandleRead(id, event.res)) {
+                    return;
+                }
             } else {
                 HandleWrite(id);
             }
         }
     }
 
-    void HandleRead(TransferId id, int64_t size) {
+    bool HandleRead(TransferId id, int64_t size) {
         uint64_t read_idx = id.id % kUsbReadQueueDepth;
         IoReadBlock* block = &read_requests_[read_idx];
         block->pending = false;
@@ -545,7 +547,7 @@
         if (block->id().id != needed_read_id_) {
             LOG(VERBOSE) << "read " << block->id().id << " completed while waiting for "
                          << needed_read_id_;
-            return;
+            return true;
         }
 
         for (uint64_t id = needed_read_id_;; ++id) {
@@ -554,15 +556,22 @@
             if (current_block->pending) {
                 break;
             }
-            ProcessRead(current_block);
+            if (!ProcessRead(current_block)) {
+                return false;
+            }
             ++needed_read_id_;
         }
+
+        return true;
     }
 
-    void ProcessRead(IoReadBlock* block) {
+    bool ProcessRead(IoReadBlock* block) {
         if (!block->payload.empty()) {
             if (!incoming_header_.has_value()) {
-                CHECK_EQ(sizeof(amessage), block->payload.size());
+                if (block->payload.size() != sizeof(amessage)) {
+                    HandleError("received packet of unexpected length while reading header");
+                    return false;
+                }
                 amessage& msg = incoming_header_.emplace();
                 memcpy(&msg, block->payload.data(), sizeof(msg));
                 LOG(DEBUG) << "USB read:" << dump_header(&msg);
@@ -570,7 +579,10 @@
             } else {
                 size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
                 Block payload = std::move(block->payload);
-                CHECK_LE(payload.size(), bytes_left);
+                if (block->payload.size() > bytes_left) {
+                    HandleError("received too many bytes while waiting for payload");
+                    return false;
+                }
                 incoming_payload_.append(std::move(payload));
             }
 
@@ -593,6 +605,7 @@
 
         PrepareReadBlock(block, block->id().id + kUsbReadQueueDepth);
         SubmitRead(block);
+        return true;
     }
 
     bool SubmitRead(IoReadBlock* block) {
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index b19fa5d..cb7e2fb 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -299,6 +299,7 @@
         }
         // Signal only when writing the descriptors to ffs
         android::base::SetProperty("sys.usb.ffs.ready", "1");
+        *out_control = std::move(control);
     }
 
     bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
@@ -313,7 +314,6 @@
         return false;
     }
 
-    *out_control = std::move(control);
     *out_bulk_in = std::move(bulk_in);
     *out_bulk_out = std::move(bulk_out);
     return true;
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2c9dec9..ca120c6 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -261,7 +261,7 @@
     }
 
     // If the slot is not changing, do nothing.
-    if (slot == boot_control_hal->getCurrentSlot()) {
+    if (args[1] == device->GetCurrentSlot()) {
         return device->WriteOkay("");
     }
 
diff --git a/init/Android.bp b/init/Android.bp
index f28934e..52628f3 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -28,6 +28,7 @@
     "rlimit_parser.cpp",
     "service.cpp",
     "service_list.cpp",
+    "service_lock.cpp",
     "service_parser.cpp",
     "service_utils.cpp",
     "subcontext.cpp",
@@ -81,6 +82,7 @@
         "-Wextra",
         "-Wno-unused-parameter",
         "-Werror",
+        "-Wthread-safety",
         "-DALLOW_FIRST_STAGE_CONSOLE=0",
         "-DALLOW_LOCAL_PROP_OVERRIDE=0",
         "-DALLOW_PERMISSIVE_SELINUX=0",
@@ -88,6 +90,7 @@
         "-DWORLD_WRITABLE_KMSG=0",
         "-DDUMP_ON_UMOUNT_FAILURE=0",
         "-DSHUTDOWN_ZERO_TIMEOUT=0",
+        "-DINIT_FULL_SOURCES",
     ],
     product_variables: {
         debuggable: {
@@ -267,6 +270,37 @@
     static_libs: ["libinit"],
 }
 
+cc_defaults {
+    name: "libinit_test_utils_libraries_defaults",
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libselinux",
+        "libhidl-gen-utils",
+        "liblog",
+        "libprocessgroup",
+        "libprotobuf-cpp-lite",
+    ],
+}
+
+cc_library_static {
+    name: "libinit_test_utils",
+    defaults: ["libinit_test_utils_libraries_defaults"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wno-unused-parameter",
+        "-Werror",
+    ],
+    srcs: init_common_sources + [
+        "test_utils/service_utils.cpp",
+    ],
+    whole_static_libs: [
+        "libcap",
+    ],
+    export_include_dirs: ["test_utils/include"], // for tests
+}
+
 // Host Verifier
 // ------------------------------------------------------------------------------
 
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index ebca762..b45f5cd 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -41,10 +41,12 @@
 }
 
 void ActionManager::QueueEventTrigger(const std::string& trigger) {
+    auto lock = std::lock_guard{event_queue_lock_};
     event_queue_.emplace(trigger);
 }
 
 void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
+    auto lock = std::lock_guard{event_queue_lock_};
     event_queue_.emplace(std::make_pair(name, value));
 }
 
@@ -53,6 +55,7 @@
 }
 
 void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
+    auto lock = std::lock_guard{event_queue_lock_};
     auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
                                            std::map<std::string, std::string>{});
     action->AddCommand(std::move(func), {name}, 0);
@@ -62,15 +65,18 @@
 }
 
 void ActionManager::ExecuteOneCommand() {
-    // Loop through the event queue until we have an action to execute
-    while (current_executing_actions_.empty() && !event_queue_.empty()) {
-        for (const auto& action : actions_) {
-            if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
-                           event_queue_.front())) {
-                current_executing_actions_.emplace(action.get());
+    {
+        auto lock = std::lock_guard{event_queue_lock_};
+        // Loop through the event queue until we have an action to execute
+        while (current_executing_actions_.empty() && !event_queue_.empty()) {
+            for (const auto& action : actions_) {
+                if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
+                               event_queue_.front())) {
+                    current_executing_actions_.emplace(action.get());
+                }
             }
+            event_queue_.pop();
         }
-        event_queue_.pop();
     }
 
     if (current_executing_actions_.empty()) {
@@ -103,6 +109,7 @@
 }
 
 bool ActionManager::HasMoreCommands() const {
+    auto lock = std::lock_guard{event_queue_lock_};
     return !current_executing_actions_.empty() || !event_queue_.empty();
 }
 
@@ -113,6 +120,7 @@
 }
 
 void ActionManager::ClearQueue() {
+    auto lock = std::lock_guard{event_queue_lock_};
     // We are shutting down so don't claim the oneshot builtin actions back
     current_executing_actions_ = {};
     event_queue_ = {};
diff --git a/init/action_manager.h b/init/action_manager.h
index a2b95ac..b6f93d9 100644
--- a/init/action_manager.h
+++ b/init/action_manager.h
@@ -16,9 +16,12 @@
 
 #pragma once
 
+#include <mutex>
 #include <string>
 #include <vector>
 
+#include <android-base/thread_annotations.h>
+
 #include "action.h"
 #include "builtins.h"
 
@@ -48,7 +51,9 @@
     void operator=(ActionManager const&) = delete;
 
     std::vector<std::unique_ptr<Action>> actions_;
-    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
+    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_
+            GUARDED_BY(event_queue_lock_);
+    mutable std::mutex event_queue_lock_;
     std::queue<const Action*> current_executing_actions_;
     std::size_t current_command_;
 };
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index f316871..52f6a1f 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -21,7 +21,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
 #include "property_service.h"
 #include "selinux.h"
 #else
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..dd5af72 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -151,6 +151,7 @@
 
 template <typename F>
 static void ForEachServiceInClass(const std::string& classname, F function) {
+    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(classname)) std::invoke(function, service);
     }
@@ -162,6 +163,7 @@
         return {};
     // Starting a class does not start services which are explicitly disabled.
     // They must  be started individually.
+    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfNotDisabled(); !result.ok()) {
@@ -184,6 +186,7 @@
         // stopped either.
         return {};
     }
+    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfPostData(); !result.ok()) {
@@ -234,6 +237,7 @@
 }
 
 static Result<void> do_enable(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "Could not find service";
 
@@ -245,6 +249,7 @@
 }
 
 static Result<void> do_exec(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec service: " << service.error();
@@ -258,6 +263,7 @@
 }
 
 static Result<void> do_exec_background(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec background service: " << service.error();
@@ -271,6 +277,7 @@
 }
 
 static Result<void> do_exec_start(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* service = ServiceList::GetInstance().FindService(args[1]);
     if (!service) {
         return Error() << "Service not found";
@@ -340,6 +347,7 @@
 }
 
 static Result<void> do_interface_restart(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Restart();
@@ -347,6 +355,7 @@
 }
 
 static Result<void> do_interface_start(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -356,6 +365,7 @@
 }
 
 static Result<void> do_interface_stop(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Stop();
@@ -740,6 +750,7 @@
 }
 
 static Result<void> do_start(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -749,6 +760,7 @@
 }
 
 static Result<void> do_stop(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Stop();
@@ -756,6 +768,7 @@
 }
 
 static Result<void> do_restart(const BuiltinArguments& args) {
+    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Restart();
@@ -1111,6 +1124,7 @@
             function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
         }
     });
+    auto lock = std::lock_guard{service_lock};
     if (auto result = (*service)->ExecStart(); !result.ok()) {
         function("ExecStart failed: " + result.error().message());
     }
@@ -1250,6 +1264,7 @@
         }
         success &= parser.ParseConfigFile(c);
     }
+    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().MarkServicesUpdate();
     if (success) {
         return {};
diff --git a/init/init.cpp b/init/init.cpp
index 5bf1b36..bfef9e5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,7 +33,9 @@
 #include <functional>
 #include <map>
 #include <memory>
+#include <mutex>
 #include <optional>
+#include <thread>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -95,15 +97,148 @@
 static int signal_fd = -1;
 static int property_fd = -1;
 
-static std::unique_ptr<Timer> waiting_for_prop(nullptr);
-static std::string wait_prop_name;
-static std::string wait_prop_value;
-static std::string shutdown_command;
-static bool do_shutdown = false;
-
 static std::unique_ptr<Subcontext> subcontext;
 
+// Init epolls various FDs to wait for various inputs.  It previously waited on property changes
+// with a blocking socket that contained the information related to the change, however, it was easy
+// to fill that socket and deadlock the system.  Now we use locks to handle the property changes
+// directly in the property thread, however we still must wake the epoll to inform init that there
+// is a change to process, so we use this FD.  It is non-blocking, since we do not care how many
+// times WakeEpoll() is called, only that the epoll will wake.
+static int wake_epoll_fd = -1;
+static void InstallInitNotifier(Epoll* epoll) {
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sockets) != 0) {
+        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
+    }
+    int epoll_fd = sockets[0];
+    wake_epoll_fd = sockets[1];
+
+    auto drain_socket = [epoll_fd] {
+        char buf[512];
+        while (read(epoll_fd, buf, sizeof(buf)) > 0) {
+        }
+    };
+
+    if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
+        LOG(FATAL) << result.error();
+    }
+}
+
+static void WakeEpoll() {
+    constexpr char value[] = "1";
+    write(wake_epoll_fd, value, sizeof(value));
+}
+
+static class PropWaiterState {
+  public:
+    bool StartWaiting(const char* name, const char* value) {
+        auto lock = std::lock_guard{lock_};
+        if (waiting_for_prop_) {
+            return false;
+        }
+        if (GetProperty(name, "") != value) {
+            // Current property value is not equal to expected value
+            wait_prop_name_ = name;
+            wait_prop_value_ = value;
+            waiting_for_prop_.reset(new Timer());
+        } else {
+            LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value
+                      << "\"): already set";
+        }
+        return true;
+    }
+
+    void ResetWaitForProp() {
+        auto lock = std::lock_guard{lock_};
+        ResetWaitForPropLocked();
+    }
+
+    void CheckAndResetWait(const std::string& name, const std::string& value) {
+        auto lock = std::lock_guard{lock_};
+        // We always record how long init waited for ueventd to tell us cold boot finished.
+        // If we aren't waiting on this property, it means that ueventd finished before we even
+        // started to wait.
+        if (name == kColdBootDoneProp) {
+            auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0;
+            std::thread([time_waited] {
+                SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
+            }).detach();
+        }
+
+        if (waiting_for_prop_) {
+            if (wait_prop_name_ == name && wait_prop_value_ == value) {
+                LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_
+                          << "' took " << *waiting_for_prop_;
+                ResetWaitForPropLocked();
+                WakeEpoll();
+            }
+        }
+    }
+
+    // This is not thread safe because it releases the lock when it returns, so the waiting state
+    // may change.  However, we only use this function to prevent running commands in the main
+    // thread loop when we are waiting, so we do not care about false positives; only false
+    // negatives.  StartWaiting() and this function are always called from the same thread, so false
+    // negatives are not possible and therefore we're okay.
+    bool MightBeWaiting() {
+        auto lock = std::lock_guard{lock_};
+        return static_cast<bool>(waiting_for_prop_);
+    }
+
+  private:
+    void ResetWaitForPropLocked() {
+        wait_prop_name_.clear();
+        wait_prop_value_.clear();
+        waiting_for_prop_.reset();
+    }
+
+    std::mutex lock_;
+    std::unique_ptr<Timer> waiting_for_prop_{nullptr};
+    std::string wait_prop_name_;
+    std::string wait_prop_value_;
+
+} prop_waiter_state;
+
+bool start_waiting_for_property(const char* name, const char* value) {
+    return prop_waiter_state.StartWaiting(name, value);
+}
+
+void ResetWaitForProp() {
+    prop_waiter_state.ResetWaitForProp();
+}
+
+static class ShutdownState {
+  public:
+    void TriggerShutdown(const std::string& command) {
+        // We can't call HandlePowerctlMessage() directly in this function,
+        // because it modifies the contents of the action queue, which can cause the action queue
+        // to get into a bad state if this function is called from a command being executed by the
+        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
+        // command is run in the main init loop.
+        auto lock = std::lock_guard{shutdown_command_lock_};
+        shutdown_command_ = command;
+        do_shutdown_ = true;
+        WakeEpoll();
+    }
+
+    std::optional<std::string> CheckShutdown() {
+        auto lock = std::lock_guard{shutdown_command_lock_};
+        if (do_shutdown_ && !IsShuttingDown()) {
+            do_shutdown_ = false;
+            return shutdown_command_;
+        }
+        return {};
+    }
+
+  private:
+    std::mutex shutdown_command_lock_;
+    std::string shutdown_command_;
+    bool do_shutdown_ = false;
+} shutdown_state;
+
 void DumpState() {
+    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().DumpState();
     ActionManager::GetInstance().DumpState();
 }
@@ -156,40 +291,7 @@
     }
 }
 
-bool start_waiting_for_property(const char *name, const char *value)
-{
-    if (waiting_for_prop) {
-        return false;
-    }
-    if (GetProperty(name, "") != value) {
-        // Current property value is not equal to expected value
-        wait_prop_name = name;
-        wait_prop_value = value;
-        waiting_for_prop.reset(new Timer());
-    } else {
-        LOG(INFO) << "start_waiting_for_property(\""
-                  << name << "\", \"" << value << "\"): already set";
-    }
-    return true;
-}
-
-void ResetWaitForProp() {
-    wait_prop_name.clear();
-    wait_prop_value.clear();
-    waiting_for_prop.reset();
-}
-
-static void TriggerShutdown(const std::string& command) {
-    // We can't call HandlePowerctlMessage() directly in this function,
-    // because it modifies the contents of the action queue, which can cause the action queue
-    // to get into a bad state if this function is called from a command being executed by the
-    // action queue.  Instead we set this flag and ensure that shutdown happens before the next
-    // command is run in the main init loop.
-    shutdown_command = command;
-    do_shutdown = true;
-}
-
-void property_changed(const std::string& name, const std::string& value) {
+void PropertyChanged(const std::string& name, const std::string& value) {
     // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
     // This is to ensure that init will always and immediately shutdown/reboot, regardless of
     // if there are other pending events to process or if init is waiting on an exec service or
@@ -197,30 +299,20 @@
     // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
     // commands to be executed.
     if (name == "sys.powerctl") {
-        TriggerShutdown(value);
+        trigger_shutdown(value);
     }
 
-    if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
-
-    // We always record how long init waited for ueventd to tell us cold boot finished.
-    // If we aren't waiting on this property, it means that ueventd finished before we even started
-    // to wait.
-    if (name == kColdBootDoneProp) {
-        auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0;
-        SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
+    if (property_triggers_enabled) {
+        ActionManager::GetInstance().QueuePropertyChange(name, value);
+        WakeEpoll();
     }
 
-    if (waiting_for_prop) {
-        if (wait_prop_name == name && wait_prop_value == value) {
-            LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
-                      << "' took " << *waiting_for_prop;
-            ResetWaitForProp();
-        }
-    }
+    prop_waiter_state.CheckAndResetWait(name, value);
 }
 
 static std::optional<boot_clock::time_point> HandleProcessActions() {
     std::optional<boot_clock::time_point> next_process_action_time;
+    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
             auto timeout_time = s->time_started() + *s->timeout_period();
@@ -249,7 +341,7 @@
     return next_process_action_time;
 }
 
-static Result<void> DoControlStart(Service* service) {
+static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
     return service->Start();
 }
 
@@ -258,7 +350,7 @@
     return {};
 }
 
-static Result<void> DoControlRestart(Service* service) {
+static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
     service->Restart();
     return {};
 }
@@ -292,7 +384,7 @@
     return control_message_functions;
 }
 
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
     const auto& map = get_control_message_map();
     const auto it = map.find(msg);
 
@@ -301,7 +393,7 @@
         return false;
     }
 
-    std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
+    std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
     std::string process_cmdline;
     if (ReadFileToString(cmdline_path, &process_cmdline)) {
         std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -312,6 +404,8 @@
 
     const ControlMessageFunction& function = it->second;
 
+    auto lock = std::lock_guard{service_lock};
+
     Service* svc = nullptr;
 
     switch (function.target) {
@@ -329,23 +423,24 @@
 
     if (svc == nullptr) {
         LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
-                   << " from pid: " << pid << " (" << process_cmdline << ")";
+                   << " from pid: " << from_pid << " (" << process_cmdline << ")";
         return false;
     }
 
     if (auto result = function.action(svc); !result.ok()) {
         LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
-                   << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
+                   << "' from pid: " << from_pid << " (" << process_cmdline
+                   << "): " << result.error();
         return false;
     }
 
     LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
-              << "' from pid: " << pid << " (" << process_cmdline << ")";
+              << "' from pid: " << from_pid << " (" << process_cmdline << ")";
     return true;
 }
 
 static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
-    if (!start_waiting_for_property(kColdBootDoneProp, "true")) {
+    if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
         LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
     }
 
@@ -493,6 +588,7 @@
     }
 
     auto found = false;
+    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         auto svc = service.get();
         if (svc->keycodes() == keycodes) {
@@ -579,44 +675,6 @@
     }
 }
 
-static void HandlePropertyFd() {
-    auto message = ReadMessage(property_fd);
-    if (!message.ok()) {
-        LOG(ERROR) << "Could not read message from property service: " << message.error();
-        return;
-    }
-
-    auto property_message = PropertyMessage{};
-    if (!property_message.ParseFromString(*message)) {
-        LOG(ERROR) << "Could not parse message from property service";
-        return;
-    }
-
-    switch (property_message.msg_case()) {
-        case PropertyMessage::kControlMessage: {
-            auto& control_message = property_message.control_message();
-            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
-                                                control_message.pid());
-
-            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-            if (control_message.has_fd()) {
-                int fd = control_message.fd();
-                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
-                close(fd);
-            }
-            break;
-        }
-        case PropertyMessage::kChangedMessage: {
-            auto& changed_message = property_message.changed_message();
-            property_changed(changed_message.name(), changed_message.value());
-            break;
-        }
-        default:
-            LOG(ERROR) << "Unknown message type from property service: "
-                       << property_message.msg_case();
-    }
-}
-
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -624,7 +682,7 @@
 
     boot_clock::time_point start_time = boot_clock::now();
 
-    trigger_shutdown = TriggerShutdown;
+    trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
 
     SetStdioToDevNull(argv);
     InitKernelLogging(argv);
@@ -684,11 +742,8 @@
     }
 
     InstallSignalFdHandler(&epoll);
-
+    InstallInitNotifier(&epoll);
     StartPropertyService(&property_fd);
-    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) {
-        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
-    }
 
     // Make the time that init stages started available for bootstat to log.
     RecordStageBoottimes(start_time);
@@ -742,6 +797,7 @@
     Keychords keychords;
     am.QueueBuiltinAction(
             [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
+                auto lock = std::lock_guard{service_lock};
                 for (const auto& svc : ServiceList::GetInstance()) {
                     keychords.Register(svc->keycodes());
                 }
@@ -772,12 +828,12 @@
         // By default, sleep until something happens.
         auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
 
-        if (do_shutdown && !IsShuttingDown()) {
-            do_shutdown = false;
-            HandlePowerctlMessage(shutdown_command);
+        auto shutdown_command = shutdown_state.CheckShutdown();
+        if (shutdown_command) {
+            HandlePowerctlMessage(*shutdown_command);
         }
 
-        if (!(waiting_for_prop || Service::is_exec_service_running())) {
+        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
             am.ExecuteOneCommand();
         }
         if (!IsShuttingDown()) {
@@ -791,7 +847,7 @@
             }
         }
 
-        if (!(waiting_for_prop || Service::is_exec_service_running())) {
+        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
             // If there's more work to do, wake up again immediately.
             if (am.HasMoreCommands()) epoll_timeout = 0ms;
         }
diff --git a/init/init.h b/init/init.h
index 4bbca6f..bcf24e7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -41,6 +41,9 @@
 void SendStopSendingMessagesMessage();
 void SendStartSendingMessagesMessage();
 
+void PropertyChanged(const std::string& name, const std::string& value);
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
+
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/init_test.cpp b/init/init_test.cpp
index caf3e03..3053bd8 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -167,6 +167,7 @@
 
     ServiceList service_list;
     TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
+    auto lock = std::lock_guard{service_lock};
     ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
 
     auto service = service_list.begin()->get();
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index dd1ab4d..a531d0a 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,7 +79,8 @@
 }
 
 static void RegisterServices(pid_t exclude_pid) {
-    for (const auto& service : ServiceList::GetInstance().services()) {
+    auto lock = std::lock_guard{service_lock};
+    for (const auto& service : ServiceList::GetInstance()) {
         auto svc = service.get();
         if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
             // skip if process is excluded or not yet forked (pid==0)
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 0749fe3..2175075 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -29,6 +29,7 @@
 #include <android-base/unique_fd.h>
 #include <apex_manifest.pb.h>
 
+#include "property_service.h"
 #include "util.h"
 
 namespace android {
@@ -290,6 +291,14 @@
         return true;
     }
     if (default_ns_id != GetMountNamespaceId()) {
+        // The property service thread and its descendent threads must be in the correct mount
+        // namespace to call Service::Start(), however setns() only operates on a single thread and
+        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
+        // must join the property service thread and its descendents before the setns() call.  Those
+        // threads are then started again after the setns() call, and they'll be in the proper
+        // namespace.
+        PausePropertyService();
+
         if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
             return false;
@@ -299,6 +308,8 @@
             LOG(ERROR) << result.error();
             return false;
         }
+
+        ResumePropertyService();
     }
 
     LOG(INFO) << "Switched to default mount namespace";
@@ -312,10 +323,20 @@
     }
     if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
         IsApexUpdatable()) {
+        // The property service thread and its descendent threads must be in the correct mount
+        // namespace to call Service::Start(), however setns() only operates on a single thread and
+        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
+        // must join the property service thread and its descendents before the setns() call.  Those
+        // threads are then started again after the setns() call, and they'll be in the proper
+        // namespace.
+        PausePropertyService();
+
         if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
             return false;
         }
+
+        ResumePropertyService();
     }
     return true;
 }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 730bf6d..319a241 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -92,8 +92,10 @@
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
+static int from_init_socket = -1;
 static int init_socket = -1;
 static bool accept_messages = false;
+static std::thread property_service_thread;
 
 static PropertyInfoAreaFile property_info_area;
 
@@ -147,17 +149,6 @@
     return has_access;
 }
 
-static void SendPropertyChanged(const std::string& name, const std::string& value) {
-    auto property_msg = PropertyMessage{};
-    auto* changed_message = property_msg.mutable_changed_message();
-    changed_message->set_name(name);
-    changed_message->set_value(value);
-
-    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
-        LOG(ERROR) << "Failed to send property changed message: " << result.error();
-    }
-}
-
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -196,47 +187,137 @@
     // If init hasn't started its main loop, then it won't be handling property changed messages
     // anyway, so there's no need to try to send them.
     if (accept_messages) {
-        SendPropertyChanged(name, value);
+        PropertyChanged(name, value);
     }
     return PROP_SUCCESS;
 }
 
-class AsyncRestorecon {
+template <typename T>
+class SingleThreadExecutor {
   public:
-    void TriggerRestorecon(const std::string& path) {
-        auto guard = std::lock_guard{mutex_};
-        paths_.emplace(path);
+    virtual ~SingleThreadExecutor() {}
 
-        if (!thread_started_) {
-            thread_started_ = true;
-            std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
+    template <typename F = T>
+    void Run(F&& item) {
+        auto guard = std::lock_guard{mutex_};
+        items_.emplace(std::forward<F>(item));
+
+        if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
+            return;
+        }
+
+        if (thread_state_ == ThreadState::kPendingJoin) {
+            thread_.join();
+        }
+
+        StartThread();
+    }
+
+    void StopAndJoin() {
+        auto lock = std::unique_lock{mutex_};
+        if (thread_state_ == ThreadState::kPendingJoin) {
+            thread_.join();
+        } else if (thread_state_ == ThreadState::kRunning) {
+            thread_state_ = ThreadState::kStopped;
+            lock.unlock();
+            thread_.join();
+            lock.lock();
+        }
+
+        thread_state_ = ThreadState::kStopped;
+    }
+
+    void Restart() {
+        auto guard = std::lock_guard{mutex_};
+        if (items_.empty()) {
+            thread_state_ = ThreadState::kNotStarted;
+        } else {
+            StartThread();
+        }
+    }
+
+    void MaybeJoin() {
+        auto guard = std::lock_guard{mutex_};
+        if (thread_state_ == ThreadState::kPendingJoin) {
+            thread_.join();
+            thread_state_ = ThreadState::kNotStarted;
         }
     }
 
   private:
+    virtual void Execute(T&& item) = 0;
+
+    void StartThread() {
+        thread_state_ = ThreadState::kRunning;
+        auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
+        std::swap(thread_, thread);
+    }
+
     void ThreadFunction() {
         auto lock = std::unique_lock{mutex_};
 
-        while (!paths_.empty()) {
-            auto path = paths_.front();
-            paths_.pop();
+        while (!items_.empty()) {
+            auto item = items_.front();
+            items_.pop();
 
             lock.unlock();
-            if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
-                LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
-            }
-            android::base::SetProperty(kRestoreconProperty, path);
+            Execute(std::move(item));
             lock.lock();
         }
 
-        thread_started_ = false;
+        if (thread_state_ != ThreadState::kStopped) {
+            thread_state_ = ThreadState::kPendingJoin;
+        }
     }
 
     std::mutex mutex_;
-    std::queue<std::string> paths_;
-    bool thread_started_ = false;
+    std::queue<T> items_;
+    enum class ThreadState {
+        kNotStarted,  // Initial state when starting the program or when restarting with no items to
+                      // process.
+        kRunning,     // The thread is running and is in a state that it will process new items if
+                      // are run.
+        kPendingJoin,  // The thread has run to completion and is pending join().  A new thread must
+                       // be launched for new items to be processed.
+        kStopped,  // This executor has stopped and will not process more items until Restart() is
+                   // called.  Currently pending items will be processed and the thread will be
+                   // joined.
+    };
+    ThreadState thread_state_ = ThreadState::kNotStarted;
+    std::thread thread_;
 };
 
+class RestoreconThread : public SingleThreadExecutor<std::string> {
+    virtual void Execute(std::string&& path) override {
+        if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+            LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+        }
+        android::base::SetProperty(kRestoreconProperty, path);
+    }
+};
+
+struct ControlMessageInfo {
+    std::string message;
+    std::string name;
+    pid_t pid;
+    int fd;
+};
+
+class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
+    virtual void Execute(ControlMessageInfo&& info) override {
+        bool success = HandleControlMessage(info.message, info.name, info.pid);
+
+        uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+        if (info.fd != -1) {
+            TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
+            close(info.fd);
+        }
+    }
+};
+
+static RestoreconThread restorecon_thread;
+static ControlMessageThread control_message_thread;
+
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -378,29 +459,17 @@
         return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
     }
 
-    auto property_msg = PropertyMessage{};
-    auto* control_message = property_msg.mutable_control_message();
-    control_message->set_msg(msg);
-    control_message->set_name(name);
-    control_message->set_pid(pid);
-
-    // We must release the fd before sending it to init, otherwise there will be a race with init.
-    // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
+    // We must release the fd before spawning the thread, otherwise there will be a race with the
+    // thread. If the thread calls close() before this function calls Release(), then fdsan will see
+    // the wrong tag and abort().
     int fd = -1;
     if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
         fd = socket->Release();
-        control_message->set_fd(fd);
     }
 
-    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
-        // We've already released the fd above, so if we fail to send the message to init, we need
-        // to manually free it here.
-        if (fd != -1) {
-            close(fd);
-        }
-        *error = "Failed to send control message: " + result.error().message();
-        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-    }
+    // Handling a control message likely calls SetProperty, which we must synchronously handle,
+    // therefore we must fork a thread to handle it.
+    control_message_thread.Run({msg, name, pid, fd});
 
     return PROP_SUCCESS;
 }
@@ -502,8 +571,7 @@
     // We use a thread to do this restorecon operation to prevent holding up init, as it may take
     // a long time to complete.
     if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
-        static AsyncRestorecon async_restorecon;
-        async_restorecon.TriggerRestorecon(value);
+        restorecon_thread.Run(value);
         return PROP_SUCCESS;
     }
 
@@ -1084,6 +1152,8 @@
     PropertyLoadBootDefaults();
 }
 
+static bool pause_property_service = false;
+
 static void HandleInitSocket() {
     auto message = ReadMessage(init_socket);
     if (!message.ok()) {
@@ -1118,6 +1188,10 @@
             accept_messages = true;
             break;
         }
+        case InitMessage::kPausePropertyService: {
+            pause_property_service = true;
+            break;
+        }
         default:
             LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
     }
@@ -1138,7 +1212,7 @@
         LOG(FATAL) << result.error();
     }
 
-    while (true) {
+    while (!pause_property_service) {
         auto pending_functions = epoll.Wait(std::nullopt);
         if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
@@ -1147,9 +1221,34 @@
                 (*function)();
             }
         }
+        control_message_thread.MaybeJoin();
+        restorecon_thread.MaybeJoin();
     }
 }
 
+void SendStopPropertyServiceMessage() {
+    auto init_message = InitMessage{};
+    init_message.set_pause_property_service(true);
+    if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
+        LOG(ERROR) << "Failed to send stop property service message: " << result.error();
+    }
+}
+
+void PausePropertyService() {
+    control_message_thread.StopAndJoin();
+    restorecon_thread.StopAndJoin();
+    SendStopPropertyServiceMessage();
+    property_service_thread.join();
+}
+
+void ResumePropertyService() {
+    pause_property_service = false;
+    auto new_thread = std::thread{PropertyServiceThread};
+    property_service_thread.swap(new_thread);
+    restorecon_thread.Restart();
+    control_message_thread.Restart();
+}
+
 void StartPropertyService(int* epoll_socket) {
     InitPropertySet("ro.property_service.version", "2");
 
@@ -1157,7 +1256,7 @@
     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
         PLOG(FATAL) << "Failed to socketpair() between property_service and init";
     }
-    *epoll_socket = sockets[0];
+    *epoll_socket = from_init_socket = sockets[0];
     init_socket = sockets[1];
     accept_messages = true;
 
@@ -1171,7 +1270,8 @@
 
     listen(property_set_fd, 8);
 
-    std::thread{PropertyServiceThread}.detach();
+    auto new_thread = std::thread{PropertyServiceThread};
+    property_service_thread.swap(new_thread);
 }
 
 }  // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 506d116..e921326 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -31,6 +31,8 @@
 
 void PropertyInit();
 void StartPropertyService(int* epoll_socket);
+void ResumePropertyService();
+void PausePropertyService();
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
index 08268d9..36245b2 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -41,5 +41,6 @@
         bool load_persistent_properties = 1;
         bool stop_sending_messages = 2;
         bool start_sending_messages = 3;
+        bool pause_property_service = 4;
     };
 }
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 8d8bd8e..cad192d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -85,7 +85,7 @@
 
 static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
 
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
+static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
     std::vector<Service*> ret;
     ret.reserve(kDebuggingServices.size());
     for (const auto& s : ServiceList::GetInstance()) {
@@ -181,7 +181,7 @@
 };
 
 // Turn off backlight while we are performing power down cleanup activities.
-static void TurnOffBacklight() {
+static void TurnOffBacklight() REQUIRES(service_lock) {
     Service* service = ServiceList::GetInstance().FindService("blank_screen");
     if (service == nullptr) {
         LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
@@ -589,6 +589,7 @@
     // Start reboot monitor thread
     sem_post(&reboot_semaphore);
 
+    auto lock = std::lock_guard{service_lock};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
     const std::set<std::string> to_starts{"watchdogd"};
     std::vector<Service*> stop_first;
@@ -708,6 +709,7 @@
     // Skip wait for prop if it is in progress
     ResetWaitForProp();
     // Clear EXEC flag if there is one pending
+    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         s->UnSetExec();
     }
@@ -751,6 +753,7 @@
         return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
     }
     EnterShutdown();
+    auto lock = std::lock_guard{service_lock};
     if (!SetProperty("sys.powerctl", "")) {
         return Error() << "Failed to reset sys.powerctl property";
     }
@@ -911,6 +914,7 @@
                 run_fsck = true;
             } else if (cmd_params[1] == "thermal") {
                 // Turn off sources of heat immediately.
+                auto lock = std::lock_guard{service_lock};
                 TurnOffBacklight();
                 // run_fsck is false to avoid delay
                 cmd = ANDROID_RB_THERMOFF;
diff --git a/init/service.cpp b/init/service.cpp
index 665a1b0..b12d11a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -40,7 +40,7 @@
 #include "service_list.h"
 #include "util.h"
 
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
 #include <ApexProperties.sysprop.h>
 #include <android/api-level.h>
 
@@ -303,7 +303,7 @@
         return;
     }
 
-#if defined(__ANDROID__)
+#if INIT_FULL_SOURCES
     static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
 #else
     static bool is_apex_updatable = false;
diff --git a/init/service.h b/init/service.h
index cf3f0c2..d2a4462 100644
--- a/init/service.h
+++ b/init/service.h
@@ -27,12 +27,14 @@
 #include <vector>
 
 #include <android-base/chrono_utils.h>
+#include <android-base/thread_annotations.h>
 #include <cutils/iosched_policy.h>
 
 #include "action.h"
 #include "capabilities.h"
 #include "keyword_map.h"
 #include "parser.h"
+#include "service_lock.h"
 #include "service_utils.h"
 #include "subcontext.h"
 
@@ -77,17 +79,17 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
-    Result<void> ExecStart();
-    Result<void> Start();
-    Result<void> StartIfNotDisabled();
-    Result<void> StartIfPostData();
-    Result<void> Enable();
+    Result<void> ExecStart() REQUIRES(service_lock);
+    Result<void> Start() REQUIRES(service_lock);
+    Result<void> StartIfNotDisabled() REQUIRES(service_lock);
+    Result<void> StartIfPostData() REQUIRES(service_lock);
+    Result<void> Enable() REQUIRES(service_lock);
     void Reset();
     void ResetIfPostData();
     void Stop();
     void Terminate();
     void Timeout();
-    void Restart();
+    void Restart() REQUIRES(service_lock);
     void Reap(const siginfo_t& siginfo);
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
diff --git a/init/service_list.h b/init/service_list.h
index 3b9018b..280a228 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -17,9 +17,13 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 #include <vector>
 
+#include <android-base/thread_annotations.h>
+
 #include "service.h"
+#include "service_lock.h"
 
 namespace android {
 namespace init {
@@ -32,16 +36,16 @@
     ServiceList();
     size_t CheckAllCommands();
 
-    void AddService(std::unique_ptr<Service> service);
-    void RemoveService(const Service& svc);
+    void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
+    void RemoveService(const Service& svc) REQUIRES(service_lock);
     template <class UnaryPredicate>
-    void RemoveServiceIf(UnaryPredicate predicate) {
+    void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
         services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
                         services_.end());
     }
 
     template <typename T, typename F = decltype(&Service::name)>
-    Service* FindService(T value, F function = &Service::name) const {
+    Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
         auto svc = std::find_if(services_.begin(), services_.end(),
                                 [&function, &value](const std::unique_ptr<Service>& s) {
                                     return std::invoke(function, s) == value;
@@ -52,7 +56,7 @@
         return nullptr;
     }
 
-    Service* FindInterface(const std::string& interface_name) {
+    Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
         for (const auto& svc : services_) {
             if (svc->interfaces().count(interface_name) > 0) {
                 return svc.get();
@@ -62,18 +66,20 @@
         return nullptr;
     }
 
-    void DumpState() const;
+    void DumpState() const REQUIRES(service_lock);
 
-    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;
+    auto begin() const REQUIRES(service_lock) { return services_.begin(); }
+    auto end() const REQUIRES(service_lock) { return services_.end(); }
+    const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
+        return services_;
+    }
+    const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
 
     void MarkPostData();
     bool IsPostData();
-    void MarkServicesUpdate();
+    void MarkServicesUpdate() REQUIRES(service_lock);
     bool IsServicesUpdated() const { return services_update_finished_; }
-    void DelayService(const Service& service);
+    void DelayService(const Service& service) REQUIRES(service_lock);
 
     void ResetState() {
         post_data_ = false;
diff --git a/init/service_lock.cpp b/init/service_lock.cpp
new file mode 100644
index 0000000..404d439
--- /dev/null
+++ b/init/service_lock.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "service_lock.h"
+
+namespace android {
+namespace init {
+
+RecursiveMutex service_lock;
+
+}  // namespace init
+}  // namespace android
diff --git a/init/service_lock.h b/init/service_lock.h
new file mode 100644
index 0000000..6b94271
--- /dev/null
+++ b/init/service_lock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+
+namespace android {
+namespace init {
+
+// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
+
+class CAPABILITY("mutex") RecursiveMutex {
+  public:
+    void lock() ACQUIRE() { mutex_.lock(); }
+    void unlock() RELEASE() { mutex_.unlock(); }
+
+  private:
+    std::recursive_mutex mutex_;
+};
+
+extern RecursiveMutex service_lock;
+
+}  // namespace init
+}  // namespace android
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 4b04ba0..51f4c97 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -34,7 +34,7 @@
 #include "service_utils.h"
 #include "util.h"
 
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
 #include <android/api-level.h>
 #include <sys/system_properties.h>
 
@@ -168,6 +168,7 @@
 
     const std::string fullname = interface_name + "/" + instance_name;
 
+    auto lock = std::lock_guard{service_lock};
     for (const auto& svc : *service_list_) {
         if (svc->interfaces().count(fullname) > 0) {
             return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
@@ -598,6 +599,7 @@
         }
     }
 
+    auto lock = std::lock_guard{service_lock};
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 9b2c7d9..064d64d 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -64,6 +64,8 @@
     std::string wait_string;
     Service* service = nullptr;
 
+    auto lock = std::lock_guard{service_lock};
+
     if (SubcontextChildReap(pid)) {
         name = "Subcontext";
     } else {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 3260159..5263c14 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -31,7 +31,7 @@
 #include "proto_utils.h"
 #include "util.h"
 
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
 #include <android/api-level.h>
 #include "property_service.h"
 #include "selabel.h"
diff --git a/init/test_utils/Android.bp b/init/test_utils/Android.bp
deleted file mode 100644
index 1cb05b6..0000000
--- a/init/test_utils/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-cc_library_static {
-    name: "libinit_test_utils",
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Wno-unused-parameter",
-        "-Werror",
-    ],
-    srcs: [
-        "service_utils.cpp",
-    ],
-    shared_libs: [
-        "libcutils",
-        "liblog",
-        "libjsoncpp",
-        "libprotobuf-cpp-lite",
-        "libhidl-gen-utils",
-    ],
-    whole_static_libs: [
-        "libinit",
-        "libpropertyinfoparser",
-    ],
-    static_libs: [
-        "libbase",
-    ],
-    export_include_dirs: ["include"], // for tests
-}
diff --git a/init/util.cpp b/init/util.cpp
index 503c705..24f94ec 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -41,7 +41,7 @@
 #include <cutils/sockets.h>
 #include <selinux/android.h>
 
-#if defined(__ANDROID__)
+#ifdef INIT_FULL_SOURCES
 #include <android/api-level.h>
 #include <sys/system_properties.h>
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 834b20b..1cf2061 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -207,31 +207,37 @@
     // exact entry with time specified in ms or us precision.
     if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
 
-    LogBufferElement* elem =
-        new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
-    if (log_id != LOG_ID_SECURITY) {
-        int prio = ANDROID_LOG_INFO;
-        const char* tag = nullptr;
-        size_t tag_len = 0;
-        if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
-            tag = tagToName(elem->getTag());
-            if (tag) {
-                tag_len = strlen(tag);
-            }
-        } else {
-            prio = *msg;
-            tag = msg + 1;
-            tag_len = strnlen(tag, len - 1);
+    LogBufferElement* elem = new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
+
+    // b/137093665: don't coalesce security messages.
+    if (log_id == LOG_ID_SECURITY) {
+        wrlock();
+        log(elem);
+        unlock();
+
+        return len;
+    }
+
+    int prio = ANDROID_LOG_INFO;
+    const char* tag = nullptr;
+    size_t tag_len = 0;
+    if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
+        tag = tagToName(elem->getTag());
+        if (tag) {
+            tag_len = strlen(tag);
         }
-        if (!__android_log_is_loggable_len(prio, tag, tag_len,
-                                           ANDROID_LOG_VERBOSE)) {
-            // Log traffic received to total
-            wrlock();
-            stats.addTotal(elem);
-            unlock();
-            delete elem;
-            return -EACCES;
-        }
+    } else {
+        prio = *msg;
+        tag = msg + 1;
+        tag_len = strnlen(tag, len - 1);
+    }
+    if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
+        // Log traffic received to total
+        wrlock();
+        stats.addTotal(elem);
+        unlock();
+        delete elem;
+        return -EACCES;
     }
 
     wrlock();