Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38b8bb1e authored by T.J. Mercier's avatar T.J. Mercier
Browse files

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
Change-Id: I44706faccfb7c4611b512a3642b913f06d30c1dc
parent 3b5bb3a3
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -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,20 @@ 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;
            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;