From 6761b6dcdc31a10d7e1b3652400bfae9eb2eed17 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 Merged-In: 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 870725ac14440939b9bb7939f0ee1af1102f8a67 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 Merged-In: I0ce27eea28f8713e52033bbec2d5363a7b8ff5db --- init/service.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/init/service.cpp b/init/service.cpp index 0f2443741..3fa935fdd 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -289,6 +289,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;