diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 7e27d7544..3209adf16 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -56,6 +56,7 @@ using android::base::WriteStringToFile; using namespace std::chrono_literals; #define PROCESSGROUP_CGROUP_PROCS_FILE "cgroup.procs" +#define PROCESSGROUP_CGROUP_KILL_FILE "cgroup.kill" #define PROCESSGROUP_CGROUP_EVENTS_FILE "cgroup.events" bool CgroupsAvailable() { @@ -77,6 +78,29 @@ bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) return true; } +static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { + return StringPrintf("%s/uid_%u", cgroup, uid); +} + +static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, int pid) { + return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid); +} + +static bool CgroupKillAvailable() { + static std::once_flag f; + static bool cgroup_kill_available = false; + std::call_once(f, []() { + std::string cg_kill; + CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &cg_kill); + // cgroup.kill is not on the root cgroup, so check a non-root cgroup that should always + // exist + cg_kill = ConvertUidToPath(cg_kill.c_str(), AID_ROOT) + '/' + PROCESSGROUP_CGROUP_KILL_FILE; + cgroup_kill_available = access(cg_kill.c_str(), F_OK) == 0; + }); + + return cgroup_kill_available; +} + static bool CgroupGetMemcgAppsPath(std::string* path) { CgroupController controller = CgroupMap::GetInstance().FindController("memory"); @@ -208,14 +232,6 @@ bool SetUserProfiles(uid_t uid, const std::vector& profiles) { false); } -static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { - return StringPrintf("%s/uid_%u", cgroup, uid); -} - -static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, int pid) { - return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid); -} - static int RemoveCgroup(const char* cgroup, uid_t uid, int pid) { auto path = ConvertUidPidToPath(cgroup, uid, pid); int ret = TEMP_FAILURE_RETRY(rmdir(path.c_str())); @@ -362,6 +378,28 @@ bool sendSignalToProcessGroup(uid_t uid, int initialPid, int signal) { CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, &hierarchy_root_path); cgroup_v2_path = ConvertUidPidToPath(hierarchy_root_path.c_str(), uid, initialPid); + if (signal == SIGKILL && CgroupKillAvailable()) { + LOG(VERBOSE) << "Using " << PROCESSGROUP_CGROUP_KILL_FILE << " to SIGKILL " + << cgroup_v2_path; + + // We need to kill the process group in addition to the cgroup. For normal apps they + // should completely overlap, but system_server kills depend on process group kills to + // take down apps which are in their own cgroups and not individually targeted. + if (kill(-initialPid, signal) == -1 && errno != ESRCH) { + PLOG(WARNING) << "kill(" << -initialPid << ", " << signal << ") failed"; + } + + const std::string killfilepath = cgroup_v2_path + '/' + PROCESSGROUP_CGROUP_KILL_FILE; + if (WriteStringToFile("1", killfilepath)) { + return true; + } else { + PLOG(ERROR) << "Failed to write 1 to " << killfilepath; + // Fallback to cgroup.procs below + } + } + + // Since cgroup.kill only sends SIGKILLs, we read cgroup.procs to find each process to + // signal individually. This is more costly than using cgroup.kill for SIGKILLs. LOG(VERBOSE) << "Using " << PROCESSGROUP_CGROUP_PROCS_FILE << " to signal (" << signal << ") " << cgroup_v2_path;