Cleanup: remove old memory atoms
Memory stats has been migrated to ProcessMemorySnapshot. This CL cleans
up the old atoms:
- remove telemetry-specific additions to ProcessMemoryState
- remove NativeProcessMemoryState atom
- move reading process cmdline under stats
Bug: 140986627
Test: atest MemoryStatUtilTest
Test: atest ProcfsMemoryUtilTest
Test: atest UidAtomTests#testProcessMemoryState
Change-Id: I5339577184d17e5cef6d657cf9b08a2fb8e75fca
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b71a86b..6249de3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -378,7 +378,6 @@
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
ProcessCpuTime process_cpu_time = 10035;
- NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
OnDevicePowerMeasurement on_device_power_measurement = 10038;
DeviceCalculatedPowerUse device_calculated_power_use = 10039;
@@ -412,6 +411,8 @@
// DO NOT USE field numbers above 100,000 in AOSP.
// Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
// Field numbers 200,000 and above are reserved for future use; do not use them at all.
+
+ reserved 10036;
}
/**
@@ -4019,8 +4020,8 @@
optional int64 page_major_fault = 5;
// RSS
- // Value is read from /proc/PID/status. Or from memory.stat, field
- // total_rss if per-app memory cgroups are enabled.
+ // Value is read from memory.stat, field total_rss if per-app memory
+ // cgroups are enabled. Otherwise, value from /proc/pid/stat.
optional int64 rss_in_bytes = 6;
// CACHE
@@ -4030,56 +4031,17 @@
// SWAP
// Value is read from memory.stat, field total_swap if per-app memory
- // cgroups are enabled. Otherwise, VmSwap from /proc/PID/status.
+ // cgroups are enabled. Otherwise, 0.
optional int64 swap_in_bytes = 8;
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
+ // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1.
optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true];
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22. 0 if read from per-app memory cgroups.
- optional int64 start_time_nanos = 10;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int64 start_time_nanos = 10 [deprecated = true];
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 11;
-}
-
-/*
- * Logs the memory stats for a native process (from procfs).
- *
- * Pulled from StatsCompanionService for selected native processes.
- */
-message NativeProcessMemoryState {
- // The uid if available. -1 means not available.
- optional int32 uid = 1 [(is_uid) = true];
-
- // The process name.
- // Value read from /proc/PID/cmdline.
- optional string process_name = 2;
-
- // # of page-faults
- optional int64 page_fault = 3;
-
- // # of major page-faults
- optional int64 page_major_fault = 4;
-
- // RSS
- // Value read from /proc/PID/status.
- optional int64 rss_in_bytes = 5;
-
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
- optional int64 rss_high_watermark_in_bytes = 6 [deprecated = true];
-
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22.
- optional int64 start_time_nanos = 7;
-
- // SWAP
- // Value read from /proc/PID/status, field VmSwap.
- optional int64 swap_in_bytes = 8;
-
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 9;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true];
}
/*
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 7a183a3..43e33f5 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -145,16 +145,11 @@
{.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {.additiveFields = {4, 5, 6, 7, 8, 9},
+ {.additiveFields = {4, 5, 6, 7, 8},
.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
- // native_process_memory_state
- {android::util::NATIVE_PROCESS_MEMORY_STATE,
- {.additiveFields = {3, 4, 5, 6, 8},
- .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
// process_memory_high_water_mark
{android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
- {.additiveFields = {3},
- .puller =
+ {.puller =
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// process_memory_snapshot
{android::util::PROCESS_MEMORY_SNAPSHOT,
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index fd64df9..2081b17 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -39,8 +39,7 @@
* Static utility methods related to {@link MemoryStat}.
*/
public final class MemoryStatUtil {
- static final int BYTES_IN_KILOBYTE = 1024;
- static final long JIFFY_NANOS = 1_000_000_000 / Os.sysconf(OsConstants._SC_CLK_TCK);
+ static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);
private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
@@ -52,10 +51,6 @@
private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
/** Path to procfs stat file for logging app start memory state */
private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
- /** Path to procfs status file for logging app memory state */
- private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
- /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */
- private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline";
private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -63,16 +58,9 @@
private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
- private static final Pattern PROCFS_RSS_IN_KILOBYTES =
- Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB");
- private static final Pattern PROCFS_ANON_RSS_IN_KILOBYTES =
- Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB");
- private static final Pattern PROCFS_SWAP_IN_KILOBYTES =
- Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB");
-
private static final int PGFAULT_INDEX = 9;
private static final int PGMAJFAULT_INDEX = 11;
- private static final int START_TIME_INDEX = 21;
+ private static final int RSS_IN_PAGES_INDEX = 23;
private MemoryStatUtil() {}
@@ -106,19 +94,7 @@
@Nullable
public static MemoryStat readMemoryStatFromProcfs(int pid) {
final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
- final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid);
- return parseMemoryStatFromProcfs(readFileContents(statPath), readFileContents(statusPath));
- }
-
- /**
- * Reads cmdline of a process from procfs.
- *
- * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
- * if the file is not available.
- */
- public static String readCmdlineFromProcfs(int pid) {
- final String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid);
- return parseCmdlineFromProcfs(readFileContents(path));
+ return parseMemoryStatFromProcfs(readFileContents(statPath));
}
private static String readFileContents(String path) {
@@ -160,31 +136,19 @@
*/
@VisibleForTesting
@Nullable
- static MemoryStat parseMemoryStatFromProcfs(
- String procStatContents, String procStatusContents) {
+ static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {
if (procStatContents == null || procStatContents.isEmpty()) {
return null;
}
- if (procStatusContents == null || procStatusContents.isEmpty()) {
- return null;
- }
-
final String[] splits = procStatContents.split(" ");
if (splits.length < 24) {
return null;
}
-
try {
final MemoryStat memoryStat = new MemoryStat();
memoryStat.pgfault = Long.parseLong(splits[PGFAULT_INDEX]);
memoryStat.pgmajfault = Long.parseLong(splits[PGMAJFAULT_INDEX]);
- memoryStat.rssInBytes =
- tryParseLong(PROCFS_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
- memoryStat.anonRssInBytes =
- tryParseLong(PROCFS_ANON_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
- memoryStat.swapInBytes =
- tryParseLong(PROCFS_SWAP_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
- memoryStat.startTimeNanos = Long.parseLong(splits[START_TIME_INDEX]) * JIFFY_NANOS;
+ memoryStat.rssInBytes = Long.parseLong(splits[RSS_IN_PAGES_INDEX]) * PAGE_SIZE;
return memoryStat;
} catch (NumberFormatException e) {
Slog.e(TAG, "Failed to parse value", e);
@@ -193,23 +157,6 @@
}
/**
- * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
- *
- * Parsing is required to strip anything after first null byte.
- */
- @VisibleForTesting
- static String parseCmdlineFromProcfs(String cmdline) {
- if (cmdline == null) {
- return "";
- }
- int firstNullByte = cmdline.indexOf("\0");
- if (firstNullByte == -1) {
- return cmdline;
- }
- return cmdline.substring(0, firstNullByte);
- }
-
- /**
* Returns whether per-app memcg is available on device.
*/
static boolean hasMemcg() {
@@ -237,13 +184,9 @@
public long pgmajfault;
/** For memcg stats, the anon rss + swap cache size. Otherwise total RSS. */
public long rssInBytes;
- /** Number of bytes of the anonymous RSS. Only present for non-memcg stats. */
- public long anonRssInBytes;
/** Number of bytes of page cache memory. Only present for memcg stats. */
public long cacheInBytes;
/** Number of bytes of swap usage */
public long swapInBytes;
- /** Device time when the processes started. */
- public long startTimeNanos;
}
}
diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
index 2b25b89..8431ae4 100644
--- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
@@ -72,6 +72,30 @@
return null;
}
+ /**
+ * Reads cmdline of a process from procfs.
+ *
+ * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
+ * if the file is not available.
+ */
+ public static String readCmdlineFromProcfs(int pid) {
+ return parseCmdline(readFile("/proc/" + pid + "/cmdline"));
+ }
+
+ /**
+ * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
+ *
+ * Parsing is required to strip anything after the first null byte.
+ */
+ @VisibleForTesting
+ static String parseCmdline(String contents) {
+ int firstNullByte = contents.indexOf("\0");
+ if (firstNullByte == -1) {
+ return contents;
+ }
+ return contents.substring(0, firstNullByte);
+ }
+
private static String readFile(String path) {
try {
final File file = new File(path);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 67830a9..1d3ac6a 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -24,11 +24,10 @@
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
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.readCmdlineFromProcfs;
import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
import android.annotation.NonNull;
@@ -1193,48 +1192,13 @@
e.writeLong(memoryStat.rssInBytes);
e.writeLong(memoryStat.cacheInBytes);
e.writeLong(memoryStat.swapInBytes);
- e.writeLong(0); // unused
- e.writeLong(memoryStat.startTimeNanos);
- e.writeInt(anonAndSwapInKilobytes(memoryStat));
+ e.writeLong(-1); // unused
+ e.writeLong(-1); // unused
+ e.writeInt(-1); // unsed
pulledData.add(e);
}
}
- private void pullNativeProcessMemoryState(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
- for (int pid : pids) {
- String processName = readCmdlineFromProcfs(pid);
- MemoryStat memoryStat = readMemoryStatFromProcfs(pid);
- if (memoryStat == null) {
- continue;
- }
- int uid = getUidForPid(pid);
- // Sometimes we get here a process that is not included in the whitelist. It comes
- // from forking the zygote for an app. We can ignore that sample because this process
- // is collected by ProcessMemoryState.
- if (isAppUid(uid)) {
- continue;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(uid);
- e.writeString(processName);
- e.writeLong(memoryStat.pgfault);
- e.writeLong(memoryStat.pgmajfault);
- e.writeLong(memoryStat.rssInBytes);
- e.writeLong(0); // unused
- e.writeLong(memoryStat.startTimeNanos);
- e.writeLong(memoryStat.swapInBytes);
- e.writeInt(anonAndSwapInKilobytes(memoryStat));
- pulledData.add(e);
- }
- }
-
- private static int anonAndSwapInKilobytes(MemoryStat memoryStat) {
- return (int) ((memoryStat.anonRssInBytes + memoryStat.swapInBytes) / 1024);
- }
-
private void pullProcessMemoryHighWaterMark(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
@@ -2405,10 +2369,6 @@
pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
- case StatsLog.NATIVE_PROCESS_MEMORY_STATE: {
- pullNativeProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: {
pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
break;
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 9e3b54d..c3a1243 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -16,10 +16,8 @@
package com.android.server.am;
-import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
-import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
-import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
+import static com.android.server.am.MemoryStatUtil.PAGE_SIZE;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
@@ -30,7 +28,6 @@
import org.junit.Test;
-import java.io.ByteArrayOutputStream;
import java.util.Collections;
/**
@@ -99,7 +96,7 @@
"0",
"2222", // this in start time (in ticks per second)
"1257177088",
- "3",
+ "3", // this is RSS in pages
"4294967295",
"2936971264",
"2936991289",
@@ -129,53 +126,6 @@
"3198889956",
"0");
- private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n"
- + "State:\tS (sleeping)\n"
- + "Tgid:\t12088\n"
- + "Pid:\t12088\n"
- + "PPid:\t723\n"
- + "TracerPid:\t0\n"
- + "Uid:\t10083\t10083\t10083\t10083\n"
- + "Gid:\t10083\t10083\t10083\t10083\n"
- + "Ngid:\t0\n"
- + "FDSize:\t128\n"
- + "Groups:\t3003 9997 20083 50083 \n"
- + "VmPeak:\t 4546844 kB\n"
- + "VmSize:\t 4542636 kB\n"
- + "VmLck:\t 0 kB\n"
- + "VmPin:\t 0 kB\n"
- + "VmHWM:\t 137668 kB\n" // RSS high-water mark
- + "VmRSS:\t 126776 kB\n" // RSS
- + "RssAnon:\t 37860 kB\n"
- + "RssFile:\t 88764 kB\n"
- + "RssShmem:\t 152 kB\n"
- + "VmData:\t 4125112 kB\n"
- + "VmStk:\t 8192 kB\n"
- + "VmExe:\t 24 kB\n"
- + "VmLib:\t 102432 kB\n"
- + "VmPTE:\t 1300 kB\n"
- + "VmPMD:\t 36 kB\n"
- + "VmSwap:\t 22 kB\n" // Swap
- + "Threads:\t95\n"
- + "SigQ:\t0/13641\n"
- + "SigPnd:\t0000000000000000\n"
- + "ShdPnd:\t0000000000000000\n"
- + "SigBlk:\t0000000000001204\n"
- + "SigIgn:\t0000000000000001\n"
- + "SigCgt:\t00000006400084f8\n"
- + "CapInh:\t0000000000000000\n"
- + "CapPrm:\t0000000000000000\n"
- + "CapEff:\t0000000000000000\n"
- + "CapBnd:\t0000000000000000\n"
- + "CapAmb:\t0000000000000000\n"
- + "Seccomp:\t2\n"
- + "Cpus_allowed:\tff\n"
- + "Cpus_allowed_list:\t0-7\n"
- + "Mems_allowed:\t1\n"
- + "Mems_allowed_list:\t0\n"
- + "voluntary_ctxt_switches:\t903\n"
- + "nonvoluntary_ctxt_switches:\t104\n";
-
@Test
public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
@@ -197,71 +147,26 @@
@Test
public void testParseMemoryStatFromProcfs_parsesCorrectValues() {
- MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, PROC_STATUS_CONTENTS);
+ MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS);
assertEquals(1, stat.pgfault);
assertEquals(2, stat.pgmajfault);
- assertEquals(126776 * BYTES_IN_KILOBYTE, stat.rssInBytes);
+ assertEquals(3 * PAGE_SIZE, stat.rssInBytes);
assertEquals(0, stat.cacheInBytes);
- assertEquals(22 * BYTES_IN_KILOBYTE, stat.swapInBytes);
- assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos);
- assertEquals(37860 * BYTES_IN_KILOBYTE, stat.anonRssInBytes);
+ assertEquals(0, stat.swapInBytes);
}
@Test
public void testParseMemoryStatFromProcfs_emptyContents() {
- MemoryStat stat = parseMemoryStatFromProcfs("", PROC_STATUS_CONTENTS);
+ MemoryStat stat = parseMemoryStatFromProcfs("");
assertNull(stat);
- stat = parseMemoryStatFromProcfs(null, PROC_STATUS_CONTENTS);
- assertNull(stat);
-
- stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, "");
- assertNull(stat);
-
- stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, null);
+ stat = parseMemoryStatFromProcfs(null);
assertNull(stat);
}
@Test
public void testParseMemoryStatFromProcfs_invalidValue() {
String contents = String.join(" ", Collections.nCopies(24, "memory"));
- assertNull(parseMemoryStatFromProcfs(contents, PROC_STATUS_CONTENTS));
- }
-
- @Test
- public void testParseCmdlineFromProcfs_invalidValue() {
- byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
-
- assertEquals("", parseCmdlineFromProcfs(bytesToString(nothing)));
- }
-
- @Test
- public void testParseCmdlineFromProcfs_correctValue_noNullBytes() {
- assertEquals("com.google.app", parseCmdlineFromProcfs("com.google.app"));
- }
-
- @Test
- public void testParseCmdlineFromProcfs_correctValue_withNullBytes() {
- byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
-
- assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
-
- // test\0\0test
- byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
-
- assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
- }
-
- @Test
- public void testParseCmdlineFromProcfs_emptyContents() {
- assertEquals("", parseCmdlineFromProcfs(""));
-
- assertEquals("", parseCmdlineFromProcfs(null));
- }
-
- private static String bytesToString(byte[] bytes) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- output.write(bytes, 0, bytes.length);
- return output.toString();
+ assertNull(parseMemoryStatFromProcfs(contents));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
index dd2ee5c..d1ac19c 100644
--- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.stats;
+import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline;
import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus;
import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +26,8 @@
import org.junit.Test;
+import java.io.ByteArrayOutputStream;
+
/**
* Build/Install/Run:
* atest FrameworksServicesTests:ProcfsMemoryUtilTest
@@ -100,4 +103,39 @@
MemorySnapshot snapshot = parseMemorySnapshotFromStatus("");
assertThat(snapshot).isNull();
}
+
+ @Test
+ public void testParseCmdline_invalidValue() {
+ byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
+
+ assertThat(parseCmdline(bytesToString(nothing))).isEmpty();
+ }
+
+ @Test
+ public void testParseCmdline_correctValue_noNullBytes() {
+ assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app");
+ }
+
+ @Test
+ public void testParseCmdline_correctValue_withNullBytes() {
+ byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
+
+ assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
+
+ // test\0\0test
+ byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
+
+ assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
+ }
+
+ @Test
+ public void testParseCmdline_emptyContents() {
+ assertThat(parseCmdline("")).isEmpty();
+ }
+
+ private static String bytesToString(byte[] bytes) {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ output.write(bytes, 0, bytes.length);
+ return output.toString();
+ }
}