Skip bg PSS collection for apps using a camera

Bug: 144138979
Test: grant camera appOp and observe logging
Test: use camera app and observe logging
Change-Id: I6422b432f0d6fcf411073c0528a4ee485d46f005
(cherry picked from commit 5a7e66275155eb1df02012132cd7104feb73251f)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9994f66..ec24014 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -292,6 +292,7 @@
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
@@ -311,6 +312,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.ProcessMap;
@@ -655,6 +657,14 @@
     int mUidChangeDispatchCount;
 
     /**
+     * Uids of apps with current active camera sessions.  Access synchronized on
+     * the IntArray instance itself, and no other locks must be acquired while that
+     * one is held.
+     */
+    @GuardedBy("mActiveCameraUids")
+    final IntArray mActiveCameraUids = new IntArray(4);
+
+    /**
      * Helper class which strips out priority and proto arguments then calls the dump function with
      * the appropriate arguments. If priority arguments are omitted, function calls the legacy
      * dump command.
@@ -2032,7 +2042,10 @@
                     }
                     if (proc != null) {
                         long startTime = SystemClock.currentThreadTimeMillis();
-                        long pss = Debug.getPss(pid, tmp, null);
+                        // skip background PSS calculation of apps that are capturing
+                        // camera imagery
+                        final boolean usingCamera = isCameraActiveForUid(proc.uid);
+                        long pss = usingCamera ? 0 : Debug.getPss(pid, tmp, null);
                         long endTime = SystemClock.currentThreadTimeMillis();
                         synchronized (ActivityManagerService.this) {
                             if (pss != 0 && proc.thread != null && proc.setProcState == procState
@@ -2045,6 +2058,7 @@
                                 ProcessList.abortNextPssTime(proc.procStateMemTracker);
                                 if (DEBUG_PSS) Slog.d(TAG_PSS, "Skipped pss collection of " + pid +
                                         ": " + (proc.thread == null ? "NO_THREAD " : "") +
+                                        (usingCamera ? "CAMERA " : "") +
                                         (proc.pid != pid ? "PID_CHANGED " : "") +
                                         " initState=" + procState + " curState=" +
                                         proc.setProcState + " " +
@@ -2134,6 +2148,14 @@
                         }
                     }
                 });
+
+        final int[] cameraOp = {AppOpsManager.OP_CAMERA};
+        mAppOpsService.startWatchingActive(cameraOp, new IAppOpsActiveCallback.Stub() {
+            @Override
+            public void opActiveChanged(int op, int uid, String packageName, boolean active) {
+                cameraActiveChanged(uid, active);
+            }
+        });
     }
 
     public void setWindowManager(WindowManagerService wm) {
@@ -18224,6 +18246,27 @@
         }
     }
 
+    final void cameraActiveChanged(@UserIdInt int uid, boolean active) {
+        synchronized (mActiveCameraUids) {
+            final int curIndex = mActiveCameraUids.indexOf(uid);
+            if (active) {
+                if (curIndex < 0) {
+                    mActiveCameraUids.add(uid);
+                }
+            } else {
+                if (curIndex >= 0) {
+                    mActiveCameraUids.remove(curIndex);
+                }
+            }
+        }
+    }
+
+    final boolean isCameraActiveForUid(@UserIdInt int uid) {
+        synchronized (mActiveCameraUids) {
+            return mActiveCameraUids.indexOf(uid) >= 0;
+        }
+    }
+
     @GuardedBy("this")
     final void doStopUidLocked(int uid, final UidRecord uidRec) {
         mServices.stopInBackgroundLocked(uid);