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

Commit c9692cd2 authored by Shadman Shadid's avatar Shadman Shadid Committed by Android (Google) Code Review
Browse files

Merge "Add puller for memcg" into main

parents 18daea71 1b71342c
Loading
Loading
Loading
Loading
+118 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.os;

import static android.os.Process.PROC_OUT_LONG;

import android.annotation.Nullable;
import android.os.Process;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public final class MemcgProcMemoryUtil {

    private static final String TAG = "MemcgProcMemoryUtil";

    private static final int[] MEMCG_MEMORY_FORMAT = new int[] {PROC_OUT_LONG};
    private static final String CGROUP_ROOT = "/sys/fs/cgroup";
    private static final String PROC_ROOT = "/proc/";

    private MemcgProcMemoryUtil() {}

     /**
      * Reads memcg accounting of memory stats of a process.
      *
      * Returns values of memory.current, memory.swap in bytes or -1 if not available.
      */
    public static MemcgMemorySnapshot readMemcgMemorySnapshot(int pid) {
        String cgroupPath = getCgroupPathForPid(pid);
        if (cgroupPath == null) {
            return null;
        }
        return readMemcgMemorySnapshot(cgroupPath);
    }

    /**
     * Gets the cgroup v2 path for a given process ID (pid).
     *
     * @param pid The process ID.
     * @return The cgroup v2 path string, or null if not found or an error occurs.
     */
    @Nullable
    private static String getCgroupPathForPid(int pid) {
        Path cgroupPathFile = Paths.get(PROC_ROOT, String.valueOf(pid), "cgroup");

        try (BufferedReader reader = Files.newBufferedReader(cgroupPathFile)) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("0::")) {
                    return line.substring(3);
                }
            }
        } catch (IOException e) {
            Log.d(TAG, "Failed to read cgroup file for pid " + pid, e);
        }
        return null;
    }

    private static MemcgMemorySnapshot readMemcgMemorySnapshot(String cgroupPath) {
        Path fullMemcgPath = Paths.get(CGROUP_ROOT, cgroupPath);

        final MemcgMemorySnapshot snapshot = new MemcgMemorySnapshot();

        long[] currentMemoryOutput = new long[1];
        String memoryCurrentPath = fullMemcgPath.resolve("memory.current").toString();
        if (Process.readProcFile(
                memoryCurrentPath,
                MEMCG_MEMORY_FORMAT,
                null,
                currentMemoryOutput,
                null
        )) {
            snapshot.memcgMemoryInBytes = currentMemoryOutput[0];
        } else {
            Log.d(TAG, "Failed to read memory.current for " + cgroupPath);
            return null;
        }

        long[] currentSwapMemoryOutput = new long[1];
        String memorySwapPath =
                fullMemcgPath.resolve("memory.swap.current").toString();
        if (Process.readProcFile(
                memorySwapPath,
                MEMCG_MEMORY_FORMAT,
                null,
                currentSwapMemoryOutput,
                null
        )) {
            snapshot.memcgSwapMemoryInBytes = currentSwapMemoryOutput[0];
        } else {
            Log.d(TAG, "Failed to read memory.current for " + cgroupPath);
            return null;
        }
        return snapshot;
    }

    public static final class MemcgMemorySnapshot {
        public long memcgMemoryInBytes;
        public long memcgSwapMemoryInBytes;
    }
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -19,3 +19,6 @@ per-file TimeoutRecord.java = file:/PERFORMANCE_OWNERS


# ApplicationSharedMemory
# ApplicationSharedMemory
per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS
per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS

# Memcg memory accounting
per-file MemcgProcMemoryUtil.java = file:/PERFORMANCE_OWNERS
+44 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
import static android.util.MathUtils.constrain;
import static android.util.MathUtils.constrain;
import static android.view.Display.HdrCapabilities.HDR_TYPE_INVALID;
import static android.view.Display.HdrCapabilities.HDR_TYPE_INVALID;


