OSDN Git Service

init: Run restorecon_recursive asynchronously
authorTom Marshall <tdm.code@gmail.com>
Fri, 9 Jun 2017 18:07:34 +0000 (18:07 +0000)
committerMichael Bestas <mkbestas@lineageos.org>
Tue, 20 Jun 2017 10:48:56 +0000 (10:48 +0000)
restorecon_recursive may take a long time if there are a lot of files on
the volume.  This can trigger a watchdog timeout in any process that
tries to set a property while it is running.  Fix this by running
restorecon_recursive in its own process.

See https://jira.lineageos.org/browse/BUGBASH-555

Change-Id: I2ce26ff2b5bfc9a133ea42f4dbac50a3ac289c04

init/property_service.cpp
init/property_service.h
init/service.cpp

index 8644329..fc14796 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/poll.h>
 
 #include <memory>
+#include <queue>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -201,16 +202,6 @@ static int property_set_impl(const char* name, const char* value) {
     if (!is_legal_property_name(name, namelen)) return -1;
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
-    if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
-        if (selinux_reload_policy() != 0) {
-            ERROR("Failed to reload policy\n");
-        }
-    } else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
-        if (restorecon_recursive(value) != 0) {
-            ERROR("Failed to restorecon_recursive %s\n", value);
-        }
-    }
-
     prop_info* pi = (prop_info*) __system_property_find(name);
 
     if(pi != 0) {
@@ -247,7 +238,108 @@ static int property_set_impl(const char* name, const char* value) {
     return 0;
 }
 
+typedef int (*property_async_func_t)(const char* name, const char* value);
+
+struct property_child_info {
+    pid_t                       pid;
+    property_async_func_t       func;
+    char*                       name;
+    char*                       value;
+};
+
+static std::queue<property_child_info> property_children;
+
+static void property_child_launch(void)
+{
+    auto& info = property_children.front();
+    pid_t pid = fork();
+    if (pid < 0) {
+        ERROR("Failed to fork property child process\n");
+        while (!property_children.empty()) {
+            info = property_children.front();
+            free(info.name);
+            free(info.value);
+            property_children.pop();
+        }
+        return;
+    }
+    if (pid != 0) {
+        info.pid = pid;
+    }
+    else {
+        if (info.func(info.name, info.value) != 0) {
+            ERROR("Failed to set async property %s\n", info.name);
+        }
+
+        exit(0);
+    }
+}
+
+bool property_child_reap(pid_t pid)
+{
+    if (property_children.empty()) {
+        return false;
+    }
+    auto& info = property_children.front();
+    if (info.pid != pid) {
+        return false;
+    }
+    int rc = property_set_impl(info.name, info.value);
+    if (rc != 0) {
+        ERROR("property_set(\"%s\", \"%s\") failed\n", info.name, info.value);
+    }
+    free(info.name);
+    free(info.value);
+    property_children.pop();
+    if (property_children.size() > 0) {
+        property_child_launch();
+    }
+    return true;
+}
+
+static bool property_set_async(const char* name,
+                               const char* value,
+                               property_async_func_t func)
+{
+    if (!*value) {
+        int rc = property_set_impl(name, value);
+        return (rc == 0);
+    }
+
+    property_child_info info;
+    memset(&info, 0, sizeof(info));
+    info.func = func;
+    info.name = strdup(name);
+    info.value = strdup(value);
+    property_children.push(info);
+    if (property_children.size() == 1) {
+        ERROR("property_set_async: launch child\n");
+        property_child_launch();
+    }
+    return true;
+}
+
+static int restorecon_recursive_async(const char* name, const char* value)
+{
+    return restorecon_recursive(value);
+}
+
 int property_set(const char* name, const char* value) {
+
+    // Handle magic properties
+    if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
+        if (selinux_reload_policy() != 0) {
+            ERROR("Failed to reload policy\n");
+        }
+    } else if (strcmp("selinux.restorecon_recursive", name) == 0 ||
+               strncmp("selinux.restorecon_recursive.", name,
+                       strlen("selinux.restorecon_recursive.")) == 0) {
+        if (!property_set_async(name, value, restorecon_recursive_async)) {
+            ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
+        }
+        return 0;
+    }
+
     int rc = property_set_impl(name, value);
     if (rc == -1) {
         ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
index aa92fa5..8735eea 100644 (file)
@@ -27,6 +27,8 @@ struct property_audit_data {
     const char* name;
 };
 
+extern bool property_child_reap(pid_t pid);
+
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
index 76e0bc8..8127e70 100644 (file)
@@ -780,6 +780,8 @@ bool ServiceManager::ReapOneProcess() {
     } else if (pid == -1) {
         ERROR("waitpid failed: %s\n", strerror(errno));
         return false;
+    } else if (property_child_reap(pid)) {
+        return true;
     }
 
     Service* svc = FindServiceByPid(pid);