summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Makoto Onuki <omakoto@google.com> 2021-05-13 09:30:42 -0700
committer Makoto Onuki <omakoto@google.com> 2021-05-13 12:21:39 -0700
commitdc4aa4b86e87f4eabecd236a9d75dff8b89fd623 (patch)
treed07cbeeb15628146fe642782ea891977a390cfa4
parentb04efdff7045dfe585b7dbc9571dd95b0e35f204 (diff)
Add a permission for CDM apps to start FGS from the background
Previously, any apps with a CDM association was allowed to start foreground services from the background. Now, only apps with REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND (or REQUEST_COMPANION_RUN_IN_BACKGROUND) are allowed to do so. Bug: 186536261 Test: Manual test with a test app using CDM. With and without these permissions. Change-Id: Ic00aa1c7cfefc37bf89ea3079ef0977aee12499b
-rw-r--r--core/api/current.txt1
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java36
-rw-r--r--services/core/java/com/android/server/am/ProcessStateRecord.java12
4 files changed, 35 insertions, 20 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 324ad33166a1..4a053073997c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -141,6 +141,7 @@ package android {
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
+ field public static final String REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ffb8d1daac90..bcecd7442e9c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2900,6 +2900,12 @@
android:description="@string/permdesc_runInBackground"
android:protectionLevel="normal" />
+ <!-- Allows a companion app to start a foreground service from the background.
+ {@see android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+ android:protectionLevel="normal"/>
+
<!-- Allows a companion app to use data in the background.
<p>Protection level: normal
-->
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index aadb25c7ef7f..f480cbc26ff4 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND;
+import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
@@ -5831,6 +5833,26 @@ public final class ActiveServices {
}
}
+ // Check for CDM apps with either REQUEST_COMPANION_RUN_IN_BACKGROUND or
+ // REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND.
+ // Note: When a CDM app has REQUEST_COMPANION_RUN_IN_BACKGROUND, the app is also put
+ // in the user-allowlist. However, in this case, we want to use the reason code
+ // REASON_COMPANION_DEVICE_MANAGER, so this check needs to be before the
+ // isAllowlistedForFgsStartLOSP check.
+ if (ret == REASON_DENIED) {
+ final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
+ UserHandle.getUserId(callingUid), callingUid);
+ if (isCompanionApp) {
+ if (isPermissionGranted(
+ REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND,
+ callingPid, callingUid)
+ || isPermissionGranted(REQUEST_COMPANION_RUN_IN_BACKGROUND,
+ callingPid, callingUid)) {
+ ret = REASON_COMPANION_DEVICE_MANAGER;
+ }
+ }
+ }
+
if (ret == REASON_DENIED) {
ActivityManagerService.FgsTempAllowListItem item =
mAm.isAllowlistedForFgsStartLOSP(callingUid);
@@ -5858,14 +5880,6 @@ public final class ActiveServices {
}
if (ret == REASON_DENIED) {
- final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
- UserHandle.getUserId(callingUid), callingUid);
- if (isCompanionApp) {
- ret = REASON_COMPANION_DEVICE_MANAGER;
- }
- }
-
- if (ret == REASON_DENIED) {
final AppOpsManager appOpsManager = mAm.getAppOpsManager();
if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, callingUid,
callingPackage) == AppOpsManager.MODE_ALLOWED) {
@@ -5884,6 +5898,10 @@ public final class ActiveServices {
return ret;
}
+ private boolean isPermissionGranted(String permission, int callingPid, int callingUid) {
+ return mAm.checkPermission(permission, callingPid, callingUid) == PERMISSION_GRANTED;
+ }
+
private static boolean isFgsBgStart(@ReasonCode int code) {
return code != REASON_PROC_STATE_PERSISTENT
&& code != REASON_PROC_STATE_PERSISTENT_UI
@@ -5957,7 +5975,7 @@ public final class ActiveServices {
}
FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid,
- r.shortInstanceName,
+ null,
state,
r.mAllowWhileInUsePermissionInFgs,
r.mAllowStartForeground,
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 6429b79f6111..801e3824d7b0 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -25,7 +25,6 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
@@ -1217,6 +1216,7 @@ final class ProcessStateRecord {
mAllowStartFgs = mAllowStartFgsByPermission = ret;
}
+ // TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
@GuardedBy("mService")
void setAllowStartFgs() {
if (mAllowStartFgs != REASON_DENIED) {
@@ -1238,16 +1238,6 @@ final class ProcessStateRecord {
}
if (mAllowStartFgs == REASON_DENIED) {
- if (mService.mInternal != null) {
- final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp(
- UserHandle.getUserId(mApp.info.uid), mApp.info.uid);
- if (isCompanionApp) {
- mAllowStartFgs = REASON_COMPANION_DEVICE_MANAGER;
- }
- }
- }
-
- if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a profile owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isProfileOwner(mApp.info.uid)) {