Allow processes that are bound to by a currently foreground app to
start activities from background

Maintain a set of all client UIDs currently bound to a process, by
updating it accordingly when a service is added/removed to a
process, or the connection is added/removed to the process' service.

Test: atest WmTests:ActivityStarterTests
Bug: 128467234
Bug: 123333161 (daydream case)
Bug: 123500216 (google lens case)
Bug: 129000609 (dialer-duo case)
Change-Id: Ied3ffd8357292d2ad25560c87cd69dc100c9e565
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a90e994..ce13cd8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -259,6 +259,8 @@
     // A set of tokens that currently contribute to this process being temporarily whitelisted
     // to start activities even if it's not in the foreground
     final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
+    // a set of UIDs of all bound clients
+    private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
 
     String isolatedEntryPoint;  // Class to run on start if this is a special isolated process.
     String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -1193,6 +1195,53 @@
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
     }
 
+    void addBoundClientUids(ArraySet<Integer> clientUids) {
+        mBoundClientUids.addAll(clientUids);
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void updateBoundClientUids() {
+        if (services.isEmpty()) {
+            clearBoundClientUids();
+            return;
+        }
+        // grab a set of clientUids of all connections of all services
+        ArraySet<Integer> boundClientUids = new ArraySet<>();
+        final int K = services.size();
+        for (int j = 0; j < K; j++) {
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+                    services.valueAt(j).getConnections();
+            final int N = conns.size();
+            for (int conni = 0; conni < N; conni++) {
+                ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+                for (int i = 0; i < c.size(); i++) {
+                    boundClientUids.add(c.get(i).clientUid);
+                }
+            }
+        }
+        mBoundClientUids = boundClientUids;
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void addBoundClientUidsOfNewService(ServiceRecord sr) {
+        if (sr == null) {
+            return;
+        }
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = sr.getConnections();
+        for (int conni = conns.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+            for (int i = 0; i < c.size(); i++) {
+                mBoundClientUids.add(c.get(i).clientUid);
+            }
+        }
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void clearBoundClientUids() {
+        mBoundClientUids.clear();
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
     void setActiveInstrumentation(ActiveInstrumentation instr) {
         mInstr = instr;
         boolean isInstrumenting = instr != null;