Loading cmds/statsd/src/atoms.proto +42 −1 Original line number Diff line number Diff line Loading @@ -340,7 +340,7 @@ message Atom { } // Pulled events will start at field 10000. // Next: 10064 // Next: 10065 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; Loading Loading @@ -406,6 +406,7 @@ message Atom { ProcessSystemIonHeapSize process_system_ion_heap_size = 10061; SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062; SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063; ProcessMemorySnapshot process_memory_snapshot = 10064; } // DO NOT USE field numbers above 100,000 in AOSP. Loading Loading @@ -4107,6 +4108,46 @@ message ProcessMemoryHighWaterMark { optional int32 rss_high_water_mark_in_kilobytes = 4; } /* * Logs the memory stats for a process. * * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService) * and for selected native processes. */ message ProcessMemorySnapshot { // The uid if available. -1 means not available. optional int32 uid = 1 [(is_uid) = true]; // The process name. // Usually package name or process cmdline. // Provided by ActivityManagerService or read from /proc/PID/cmdline. optional string process_name = 2; // The pid of the process. // Allows to disambiguate instances of the process. optional int32 pid = 3; // The current OOM score adjustment value. // Read from ProcessRecord for managed processes. // Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones. optional int32 oom_score_adj = 4; // The current RSS of the process. // VmRSS from /proc/pid/status. optional int32 rss_in_kilobytes = 5; // The current anon RSS of the process. // RssAnon from /proc/pid/status. optional int32 anon_rss_in_kilobytes = 6; // The current swap size of the process. // VmSwap from /proc/pid/status. optional int32 swap_in_kilobytes = 7; // The sum of rss_in_kilobytes and swap_in_kilobytes. optional int32 anon_rss_and_swap_in_kilobytes = 8; } /* * Elapsed real time from SystemClock. */ Loading cmds/statsd/src/external/StatsPullerManager.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {.additiveFields = {3}, .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, // process_memory_snapshot {android::util::PROCESS_MEMORY_SNAPSHOT, {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}}, // system_ion_heap_size {android::util::SYSTEM_ION_HEAP_SIZE, {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}}, Loading services/core/java/com/android/server/stats/ProcfsMemoryUtil.java +45 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,12 @@ final class ProcfsMemoryUtil { private static final Pattern RSS_HIGH_WATER_MARK_IN_KILOBYTES = Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); private static final Pattern RSS_IN_KILOBYTES = Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB"); private static final Pattern ANON_RSS_IN_KILOBYTES = Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB"); private static final Pattern SWAP_IN_KILOBYTES = Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB"); private ProcfsMemoryUtil() {} Loading @@ -52,10 +58,41 @@ final class ProcfsMemoryUtil { */ @VisibleForTesting static int parseVmHWMFromStatus(String contents) { return tryParseInt(contents, RSS_HIGH_WATER_MARK_IN_KILOBYTES); } /** * Reads memory stat of a process from procfs. Returns values of the VmRss, AnonRSS, VmSwap * fields in /proc/pid/status in kilobytes or 0 if not available. */ static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { final String statusPath = String.format(Locale.US, STATUS_FILE_FMT, pid); return parseMemorySnapshotFromStatus(readFile(statusPath)); } @VisibleForTesting static MemorySnapshot parseMemorySnapshotFromStatus(String contents) { final MemorySnapshot snapshot = new MemorySnapshot(); snapshot.rssInKilobytes = tryParseInt(contents, RSS_IN_KILOBYTES); snapshot.anonRssInKilobytes = tryParseInt(contents, ANON_RSS_IN_KILOBYTES); snapshot.swapInKilobytes = tryParseInt(contents, SWAP_IN_KILOBYTES); return snapshot; } private static String readFile(String path) { try { final File file = new File(path); return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); } catch (IOException e) { return ""; } } private static int tryParseInt(String contents, Pattern pattern) { if (contents.isEmpty()) { return 0; } final Matcher matcher = RSS_HIGH_WATER_MARK_IN_KILOBYTES.matcher(contents); final Matcher matcher = pattern.matcher(contents); try { return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; } catch (NumberFormatException e) { Loading @@ -64,12 +101,13 @@ final class ProcfsMemoryUtil { } } private static String readFile(String path) { try { final File file = new File(path); return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); } catch (IOException e) { return ""; static final class MemorySnapshot { public int rssInKilobytes; public int anonRssInKilobytes; public int swapInKilobytes; boolean isEmpty() { return (anonRssInKilobytes + swapInKilobytes) == 0; } } } services/core/java/com/android/server/stats/StatsCompanionService.java +47 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; import static com.android.server.stats.ProcfsMemoryUtil.readRssHighWaterMarkFromProcfs; import android.annotation.NonNull; Loading Loading @@ -141,6 +142,7 @@ import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.role.RoleManagerInternal; import com.android.server.stats.IonMemoryUtil.IonAllocations; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; Loading Loading @@ -1270,6 +1272,47 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { SystemProperties.set("sys.rss_hwm_reset.on", "1"); } private void pullProcessMemorySnapshot( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { List<ProcessMemoryState> managedProcessList = LocalServices.getService( ActivityManagerInternal.class).getMemoryStateForProcesses(); for (ProcessMemoryState managedProcess : managedProcessList) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(managedProcess.uid); e.writeString(managedProcess.processName); e.writeInt(managedProcess.pid); e.writeInt(managedProcess.oomScore); final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); if (snapshot.isEmpty()) { continue; } e.writeInt(snapshot.rssInKilobytes); e.writeInt(snapshot.anonRssInKilobytes); e.writeInt(snapshot.swapInKilobytes); e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); } int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES); for (int pid : pids) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(getUidForPid(pid)); e.writeString(readCmdlineFromProcfs(pid)); e.writeInt(pid); e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1. final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); if (snapshot.isEmpty()) { continue; } e.writeInt(snapshot.rssInKilobytes); e.writeInt(snapshot.anonRssInKilobytes); e.writeInt(snapshot.swapInKilobytes); e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); } } private void pullSystemIonHeapSize( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { Loading Loading @@ -2352,6 +2395,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.PROCESS_MEMORY_SNAPSHOT: { pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.SYSTEM_ION_HEAP_SIZE: { pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret); break; Loading services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java +31 −0 Original line number Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ package com.android.server.stats; import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus; import static com.android.server.stats.ProcfsMemoryUtil.parseVmHWMFromStatus; import static com.google.common.truth.Truth.assertThat; import androidx.test.filters.SmallTest; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import org.junit.Test; /** Loading Loading @@ -90,4 +93,32 @@ public class ProcfsMemoryUtilTest { public void testParseVmHWMFromStatus_emptyContents() { assertThat(parseVmHWMFromStatus("")).isEqualTo(0); } @Test public void testParseMemorySnapshotFromStatus_parsesCorrectValue() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS); assertThat(snapshot.rssInKilobytes).isEqualTo(126776); assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860); assertThat(snapshot.swapInKilobytes).isEqualTo(22); assertThat(snapshot.isEmpty()).isFalse(); } @Test public void testParseMemorySnapshotFromStatus_invalidValue() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest"); assertThat(snapshot.rssInKilobytes).isEqualTo(0); assertThat(snapshot.anonRssInKilobytes).isEqualTo(0); assertThat(snapshot.swapInKilobytes).isEqualTo(1); assertThat(snapshot.isEmpty()).isFalse(); } @Test public void testParseMemorySnapshotFromStatus_emptyContents() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus(""); assertThat(snapshot.rssInKilobytes).isEqualTo(0); assertThat(snapshot.anonRssInKilobytes).isEqualTo(0); assertThat(snapshot.swapInKilobytes).isEqualTo(0); assertThat(snapshot.isEmpty()).isTrue(); } } Loading
cmds/statsd/src/atoms.proto +42 −1 Original line number Diff line number Diff line Loading @@ -340,7 +340,7 @@ message Atom { } // Pulled events will start at field 10000. // Next: 10064 // Next: 10065 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; Loading Loading @@ -406,6 +406,7 @@ message Atom { ProcessSystemIonHeapSize process_system_ion_heap_size = 10061; SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062; SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063; ProcessMemorySnapshot process_memory_snapshot = 10064; } // DO NOT USE field numbers above 100,000 in AOSP. Loading Loading @@ -4107,6 +4108,46 @@ message ProcessMemoryHighWaterMark { optional int32 rss_high_water_mark_in_kilobytes = 4; } /* * Logs the memory stats for a process. * * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService) * and for selected native processes. */ message ProcessMemorySnapshot { // The uid if available. -1 means not available. optional int32 uid = 1 [(is_uid) = true]; // The process name. // Usually package name or process cmdline. // Provided by ActivityManagerService or read from /proc/PID/cmdline. optional string process_name = 2; // The pid of the process. // Allows to disambiguate instances of the process. optional int32 pid = 3; // The current OOM score adjustment value. // Read from ProcessRecord for managed processes. // Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones. optional int32 oom_score_adj = 4; // The current RSS of the process. // VmRSS from /proc/pid/status. optional int32 rss_in_kilobytes = 5; // The current anon RSS of the process. // RssAnon from /proc/pid/status. optional int32 anon_rss_in_kilobytes = 6; // The current swap size of the process. // VmSwap from /proc/pid/status. optional int32 swap_in_kilobytes = 7; // The sum of rss_in_kilobytes and swap_in_kilobytes. optional int32 anon_rss_and_swap_in_kilobytes = 8; } /* * Elapsed real time from SystemClock. */ Loading
cmds/statsd/src/external/StatsPullerManager.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {.additiveFields = {3}, .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, // process_memory_snapshot {android::util::PROCESS_MEMORY_SNAPSHOT, {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}}, // system_ion_heap_size {android::util::SYSTEM_ION_HEAP_SIZE, {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}}, Loading
services/core/java/com/android/server/stats/ProcfsMemoryUtil.java +45 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,12 @@ final class ProcfsMemoryUtil { private static final Pattern RSS_HIGH_WATER_MARK_IN_KILOBYTES = Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); private static final Pattern RSS_IN_KILOBYTES = Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB"); private static final Pattern ANON_RSS_IN_KILOBYTES = Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB"); private static final Pattern SWAP_IN_KILOBYTES = Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB"); private ProcfsMemoryUtil() {} Loading @@ -52,10 +58,41 @@ final class ProcfsMemoryUtil { */ @VisibleForTesting static int parseVmHWMFromStatus(String contents) { return tryParseInt(contents, RSS_HIGH_WATER_MARK_IN_KILOBYTES); } /** * Reads memory stat of a process from procfs. Returns values of the VmRss, AnonRSS, VmSwap * fields in /proc/pid/status in kilobytes or 0 if not available. */ static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { final String statusPath = String.format(Locale.US, STATUS_FILE_FMT, pid); return parseMemorySnapshotFromStatus(readFile(statusPath)); } @VisibleForTesting static MemorySnapshot parseMemorySnapshotFromStatus(String contents) { final MemorySnapshot snapshot = new MemorySnapshot(); snapshot.rssInKilobytes = tryParseInt(contents, RSS_IN_KILOBYTES); snapshot.anonRssInKilobytes = tryParseInt(contents, ANON_RSS_IN_KILOBYTES); snapshot.swapInKilobytes = tryParseInt(contents, SWAP_IN_KILOBYTES); return snapshot; } private static String readFile(String path) { try { final File file = new File(path); return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); } catch (IOException e) { return ""; } } private static int tryParseInt(String contents, Pattern pattern) { if (contents.isEmpty()) { return 0; } final Matcher matcher = RSS_HIGH_WATER_MARK_IN_KILOBYTES.matcher(contents); final Matcher matcher = pattern.matcher(contents); try { return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; } catch (NumberFormatException e) { Loading @@ -64,12 +101,13 @@ final class ProcfsMemoryUtil { } } private static String readFile(String path) { try { final File file = new File(path); return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); } catch (IOException e) { return ""; static final class MemorySnapshot { public int rssInKilobytes; public int anonRssInKilobytes; public int swapInKilobytes; boolean isEmpty() { return (anonRssInKilobytes + swapInKilobytes) == 0; } } }
services/core/java/com/android/server/stats/StatsCompanionService.java +47 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; import static com.android.server.stats.ProcfsMemoryUtil.readRssHighWaterMarkFromProcfs; import android.annotation.NonNull; Loading Loading @@ -141,6 +142,7 @@ import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.role.RoleManagerInternal; import com.android.server.stats.IonMemoryUtil.IonAllocations; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; Loading Loading @@ -1270,6 +1272,47 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { SystemProperties.set("sys.rss_hwm_reset.on", "1"); } private void pullProcessMemorySnapshot( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { List<ProcessMemoryState> managedProcessList = LocalServices.getService( ActivityManagerInternal.class).getMemoryStateForProcesses(); for (ProcessMemoryState managedProcess : managedProcessList) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(managedProcess.uid); e.writeString(managedProcess.processName); e.writeInt(managedProcess.pid); e.writeInt(managedProcess.oomScore); final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); if (snapshot.isEmpty()) { continue; } e.writeInt(snapshot.rssInKilobytes); e.writeInt(snapshot.anonRssInKilobytes); e.writeInt(snapshot.swapInKilobytes); e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); } int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES); for (int pid : pids) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(getUidForPid(pid)); e.writeString(readCmdlineFromProcfs(pid)); e.writeInt(pid); e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1. final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); if (snapshot.isEmpty()) { continue; } e.writeInt(snapshot.rssInKilobytes); e.writeInt(snapshot.anonRssInKilobytes); e.writeInt(snapshot.swapInKilobytes); e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); } } private void pullSystemIonHeapSize( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { Loading Loading @@ -2352,6 +2395,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.PROCESS_MEMORY_SNAPSHOT: { pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret); break; } case StatsLog.SYSTEM_ION_HEAP_SIZE: { pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret); break; Loading
services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java +31 −0 Original line number Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ package com.android.server.stats; import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus; import static com.android.server.stats.ProcfsMemoryUtil.parseVmHWMFromStatus; import static com.google.common.truth.Truth.assertThat; import androidx.test.filters.SmallTest; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import org.junit.Test; /** Loading Loading @@ -90,4 +93,32 @@ public class ProcfsMemoryUtilTest { public void testParseVmHWMFromStatus_emptyContents() { assertThat(parseVmHWMFromStatus("")).isEqualTo(0); } @Test public void testParseMemorySnapshotFromStatus_parsesCorrectValue() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS); assertThat(snapshot.rssInKilobytes).isEqualTo(126776); assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860); assertThat(snapshot.swapInKilobytes).isEqualTo(22); assertThat(snapshot.isEmpty()).isFalse(); } @Test public void testParseMemorySnapshotFromStatus_invalidValue() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest"); assertThat(snapshot.rssInKilobytes).isEqualTo(0); assertThat(snapshot.anonRssInKilobytes).isEqualTo(0); assertThat(snapshot.swapInKilobytes).isEqualTo(1); assertThat(snapshot.isEmpty()).isFalse(); } @Test public void testParseMemorySnapshotFromStatus_emptyContents() { MemorySnapshot snapshot = parseMemorySnapshotFromStatus(""); assertThat(snapshot.rssInKilobytes).isEqualTo(0); assertThat(snapshot.anonRssInKilobytes).isEqualTo(0); assertThat(snapshot.swapInKilobytes).isEqualTo(0); assertThat(snapshot.isEmpty()).isTrue(); } }