Merge "libion: convert a header file using update_all.py"
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index cb09433..8979b0c 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -1253,7 +1253,12 @@
         echo 1 reboot,empty # negative test (ID for unknown is 1)
         ;;
       reboot)
-        echo 1 reboo        # negative test (ID for unknown is 1)
+        echo 1 reboog       # negative test (ID for unknown is 1)
+        ;;
+      'reboot,pmic_off_fault,.*')
+        echo ${id} reboot,pmic_off_fault,hello,world
+        echo ${id} reboot,pmic_off_fault,
+        echo 1 reboot,pmic_off_fault
         ;;
     esac
     echo ${id} "${match}"   # matches b/c of exact
@@ -1266,6 +1271,8 @@
 - (wait until screen is up, boot has completed)
 - read bootstat for kBootReasonMap entries and test them all" ]
 test_kBootReasonMap() {
+  checkDebugBuild || return
+  duration_test 15
   local tempfile="`mktemp`"
   local arg=--boot_reason_enum
   adb_su bootstat ${arg} </dev/null 2>/dev/null |
@@ -1295,7 +1302,8 @@
   report_bootstat_logs -t${T} \
     '-bootstat: Service started: bootstat --boot_reason_enum=' \
     '-bootstat: Unknown boot reason: reboot,empty' \
-    '-bootstat: Unknown boot reason: reboo'
+    '-bootstat: Unknown boot reason: reboog' \
+    '-bootstat: Unknown boot reason: reboot,pmic_off_fault'
 }
 
 [ "USAGE: ${progname} [-s SERIAL] [tests]...
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 617ea4f..558e6c4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -301,6 +301,9 @@
     {"reboot,dm-verity_device_corrupted", 172},
     {"reboot,dm-verity_enforcing", 173},
     {"reboot,keys_clear", 174},
+    {"reboot,pmic_off_fault,.*", 175},
+    {"reboot,pmic_off_s3rst,.*", 176},
+    {"reboot,pmic_off_other,.*", 177},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 9766584..a1e9551 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -41,7 +41,9 @@
 
 #include <map>
 #include <memory>
+#include <mutex>
 #include <queue>
+#include <thread>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -83,6 +85,8 @@
 namespace android {
 namespace init {
 
+static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
+
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
@@ -204,88 +208,51 @@
     return PROP_SUCCESS;
 }
 
-typedef int (*PropertyAsyncFunc)(const std::string&, const std::string&);
+class AsyncRestorecon {
+  public:
+    void TriggerRestorecon(const std::string& path) {
+        auto guard = std::lock_guard{mutex_};
+        paths_.emplace(path);
 
-struct PropertyChildInfo {
-    pid_t pid;
-    PropertyAsyncFunc func;
-    std::string name;
-    std::string value;
+        if (!thread_started_) {
+            thread_started_ = true;
+            std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
+        }
+    }
+
+  private:
+    void ThreadFunction() {
+        auto lock = std::unique_lock{mutex_};
+
+        while (!paths_.empty()) {
+            auto path = paths_.front();
+            paths_.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);
+            lock.lock();
+        }
+
+        thread_started_ = false;
+    }
+
+    std::mutex mutex_;
+    std::queue<std::string> paths_;
+    bool thread_started_ = false;
 };
 
-static std::queue<PropertyChildInfo> property_children;
-
-static void PropertyChildLaunch() {
-    auto& info = property_children.front();
-    pid_t pid = fork();
-    if (pid < 0) {
-        LOG(ERROR) << "Failed to fork for property_set_async";
-        while (!property_children.empty()) {
-            property_children.pop();
-        }
-        return;
-    }
-    if (pid != 0) {
-        info.pid = pid;
-    } else {
-        if (info.func(info.name, info.value) != 0) {
-            LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value
-                       << "\") failed";
-        }
-        _exit(0);
-    }
-}
-
-bool PropertyChildReap(pid_t pid) {
-    if (property_children.empty()) {
-        return false;
-    }
-    auto& info = property_children.front();
-    if (info.pid != pid) {
-        return false;
-    }
-    std::string error;
-    if (PropertySet(info.name, info.value, &error) != PROP_SUCCESS) {
-        LOG(ERROR) << "Failed to set async property " << info.name << " to " << info.value << ": "
-                   << error;
-    }
-    property_children.pop();
-    if (!property_children.empty()) {
-        PropertyChildLaunch();
-    }
-    return true;
-}
-
-static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
-                                 PropertyAsyncFunc func, std::string* error) {
-    if (value.empty()) {
-        return PropertySet(name, value, error);
-    }
-
-    PropertyChildInfo info;
-    info.func = func;
-    info.name = name;
-    info.value = value;
-    property_children.push(info);
-    if (property_children.size() == 1) {
-        PropertyChildLaunch();
-    }
-    return PROP_SUCCESS;
-}
-
-static int RestoreconRecursiveAsync(const std::string& name, const std::string& value) {
-    return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
-}
-
 uint32_t InitPropertySet(const std::string& name, const std::string& value) {
     if (StartsWith(name, "ctl.")) {
         LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
                       "functions directly";
         return PROP_ERROR_INVALID_NAME;
     }
-    if (name == "selinux.restorecon_recursive") {
-        LOG(ERROR) << "InitPropertySet: Do not set selinux.restorecon_recursive from init; use the "
-                      "restorecon builtin directly";
+    if (name == kRestoreconProperty) {
+        LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty
+                   << "' from init; use the restorecon builtin directly";
         return PROP_ERROR_INVALID_NAME;
     }
 
@@ -525,8 +492,14 @@
                   << process_log_string;
     }
 
-    if (name == "selinux.restorecon_recursive") {
-        return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
+    // If a process other than init is writing a non-empty value, it means that process is
+    // requesting that init performs a restorecon operation on the path specified by 'value'.
+    // 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);
+        return PROP_SUCCESS;
     }
 
     return PropertySet(name, value, error);
@@ -692,7 +665,7 @@
             }
 
             if (StartsWith(key, "ctl.") || key == "sys.powerctl"s ||
-                key == "selinux.restorecon_recursive"s) {
+                std::string{key} == kRestoreconProperty) {
                 LOG(ERROR) << "Ignoring disallowed property '" << key
                            << "' with special meaning in prop file '" << filename << "'";
                 continue;
diff --git a/init/property_service.h b/init/property_service.h
index 207c03b..7f9f844 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,8 +32,6 @@
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                            const std::string& source_context, const ucred& cr, std::string* error);
 
-extern bool PropertyChildReap(pid_t pid);
-
 void property_init();
 void property_load_boot_defaults(bool load_debug_prop);
 void load_persist_props();
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 0b03324..987b2f9 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -29,7 +29,6 @@
 #include <android-base/stringprintf.h>
 
 #include "init.h"
-#include "property_service.h"
 #include "service.h"
 
 using android::base::StringPrintf;
@@ -61,9 +60,7 @@
     std::string wait_string;
     Service* service = nullptr;
 
-    if (PropertyChildReap(pid)) {
-        name = "Async property child";
-    } else if (SubcontextChildReap(pid)) {
+    if (SubcontextChildReap(pid)) {
         name = "Subcontext";
     } else {
         service = ServiceList::GetInstance().FindService(pid, &Service::pid);