Add anon RSS + swap metric

We are planning to use this metric to detect leaks.

This CL also decouples the actual memory sampling from AM. This means:
- Less time locking the pid list (we used to lock and then read proc)
- Less serialization / deserialization for the parcel
- Simpler to evolve (e.g. removed the HWM-specific method in AM)

Change-Id: I87a7243156dd8c88cfa85038e7e6cf4963e271e1
Test: manual, MemoryStatUtilTest, UidAtomTests
Bug: b/135418017
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d457ff9..f47767e 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3948,7 +3948,7 @@
     optional int64 page_major_fault = 5;
 
     // RSS
-    // Value is read from /proc/PID/stat, field 24. Or from memory.stat, field
+    // Value is read from /proc/PID/status. Or from memory.stat, field
     // total_rss if per-app memory cgroups are enabled.
     optional int64 rss_in_bytes = 6;
 
@@ -3968,6 +3968,9 @@
     // 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;
+
+    // Anonymous page size plus swap size. Values are read from /proc/PID/status.
+    optional int32 anon_rss_and_swap_in_kilobytes = 11;
 }
 
 /*
@@ -3990,7 +3993,7 @@
     optional int64 page_major_fault = 4;
 
     // RSS
-    // Value read from /proc/PID/stat, field 24.
+    // Value read from /proc/PID/status.
     optional int64 rss_in_bytes = 5;
 
     // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
@@ -4003,6 +4006,9 @@
     // 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;
 }
 
 /*
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0b25b2e..8508c2c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -168,20 +168,13 @@
     public abstract boolean isUidActive(int uid);
 
     /**
-     * Returns a list that contains the memory stats for currently running processes.
+     * Returns a list of running processes along with corresponding uids, pids and their oom score.
      *
      * Only processes managed by ActivityManagerService are included.
      */
     public abstract List<ProcessMemoryState> getMemoryStateForProcesses();
 
     /**
-     * Returns a list that contains the memory high-water mark for currently running processes.
-     *
-     * Only processes managed by ActivityManagerService are included.
-     */
-    public abstract List<ProcessMemoryHighWaterMark> getMemoryHighWaterMarkForProcesses();
-
-    /**
      * Checks to see if the calling pid is allowed to handle the user. Returns adjusted user id as
      * needed.
      */
