Merge changes Ice773436,Ib8a4835c into rvc-dev
* changes: init: handle property messages asynchronously #2 Revert "init: handle property service callbacks asynchronously"
This commit is contained in:
commit
adc2a7c520
17 changed files with 128 additions and 328 deletions
|
|
@ -28,7 +28,6 @@ init_common_sources = [
|
|||
"rlimit_parser.cpp",
|
||||
"service.cpp",
|
||||
"service_list.cpp",
|
||||
"service_lock.cpp",
|
||||
"service_parser.cpp",
|
||||
"service_utils.cpp",
|
||||
"subcontext.cpp",
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ static Result<void> reboot_into_recovery(const std::vector<std::string>& options
|
|||
|
||||
template <typename F>
|
||||
static void ForEachServiceInClass(const std::string& classname, F function) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
if (service->classnames().count(classname)) std::invoke(function, service);
|
||||
}
|
||||
|
|
@ -163,7 +162,6 @@ static Result<void> do_class_start(const BuiltinArguments& args) {
|
|||
return {};
|
||||
// Starting a class does not start services which are explicitly disabled.
|
||||
// They must be started individually.
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
if (service->classnames().count(args[1])) {
|
||||
if (auto result = service->StartIfNotDisabled(); !result.ok()) {
|
||||
|
|
@ -186,7 +184,6 @@ static Result<void> do_class_start_post_data(const BuiltinArguments& args) {
|
|||
// stopped either.
|
||||
return {};
|
||||
}
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
if (service->classnames().count(args[1])) {
|
||||
if (auto result = service->StartIfPostData(); !result.ok()) {
|
||||
|
|
@ -237,7 +234,6 @@ static Result<void> do_domainname(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_enable(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "Could not find service";
|
||||
|
||||
|
|
@ -249,7 +245,6 @@ static Result<void> do_enable(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_exec(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
auto service = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!service.ok()) {
|
||||
return Error() << "Could not create exec service: " << service.error();
|
||||
|
|
@ -263,7 +258,6 @@ static Result<void> do_exec(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_exec_background(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
auto service = Service::MakeTemporaryOneshotService(args.args);
|
||||
if (!service.ok()) {
|
||||
return Error() << "Could not create exec background service: " << service.error();
|
||||
|
|
@ -277,7 +271,6 @@ static Result<void> do_exec_background(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_exec_start(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* service = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!service) {
|
||||
return Error() << "Service not found";
|
||||
|
|
@ -347,7 +340,6 @@ static Result<void> do_insmod(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_interface_restart(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
|
||||
if (!svc) return Error() << "interface " << args[1] << " not found";
|
||||
svc->Restart();
|
||||
|
|
@ -355,7 +347,6 @@ static Result<void> do_interface_restart(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_interface_start(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
|
||||
if (!svc) return Error() << "interface " << args[1] << " not found";
|
||||
if (auto result = svc->Start(); !result.ok()) {
|
||||
|
|
@ -365,7 +356,6 @@ static Result<void> do_interface_start(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_interface_stop(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
|
||||
if (!svc) return Error() << "interface " << args[1] << " not found";
|
||||
svc->Stop();
|
||||
|
|
@ -750,7 +740,6 @@ static Result<void> do_setrlimit(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_start(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "service " << args[1] << " not found";
|
||||
if (auto result = svc->Start(); !result.ok()) {
|
||||
|
|
@ -760,7 +749,6 @@ static Result<void> do_start(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_stop(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "service " << args[1] << " not found";
|
||||
svc->Stop();
|
||||
|
|
@ -768,7 +756,6 @@ static Result<void> do_stop(const BuiltinArguments& args) {
|
|||
}
|
||||
|
||||
static Result<void> do_restart(const BuiltinArguments& args) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) return Error() << "service " << args[1] << " not found";
|
||||
svc->Restart();
|
||||
|
|
@ -1124,7 +1111,6 @@ static Result<void> ExecWithFunctionOnFailure(const std::vector<std::string>& ar
|
|||
function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
|
||||
}
|
||||
});
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
if (auto result = (*service)->ExecStart(); !result.ok()) {
|
||||
function("ExecStart failed: " + result.error().message());
|
||||
}
|
||||
|
|
@ -1264,7 +1250,6 @@ static Result<void> parse_apex_configs() {
|
|||
}
|
||||
success &= parser.ParseConfigFile(c);
|
||||
}
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
if (success) {
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -99,6 +99,15 @@ static int property_fd = -1;
|
|||
|
||||
static std::unique_ptr<Subcontext> subcontext;
|
||||
|
||||
struct PendingControlMessage {
|
||||
std::string message;
|
||||
std::string name;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
};
|
||||
static std::mutex pending_control_messages_lock;
|
||||
static std::queue<PendingControlMessage> pending_control_messages;
|
||||
|
||||
// Init epolls various FDs to wait for various inputs. It previously waited on property changes
|
||||
// with a blocking socket that contained the information related to the change, however, it was easy
|
||||
// to fill that socket and deadlock the system. Now we use locks to handle the property changes
|
||||
|
|
@ -120,7 +129,7 @@ static void InstallInitNotifier(Epoll* epoll) {
|
|||
}
|
||||
};
|
||||
|
||||
if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
|
||||
if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) {
|
||||
LOG(FATAL) << result.error();
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +247,6 @@ static class ShutdownState {
|
|||
} shutdown_state;
|
||||
|
||||
void DumpState() {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
ServiceList::GetInstance().DumpState();
|
||||
ActionManager::GetInstance().DumpState();
|
||||
}
|
||||
|
|
@ -312,7 +320,6 @@ void PropertyChanged(const std::string& name, const std::string& value) {
|
|||
|
||||
static std::optional<boot_clock::time_point> HandleProcessActions() {
|
||||
std::optional<boot_clock::time_point> next_process_action_time;
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
|
||||
auto timeout_time = s->time_started() + *s->timeout_period();
|
||||
|
|
@ -341,7 +348,7 @@ static std::optional<boot_clock::time_point> HandleProcessActions() {
|
|||
return next_process_action_time;
|
||||
}
|
||||
|
||||
static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
|
||||
static Result<void> DoControlStart(Service* service) {
|
||||
return service->Start();
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +357,7 @@ static Result<void> DoControlStop(Service* service) {
|
|||
return {};
|
||||
}
|
||||
|
||||
static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
|
||||
static Result<void> DoControlRestart(Service* service) {
|
||||
service->Restart();
|
||||
return {};
|
||||
}
|
||||
|
|
@ -384,7 +391,7 @@ static const std::map<std::string, ControlMessageFunction>& get_control_message_
|
|||
return control_message_functions;
|
||||
}
|
||||
|
||||
bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
|
||||
bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
|
||||
const auto& map = get_control_message_map();
|
||||
const auto it = map.find(msg);
|
||||
|
||||
|
|
@ -393,7 +400,7 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
|
||||
std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
|
||||
std::string process_cmdline;
|
||||
if (ReadFileToString(cmdline_path, &process_cmdline)) {
|
||||
std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
|
||||
|
|
@ -404,8 +411,6 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t
|
|||
|
||||
const ControlMessageFunction& function = it->second;
|
||||
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
|
||||
Service* svc = nullptr;
|
||||
|
||||
switch (function.target) {
|
||||
|
|
@ -423,22 +428,59 @@ bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t
|
|||
|
||||
if (svc == nullptr) {
|
||||
LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
|
||||
<< " from pid: " << from_pid << " (" << process_cmdline << ")";
|
||||
<< " from pid: " << pid << " (" << process_cmdline << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto result = function.action(svc); !result.ok()) {
|
||||
LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
|
||||
<< "' from pid: " << from_pid << " (" << process_cmdline
|
||||
<< "): " << result.error();
|
||||
<< "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
|
||||
<< "' from pid: " << from_pid << " (" << process_cmdline << ")";
|
||||
<< "' from pid: " << pid << " (" << process_cmdline << ")";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd) {
|
||||
auto lock = std::lock_guard{pending_control_messages_lock};
|
||||
if (pending_control_messages.size() > 100) {
|
||||
LOG(ERROR) << "Too many pending control messages, dropped '" << message << "' for '" << name
|
||||
<< "' from pid: " << pid;
|
||||
return false;
|
||||
}
|
||||
pending_control_messages.push({message, name, pid, fd});
|
||||
WakeEpoll();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HandleControlMessages() {
|
||||
auto lock = std::unique_lock{pending_control_messages_lock};
|
||||
// Init historically would only execute handle one property message, including control messages
|
||||
// in each iteration of its main loop. We retain this behavior here to prevent starvation of
|
||||
// other actions in the main loop.
|
||||
if (!pending_control_messages.empty()) {
|
||||
auto control_message = pending_control_messages.front();
|
||||
pending_control_messages.pop();
|
||||
lock.unlock();
|
||||
|
||||
bool success = HandleControlMessage(control_message.message, control_message.name,
|
||||
control_message.pid);
|
||||
|
||||
uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
||||
if (control_message.fd != -1) {
|
||||
TEMP_FAILURE_RETRY(send(control_message.fd, &response, sizeof(response), 0));
|
||||
close(control_message.fd);
|
||||
}
|
||||
lock.lock();
|
||||
}
|
||||
// If we still have items to process, make sure we wake back up to do so.
|
||||
if (!pending_control_messages.empty()) {
|
||||
WakeEpoll();
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
|
||||
if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
|
||||
LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
|
||||
|
|
@ -588,7 +630,6 @@ void HandleKeychord(const std::vector<int>& keycodes) {
|
|||
}
|
||||
|
||||
auto found = false;
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
auto svc = service.get();
|
||||
if (svc->keycodes() == keycodes) {
|
||||
|
|
@ -659,22 +700,6 @@ void SendLoadPersistentPropertiesMessage() {
|
|||
}
|
||||
}
|
||||
|
||||
void SendStopSendingMessagesMessage() {
|
||||
auto init_message = InitMessage{};
|
||||
init_message.set_stop_sending_messages(true);
|
||||
if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
|
||||
LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error();
|
||||
}
|
||||
}
|
||||
|
||||
void SendStartSendingMessagesMessage() {
|
||||
auto init_message = InitMessage{};
|
||||
init_message.set_start_sending_messages(true);
|
||||
if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
|
||||
LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error();
|
||||
}
|
||||
}
|
||||
|
||||
int SecondStageMain(int argc, char** argv) {
|
||||
if (REBOOT_BOOTLOADER_ON_PANIC) {
|
||||
InstallRebootSignalHandlers();
|
||||
|
|
@ -796,7 +821,6 @@ int SecondStageMain(int argc, char** argv) {
|
|||
Keychords keychords;
|
||||
am.QueueBuiltinAction(
|
||||
[&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& svc : ServiceList::GetInstance()) {
|
||||
keychords.Register(svc->keycodes());
|
||||
}
|
||||
|
|
@ -863,6 +887,7 @@ int SecondStageMain(int argc, char** argv) {
|
|||
(*function)();
|
||||
}
|
||||
}
|
||||
HandleControlMessages();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -38,11 +38,9 @@ void DumpState();
|
|||
void ResetWaitForProp();
|
||||
|
||||
void SendLoadPersistentPropertiesMessage();
|
||||
void SendStopSendingMessagesMessage();
|
||||
void SendStartSendingMessagesMessage();
|
||||
|
||||
void PropertyChanged(const std::string& name, const std::string& value);
|
||||
bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
|
||||
bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd);
|
||||
|
||||
int SecondStageMain(int argc, char** argv);
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ service A something
|
|||
|
||||
ServiceList service_list;
|
||||
TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
|
||||
|
||||
auto service = service_list.begin()->get();
|
||||
|
|
|
|||
|
|
@ -79,8 +79,7 @@ static bool UnregisterProcess(pid_t pid) {
|
|||
}
|
||||
|
||||
static void RegisterServices(pid_t exclude_pid) {
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
for (const auto& service : ServiceList::GetInstance().services()) {
|
||||
auto svc = service.get();
|
||||
if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
|
||||
// skip if process is excluded or not yet forked (pid==0)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include <android-base/unique_fd.h>
|
||||
#include <apex_manifest.pb.h>
|
||||
|
||||
#include "property_service.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace android {
|
||||
|
|
@ -291,14 +290,6 @@ bool SwitchToDefaultMountNamespace() {
|
|||
return true;
|
||||
}
|
||||
if (default_ns_id != GetMountNamespaceId()) {
|
||||
// The property service thread and its descendent threads must be in the correct mount
|
||||
// namespace to call Service::Start(), however setns() only operates on a single thread and
|
||||
// fails when secondary threads attempt to join the same mount namespace. Therefore, we
|
||||
// must join the property service thread and its descendents before the setns() call. Those
|
||||
// threads are then started again after the setns() call, and they'll be in the proper
|
||||
// namespace.
|
||||
PausePropertyService();
|
||||
|
||||
if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
|
||||
PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
|
||||
return false;
|
||||
|
|
@ -308,8 +299,6 @@ bool SwitchToDefaultMountNamespace() {
|
|||
LOG(ERROR) << result.error();
|
||||
return false;
|
||||
}
|
||||
|
||||
ResumePropertyService();
|
||||
}
|
||||
|
||||
LOG(INFO) << "Switched to default mount namespace";
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ static int property_set_fd = -1;
|
|||
static int from_init_socket = -1;
|
||||
static int init_socket = -1;
|
||||
static bool accept_messages = false;
|
||||
static std::mutex accept_messages_lock;
|
||||
static std::thread property_service_thread;
|
||||
|
||||
static PropertyInfoAreaFile property_info_area;
|
||||
|
|
@ -117,6 +118,16 @@ static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf
|
|||
return 0;
|
||||
}
|
||||
|
||||
void StartSendingMessages() {
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
accept_messages = true;
|
||||
}
|
||||
|
||||
void StopSendingMessages() {
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
accept_messages = true;
|
||||
}
|
||||
|
||||
bool CanReadProperty(const std::string& source_context, const std::string& name) {
|
||||
const char* target_context = nullptr;
|
||||
property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
|
||||
|
|
@ -186,138 +197,49 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s
|
|||
}
|
||||
// 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.
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
if (accept_messages) {
|
||||
PropertyChanged(name, value);
|
||||
}
|
||||
return PROP_SUCCESS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class SingleThreadExecutor {
|
||||
class AsyncRestorecon {
|
||||
public:
|
||||
virtual ~SingleThreadExecutor() {}
|
||||
|
||||
template <typename F = T>
|
||||
void Run(F&& item) {
|
||||
void TriggerRestorecon(const std::string& path) {
|
||||
auto guard = std::lock_guard{mutex_};
|
||||
items_.emplace(std::forward<F>(item));
|
||||
paths_.emplace(path);
|
||||
|
||||
if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread_state_ == ThreadState::kPendingJoin) {
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
StartThread();
|
||||
}
|
||||
|
||||
void StopAndJoin() {
|
||||
auto lock = std::unique_lock{mutex_};
|
||||
if (thread_state_ == ThreadState::kPendingJoin) {
|
||||
thread_.join();
|
||||
} else if (thread_state_ == ThreadState::kRunning) {
|
||||
thread_state_ = ThreadState::kStopped;
|
||||
lock.unlock();
|
||||
thread_.join();
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
thread_state_ = ThreadState::kStopped;
|
||||
}
|
||||
|
||||
void Restart() {
|
||||
auto guard = std::lock_guard{mutex_};
|
||||
if (items_.empty()) {
|
||||
thread_state_ = ThreadState::kNotStarted;
|
||||
} else {
|
||||
StartThread();
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeJoin() {
|
||||
auto guard = std::lock_guard{mutex_};
|
||||
if (thread_state_ == ThreadState::kPendingJoin) {
|
||||
thread_.join();
|
||||
thread_state_ = ThreadState::kNotStarted;
|
||||
if (!thread_started_) {
|
||||
thread_started_ = true;
|
||||
std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void Execute(T&& item) = 0;
|
||||
|
||||
void StartThread() {
|
||||
thread_state_ = ThreadState::kRunning;
|
||||
auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
|
||||
std::swap(thread_, thread);
|
||||
}
|
||||
|
||||
void ThreadFunction() {
|
||||
auto lock = std::unique_lock{mutex_};
|
||||
|
||||
while (!items_.empty()) {
|
||||
auto item = items_.front();
|
||||
items_.pop();
|
||||
while (!paths_.empty()) {
|
||||
auto path = paths_.front();
|
||||
paths_.pop();
|
||||
|
||||
lock.unlock();
|
||||
Execute(std::move(item));
|
||||
if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
|
||||
LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
|
||||
}
|
||||
android::base::SetProperty(kRestoreconProperty, path);
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
if (thread_state_ != ThreadState::kStopped) {
|
||||
thread_state_ = ThreadState::kPendingJoin;
|
||||
}
|
||||
thread_started_ = false;
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::queue<T> items_;
|
||||
enum class ThreadState {
|
||||
kNotStarted, // Initial state when starting the program or when restarting with no items to
|
||||
// process.
|
||||
kRunning, // The thread is running and is in a state that it will process new items if
|
||||
// are run.
|
||||
kPendingJoin, // The thread has run to completion and is pending join(). A new thread must
|
||||
// be launched for new items to be processed.
|
||||
kStopped, // This executor has stopped and will not process more items until Restart() is
|
||||
// called. Currently pending items will be processed and the thread will be
|
||||
// joined.
|
||||
};
|
||||
ThreadState thread_state_ = ThreadState::kNotStarted;
|
||||
std::thread thread_;
|
||||
std::queue<std::string> paths_;
|
||||
bool thread_started_ = false;
|
||||
};
|
||||
|
||||
class RestoreconThread : public SingleThreadExecutor<std::string> {
|
||||
virtual void Execute(std::string&& path) override {
|
||||
if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
|
||||
LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
|
||||
}
|
||||
android::base::SetProperty(kRestoreconProperty, path);
|
||||
}
|
||||
};
|
||||
|
||||
struct ControlMessageInfo {
|
||||
std::string message;
|
||||
std::string name;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
|
||||
virtual void Execute(ControlMessageInfo&& info) override {
|
||||
bool success = HandleControlMessage(info.message, info.name, info.pid);
|
||||
|
||||
uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
||||
if (info.fd != -1) {
|
||||
TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
|
||||
close(info.fd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static RestoreconThread restorecon_thread;
|
||||
static ControlMessageThread control_message_thread;
|
||||
|
||||
class SocketConnection {
|
||||
public:
|
||||
SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
|
||||
|
|
@ -454,22 +376,25 @@ class SocketConnection {
|
|||
|
||||
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
|
||||
SocketConnection* socket, std::string* error) {
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
if (!accept_messages) {
|
||||
*error = "Received control message after shutdown, ignoring";
|
||||
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
||||
}
|
||||
|
||||
// We must release the fd before spawning the thread, otherwise there will be a race with the
|
||||
// thread. If the thread calls close() before this function calls Release(), then fdsan will see
|
||||
// the wrong tag and abort().
|
||||
// We must release the fd before sending it to init, otherwise there will be a race with init.
|
||||
// If init calls close() before Release(), then fdsan will see the wrong tag and abort().
|
||||
int fd = -1;
|
||||
if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
|
||||
fd = socket->Release();
|
||||
}
|
||||
|
||||
// Handling a control message likely calls SetProperty, which we must synchronously handle,
|
||||
// therefore we must fork a thread to handle it.
|
||||
control_message_thread.Run({msg, name, pid, fd});
|
||||
bool queue_success = QueueControlMessage(msg, name, pid, fd);
|
||||
if (!queue_success && fd != -1) {
|
||||
uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
|
||||
TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return PROP_SUCCESS;
|
||||
}
|
||||
|
|
@ -571,7 +496,8 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
|
|||
// We use a thread to do this restorecon operation to prevent holding up init, as it may take
|
||||
// a long time to complete.
|
||||
if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
|
||||
restorecon_thread.Run(value);
|
||||
static AsyncRestorecon async_restorecon;
|
||||
async_restorecon.TriggerRestorecon(value);
|
||||
return PROP_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -1152,8 +1078,6 @@ void PropertyInit() {
|
|||
PropertyLoadBootDefaults();
|
||||
}
|
||||
|
||||
static bool pause_property_service = false;
|
||||
|
||||
static void HandleInitSocket() {
|
||||
auto message = ReadMessage(init_socket);
|
||||
if (!message.ok()) {
|
||||
|
|
@ -1180,18 +1104,6 @@ static void HandleInitSocket() {
|
|||
persistent_properties_loaded = true;
|
||||
break;
|
||||
}
|
||||
case InitMessage::kStopSendingMessages: {
|
||||
accept_messages = false;
|
||||
break;
|
||||
}
|
||||
case InitMessage::kStartSendingMessages: {
|
||||
accept_messages = true;
|
||||
break;
|
||||
}
|
||||
case InitMessage::kPausePropertyService: {
|
||||
pause_property_service = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
|
||||
}
|
||||
|
|
@ -1212,7 +1124,7 @@ static void PropertyServiceThread() {
|
|||
LOG(FATAL) << result.error();
|
||||
}
|
||||
|
||||
while (!pause_property_service) {
|
||||
while (true) {
|
||||
auto pending_functions = epoll.Wait(std::nullopt);
|
||||
if (!pending_functions.ok()) {
|
||||
LOG(ERROR) << pending_functions.error();
|
||||
|
|
@ -1221,34 +1133,9 @@ static void PropertyServiceThread() {
|
|||
(*function)();
|
||||
}
|
||||
}
|
||||
control_message_thread.MaybeJoin();
|
||||
restorecon_thread.MaybeJoin();
|
||||
}
|
||||
}
|
||||
|
||||
void SendStopPropertyServiceMessage() {
|
||||
auto init_message = InitMessage{};
|
||||
init_message.set_pause_property_service(true);
|
||||
if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
|
||||
LOG(ERROR) << "Failed to send stop property service message: " << result.error();
|
||||
}
|
||||
}
|
||||
|
||||
void PausePropertyService() {
|
||||
control_message_thread.StopAndJoin();
|
||||
restorecon_thread.StopAndJoin();
|
||||
SendStopPropertyServiceMessage();
|
||||
property_service_thread.join();
|
||||
}
|
||||
|
||||
void ResumePropertyService() {
|
||||
pause_property_service = false;
|
||||
auto new_thread = std::thread{PropertyServiceThread};
|
||||
property_service_thread.swap(new_thread);
|
||||
restorecon_thread.Restart();
|
||||
control_message_thread.Restart();
|
||||
}
|
||||
|
||||
void StartPropertyService(int* epoll_socket) {
|
||||
InitPropertySet("ro.property_service.version", "2");
|
||||
|
||||
|
|
@ -1258,7 +1145,7 @@ void StartPropertyService(int* epoll_socket) {
|
|||
}
|
||||
*epoll_socket = from_init_socket = sockets[0];
|
||||
init_socket = sockets[1];
|
||||
accept_messages = true;
|
||||
StartSendingMessages();
|
||||
|
||||
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
false, 0666, 0, 0, {});
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ bool CanReadProperty(const std::string& source_context, const std::string& name)
|
|||
|
||||
void PropertyInit();
|
||||
void StartPropertyService(int* epoll_socket);
|
||||
void ResumePropertyService();
|
||||
void PausePropertyService();
|
||||
|
||||
void StartSendingMessages();
|
||||
void StopSendingMessages();
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -41,6 +41,5 @@ message InitMessage {
|
|||
bool load_persistent_properties = 1;
|
||||
bool stop_sending_messages = 2;
|
||||
bool start_sending_messages = 3;
|
||||
bool pause_property_service = 4;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include "builtin_arguments.h"
|
||||
#include "init.h"
|
||||
#include "mount_namespace.h"
|
||||
#include "property_service.h"
|
||||
#include "reboot_utils.h"
|
||||
#include "service.h"
|
||||
#include "service_list.h"
|
||||
|
|
@ -85,7 +86,7 @@ static bool shutting_down = false;
|
|||
|
||||
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
|
||||
|
||||
static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
|
||||
static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
|
||||
std::vector<Service*> ret;
|
||||
ret.reserve(kDebuggingServices.size());
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
|
|
@ -181,7 +182,7 @@ class MountEntry {
|
|||
};
|
||||
|
||||
// Turn off backlight while we are performing power down cleanup activities.
|
||||
static void TurnOffBacklight() REQUIRES(service_lock) {
|
||||
static void TurnOffBacklight() {
|
||||
Service* service = ServiceList::GetInstance().FindService("blank_screen");
|
||||
if (service == nullptr) {
|
||||
LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
|
||||
|
|
@ -589,7 +590,6 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
|
|||
// Start reboot monitor thread
|
||||
sem_post(&reboot_semaphore);
|
||||
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
|
||||
const std::set<std::string> to_starts{"watchdogd"};
|
||||
std::vector<Service*> stop_first;
|
||||
|
|
@ -709,21 +709,15 @@ static void EnterShutdown() {
|
|||
// Skip wait for prop if it is in progress
|
||||
ResetWaitForProp();
|
||||
// Clear EXEC flag if there is one pending
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
s->UnSetExec();
|
||||
}
|
||||
// We no longer process messages about properties changing coming from property service, so we
|
||||
// need to tell property service to stop sending us these messages, otherwise it'll fill the
|
||||
// buffers and block indefinitely, causing future property sets, including those that init makes
|
||||
// during shutdown in Service::NotifyStateChange() to also block indefinitely.
|
||||
SendStopSendingMessagesMessage();
|
||||
}
|
||||
|
||||
static void LeaveShutdown() {
|
||||
LOG(INFO) << "Leaving shutdown mode";
|
||||
shutting_down = false;
|
||||
SendStartSendingMessagesMessage();
|
||||
StartSendingMessages();
|
||||
}
|
||||
|
||||
static Result<void> UnmountAllApexes() {
|
||||
|
|
@ -753,7 +747,6 @@ static Result<void> DoUserspaceReboot() {
|
|||
return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
|
||||
}
|
||||
EnterShutdown();
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
if (!SetProperty("sys.powerctl", "")) {
|
||||
return Error() << "Failed to reset sys.powerctl property";
|
||||
}
|
||||
|
|
@ -914,7 +907,6 @@ void HandlePowerctlMessage(const std::string& command) {
|
|||
run_fsck = true;
|
||||
} else if (cmd_params[1] == "thermal") {
|
||||
// Turn off sources of heat immediately.
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
TurnOffBacklight();
|
||||
// run_fsck is false to avoid delay
|
||||
cmd = ANDROID_RB_THERMOFF;
|
||||
|
|
@ -985,6 +977,10 @@ void HandlePowerctlMessage(const std::string& command) {
|
|||
return;
|
||||
}
|
||||
|
||||
// We do not want to process any messages (queue'ing triggers, shutdown messages, control
|
||||
// messages, etc) from properties during reboot.
|
||||
StopSendingMessages();
|
||||
|
||||
if (userspace_reboot) {
|
||||
HandleUserspaceReboot();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -27,14 +27,12 @@
|
|||
#include <vector>
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <cutils/iosched_policy.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "capabilities.h"
|
||||
#include "keyword_map.h"
|
||||
#include "parser.h"
|
||||
#include "service_lock.h"
|
||||
#include "service_utils.h"
|
||||
#include "subcontext.h"
|
||||
|
||||
|
|
@ -79,17 +77,17 @@ class Service {
|
|||
|
||||
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
|
||||
bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
|
||||
Result<void> ExecStart() REQUIRES(service_lock);
|
||||
Result<void> Start() REQUIRES(service_lock);
|
||||
Result<void> StartIfNotDisabled() REQUIRES(service_lock);
|
||||
Result<void> StartIfPostData() REQUIRES(service_lock);
|
||||
Result<void> Enable() REQUIRES(service_lock);
|
||||
Result<void> ExecStart();
|
||||
Result<void> Start();
|
||||
Result<void> StartIfNotDisabled();
|
||||
Result<void> StartIfPostData();
|
||||
Result<void> Enable();
|
||||
void Reset();
|
||||
void ResetIfPostData();
|
||||
void Stop();
|
||||
void Terminate();
|
||||
void Timeout();
|
||||
void Restart() REQUIRES(service_lock);
|
||||
void Restart();
|
||||
void Reap(const siginfo_t& siginfo);
|
||||
void DumpState() const;
|
||||
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
|
||||
|
|
|
|||
|
|
@ -17,13 +17,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include "service.h"
|
||||
#include "service_lock.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
|
@ -36,16 +32,16 @@ class ServiceList {
|
|||
ServiceList();
|
||||
size_t CheckAllCommands();
|
||||
|
||||
void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
|
||||
void RemoveService(const Service& svc) REQUIRES(service_lock);
|
||||
void AddService(std::unique_ptr<Service> service);
|
||||
void RemoveService(const Service& svc);
|
||||
template <class UnaryPredicate>
|
||||
void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
|
||||
void RemoveServiceIf(UnaryPredicate predicate) {
|
||||
services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
|
||||
services_.end());
|
||||
}
|
||||
|
||||
template <typename T, typename F = decltype(&Service::name)>
|
||||
Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
|
||||
Service* FindService(T value, F function = &Service::name) const {
|
||||
auto svc = std::find_if(services_.begin(), services_.end(),
|
||||
[&function, &value](const std::unique_ptr<Service>& s) {
|
||||
return std::invoke(function, s) == value;
|
||||
|
|
@ -56,7 +52,7 @@ class ServiceList {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
|
||||
Service* FindInterface(const std::string& interface_name) {
|
||||
for (const auto& svc : services_) {
|
||||
if (svc->interfaces().count(interface_name) > 0) {
|
||||
return svc.get();
|
||||
|
|
@ -66,20 +62,18 @@ class ServiceList {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void DumpState() const REQUIRES(service_lock);
|
||||
void DumpState() const;
|
||||
|
||||
auto begin() const REQUIRES(service_lock) { return services_.begin(); }
|
||||
auto end() const REQUIRES(service_lock) { return services_.end(); }
|
||||
const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
|
||||
return services_;
|
||||
}
|
||||
const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
|
||||
auto begin() const { return services_.begin(); }
|
||||
auto end() const { return services_.end(); }
|
||||
const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
|
||||
const std::vector<Service*> services_in_shutdown_order() const;
|
||||
|
||||
void MarkPostData();
|
||||
bool IsPostData();
|
||||
void MarkServicesUpdate() REQUIRES(service_lock);
|
||||
void MarkServicesUpdate();
|
||||
bool IsServicesUpdated() const { return services_update_finished_; }
|
||||
void DelayService(const Service& service) REQUIRES(service_lock);
|
||||
void DelayService(const Service& service);
|
||||
|
||||
void ResetState() {
|
||||
post_data_ = false;
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include "service_lock.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
RecursiveMutex service_lock;
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <mutex>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
|
||||
|
||||
class CAPABILITY("mutex") RecursiveMutex {
|
||||
public:
|
||||
void lock() ACQUIRE() { mutex_.lock(); }
|
||||
void unlock() RELEASE() { mutex_.unlock(); }
|
||||
|
||||
private:
|
||||
std::recursive_mutex mutex_;
|
||||
};
|
||||
|
||||
extern RecursiveMutex service_lock;
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
@ -168,7 +168,6 @@ Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
|
|||
|
||||
const std::string fullname = interface_name + "/" + instance_name;
|
||||
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
for (const auto& svc : *service_list_) {
|
||||
if (svc->interfaces().count(fullname) > 0) {
|
||||
return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
|
||||
|
|
@ -599,7 +598,6 @@ Result<void> ServiceParser::EndSection() {
|
|||
}
|
||||
}
|
||||
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
Service* old_service = service_list_->FindService(service_->name());
|
||||
if (old_service) {
|
||||
if (!service_->is_override()) {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,6 @@ static pid_t ReapOneProcess() {
|
|||
std::string wait_string;
|
||||
Service* service = nullptr;
|
||||
|
||||
auto lock = std::lock_guard{service_lock};
|
||||
|
||||
if (SubcontextChildReap(pid)) {
|
||||
name = "Subcontext";
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue