Reland^2: "init: run property service in a thread"
It's been a long standing issue that init cannot respond to property
set messages when it is running a builtin command. This is
particularly problematic when the commands involve IPC to vold or
other daemons, as it prevents them from being able to set properties.
This change has init run property service in a thread, which
eliminates the above issue.
This change may also serve as a starting block to running property
service in an entirely different process to better isolate init from
handling property requests.
Reland: during reboot, init stops processing property_changed messages
from property service, since it will not act on these anyway. This
had an unexpected effect of causing future property_set calls to block
indefinitely, since the buffer between init and property_service was
filling up and the send() call from property_service would then
block. This change has init tell property_service to stop sending it
property_changed messages once reboot begins.
Test: CF boots, walleye boots, properties are set appropriately
Change-Id: I26902708e8be788caa6dbcf4b6d2968d90962785
diff --git a/init/init.cpp b/init/init.cpp
index d4cbb5f..ec3eb3c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -28,6 +28,9 @@
#include <sys/types.h>
#include <unistd.h>
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
#include <functional>
#include <map>
#include <memory>
@@ -61,6 +64,7 @@
#include "mount_handler.h"
#include "mount_namespace.h"
#include "property_service.h"
+#include "proto_utils.h"
#include "reboot.h"
#include "reboot_utils.h"
#include "security.h"
@@ -69,6 +73,7 @@
#include "service.h"
#include "service_parser.h"
#include "sigchld_handler.h"
+#include "system/core/init/property_service.pb.h"
#include "util.h"
using namespace std::chrono_literals;
@@ -90,6 +95,7 @@
static char qemu[32];
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;
@@ -615,6 +621,60 @@
selinux_start_time_ns));
}
+void SendLoadPersistentPropertiesMessage() {
+ auto init_message = InitMessage{};
+ init_message.set_load_persistent_properties(true);
+ if (auto result = SendMessage(property_fd, init_message); !result) {
+ LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+ }
+}
+
+void SendStopSendingMessagesMessage() {
+ auto init_message = InitMessage{};
+ init_message.set_stop_sending_messages(true);
+ if (auto result = SendMessage(property_fd, init_message); !result) {
+ LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+ }
+}
+
+static void HandlePropertyFd() {
+ auto message = ReadMessage(property_fd);
+ if (!message) {
+ 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();
@@ -686,7 +746,12 @@
UmountDebugRamdisk();
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
- StartPropertyService(&epoll);
+
+ StartPropertyService(&property_fd);
+ if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
+ LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
+ }
+
MountHandler mount_handler(&epoll);
set_usb_controller();