diff --git a/init/devices.cpp b/init/devices.cpp index ed4a7398a..ba08180c3 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -372,7 +372,7 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d } } -void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) { +void DeviceHandler::HandleUevent(const Uevent& uevent) { if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") { FixupSysPermissions(uevent.path, uevent.subsystem); } @@ -418,6 +418,10 @@ void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) { HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links); } +void DeviceHandler::ColdbootDone() { + skip_restorecon_ = true; +} + DeviceHandler::DeviceHandler(std::vector dev_permissions, std::vector sysfs_permissions, std::vector subsystems, std::set boot_devices, diff --git a/init/devices.h b/init/devices.h index 0be660f80..9d39eaace 100644 --- a/init/devices.h +++ b/init/devices.h @@ -29,6 +29,7 @@ #include #include "uevent.h" +#include "uevent_handler.h" namespace android { namespace init { @@ -105,7 +106,7 @@ class Subsystem { std::string dir_name_ = "/dev"; }; -class DeviceHandler { +class DeviceHandler : public UeventHandler { public: friend class DeviceHandlerTester; @@ -113,11 +114,12 @@ class DeviceHandler { DeviceHandler(std::vector dev_permissions, std::vector sysfs_permissions, std::vector subsystems, std::set boot_devices, bool skip_restorecon); + virtual ~DeviceHandler() = default; - void HandleDeviceEvent(const Uevent& uevent); + void HandleUevent(const Uevent& uevent) override; + void ColdbootDone() override; std::vector GetBlockDeviceSymlinks(const Uevent& uevent) const; - void set_skip_restorecon(bool value) { skip_restorecon_ = value; } private: bool FindPlatformDevice(std::string path, std::string* platform_device_path) const; diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp index 28bda34a2..740e82c99 100644 --- a/init/firmware_handler.cpp +++ b/init/firmware_handler.cpp @@ -35,8 +35,6 @@ using android::base::WriteFully; namespace android { namespace init { -std::vector firmware_directories; - static void LoadFirmware(const Uevent& uevent, const std::string& root, int fw_fd, size_t fw_size, int loading_fd, int data_fd) { // Start transfer. @@ -58,7 +56,10 @@ static bool IsBooting() { return access("/dev/.booting", F_OK) == 0; } -static void ProcessFirmwareEvent(const Uevent& uevent) { +FirmwareHandler::FirmwareHandler(std::vector firmware_directories) + : firmware_directories_(std::move(firmware_directories)) {} + +void FirmwareHandler::ProcessFirmwareEvent(const Uevent& uevent) { int booting = IsBooting(); LOG(INFO) << "firmware: loading '" << uevent.firmware << "' for '" << uevent.path << "'"; @@ -80,7 +81,7 @@ static void ProcessFirmwareEvent(const Uevent& uevent) { } try_loading_again: - for (const auto& firmware_directory : firmware_directories) { + for (const auto& firmware_directory : firmware_directories_) { std::string file = firmware_directory + uevent.firmware; unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC)); struct stat sb; @@ -104,7 +105,7 @@ try_loading_again: write(loading_fd, "-1", 2); } -void HandleFirmwareEvent(const Uevent& uevent) { +void FirmwareHandler::HandleUevent(const Uevent& uevent) { if (uevent.subsystem != "firmware" || uevent.action != "add") return; // Loading the firmware in a child means we can do that in parallel... diff --git a/init/firmware_handler.h b/init/firmware_handler.h index 6081511b5..399609693 100644 --- a/init/firmware_handler.h +++ b/init/firmware_handler.h @@ -21,13 +21,23 @@ #include #include "uevent.h" +#include "uevent_handler.h" namespace android { namespace init { -extern std::vector firmware_directories; +class FirmwareHandler : public UeventHandler { + public: + explicit FirmwareHandler(std::vector firmware_directories); + virtual ~FirmwareHandler() = default; -void HandleFirmwareEvent(const Uevent& uevent); + void HandleUevent(const Uevent& uevent) override; + + private: + void ProcessFirmwareEvent(const Uevent& uevent); + + std::vector firmware_directories_; +}; } // namespace init } // namespace android diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 43075b268..41e8fff55 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -206,7 +206,7 @@ bool FirstStageMount::InitRequiredDevices() { bool found = false; auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) { if (uevent.path == dm_path) { - device_handler_->HandleDeviceEvent(uevent); + device_handler_->HandleUevent(uevent); found = true; return ListenerAction::kStop; } @@ -273,7 +273,7 @@ ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const lp_metadata_partition_ = links[0]; } required_devices_partition_names_.erase(iter); - device_handler_->HandleDeviceEvent(uevent); + device_handler_->HandleUevent(uevent); if (required_devices_partition_names_.empty()) { return ListenerAction::kStop; } else { @@ -310,7 +310,7 @@ bool FirstStageMount::InitMappedDevice(const std::string& dm_device) { auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) { if (uevent.device_name == device_name) { LOG(VERBOSE) << "Creating device-mapper device : " << dm_device; - device_handler_->HandleDeviceEvent(uevent); + device_handler_->HandleUevent(uevent); found = true; return ListenerAction::kStop; } diff --git a/init/modalias_handler.cpp b/init/modalias_handler.cpp index 1734a7e0f..1e0db5731 100644 --- a/init/modalias_handler.cpp +++ b/init/modalias_handler.cpp @@ -139,7 +139,7 @@ Result ModaliasHandler::InsmodWithDeps(const std::string& module_name, return Insmod(dependencies[0], args); } -void ModaliasHandler::HandleModaliasEvent(const Uevent& uevent) { +void ModaliasHandler::HandleUevent(const Uevent& uevent) { if (uevent.modalias.empty()) return; for (const auto& [alias, module] : module_aliases_) { diff --git a/init/modalias_handler.h b/init/modalias_handler.h index e79da3275..3247c86d4 100644 --- a/init/modalias_handler.h +++ b/init/modalias_handler.h @@ -16,22 +16,23 @@ #pragma once -#include "result.h" -#include "uevent.h" - #include #include #include +#include "result.h" +#include "uevent.h" +#include "uevent_handler.h" + namespace android { namespace init { -class ModaliasHandler { +class ModaliasHandler : public UeventHandler { public: ModaliasHandler(); - ~ModaliasHandler(){}; + virtual ~ModaliasHandler() = default; - void HandleModaliasEvent(const Uevent& uevent); + void HandleUevent(const Uevent& uevent) override; private: Result InsmodWithDeps(const std::string& module_name, const std::string& args); diff --git a/init/uevent_handler.h b/init/uevent_handler.h new file mode 100644 index 000000000..75d19902e --- /dev/null +++ b/init/uevent_handler.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "uevent.h" + +namespace android { +namespace init { + +class UeventHandler { + public: + virtual ~UeventHandler() = default; + + virtual void HandleUevent(const Uevent& uevent) = 0; + + virtual void ColdbootDone() {} +}; + +} // namespace init +} // namespace android diff --git a/init/ueventd.cpp b/init/ueventd.cpp index e9d829b51..95be6af52 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -38,6 +38,7 @@ #include "firmware_handler.h" #include "modalias_handler.h" #include "selinux.h" +#include "uevent_handler.h" #include "uevent_listener.h" #include "ueventd_parser.h" #include "util.h" @@ -107,11 +108,10 @@ namespace init { class ColdBoot { public: - ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler, - ModaliasHandler& modalias_handler) + ColdBoot(UeventListener& uevent_listener, + std::vector>& uevent_handlers) : uevent_listener_(uevent_listener), - device_handler_(device_handler), - modalias_handler_(modalias_handler), + uevent_handlers_(uevent_handlers), num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {} void Run(); @@ -124,8 +124,7 @@ class ColdBoot { void WaitForSubProcesses(); UeventListener& uevent_listener_; - DeviceHandler& device_handler_; - ModaliasHandler& modalias_handler_; + std::vector>& uevent_handlers_; unsigned int num_handler_subprocesses_; std::vector uevent_queue_; @@ -136,16 +135,16 @@ class ColdBoot { void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) { for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) { auto& uevent = uevent_queue_[i]; - device_handler_.HandleDeviceEvent(uevent); - modalias_handler_.HandleModaliasEvent(uevent); + + for (auto& uevent_handler : uevent_handlers_) { + uevent_handler->HandleUevent(uevent); + } } _exit(EXIT_SUCCESS); } void ColdBoot::RegenerateUevents() { uevent_listener_.RegenerateUevents([this](const Uevent& uevent) { - HandleFirmwareEvent(uevent); - uevent_queue_.emplace_back(std::move(uevent)); return ListenerAction::kContinue; }); @@ -168,7 +167,6 @@ void ColdBoot::ForkSubProcesses() { void ColdBoot::DoRestoreCon() { selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE); - device_handler_.set_skip_restorecon(false); } void ColdBoot::WaitForSubProcesses() { @@ -234,8 +232,7 @@ int ueventd_main(int argc, char** argv) { SelinuxSetupKernelLogging(); SelabelInitialize(); - DeviceHandler device_handler; - ModaliasHandler modalias_handler; + std::vector> uevent_handlers; UeventListener uevent_listener; { @@ -248,19 +245,27 @@ int ueventd_main(int argc, char** argv) { ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc", "/ueventd." + hardware + ".rc"}); - device_handler = DeviceHandler{std::move(ueventd_configuration.dev_permissions), - std::move(ueventd_configuration.sysfs_permissions), - std::move(ueventd_configuration.subsystems), - fs_mgr_get_boot_devices(), true}; + uevent_handlers.emplace_back(std::make_unique( + std::move(ueventd_configuration.dev_permissions), + std::move(ueventd_configuration.sysfs_permissions), + std::move(ueventd_configuration.subsystems), fs_mgr_get_boot_devices(), true)); + uevent_handlers.emplace_back(std::make_unique( + std::move(ueventd_configuration.firmware_directories))); - firmware_directories = ueventd_configuration.firmware_directories; + if (ueventd_configuration.enable_modalias_handling) { + uevent_handlers.emplace_back(std::make_unique()); + } } if (access(COLDBOOT_DONE, F_OK) != 0) { - ColdBoot cold_boot(uevent_listener, device_handler, modalias_handler); + ColdBoot cold_boot(uevent_listener, uevent_handlers); cold_boot.Run(); } + for (auto& uevent_handler : uevent_handlers) { + uevent_handler->ColdbootDone(); + } + // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now. signal(SIGCHLD, SIG_IGN); // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN @@ -268,10 +273,10 @@ int ueventd_main(int argc, char** argv) { while (waitpid(-1, nullptr, WNOHANG) > 0) { } - uevent_listener.Poll([&device_handler, &modalias_handler](const Uevent& uevent) { - HandleFirmwareEvent(uevent); - modalias_handler.HandleModaliasEvent(uevent); - device_handler.HandleDeviceEvent(uevent); + uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) { + for (auto& uevent_handler : uevent_handlers) { + uevent_handler->HandleUevent(uevent); + } return ListenerAction::kContinue; }); diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp index 54b0d16aa..677938e10 100644 --- a/init/ueventd_parser.cpp +++ b/init/ueventd_parser.cpp @@ -84,6 +84,23 @@ Result ParseFirmwareDirectoriesLine(std::vector&& args, return Success(); } +Result ParseModaliasHandlingLine(std::vector&& args, + bool* enable_modalias_handling) { + if (args.size() != 2) { + return Error() << "modalias_handling lines take exactly one parameter"; + } + + if (args[1] == "enabled") { + *enable_modalias_handling = true; + } else if (args[1] == "disabled") { + *enable_modalias_handling = false; + } else { + return Error() << "modalias_handling takes either 'enabled' or 'disabled' as a parameter"; + } + + return Success(); +} + class SubsystemParser : public SectionParser { public: SubsystemParser(std::vector* subsystems) : subsystems_(subsystems) {} @@ -182,6 +199,9 @@ UeventdConfiguration ParseConfig(const std::vector& configs) { parser.AddSingleLineParser("firmware_directories", std::bind(ParseFirmwareDirectoriesLine, _1, &ueventd_configuration.firmware_directories)); + parser.AddSingleLineParser("modalias_handling", + std::bind(ParseModaliasHandlingLine, _1, + &ueventd_configuration.enable_modalias_handling)); for (const auto& config : configs) { parser.ParseConfig(config); diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h index 343d58bfd..7d30edf4f 100644 --- a/init/ueventd_parser.h +++ b/init/ueventd_parser.h @@ -30,6 +30,7 @@ struct UeventdConfiguration { std::vector sysfs_permissions; std::vector dev_permissions; std::vector firmware_directories; + bool enable_modalias_handling = false; }; UeventdConfiguration ParseConfig(const std::vector& configs);