diff --git a/core/java/android/app/ProcessMemoryHighWaterMark.java b/core/java/android/app/ProcessMemoryHighWaterMark.java
deleted file mode 100644
index d1cae94..0000000
--- a/core/java/android/app/ProcessMemoryHighWaterMark.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.app;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * The memory high-water mark value for a process.
- * {@hide}
- */
-public final class ProcessMemoryHighWaterMark implements Parcelable {
-    public final int uid;
-    public final String processName;
-    public final long rssHighWaterMarkInBytes;
-
-    public ProcessMemoryHighWaterMark(int uid, String processName, long rssHighWaterMarkInBytes) {
-        this.uid = uid;
-        this.processName = processName;
-        this.rssHighWaterMarkInBytes = rssHighWaterMarkInBytes;
-    }
-
-    private ProcessMemoryHighWaterMark(Parcel in) {
-        uid = in.readInt();
-        processName = in.readString();
-        rssHighWaterMarkInBytes = in.readLong();
-    }
-
-    public static final @android.annotation.NonNull Creator<ProcessMemoryHighWaterMark> CREATOR =
-            new Creator<ProcessMemoryHighWaterMark>() {
-                @Override
-                public ProcessMemoryHighWaterMark createFromParcel(Parcel in) {
-                    return new ProcessMemoryHighWaterMark(in);
-                }
-
-                @Override
-                public ProcessMemoryHighWaterMark[] newArray(int size) {
-                    return new ProcessMemoryHighWaterMark[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(uid);
-        parcel.writeString(processName);
-        parcel.writeLong(rssHighWaterMarkInBytes);
-    }
-}
diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java
index e28d79c..24914a6 100644
--- a/core/java/android/app/ProcessMemoryState.java
+++ b/core/java/android/app/ProcessMemoryState.java
@@ -20,44 +20,27 @@
 import android.os.Parcelable;
 
 /**
- * The memory stats for a process.
+ * State (oom score) for processes known to activity manager.
  * {@hide}
  */
 public final class ProcessMemoryState implements Parcelable {
     public final int uid;
+    public final int pid;
     public final String processName;
     public final int oomScore;
-    public final long pgfault;
-    public final long pgmajfault;
-    public final long rssInBytes;
-    public final long cacheInBytes;
-    public final long swapInBytes;
-    public final long startTimeNanos;
 
-    public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,
-                              long pgmajfault, long rssInBytes, long cacheInBytes,
-                              long swapInBytes, long startTimeNanos) {
+    public ProcessMemoryState(int uid, int pid, String processName, int oomScore) {
         this.uid = uid;
+        this.pid = pid;
         this.processName = processName;
         this.oomScore = oomScore;
-        this.pgfault = pgfault;
-        this.pgmajfault = pgmajfault;
-        this.rssInBytes = rssInBytes;
-        this.cacheInBytes = cacheInBytes;
-        this.swapInBytes = swapInBytes;
-        this.startTimeNanos = startTimeNanos;
     }
 
     private ProcessMemoryState(Parcel in) {
         uid = in.readInt();
+        pid = in.readInt();
         processName = in.readString();
         oomScore = in.readInt();
-        pgfault = in.readLong();
-        pgmajfault = in.readLong();
-        rssInBytes = in.readLong();
-        cacheInBytes = in.readLong();
-        swapInBytes = in.readLong();
-        startTimeNanos = in.readLong();
     }
 
     public static final @android.annotation.NonNull Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() {
@@ -80,13 +63,8 @@
     @Override
     public void writeToParcel(Parcel parcel, int i) {
         parcel.writeInt(uid);
+        parcel.writeInt(pid);
         parcel.writeString(processName);
         parcel.writeInt(oomScore);
-        parcel.writeLong(pgfault);
-        parcel.writeLong(pgmajfault);
-        parcel.writeLong(rssInBytes);
-        parcel.writeLong(cacheInBytes);
-        parcel.writeLong(swapInBytes);
-        parcel.writeLong(startTimeNanos);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 627ca91..b342d37 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -120,8 +120,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.MemoryStatUtil.hasMemcg;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -178,7 +176,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.ProcessMemoryHighWaterMark;
 import android.app.ProcessMemoryState;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
@@ -349,7 +346,6 @@
 import com.android.server.ThreadPriorityBooster;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
-import com.android.server.am.MemoryStatUtil.MemoryStat;
 import com.android.server.appop.AppOpsService;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.firewall.IntentFirewall;
@@ -17861,43 +17857,14 @@
             synchronized (mPidsSelfLocked) {
                 for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) {
                     final ProcessRecord r = mPidsSelfLocked.valueAt(i);
-                    final int pid = r.pid;
-                    final int uid = r.uid;
-                    final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
-                    if (memoryStat == null) {
-                        continue;
-                    }
-                    ProcessMemoryState processMemoryState =
-                            new ProcessMemoryState(uid,
-                                    r.processName,
-                                    r.curAdj,
-                                    memoryStat.pgfault,
-                                    memoryStat.pgmajfault,
-                                    memoryStat.rssInBytes,
-                                    memoryStat.cacheInBytes,
-                                    memoryStat.swapInBytes,
-                                    memoryStat.startTimeNanos);
-                    processMemoryStates.add(processMemoryState);
+                    processMemoryStates.add(
+                            new ProcessMemoryState(r.uid, r.pid, r.processName, r.curAdj));
                 }
             }
             return processMemoryStates;
         }
 
         @Override
-        public List<ProcessMemoryHighWaterMark> getMemoryHighWaterMarkForProcesses() {
-            List<ProcessMemoryHighWaterMark> results = new ArrayList<>();
-            synchronized (mPidsSelfLocked) {
-                for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) {
-                    final ProcessRecord r = mPidsSelfLocked.valueAt(i);
-                    final long rssHighWaterMarkInBytes = readRssHighWaterMarkFromProcfs(r.pid);
-                    results.add(new ProcessMemoryHighWaterMark(r.uid, r.processName,
-                            rssHighWaterMarkInBytes));
-                }
-            }
-            return results;
-        }
-
-        @Override
         public int handleIncomingUser(int callingPid, int callingUid, int userId,
                 boolean allowAll, int allowMode, String name, String callerPackage) {
             return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 78d2634..58d9965 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -69,6 +69,8 @@
             Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB");
     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");
 
@@ -204,6 +206,8 @@
             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;
@@ -284,9 +288,11 @@
         public long pgfault;
         /** Number of major page faults */
         public long pgmajfault;
-        /** Number of bytes of anonymous and swap cache memory */
+        /** For memcg stats, the anon rss + swap cache size. Otherwise total RSS. */
         public long rssInBytes;
-        /** Number of bytes of page cache memory */
+        /** 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;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 63439d5..f0b2eca 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -25,6 +25,7 @@
 
 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.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readSystemIonHeapSizeFromDebugfs;
@@ -39,7 +40,6 @@
 import android.app.AppOpsManager.HistoricalOpsRequest;
 import android.app.AppOpsManager.HistoricalPackageOps;
 import android.app.AppOpsManager.HistoricalUidOps;
-import android.app.ProcessMemoryHighWaterMark;
 import android.app.ProcessMemoryState;
 import android.app.StatsManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -1170,17 +1170,23 @@
                 LocalServices.getService(
                         ActivityManagerInternal.class).getMemoryStateForProcesses();
         for (ProcessMemoryState processMemoryState : processMemoryStates) {
+            final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid,
+                    processMemoryState.pid);
+            if (memoryStat == null) {
+                continue;
+            }
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(processMemoryState.uid);
             e.writeString(processMemoryState.processName);
             e.writeInt(processMemoryState.oomScore);
-            e.writeLong(processMemoryState.pgfault);
-            e.writeLong(processMemoryState.pgmajfault);
-            e.writeLong(processMemoryState.rssInBytes);
-            e.writeLong(processMemoryState.cacheInBytes);
-            e.writeLong(processMemoryState.swapInBytes);
+            e.writeLong(memoryStat.pgfault);
+            e.writeLong(memoryStat.pgmajfault);
+            e.writeLong(memoryStat.rssInBytes);
+            e.writeLong(memoryStat.cacheInBytes);
+            e.writeLong(memoryStat.swapInBytes);
             e.writeLong(0);  // unused
-            e.writeLong(processMemoryState.startTimeNanos);
+            e.writeLong(memoryStat.startTimeNanos);
+            e.writeInt(anonAndSwapInKilobytes(memoryStat));
             pulledData.add(e);
         }
     }
@@ -1213,20 +1219,31 @@
             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) {
-        List<ProcessMemoryHighWaterMark> results = LocalServices.getService(
-                ActivityManagerInternal.class).getMemoryHighWaterMarkForProcesses();
-        for (ProcessMemoryHighWaterMark processMemoryHighWaterMark : results) {
+        List<ProcessMemoryState> managedProcessList =
+                LocalServices.getService(
+                        ActivityManagerInternal.class).getMemoryStateForProcesses();
+        for (ProcessMemoryState managedProcess : managedProcessList) {
+            final long rssHighWaterMarkInBytes =
+                    readRssHighWaterMarkFromProcfs(managedProcess.pid);
+            if (rssHighWaterMarkInBytes == 0) {
+                continue;
+            }
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-            e.writeInt(processMemoryHighWaterMark.uid);
-            e.writeString(processMemoryHighWaterMark.processName);
-            e.writeLong(processMemoryHighWaterMark.rssHighWaterMarkInBytes);
+            e.writeInt(managedProcess.uid);
+            e.writeString(managedProcess.processName);
+            e.writeLong(rssHighWaterMarkInBytes);
             pulledData.add(e);
         }
         int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
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 174571d..213c939 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -233,6 +233,7 @@
         assertEquals(0, stat.cacheInBytes);
         assertEquals(22 * BYTES_IN_KILOBYTE, stat.swapInBytes);
         assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos);
+        assertEquals(37860 * BYTES_IN_KILOBYTE, stat.anonRssInBytes);
     }
 
     @Test