libprocessgroup: Use cgroup.kill
By using cgroup.kill we don't need to read cgroup.procs at all for SIGKILLs, which is more efficient and should help reduce CPU contention and cgroup lock contention. Fallback to cgroup.procs if we encounter an error trying to use cgroup.kill, but if cgroup.kill fails it's likely that cgroup.procs will too. Bug: 239829790 Test: atest StagedRollbackTest:com.android.tests.rollback.host.StagedRollbackTest#testNativeWatchdogTriggersRebootlessApexRollback Change-Id: I9da67efd00af49b7b4b502fb742c1095d5c7b9e9
This commit is contained in:
parent
4928b6ef57
commit
a103630b5c
1 changed files with 46 additions and 8 deletions
|
@ -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<std::string>& 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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue