Add new foreground service type camera and microphone.

To be used to configure foreground service camera/microphone
while-in-use permission.

For apps with targetSdkVersion R and above, a foreground service
will not be able to access camera/microphone if the foreground service
type is not specified in the manifest and in
android.app.Service#startForeground().

Bug: 136219221
Test: atest android.app.cts.ActivityManagerProcessStateTest

Change-Id: I75c62efca5f07ba1239e21d9a6f6673f822eabba
diff --git a/api/current.txt b/api/current.txt
index ee80b14..ec47aaa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12226,12 +12226,14 @@
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
     field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
+    field public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
     field public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
     field public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
     field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
     field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
     field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2
     field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20
+    field public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80
     field public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0
     field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4
     field public int flags;
diff --git a/api/test-current.txt b/api/test-current.txt
index 190f9fe..5df07e5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -74,8 +74,10 @@
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
     method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle);
-    field public static final int PROCESS_CAPABILITY_ALL = 1; // 0x1
+    field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
+    field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
     field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
+    field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
     field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
   }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2010cc9..fc2b3c2 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -571,6 +571,8 @@
     @IntDef(flag = true, prefix = { "PROCESS_CAPABILITY_" }, value = {
             PROCESS_CAPABILITY_NONE,
             PROCESS_CAPABILITY_FOREGROUND_LOCATION,
+            PROCESS_CAPABILITY_FOREGROUND_CAMERA,
+            PROCESS_CAPABILITY_FOREGROUND_MICROPHONE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProcessCapability {}
@@ -583,9 +585,19 @@
     @TestApi
     public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 0;
 
+    /** @hide Process can access camera while in foreground */
+    @TestApi
+    public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 1;
+
+    /** @hide Process can access microphone while in foreground */
+    @TestApi
+    public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
+
     /** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
     @TestApi
-    public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+    public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
+            | PROCESS_CAPABILITY_FOREGROUND_CAMERA
+            | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 
     // NOTE: If PROCESS_STATEs are added, then new fields must be added
     // to frameworks/base/core/proto/android/app/enums.proto and the following method must
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 00507e1..5f90b6c 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -147,6 +147,28 @@
     public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 1 << 5;
 
     /**
+     * Constant corresponding to {@code camera} in
+     * the {@link android.R.attr#foregroundServiceType} attribute.
+     * Use the camera device or record video.
+     * For apps with <code>targetSdkVersion</code> {@link android.os.Build.VERSION_CODES#R} and
+     * above, a foreground service will not be able to access the camera if this type is not
+     * specified in the manifest and in
+     * {@link android.app.Service#startForeground(int, android.app.Notification, int)}.
+     */
+    public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 1 << 6;
+
+    /**
+     * Constant corresponding to {@code microphone} in
+     * the {@link android.R.attr#foregroundServiceType} attribute.
+     * Use the microphone device or record audio.
+     * For apps with <code>targetSdkVersion</code> {@link android.os.Build.VERSION_CODES#R} and
+     * above, a foreground service will not be able to access the microphone if this type is not
+     * specified in the manifest and in
+     * {@link android.app.Service#startForeground(int, android.app.Notification, int)}.
+     */
+    public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 1 << 7;
+
+    /**
      * A special value indicates to use all types set in manifest file.
      */
     public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1;
@@ -166,6 +188,8 @@
             FOREGROUND_SERVICE_TYPE_LOCATION,
             FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE,
             FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION,
+            FOREGROUND_SERVICE_TYPE_CAMERA,
+            FOREGROUND_SERVICE_TYPE_MICROPHONE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ForegroundServiceType {}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 94f3b8a..0895edc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1520,6 +1520,22 @@
         <!-- Managing a media projection session, e.g, for screen recording or taking
              screenshots.-->
         <flag name="mediaProjection" value="0x20" />
+        <!-- Use the camera device or record video.
+
+            <p>For apps with <code>targetSdkVersion</code> {@link android.os.Build.VERSION_CODES#R}
+            and above, a foreground service will not be able to access the camera if this type is
+            not specified in the manifest and in
+            {@link android.app.Service#startForeground(int, android.app.Notification, int)}.
+            -->
+        <flag name="camera" value="0x40" />
+        <!--Use the microphone device or record audio.
+
+            <p>For apps with <code>targetSdkVersion</code> {@link android.os.Build.VERSION_CODES#R}
+            and above, a foreground service will not be able to access the microphone if this type
+            is not specified in the manifest and in
+            {@link android.app.Service#startForeground(int, android.app.Notification, int)}.
+            -->
+        <flag name="microphone" value="0x80" />
     </attr>
 
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index f86d6a7..6e95253 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -17,7 +17,9 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
@@ -33,6 +35,9 @@
 import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
 import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.THREAD_GROUP_BACKGROUND;
 import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -1220,10 +1225,6 @@
             }
         }
 
-        if (app.hasLocationForegroundServices()) {
-            capability |= PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-        }
-
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                 || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
             if (app.hasForegroundServices()) {
@@ -1387,6 +1388,7 @@
             }
         }
 
+        int capabilityFromFGS = 0; // capability from foreground service.
         for (int is = app.services.size() - 1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
@@ -1435,6 +1437,24 @@
                 }
             }
 
+            if (s.isForeground) {
+                final int fgsType = s.foregroundServiceType;
+                capabilityFromFGS |=
+                        (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
+                                != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
+                if (s.appInfo.targetSdkVersion < Build.VERSION_CODES.R) {
+                    capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
+                            | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+                } else {
+                    capabilityFromFGS |=
+                            (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
+                                    != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
+                    capabilityFromFGS |=
+                            (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
+                                    != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
+                }
+            }
+
             ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
             for (int conni = serviceConnections.size() - 1;
                     conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -1895,6 +1915,10 @@
             }
         }
 
+        // apply capability from FGS.
+        if (app.hasForegroundServices()) {
+            capability |= capabilityFromFGS;
+        }
         // TOP process has all capabilities.
         if (procState <= PROCESS_STATE_TOP) {
             capability = PROCESS_CAPABILITY_ALL;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index e3b761e..08136a3 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,7 +16,9 @@
 
 package com.android.server.appop;
 
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
@@ -467,6 +469,12 @@
                         case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
                             return ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0)
                                 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+                        case OP_CAMERA:
+                            return ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0)
+                                    ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+                        case OP_RECORD_AUDIO:
+                            return ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0)
+                                    ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
                         default:
                             return AppOpsManager.MODE_ALLOWED;
                     }