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();
+    }
 }