init: Run restorecon_recursive asynchronously
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
This commit is contained in:
parent
243ab9cc7e
commit
62696908ff
|
@ -39,6 +39,7 @@
|
|||
#include <sys/_system_properties.h>
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
@ -162,7 +163,7 @@ bool is_legal_property_name(const std::string& name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32_t property_set(const std::string& name, const std::string& value) {
|
||||
static uint32_t PropertySetImpl(const std::string& name, const std::string& value) {
|
||||
size_t valuelen = value.size();
|
||||
|
||||
if (!is_legal_property_name(name)) {
|
||||
|
@ -176,12 +177,6 @@ uint32_t property_set(const std::string& name, const std::string& value) {
|
|||
return PROP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (name == "selinux.restorecon_recursive" && valuelen > 0) {
|
||||
if (selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
|
||||
LOG(ERROR) << "Failed to restorecon_recursive " << value;
|
||||
}
|
||||
}
|
||||
|
||||
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
|
||||
if (pi != nullptr) {
|
||||
// ro.* properties are actually "write-once".
|
||||
|
@ -210,6 +205,85 @@ uint32_t property_set(const std::string& name, const std::string& value) {
|
|||
return PROP_SUCCESS;
|
||||
}
|
||||
|
||||
typedef int (*PropertyAsyncFunc)(const std::string&, const std::string&);
|
||||
|
||||
struct PropertyChildInfo {
|
||||
pid_t pid;
|
||||
PropertyAsyncFunc func;
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
if (PropertySetImpl(info.name, info.value) != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Failed to set async property " << info.name;
|
||||
}
|
||||
property_children.pop();
|
||||
if (!property_children.empty()) {
|
||||
PropertyChildLaunch();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
|
||||
PropertyAsyncFunc func) {
|
||||
if (value.empty()) {
|
||||
return PropertySetImpl(name, value);
|
||||
}
|
||||
|
||||
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 property_set(const std::string& name, const std::string& value) {
|
||||
if (name == "selinux.restorecon_recursive") {
|
||||
return PropertySetAsync(name, value, RestoreconRecursiveAsync);
|
||||
}
|
||||
|
||||
return PropertySetImpl(name, value);
|
||||
}
|
||||
|
||||
class SocketConnection {
|
||||
public:
|
||||
SocketConnection(int socket, const struct ucred& cred)
|
||||
|
|
|
@ -26,6 +26,8 @@ struct property_audit_data {
|
|||
const char* name;
|
||||
};
|
||||
|
||||
extern bool PropertyChildReap(pid_t pid);
|
||||
|
||||
void property_init(void);
|
||||
void property_load_boot_defaults(void);
|
||||
void load_persist_props(void);
|
||||
|
|
|
@ -1085,6 +1085,8 @@ bool ServiceManager::ReapOneProcess() {
|
|||
} else if (pid == -1) {
|
||||
PLOG(ERROR) << "waitpid failed";
|
||||
return false;
|
||||
} else if (PropertyChildReap(pid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Service* svc = FindServiceByPid(pid);
|
||||
|
|
Loading…
Reference in New Issue