init: Handle properties in the background of calling fs_mgr
It's been a long standing problem that init calls fs_mgr functions
synchronously and therefore stops handling properties, which causes
deadlocks if either fs_mgr, or vdc, or vold attempt to set
properties.
Previous work, b/21904461, shows that there is a large performance
penalty for adding any amount of locking to properties, so moving
property service into its own thread generically is not a viable
option. However, we can be sure that init is not setting properties
while the fs_mgr functions are running, so we can poll the property
socket in a thread while we call these functions.
The other alternative would have been to separate the fs_mgr functions
into smaller pieces and revisit the main init loop between each
piece. Unfortunately, this would be difficult, since
fs_mgr_mount_all() calls out to different processes via logwrapper,
which synchronously polls on a logging FD from the child, among other
complexities that would make this strategy much more difficult than it
would be worth.
Bug: 21904461
Test: device boots, including when setting property in
fs_mgr_mount_all()
Change-Id: Ib0b7123024035884f9d90f9b489c1e2f5a2e1707
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 14bb819..1520c9f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -39,6 +39,7 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <atomic>
#include <map>
#include <memory>
#include <mutex>
@@ -52,6 +53,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <property_info_parser/property_info_parser.h>
#include <property_info_serializer/property_info_serializer.h>
#include <selinux/android.h>
@@ -59,7 +61,6 @@
#include <selinux/selinux.h>
#include "debug_ramdisk.h"
-#include "epoll.h"
#include "init.h"
#include "persistent_properties.h"
#include "property_type.h"
@@ -76,6 +77,7 @@
using android::base::StringPrintf;
using android::base::Timer;
using android::base::Trim;
+using android::base::unique_fd;
using android::base::WriteStringToFile;
using android::properties::BuildTrie;
using android::properties::ParsePropertyInfoFile;
@@ -1006,5 +1008,42 @@
}
}
+Result<int> CallFunctionAndHandlePropertiesImpl(const std::function<int()>& f) {
+ unique_fd reader;
+ unique_fd writer;
+ if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &reader, &writer)) {
+ return ErrnoError() << "Could not create socket pair";
+ }
+
+ int result = 0;
+ std::atomic<bool> end = false;
+ auto thread = std::thread{[&f, &result, &end, &writer] {
+ result = f();
+ end = true;
+ send(writer, "1", 1, 0);
+ }};
+
+ Epoll epoll;
+ if (auto result = epoll.Open(); !result) {
+ return Error() << "Could not create epoll: " << result.error();
+ }
+ if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
+ return Error() << "Could not register epoll handler for property fd: " << result.error();
+ }
+
+ // No-op function, just used to break from loop.
+ if (auto result = epoll.RegisterHandler(reader, [] {}); !result) {
+ return Error() << "Could not register epoll handler for ending thread:" << result.error();
+ }
+
+ while (!end) {
+ epoll.Wait({});
+ }
+
+ thread.join();
+
+ return result;
+}
+
} // namespace init
} // namespace android