SystemServer: Implement lazy spawning

For services explicitly configured as lazy, SystemServer will now listen
on the socket and only spawn the service once a client attempts to connect
to the socket.
This commit is contained in:
Sergey Bugaev 2019-11-26 19:41:16 +03:00 committed by Andreas Kling
parent ab98969403
commit 52b0bd06a8
Notes: sideshowbarker 2024-07-19 11:03:26 +09:00
4 changed files with 40 additions and 4 deletions

View file

@ -6,12 +6,14 @@ Priority=high
[ProtocolServer] [ProtocolServer]
Socket=/tmp/portal/protocol Socket=/tmp/portal/protocol
Lazy=1
Priority=low Priority=low
KeepAlive=1 KeepAlive=1
User=anon User=anon
[LookupServer] [LookupServer]
Socket=/tmp/portal/lookup Socket=/tmp/portal/lookup
Lazy=1
Priority=low Priority=low
KeepAlive=1 KeepAlive=1
User=anon User=anon
@ -24,6 +26,7 @@ User=anon
[AudioServer] [AudioServer]
Socket=/tmp/portal/audio Socket=/tmp/portal/audio
# TODO: we may want to start it lazily, but right now WindowServer connects to it immediately on startup
Priority=high Priority=high
KeepAlive=1 KeepAlive=1
User=anon User=anon

View file

@ -101,6 +101,31 @@ void Service::setup_socket()
} }
} }
void Service::setup_notifier()
{
ASSERT(m_lazy);
ASSERT(m_socket_fd >= 0);
ASSERT(!m_socket_notifier);
m_socket_notifier = CNotifier::construct(m_socket_fd, CNotifier::Event::Read, this);
m_socket_notifier->on_ready_to_read = [this] {
dbg() << "Ready to read on behalf of " << name();
remove_child(*m_socket_notifier);
m_socket_notifier = nullptr;
spawn();
};
}
void Service::activate()
{
ASSERT(m_pid < 0);
if (m_lazy)
setup_notifier();
else
spawn();
}
void Service::spawn() void Service::spawn()
{ {
dbg() << "Spawning " << name(); dbg() << "Spawning " << name();
@ -172,7 +197,7 @@ void Service::did_exit(int exit_code)
m_pid = -1; m_pid = -1;
if (m_keep_alive) if (m_keep_alive)
spawn(); activate();
} }
Service::Service(const CConfigFile& config, const StringView& name) Service::Service(const CConfigFile& config, const StringView& name)
@ -198,6 +223,7 @@ Service::Service(const CConfigFile& config, const StringView& name)
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
m_keep_alive = config.read_bool_entry(name, "KeepAlive"); m_keep_alive = config.read_bool_entry(name, "KeepAlive");
m_lazy = config.read_bool_entry(name, "Lazy");
m_socket_path = config.read_entry(name, "Socket"); m_socket_path = config.read_entry(name, "Socket");
if (!m_socket_path.is_null()) { if (!m_socket_path.is_null()) {
@ -227,6 +253,7 @@ void Service::save_to(JsonObject& json)
json.set("priority", m_priority); json.set("priority", m_priority);
json.set("keep_alive", m_keep_alive); json.set("keep_alive", m_keep_alive);
json.set("socket_path", m_socket_path); json.set("socket_path", m_socket_path);
json.set("lazy", m_lazy);
json.set("user", m_user); json.set("user", m_user);
json.set("uid", m_uid); json.set("uid", m_uid);
json.set("gid", m_gid); json.set("gid", m_gid);

View file

@ -15,7 +15,7 @@ class Service final : public CObject {
C_OBJECT(Service) C_OBJECT(Service)
public: public:
void spawn(); void activate();
void did_exit(int exit_code); void did_exit(int exit_code);
static Service* find_by_pid(pid_t); static Service* find_by_pid(pid_t);
@ -25,6 +25,8 @@ public:
private: private:
Service(const CConfigFile&, const StringView& name); Service(const CConfigFile&, const StringView& name);
void spawn();
// Path to the executable. By default this is /bin/{m_name}. // Path to the executable. By default this is /bin/{m_name}.
String m_executable_path; String m_executable_path;
// Extra arguments, starting from argv[1], to pass when exec'ing. // Extra arguments, starting from argv[1], to pass when exec'ing.
@ -36,6 +38,8 @@ private:
bool m_keep_alive { false }; bool m_keep_alive { false };
// Path to the socket to create and listen on on behalf of this service. // Path to the socket to create and listen on on behalf of this service.
String m_socket_path; String m_socket_path;
// Whether we should only spawn this service once somebody connects to the socket.
bool m_lazy;
// The name of the user we should run this service as. // The name of the user we should run this service as.
String m_user; String m_user;
uid_t m_uid { 0 }; uid_t m_uid { 0 };
@ -45,7 +49,9 @@ private:
pid_t m_pid { -1 }; pid_t m_pid { -1 };
// An open fd to the socket. // An open fd to the socket.
int m_socket_fd { -1 }; int m_socket_fd { -1 };
RefPtr<CNotifier> m_socket_notifier;
void resolve_user(); void resolve_user();
void setup_socket(); void setup_socket();
void setup_notifier();
}; };

View file

@ -95,9 +95,9 @@ int main(int, char**)
for (auto name : config->groups()) for (auto name : config->groups())
services.append(Service::construct(*config, name)); services.append(Service::construct(*config, name));
// After we've set them all up, spawn them! // After we've set them all up, activate them!
for (auto& service : services) for (auto& service : services)
service->spawn(); service->activate();
// This won't return if we're in test mode. // This won't return if we're in test mode.
check_for_test_mode(); check_for_test_mode();