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;
}