From 4345f3f50adcea6f5e08842b7c949cd1770718e2 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 28 Apr 2022 13:24:28 -0700 Subject: [PATCH 1/2] libprocessgroup: Add a function to remove only empty process groups When system_server and zygote crash or get killed, all apps also get killed but their process groups are left empty. Provide a function to remove all empty process groups so that init can purge them when this even happens. Bug: 228160715 Signed-off-by: Suren Baghdasaryan Change-Id: Ife38ca021e80cd38106f218ae13183e8c2631bf0 --- .../include/processgroup/processgroup.h | 1 + libprocessgroup/processgroup.cpp | 33 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index c5badc941..39b9f3fc0 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -67,6 +67,7 @@ bool setProcessGroupSoftLimit(uid_t uid, int initialPid, int64_t softLimitInByte bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes); void removeAllProcessGroups(void); +void removeAllEmptyProcessGroups(void); // Provides the path for an attribute in a specific process group // Returns false in case of error, true in case of success diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index e3a80e97b..267e62c67 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -200,7 +200,7 @@ static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned i return ret; } -static bool RemoveUidProcessGroups(const std::string& uid_path) { +static bool RemoveUidProcessGroups(const std::string& uid_path, bool empty_only) { std::unique_ptr uid(opendir(uid_path.c_str()), closedir); bool empty = true; if (uid != NULL) { @@ -215,6 +215,21 @@ static bool RemoveUidProcessGroups(const std::string& uid_path) { } auto path = StringPrintf("%s/%s", uid_path.c_str(), dir->d_name); + if (empty_only) { + struct stat st; + auto procs_file = StringPrintf("%s/%s", path.c_str(), + PROCESSGROUP_CGROUP_PROCS_FILE); + if (stat(procs_file.c_str(), &st) == -1) { + PLOG(ERROR) << "Failed to get stats for " << procs_file; + continue; + } + if (st.st_size > 0) { + // skip non-empty groups + LOG(VERBOSE) << "Skipping non-empty group " << path; + empty = false; + continue; + } + } LOG(VERBOSE) << "Removing " << path; if (rmdir(path.c_str()) == -1) { if (errno != EBUSY) { @@ -227,9 +242,7 @@ static bool RemoveUidProcessGroups(const std::string& uid_path) { return empty; } -void removeAllProcessGroups() { - LOG(VERBOSE) << "removeAllProcessGroups()"; - +void removeAllProcessGroupsInternal(bool empty_only) { std::vector cgroups; std::string path, memcg_apps_path; @@ -256,7 +269,7 @@ void removeAllProcessGroups() { } auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name); - if (!RemoveUidProcessGroups(path)) { + if (!RemoveUidProcessGroups(path, empty_only)) { LOG(VERBOSE) << "Skip removing " << path; continue; } @@ -269,6 +282,16 @@ void removeAllProcessGroups() { } } +void removeAllProcessGroups() { + LOG(VERBOSE) << "removeAllProcessGroups()"; + removeAllProcessGroupsInternal(false); +} + +void removeAllEmptyProcessGroups() { + LOG(VERBOSE) << "removeAllEmptyProcessGroups()"; + removeAllProcessGroupsInternal(true); +} + /** * Process groups are primarily created by the Zygote, meaning that uid/pid groups are created by * the user root. Ownership for the newly created cgroup and all of its files must thus be From af64077f8366e9fcf1567c415ef167395ad2d71a Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 28 Apr 2022 13:26:59 -0700 Subject: [PATCH 2/2] init: Purge empty process groups on zygote restart When system_server crashes or gets killed, it causes zygote to kill itself, which in turn leads to killing all processes in the same process group (all apps). This leaves empty process groups because system_server is not there to remove them. Purge empty process groups when init detects zygote death. Bug: 228160715 Signed-off-by: Suren Baghdasaryan Change-Id: I0ce27eea28f8713e52033bbec2d5363a7b8ff5db --- init/service.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/init/service.cpp b/init/service.cpp index 077477a15..95a532850 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -288,6 +288,10 @@ void Service::Reap(const siginfo_t& siginfo) { if (flags_ & SVC_EXEC) UnSetExec(); + if (name_ == "zygote" || name_ == "zygote64") { + removeAllEmptyProcessGroups(); + } + if (flags_ & SVC_TEMPORARY) return; pid_ = 0;