From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nan Wu <wnan@google.com>
Date: Fri, 2 Dec 2022 19:08:54 +0000
Subject: [PATCH] DO NOT MERGE Disallow Wallpaper service to launch activity
 from background.

Add a flag so that when a foreground client binds to a service,
disallow the bound service to launch activity from background.
Modify the WallpaperManagerService to take advantage of the new flag.

Test: atest BackgroundActivityLaunchTest WallpaperManagerServiceTests
Bug: 261072174
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4c065abfaf59bdc237f65ceb9704d76bf0819d3a)
Merged-In: Id4e4cb6144597cf3638f2aaa34ea455a239fa1a7
Change-Id: Id4e4cb6144597cf3638f2aaa34ea455a239fa1a7
---
 core/java/android/content/Context.java        |  9 +++++
 .../server/activitymanagerservice.proto       |  1 +
 .../android/server/am/ConnectionRecord.java   |  5 +++
 .../com/android/server/am/ProcessRecord.java  | 20 ++++++-----
 .../com/android/server/am/ServiceRecord.java  |  2 +-
 .../wallpaper/WallpaperManagerService.java    |  3 +-
 .../server/wm/WindowProcessController.java    | 36 ++++++++++++++++---
 7 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 414cc39f5310..6fb10c1c277c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -236,6 +236,7 @@ public abstract class Context {
             BIND_IMPORTANT,
             BIND_ADJUST_WITH_ACTIVITY,
             BIND_NOT_PERCEPTIBLE,
+            BIND_DENY_ACTIVITY_STARTS,
             BIND_INCLUDE_CAPABILITIES
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -349,6 +350,14 @@ public abstract class Context {
     /***********    Public flags above this line ***********/
     /***********    Hidden flags below this line ***********/
 
+    /**
+     * Flag for {@link #bindService}: If binding from an app that is visible, the bound service is
+     * allowed to start an activity from background. Add a flag so that this behavior can be opted
+     * out.
+     * @hide
+     */
+    public static final int BIND_DENY_ACTIVITY_STARTS = 0X000004000;
+
     /**
      * Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
      * the scheduling policy for IMEs (and any other out-of-process user-visible components that
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 7fb6f98ab662..55c5705fe0f6 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -593,6 +593,7 @@ message ConnectionRecordProto {
         DEAD = 15;
         NOT_PERCEPTIBLE = 16;
         INCLUDE_CAPABILITIES = 17;
+        DENY_ACTIVITY_STARTS = 18;
     }
     repeated Flag flags = 3;
     optional string service_name = 4;
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 459508486384..0b8b55cfdcc2 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -67,6 +67,7 @@ final class ConnectionRecord {
             Context.BIND_NOT_VISIBLE,
             Context.BIND_NOT_PERCEPTIBLE,
             Context.BIND_INCLUDE_CAPABILITIES,
+            Context.BIND_DENY_ACTIVITY_STARTS,
     };
     private static final int[] BIND_PROTO_ENUMS = new int[] {
             ConnectionRecordProto.AUTO_CREATE,
@@ -86,6 +87,7 @@ final class ConnectionRecord {
             ConnectionRecordProto.NOT_VISIBLE,
             ConnectionRecordProto.NOT_PERCEPTIBLE,
             ConnectionRecordProto.INCLUDE_CAPABILITIES,
+            ConnectionRecordProto.DENY_ACTIVITY_STARTS,
     };
 
     void dump(PrintWriter pw, String prefix) {
@@ -219,6 +221,9 @@ final class ConnectionRecord {
         if ((flags & Context.BIND_NOT_PERCEPTIBLE) != 0) {
             sb.append("!PRCP ");
         }
+        if ((flags & Context.BIND_DENY_ACTIVITY_STARTS) != 0) {
+            sb.append("BALFD ");
+        }
         if ((flags & Context.BIND_INCLUDE_CAPABILITIES) != 0) {
             sb.append("CAPS ");
         }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index ea3084274ae0..a443d29bcaf1 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1187,14 +1187,14 @@ class ProcessRecord implements WindowProcessListener {
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
     }
 
-    void addBoundClientUid(int clientUid) {
+    void addBoundClientUid(int clientUid, String clientPackageName, int bindFlags) {
         mBoundClientUids.add(clientUid);
-        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+        mWindowProcessController.addBoundClientUid(clientUid, clientPackageName, bindFlags);
     }
 
     void updateBoundClientUids() {
+        clearBoundClientUids();
         if (services.isEmpty()) {
-            clearBoundClientUids();
             return;
         }
         // grab a set of clientUids of all connections of all services
@@ -1207,12 +1207,14 @@ class ProcessRecord implements WindowProcessListener {
             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);
+                    ConnectionRecord cr = c.get(i);
+                    boundClientUids.add(cr.clientUid);
+                    mWindowProcessController
+                            .addBoundClientUid(cr.clientUid, cr.clientPackageName, cr.flags);
                 }
             }
         }
         mBoundClientUids = boundClientUids;
-        mWindowProcessController.setBoundClientUids(mBoundClientUids);
     }
 
     void addBoundClientUidsOfNewService(ServiceRecord sr) {
@@ -1223,15 +1225,17 @@ class ProcessRecord implements WindowProcessListener {
         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);
+                ConnectionRecord cr = c.get(i);
+                mBoundClientUids.add(cr.clientUid);
+                mWindowProcessController
+                        .addBoundClientUid(cr.clientUid, cr.clientPackageName, cr.flags);
             }
         }
-        mWindowProcessController.setBoundClientUids(mBoundClientUids);
     }
 
     void clearBoundClientUids() {
         mBoundClientUids.clear();
-        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+        mWindowProcessController.clearBoundClientUids();
     }
 
     void setActiveInstrumentation(ActiveInstrumentation instr) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index c408695bcb66..8262b9a334bf 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -611,7 +611,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
 
         // if we have a process attached, add bound client uid of this connection to it
         if (app != null) {
-            app.addBoundClientUid(c.clientUid);
+            app.addBoundClientUid(c.clientUid, c.clientPackageName, c.flags);
         }
     }
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 37ae3340d319..ec7414bbf768 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2713,7 +2713,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
             if (!mContext.bindServiceAsUser(intent, newConn,
                     Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
                             | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
-                            | Context.BIND_INCLUDE_CAPABILITIES,
+                            | Context.BIND_INCLUDE_CAPABILITIES
+                            | Context.BIND_DENY_ACTIVITY_STARTS,
                     new UserHandle(serviceUserId))) {
                 String msg = "Unable to bind service: "
                         + componentName;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index e0a9af543f99..39962216483c 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -44,6 +44,7 @@ import android.app.ActivityThread;
 import android.app.IApplicationThread;
 import android.app.ProfilerInfo;
 import android.app.servertransaction.ConfigurationChangeItem;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -436,16 +437,41 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
     }
 
     private boolean isBoundByForegroundUid() {
-        for (int i = mBoundClientUids.size() - 1; i >= 0; --i) {
-            if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) {
-                return true;
+        synchronized (this) {
+            if (mBoundClientUids != null) {
+                for (int i = mBoundClientUids.size() - 1; i >= 0; --i) {
+                    if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) {
+                        return true;
+                    }
+                }
             }
         }
         return false;
     }
 
-    public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
-        mBoundClientUids = boundClientUids;
+    /**
+     * Clear all bound client Uids.
+     */
+    public void clearBoundClientUids() {
+        synchronized (this) {
+            if (mBoundClientUids == null) {
+                mBoundClientUids = new ArraySet<>();
+            } else {
+                mBoundClientUids.clear();
+            }
+        }
+    }
+
+    /**
+     * Add bound client Uid.
+     */
+    public void addBoundClientUid(int clientUid, String clientPackageName, int bindFlags) {
+        if ((bindFlags & Context.BIND_DENY_ACTIVITY_STARTS) == 0) {
+            if (mBoundClientUids == null) {
+                mBoundClientUids = new ArraySet<>();
+            }
+            mBoundClientUids.add(clientUid);
+        }
     }
 
     public void setInstrumenting(boolean instrumenting,
