Loading init/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ cc_library_static { "persistent_properties.cpp", "persistent_properties.proto", "property_service.cpp", "property_service.proto", "property_type.cpp", "reboot.cpp", "reboot_utils.cpp", Loading init/builtins.cpp +30 −22 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ using namespace std::literals::string_literals; using android::base::Basename; using android::base::StartsWith; using android::base::unique_fd; using android::fs_mgr::Fstab; using android::fs_mgr::ReadFstabFromFile; Loading Loading @@ -640,12 +641,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) { if (!ReadFstabFromFile(fstab_file, &fstab)) { return Error() << "Could not read fstab"; } auto mount_fstab_return_code = CallFunctionAndHandleProperties(fs_mgr_mount_all, &fstab, mount_mode); if (!mount_fstab_return_code) { return Error() << "Could not call fs_mgr_mount_all(): " << mount_fstab_return_code.error(); } auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode); property_set(prop_name, std::to_string(t.duration().count())); if (import_rc && SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) { Loading @@ -656,7 +652,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) { if (queue_event) { /* queue_fs_event will queue event based on mount_fstab return code * and return processed return code*/ auto queue_fs_result = queue_fs_event(*mount_fstab_return_code); auto queue_fs_result = queue_fs_event(mount_fstab_return_code); if (!queue_fs_result) { return Error() << "queue_fs_event() failed: " << queue_fs_result.error(); } Loading @@ -672,13 +668,8 @@ static Result<void> do_umount_all(const BuiltinArguments& args) { return Error() << "Could not read fstab"; } auto result = CallFunctionAndHandleProperties(fs_mgr_umount_all, &fstab); if (!result) { return Error() << "Could not call fs_mgr_mount_all() " << result.error(); } if (*result != 0) { return Error() << "fs_mgr_mount_all() failed: " << *result; if (auto result = fs_mgr_umount_all(&fstab); result != 0) { return Error() << "umount_fstab() failed " << result; } return {}; } Loading @@ -689,19 +680,23 @@ static Result<void> do_swapon_all(const BuiltinArguments& args) { return Error() << "Could not read fstab '" << args[1] << "'"; } auto result = CallFunctionAndHandleProperties(fs_mgr_swapon_all, fstab); if (!result) { return Error() << "Could not call fs_mgr_swapon_all() " << result.error(); } if (*result == 0) { return Error() << "fs_mgr_swapon_all() failed."; if (!fs_mgr_swapon_all(fstab)) { return Error() << "fs_mgr_swapon_all() failed"; } return {}; } static Result<void> do_setprop(const BuiltinArguments& args) { if (StartsWith(args[1], "ctl.")) { return Error() << "Cannot set ctl. properties from init; call the Service functions directly"; } if (args[1] == kRestoreconProperty) { return Error() << "Cannot set '" << kRestoreconProperty << "' from init; use the restorecon builtin directly"; } property_set(args[1], args[2]); return {}; } Loading Loading @@ -1017,7 +1012,20 @@ static Result<void> do_loglevel(const BuiltinArguments& args) { } static Result<void> do_load_persist_props(const BuiltinArguments& args) { load_persist_props(); // Devices with FDE have load_persist_props called twice; the first time when the temporary // /data partition is mounted and then again once /data is truly mounted. We do not want to // read persistent properties from the temporary /data partition or mark persistent properties // as having been loaded during the first call, so we return in that case. std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); if (crypto_state == "encrypted" && crypto_type == "block") { static size_t num_calls = 0; if (++num_calls == 1) return {}; } SendLoadPersistentPropertiesMessage(); start_waiting_for_property("ro.persistent_properties.ready", "true"); return {}; } Loading init/init.cpp +57 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,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" Loading @@ -69,6 +70,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; Loading @@ -90,6 +92,7 @@ static int property_triggers_enabled = 0; 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; Loading Loading @@ -613,6 +616,54 @@ static void RecordStageBoottimes(const boot_clock::time_point& second_stage_star 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(); } } 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 response = HandleControlMessage(control_message.msg(), control_message.name(), control_message.pid()); auto init_message = InitMessage{}; auto* control_response = init_message.mutable_control_response(); control_response->set_result(response); if (auto result = SendMessage(property_fd, init_message); !result) { LOG(ERROR) << "Failed to send control response: " << result.error(); } 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(); Loading Loading @@ -684,7 +735,12 @@ int SecondStageMain(int argc, char** argv) { 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(); Loading init/init.h +2 −4 Original line number Diff line number Diff line Loading @@ -31,16 +31,14 @@ namespace init { Parser CreateParser(ActionManager& action_manager, ServiceList& service_list); Parser CreateServiceOnlyParser(ServiceList& service_list); bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid); void property_changed(const std::string& name, const std::string& value); bool start_waiting_for_property(const char *name, const char *value); void DumpState(); void ResetWaitForProp(); void SendLoadPersistentPropertiesMessage(); int SecondStageMain(int argc, char** argv); } // namespace init Loading init/property_service.cpp +151 −87 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> #include <atomic> #include <map> #include <memory> #include <mutex> #include <optional> #include <queue> #include <thread> #include <vector> Loading @@ -53,7 +53,6 @@ #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> Loading @@ -61,11 +60,14 @@ #include <selinux/selinux.h> #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" #include "persistent_properties.h" #include "property_type.h" #include "proto_utils.h" #include "selinux.h" #include "subcontext.h" #include "system/core/init/property_service.pb.h" #include "util.h" using namespace std::literals; Loading @@ -87,14 +89,15 @@ using android::properties::PropertyInfoEntry; namespace android { namespace init { static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; static bool persistent_properties_loaded = false; static int property_set_fd = -1; static int init_socket = -1; static PropertyInfoAreaFile property_info_area; uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr, std::string* error); uint32_t InitPropertySet(const std::string& name, const std::string& value); uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet; Loading Loading @@ -166,6 +169,17 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, return has_access; } static void SendPropertyChanged(const std::string& name, const std::string& value) { auto property_msg = PropertyMessage{}; auto* changed_message = property_msg.mutable_changed_message(); changed_message->set_name(name); changed_message->set_value(value); if (auto result = SendMessage(init_socket, property_msg); !result) { LOG(ERROR) << "Failed to send property changed message: " << result.error(); } } static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) { size_t valuelen = value.size(); Loading Loading @@ -201,7 +215,11 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s if (persistent_properties_loaded && StartsWith(name, "persist.")) { WritePersistentProperty(name, value); } property_changed(name, value); // If init hasn't started its main loop, then it won't be handling property changed messages // anyway, so there's no need to try to send them. if (init_socket != -1) { SendPropertyChanged(name, value); } return PROP_SUCCESS; } Loading Loading @@ -242,17 +260,6 @@ class AsyncRestorecon { }; 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 == kRestoreconProperty) { LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty << "' from init; use the restorecon builtin directly"; return PROP_ERROR_INVALID_NAME; } uint32_t result = 0; ucred cr = {.pid = 1, .uid = 0, .gid = 0}; std::string error; Loading @@ -268,8 +275,6 @@ class SocketConnection { public: SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {} ~SocketConnection() { close(socket_); } bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { return RecvFully(value, sizeof(*value), timeout_ms); } Loading Loading @@ -391,12 +396,62 @@ class SocketConnection { return bytes_left == 0; } int socket_; unique_fd socket_; ucred cred_; DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); }; // Init responds with whether or not the control message was successful. However, init may set // properties in the process of handling the control message, particularly when starting services. // Therefore we cannot block in SendControlMessage() to wait for init's response. Instead, we store // the SocketConnection for the socket that sent the control message. We then return to the main // poll loop and handle messages until we get the response from init. // // Note that this is a queue, since it is possible for more control messages to come while init is // handling the first. Both init and property service will handle these in order. // // Also note that the 1st version of the property service does not expect a result to be sent, so // we have a nullopt as a placeholder in the queue to keep track of which control messages have been // responded to. static std::queue<std::optional<SocketConnection>> pending_control_message_results; static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid, std::string* error) { auto property_msg = PropertyMessage{}; auto* control_message = property_msg.mutable_control_message(); control_message->set_msg(msg); control_message->set_name(name); control_message->set_pid(pid); if (auto result = SendMessage(init_socket, property_msg); !result) { *error = "Failed to send control message: " + result.error().message(); return PROP_ERROR_HANDLE_CONTROL_MESSAGE; } return PROP_SUCCESS; } void HandleControlResponse(const InitMessage& init_message) { if (pending_control_message_results.empty()) { LOG(ERROR) << "Got a control response without pending control messages"; return; } if (!pending_control_message_results.front().has_value()) { pending_control_message_results.pop(); return; } if (!pending_control_message_results.front().has_value()) { return; } auto& control_response = init_message.control_response(); uint32_t response = control_response.result() ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; pending_control_message_results.front()->SendUint32(response); pending_control_message_results.pop(); } bool CheckControlPropertyPerms(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr) { // We check the legacy method first but these properties are dontaudit, so we only log an audit Loading Loading @@ -470,9 +525,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value, } if (StartsWith(name, "ctl.")) { return HandleControlMessage(name.c_str() + 4, value, cr.pid) ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; return SendControlMessage(name.c_str() + 4, value, cr.pid, error); } // sys.powerctl is a special property that is used to make the device reboot. We want to log Loading Loading @@ -557,6 +610,10 @@ static void handle_property_set_fd() { << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } if (result == PROP_SUCCESS && StartsWith(prop_name, "ctl.")) { pending_control_message_results.emplace(std::nullopt); } break; } Loading Loading @@ -584,7 +641,12 @@ static void handle_property_set_fd() { LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } if (result == PROP_SUCCESS && StartsWith(name, "ctl.")) { pending_control_message_results.emplace(std::move(socket)); } else { socket.SendUint32(result); } break; } Loading Loading @@ -743,33 +805,6 @@ static void load_override_properties() { } } /* When booting an encrypted system, /data is not mounted when the * property service is started, so any properties stored there are * not loaded. Vold triggers init to load these properties once it * has mounted /data. */ void load_persist_props(void) { // Devices with FDE have load_persist_props called twice; the first time when the temporary // /data partition is mounted and then again once /data is truly mounted. We do not want to // read persistent properties from the temporary /data partition or mark persistent properties // as having been loaded during the first call, so we return in that case. std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); if (crypto_state == "encrypted" && crypto_type == "block") { static size_t num_calls = 0; if (++num_calls == 1) return; } load_override_properties(); /* Read persistent properties after all default values have been loaded. */ auto persistent_properties = LoadPersistentProperties(); for (const auto& persistent_property_record : persistent_properties.properties()) { property_set(persistent_property_record.name(), persistent_property_record.value()); } persistent_properties_loaded = true; property_set("ro.persistent_properties.ready", "true"); } // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly // set, derive them from ro.product.${partition}.* properties static void property_initialize_ro_product_props() { Loading Loading @@ -987,58 +1022,87 @@ void CreateSerializedPropertyInfo() { selinux_android_restorecon(kPropertyInfosPath, 0); } void StartPropertyService(Epoll* epoll) { property_set("ro.property_service.version", "2"); if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, false, 0666, 0, 0, {})) { property_set_fd = *result; } else { PLOG(FATAL) << "start_property_service socket creation failed: " << result.error(); static void HandleInitSocket() { auto message = ReadMessage(init_socket); if (!message) { LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error(); return; } listen(property_set_fd, 8); auto init_message = InitMessage{}; if (!init_message.ParseFromString(*message)) { LOG(ERROR) << "Could not parse message from init"; return; } if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) { PLOG(FATAL) << result.error(); switch (init_message.msg_case()) { case InitMessage::kControlResponse: { HandleControlResponse(init_message); break; } case InitMessage::kLoadPersistentProperties: { load_override_properties(); // Read persistent properties after all default values have been loaded. auto persistent_properties = LoadPersistentProperties(); for (const auto& persistent_property_record : persistent_properties.properties()) { InitPropertySet(persistent_property_record.name(), persistent_property_record.value()); } InitPropertySet("ro.persistent_properties.ready", "true"); persistent_properties_loaded = true; break; } default: LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case(); } 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); }}; static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result) { return Error() << "Could not create epoll: " << result.error(); LOG(FATAL) << 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(); LOG(FATAL) << 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(); if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) { LOG(FATAL) << result.error(); } while (!end) { epoll.Wait({}); while (true) { if (auto result = epoll.Wait(std::nullopt); !result) { LOG(ERROR) << result.error(); } } } thread.join(); void StartPropertyService(int* epoll_socket) { property_set("ro.property_service.version", "2"); return result; int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) { PLOG(FATAL) << "Failed to socketpair() between property_service and init"; } *epoll_socket = sockets[0]; init_socket = sockets[1]; if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC, false, 0666, 0, 0, {})) { property_set_fd = *result; } else { LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); } listen(property_set_fd, 8); std::thread{PropertyServiceThread}.detach(); property_set = [](const std::string& key, const std::string& value) -> uint32_t { android::base::SetProperty(key, value); return 0; }; } } // namespace init Loading Loading
init/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ cc_library_static { "persistent_properties.cpp", "persistent_properties.proto", "property_service.cpp", "property_service.proto", "property_type.cpp", "reboot.cpp", "reboot_utils.cpp", Loading
init/builtins.cpp +30 −22 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ using namespace std::literals::string_literals; using android::base::Basename; using android::base::StartsWith; using android::base::unique_fd; using android::fs_mgr::Fstab; using android::fs_mgr::ReadFstabFromFile; Loading Loading @@ -640,12 +641,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) { if (!ReadFstabFromFile(fstab_file, &fstab)) { return Error() << "Could not read fstab"; } auto mount_fstab_return_code = CallFunctionAndHandleProperties(fs_mgr_mount_all, &fstab, mount_mode); if (!mount_fstab_return_code) { return Error() << "Could not call fs_mgr_mount_all(): " << mount_fstab_return_code.error(); } auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode); property_set(prop_name, std::to_string(t.duration().count())); if (import_rc && SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) { Loading @@ -656,7 +652,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) { if (queue_event) { /* queue_fs_event will queue event based on mount_fstab return code * and return processed return code*/ auto queue_fs_result = queue_fs_event(*mount_fstab_return_code); auto queue_fs_result = queue_fs_event(mount_fstab_return_code); if (!queue_fs_result) { return Error() << "queue_fs_event() failed: " << queue_fs_result.error(); } Loading @@ -672,13 +668,8 @@ static Result<void> do_umount_all(const BuiltinArguments& args) { return Error() << "Could not read fstab"; } auto result = CallFunctionAndHandleProperties(fs_mgr_umount_all, &fstab); if (!result) { return Error() << "Could not call fs_mgr_mount_all() " << result.error(); } if (*result != 0) { return Error() << "fs_mgr_mount_all() failed: " << *result; if (auto result = fs_mgr_umount_all(&fstab); result != 0) { return Error() << "umount_fstab() failed " << result; } return {}; } Loading @@ -689,19 +680,23 @@ static Result<void> do_swapon_all(const BuiltinArguments& args) { return Error() << "Could not read fstab '" << args[1] << "'"; } auto result = CallFunctionAndHandleProperties(fs_mgr_swapon_all, fstab); if (!result) { return Error() << "Could not call fs_mgr_swapon_all() " << result.error(); } if (*result == 0) { return Error() << "fs_mgr_swapon_all() failed."; if (!fs_mgr_swapon_all(fstab)) { return Error() << "fs_mgr_swapon_all() failed"; } return {}; } static Result<void> do_setprop(const BuiltinArguments& args) { if (StartsWith(args[1], "ctl.")) { return Error() << "Cannot set ctl. properties from init; call the Service functions directly"; } if (args[1] == kRestoreconProperty) { return Error() << "Cannot set '" << kRestoreconProperty << "' from init; use the restorecon builtin directly"; } property_set(args[1], args[2]); return {}; } Loading Loading @@ -1017,7 +1012,20 @@ static Result<void> do_loglevel(const BuiltinArguments& args) { } static Result<void> do_load_persist_props(const BuiltinArguments& args) { load_persist_props(); // Devices with FDE have load_persist_props called twice; the first time when the temporary // /data partition is mounted and then again once /data is truly mounted. We do not want to // read persistent properties from the temporary /data partition or mark persistent properties // as having been loaded during the first call, so we return in that case. std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); if (crypto_state == "encrypted" && crypto_type == "block") { static size_t num_calls = 0; if (++num_calls == 1) return {}; } SendLoadPersistentPropertiesMessage(); start_waiting_for_property("ro.persistent_properties.ready", "true"); return {}; } Loading
init/init.cpp +57 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,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" Loading @@ -69,6 +70,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; Loading @@ -90,6 +92,7 @@ static int property_triggers_enabled = 0; 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; Loading Loading @@ -613,6 +616,54 @@ static void RecordStageBoottimes(const boot_clock::time_point& second_stage_star 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(); } } 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 response = HandleControlMessage(control_message.msg(), control_message.name(), control_message.pid()); auto init_message = InitMessage{}; auto* control_response = init_message.mutable_control_response(); control_response->set_result(response); if (auto result = SendMessage(property_fd, init_message); !result) { LOG(ERROR) << "Failed to send control response: " << result.error(); } 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(); Loading Loading @@ -684,7 +735,12 @@ int SecondStageMain(int argc, char** argv) { 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(); Loading
init/init.h +2 −4 Original line number Diff line number Diff line Loading @@ -31,16 +31,14 @@ namespace init { Parser CreateParser(ActionManager& action_manager, ServiceList& service_list); Parser CreateServiceOnlyParser(ServiceList& service_list); bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid); void property_changed(const std::string& name, const std::string& value); bool start_waiting_for_property(const char *name, const char *value); void DumpState(); void ResetWaitForProp(); void SendLoadPersistentPropertiesMessage(); int SecondStageMain(int argc, char** argv); } // namespace init Loading
init/property_service.cpp +151 −87 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> #include <atomic> #include <map> #include <memory> #include <mutex> #include <optional> #include <queue> #include <thread> #include <vector> Loading @@ -53,7 +53,6 @@ #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> Loading @@ -61,11 +60,14 @@ #include <selinux/selinux.h> #include "debug_ramdisk.h" #include "epoll.h" #include "init.h" #include "persistent_properties.h" #include "property_type.h" #include "proto_utils.h" #include "selinux.h" #include "subcontext.h" #include "system/core/init/property_service.pb.h" #include "util.h" using namespace std::literals; Loading @@ -87,14 +89,15 @@ using android::properties::PropertyInfoEntry; namespace android { namespace init { static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; static bool persistent_properties_loaded = false; static int property_set_fd = -1; static int init_socket = -1; static PropertyInfoAreaFile property_info_area; uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr, std::string* error); uint32_t InitPropertySet(const std::string& name, const std::string& value); uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet; Loading Loading @@ -166,6 +169,17 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, return has_access; } static void SendPropertyChanged(const std::string& name, const std::string& value) { auto property_msg = PropertyMessage{}; auto* changed_message = property_msg.mutable_changed_message(); changed_message->set_name(name); changed_message->set_value(value); if (auto result = SendMessage(init_socket, property_msg); !result) { LOG(ERROR) << "Failed to send property changed message: " << result.error(); } } static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) { size_t valuelen = value.size(); Loading Loading @@ -201,7 +215,11 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s if (persistent_properties_loaded && StartsWith(name, "persist.")) { WritePersistentProperty(name, value); } property_changed(name, value); // If init hasn't started its main loop, then it won't be handling property changed messages // anyway, so there's no need to try to send them. if (init_socket != -1) { SendPropertyChanged(name, value); } return PROP_SUCCESS; } Loading Loading @@ -242,17 +260,6 @@ class AsyncRestorecon { }; 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 == kRestoreconProperty) { LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty << "' from init; use the restorecon builtin directly"; return PROP_ERROR_INVALID_NAME; } uint32_t result = 0; ucred cr = {.pid = 1, .uid = 0, .gid = 0}; std::string error; Loading @@ -268,8 +275,6 @@ class SocketConnection { public: SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {} ~SocketConnection() { close(socket_); } bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { return RecvFully(value, sizeof(*value), timeout_ms); } Loading Loading @@ -391,12 +396,62 @@ class SocketConnection { return bytes_left == 0; } int socket_; unique_fd socket_; ucred cred_; DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); }; // Init responds with whether or not the control message was successful. However, init may set // properties in the process of handling the control message, particularly when starting services. // Therefore we cannot block in SendControlMessage() to wait for init's response. Instead, we store // the SocketConnection for the socket that sent the control message. We then return to the main // poll loop and handle messages until we get the response from init. // // Note that this is a queue, since it is possible for more control messages to come while init is // handling the first. Both init and property service will handle these in order. // // Also note that the 1st version of the property service does not expect a result to be sent, so // we have a nullopt as a placeholder in the queue to keep track of which control messages have been // responded to. static std::queue<std::optional<SocketConnection>> pending_control_message_results; static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid, std::string* error) { auto property_msg = PropertyMessage{}; auto* control_message = property_msg.mutable_control_message(); control_message->set_msg(msg); control_message->set_name(name); control_message->set_pid(pid); if (auto result = SendMessage(init_socket, property_msg); !result) { *error = "Failed to send control message: " + result.error().message(); return PROP_ERROR_HANDLE_CONTROL_MESSAGE; } return PROP_SUCCESS; } void HandleControlResponse(const InitMessage& init_message) { if (pending_control_message_results.empty()) { LOG(ERROR) << "Got a control response without pending control messages"; return; } if (!pending_control_message_results.front().has_value()) { pending_control_message_results.pop(); return; } if (!pending_control_message_results.front().has_value()) { return; } auto& control_response = init_message.control_response(); uint32_t response = control_response.result() ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; pending_control_message_results.front()->SendUint32(response); pending_control_message_results.pop(); } bool CheckControlPropertyPerms(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr) { // We check the legacy method first but these properties are dontaudit, so we only log an audit Loading Loading @@ -470,9 +525,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value, } if (StartsWith(name, "ctl.")) { return HandleControlMessage(name.c_str() + 4, value, cr.pid) ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; return SendControlMessage(name.c_str() + 4, value, cr.pid, error); } // sys.powerctl is a special property that is used to make the device reboot. We want to log Loading Loading @@ -557,6 +610,10 @@ static void handle_property_set_fd() { << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } if (result == PROP_SUCCESS && StartsWith(prop_name, "ctl.")) { pending_control_message_results.emplace(std::nullopt); } break; } Loading Loading @@ -584,7 +641,12 @@ static void handle_property_set_fd() { LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } if (result == PROP_SUCCESS && StartsWith(name, "ctl.")) { pending_control_message_results.emplace(std::move(socket)); } else { socket.SendUint32(result); } break; } Loading Loading @@ -743,33 +805,6 @@ static void load_override_properties() { } } /* When booting an encrypted system, /data is not mounted when the * property service is started, so any properties stored there are * not loaded. Vold triggers init to load these properties once it * has mounted /data. */ void load_persist_props(void) { // Devices with FDE have load_persist_props called twice; the first time when the temporary // /data partition is mounted and then again once /data is truly mounted. We do not want to // read persistent properties from the temporary /data partition or mark persistent properties // as having been loaded during the first call, so we return in that case. std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); if (crypto_state == "encrypted" && crypto_type == "block") { static size_t num_calls = 0; if (++num_calls == 1) return; } load_override_properties(); /* Read persistent properties after all default values have been loaded. */ auto persistent_properties = LoadPersistentProperties(); for (const auto& persistent_property_record : persistent_properties.properties()) { property_set(persistent_property_record.name(), persistent_property_record.value()); } persistent_properties_loaded = true; property_set("ro.persistent_properties.ready", "true"); } // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly // set, derive them from ro.product.${partition}.* properties static void property_initialize_ro_product_props() { Loading Loading @@ -987,58 +1022,87 @@ void CreateSerializedPropertyInfo() { selinux_android_restorecon(kPropertyInfosPath, 0); } void StartPropertyService(Epoll* epoll) { property_set("ro.property_service.version", "2"); if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, false, 0666, 0, 0, {})) { property_set_fd = *result; } else { PLOG(FATAL) << "start_property_service socket creation failed: " << result.error(); static void HandleInitSocket() { auto message = ReadMessage(init_socket); if (!message) { LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error(); return; } listen(property_set_fd, 8); auto init_message = InitMessage{}; if (!init_message.ParseFromString(*message)) { LOG(ERROR) << "Could not parse message from init"; return; } if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) { PLOG(FATAL) << result.error(); switch (init_message.msg_case()) { case InitMessage::kControlResponse: { HandleControlResponse(init_message); break; } case InitMessage::kLoadPersistentProperties: { load_override_properties(); // Read persistent properties after all default values have been loaded. auto persistent_properties = LoadPersistentProperties(); for (const auto& persistent_property_record : persistent_properties.properties()) { InitPropertySet(persistent_property_record.name(), persistent_property_record.value()); } InitPropertySet("ro.persistent_properties.ready", "true"); persistent_properties_loaded = true; break; } default: LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case(); } 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); }}; static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result) { return Error() << "Could not create epoll: " << result.error(); LOG(FATAL) << 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(); LOG(FATAL) << 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(); if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) { LOG(FATAL) << result.error(); } while (!end) { epoll.Wait({}); while (true) { if (auto result = epoll.Wait(std::nullopt); !result) { LOG(ERROR) << result.error(); } } } thread.join(); void StartPropertyService(int* epoll_socket) { property_set("ro.property_service.version", "2"); return result; int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) { PLOG(FATAL) << "Failed to socketpair() between property_service and init"; } *epoll_socket = sockets[0]; init_socket = sockets[1]; if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC, false, 0666, 0, 0, {})) { property_set_fd = *result; } else { LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); } listen(property_set_fd, 8); std::thread{PropertyServiceThread}.detach(); property_set = [](const std::string& key, const std::string& value) -> uint32_t { android::base::SetProperty(key, value); return 0; }; } } // namespace init Loading