import static com.android.internal.os.MemcgProcMemoryUtil.readMemcgMemorySnapshot;
import static com.android.internal.os.ProcfsMemoryUtil.DmaBufType;
import static com.android.internal.os.ProcfsMemoryUtil.DmaBufType;
import static com.android.internal.os.ProcfsMemoryUtil.getProcessCmdlines;
import static com.android.internal.os.ProcfsMemoryUtil.getProcessCmdlines;
import static com.android.internal.os.ProcfsMemoryUtil.readCmdlineFromProcfs;
import static com.android.internal.os.ProcfsMemoryUtil.readCmdlineFromProcfs;
@@ -76,6 +77,7 @@ import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STA
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
import static com.android.server.stats.Flags.addMemcgInformationPuller;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
import static com.android.server.stats.pull.netstats.NetworkStatsUtils.fromPublicNetworkStats;
import static com.android.server.stats.pull.netstats.NetworkStatsUtils.fromPublicNetworkStats;
@@ -213,6 +215,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeRea
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
import com.android.internal.os.LooperStats;
import com.android.internal.os.LooperStats;
import com.android.internal.os.MemcgProcMemoryUtil.MemcgMemorySnapshot;
import com.android.internal.os.PowerProfile;
import com.android.internal.os.PowerProfile;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.ProcfsMemoryUtil;
import com.android.internal.os.ProcfsMemoryUtil;
@@ -468,6 +471,10 @@ public class StatsPullAtomService extends SystemService {
     */
     */
    public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
    public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
                addMobileBytesTransferByProcStatePuller();
                addMobileBytesTransferByProcStatePuller();

    public static final boolean ENABLE_MEMCG_STATS_PULLER =
                addMemcgInformationPuller();

    private static final ArrayMap<String, Integer> mPreviousThermalThrottlingStatus =
    private static final ArrayMap<String, Integer> mPreviousThermalThrottlingStatus =
            new ArrayMap<>();
            new ArrayMap<>();
    // Puller locks
    // Puller locks
@@ -853,6 +860,8 @@ public class StatsPullAtomService extends SystemService {
                        return pullCachedAppsHighWatermark(atomTag, data);
                        return pullCachedAppsHighWatermark(atomTag, data);
                    case FrameworkStatsLog.PRESSURE_STALL_INFORMATION:
                    case FrameworkStatsLog.PRESSURE_STALL_INFORMATION:
                        return pullPressureStallInformation(atomTag, data);
                        return pullPressureStallInformation(atomTag, data);
                    case FrameworkStatsLog.MEMCG_MEMORY_SNAPSHOT:
                        return pullMemcgProcessMemoryInformation(atomTag, data);
                    default:
                    default:
                        throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                        throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                }
                }
@@ -1053,6 +1062,9 @@ public class StatsPullAtomService extends SystemService {
        registerCachedAppsHighWatermarkPuller();
        registerCachedAppsHighWatermarkPuller();
        registerPressureStallInformation();
        registerPressureStallInformation();
        registerBatteryLife();
        registerBatteryLife();
        if (ENABLE_MEMCG_STATS_PULLER) {
            registerMemcgInformation();
        }
    }
    }


    private void initMobileDataStatsPuller() {
    private void initMobileDataStatsPuller() {
@@ -5234,6 +5246,38 @@ public class StatsPullAtomService extends SystemService {
        return StatsManager.PULL_SUCCESS;
        return StatsManager.PULL_SUCCESS;
    }
    }


    private void registerMemcgInformation() {
        int tagId = FrameworkStatsLog.MEMCG_MEMORY_SNAPSHOT;
        mStatsManager.setPullAtomCallback(
                tagId,
                new PullAtomMetadata.Builder()
                        .setCoolDownMillis(MILLIS_PER_SEC)
                        .build(),
                DIRECT_EXECUTOR,
                mStatsCallbackImpl
        );
    }

    int pullMemcgProcessMemoryInformation(int atomTag, List<StatsEvent> pulledData) {
        List<ProcessMemoryState> managedProcessList =
                LocalServices.getService(ActivityManagerInternal.class)
                        .getMemoryStateForProcesses();
        for (ProcessMemoryState managedProcess : managedProcessList) {
            final MemcgMemorySnapshot snapshot = readMemcgMemorySnapshot(managedProcess.pid);
            if (snapshot == null) {
                continue;
            }
            pulledData.add(FrameworkStatsLog.buildStatsEvent(
                    atomTag,
                    managedProcess.uid,
                    managedProcess.processName,
                    snapshot.memcgMemoryInBytes / 1024,
                    snapshot.memcgSwapMemoryInBytes / 1024
            ));
        }
        return StatsManager.PULL_SUCCESS;
    }

    private int toProtoPsiResourceType(PsiData.ResourceType resourceType) {
    private int toProtoPsiResourceType(PsiData.ResourceType resourceType) {
        if (resourceType == PsiData.ResourceType.CPU) {
        if (resourceType == PsiData.ResourceType.CPU) {
            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
+7 −0
Original line number Original line Diff line number Diff line
@@ -41,3 +41,10 @@ flag {
    bug: "398327159"
    bug: "398327159"
    is_fixed_read_only: true
    is_fixed_read_only: true
}
}

flag {
    name: "add_memcg_information_puller"
    namespace: "statsd"
    description: "Adds memcgv2 atom logging"
    bug: "434920925"
}
 No newline at end of file