summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jing Ji <jji@google.com> 2023-03-09 17:04:08 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-03-09 17:04:08 +0000
commitc3a0a78db0f2e9202a2c2ddb3a5c04e23f24c5ad (patch)
tree6dee4a329d0e2bac14354e4185621c57d3c79546
parent26ac560f852d5adaf084fad8cc145f846f7e946e (diff)
parent5ce5acd11733168872fb7fb32171780a4e214965 (diff)
Merge "Allow apps to create FGS with type mediaProjection if the user granted" into udc-dev
-rw-r--r--core/java/android/app/ActivityManagerInternal.java47
-rw-r--r--core/java/android/app/ForegroundServiceTypePolicy.java260
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java34
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java57
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java9
6 files changed, 391 insertions, 23 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d810f055e96e..90427cb51c26 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -18,6 +18,7 @@ package android.app;
import static android.app.ActivityManager.StopUserOnSwitch;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.PermissionMethod;
@@ -47,6 +48,8 @@ import android.util.Pair;
import com.android.internal.os.TimeoutRecord;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -991,4 +994,48 @@ public abstract class ActivityManagerInternal {
*/
public abstract void logFgsApiEnd(int apiType, int uid, int pid);
+ /**
+ * The list of the events about the {@link android.media.projection.IMediaProjection} itself.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ MEDIA_PROJECTION_TOKEN_EVENT_CREATED,
+ MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED,
+ })
+ public @interface MediaProjectionTokenEvent{};
+
+ /**
+ * An instance of {@link android.media.projection.IMediaProjection} has been created
+ * by the system.
+ *
+ * @hide
+ */
+ public static final @MediaProjectionTokenEvent int MEDIA_PROJECTION_TOKEN_EVENT_CREATED = 0;
+
+ /**
+ * An instance of {@link android.media.projection.IMediaProjection} has been destroyed
+ * by the system.
+ *
+ * @hide
+ */
+ public static final @MediaProjectionTokenEvent int MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED = 1;
+
+ /**
+ * Called after the system created/destroyed a media projection for an app, if the user
+ * has granted the permission to start a media projection from this app.
+ *
+ * <p>This API is specifically for the use case of enforcing the FGS type
+ * {@code android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION},
+ * where the app who is starting this type of FGS must have been granted with the permission
+ * to start the projection via the {@link android.media.projection.MediaProjection} APIs.
+ *
+ * @param uid The uid of the app which the system created/destroyed a media projection for.
+ * @param projectionToken The {@link android.media.projection.IMediaProjection} token that
+ * the system created/destroyed.
+ * @param event The actual event happening to the given {@code projectionToken}.
+ */
+ public abstract void notifyMediaProjectionEvent(int uid, @NonNull IBinder projectionToken,
+ @MediaProjectionTokenEvent int event);
}
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index a7824a850e59..be012cf8e202 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -59,6 +59,9 @@ import android.hardware.usb.UsbManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.permission.PermissionCheckerManager;
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -147,6 +150,108 @@ public abstract class ForegroundServiceTypePolicy {
public static final long FGS_TYPE_PERMISSION_CHANGE_ID = 254662522L;
/**
+ * The prefix for the feature flags of the permission enforcement.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX =
+ "fgs_type_perm_enforcement_flag_";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_DATA_SYNC =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "data_sync";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_MEDIA_PLAYBACK =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "media_playback";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_PHONE_CALL},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_PHONE_CALL =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "phone_call";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_LOCATION},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_LOCATION =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "location";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_CONNECTED_DEVICE =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "connected_device";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_MEDIA_PROJECTION =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "media_projection";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_CAMERA},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_CAMERA =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "camera";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_MICROPHONE =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "microphone";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_HEALTH},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "health";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_REMOTE_MESSAGING =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "remote_messaging";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_SYSTEM_EXEMPTED =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "system_exempted";
+
+ /**
+ * The feature flag of the permission enforcement for
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE},
+ * in the namespace of {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
+ */
+ private static final String FGS_TYPE_PERM_ENFORCEMENT_FLAG_SPECIAL_USE =
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PREFIX + "special_use";
+
+ /**
* The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST}.
*
* @hide
@@ -156,8 +261,10 @@ public abstract class ForegroundServiceTypePolicy {
FOREGROUND_SERVICE_TYPE_MANIFEST,
FGS_TYPE_NONE_DEPRECATION_CHANGE_ID,
FGS_TYPE_NONE_DISABLED_CHANGE_ID,
- null,
- null
+ null /* allOfPermissions */,
+ null /* anyOfPermissions */,
+ null /* permissionEnforcementFlag */,
+ false /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -170,8 +277,10 @@ public abstract class ForegroundServiceTypePolicy {
FOREGROUND_SERVICE_TYPE_NONE,
FGS_TYPE_NONE_DEPRECATION_CHANGE_ID,
FGS_TYPE_NONE_DISABLED_CHANGE_ID,
- null,
- null
+ null /* allOfPermissions */,
+ null /* anyOfPermissions */,
+ null /* permissionEnforcementFlag */,
+ false /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -187,7 +296,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC)
}, true),
- null
+ null /* anyOfPermissions */,
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_DATA_SYNC /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -203,7 +314,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK)
}, true),
- null
+ null /* anyOfPermissions */,
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_MEDIA_PLAYBACK /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -221,7 +334,9 @@ public abstract class ForegroundServiceTypePolicy {
}, true),
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.MANAGE_OWN_CALLS)
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_PHONE_CALL /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -240,7 +355,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.ACCESS_COARSE_LOCATION),
new RegularPermission(Manifest.permission.ACCESS_FINE_LOCATION),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_LOCATION /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -268,7 +385,9 @@ public abstract class ForegroundServiceTypePolicy {
new RegularPermission(Manifest.permission.UWB_RANGING),
new UsbDevicePermission(),
new UsbAccessoryPermission(),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_CONNECTED_DEVICE /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -284,7 +403,12 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION)
}, true),
- null
+ new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
+ new RegularPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT),
+ new AppOpPermission(AppOpsManager.OP_PROJECT_MEDIA)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_MEDIA_PROJECTION /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -303,7 +427,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.CAMERA),
new RegularPermission(Manifest.permission.SYSTEM_CAMERA),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_CAMERA /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -326,7 +452,9 @@ public abstract class ForegroundServiceTypePolicy {
new RegularPermission(Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT),
new RegularPermission(Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT),
new RegularPermission(Manifest.permission.RECORD_AUDIO),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_MICROPHONE /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -347,7 +475,9 @@ public abstract class ForegroundServiceTypePolicy {
new RegularPermission(Manifest.permission.BODY_SENSORS),
new RegularPermission(Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE),
new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -363,7 +493,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING)
}, true),
- null
+ null /* anyOfPermissions */,
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_REMOTE_MESSAGING /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -383,7 +515,9 @@ public abstract class ForegroundServiceTypePolicy {
new RegularPermission(Manifest.permission.SCHEDULE_EXACT_ALARM),
new RegularPermission(Manifest.permission.USE_EXACT_ALARM),
new AppOpPermission(AppOpsManager.OP_ACTIVATE_VPN),
- }, false)
+ }, false),
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_SYSTEM_EXEMPTED /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -396,7 +530,10 @@ public abstract class ForegroundServiceTypePolicy {
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
- null /* no type specific permissions */, null /* no type specific permissions */
+ null /* allOfPermissions */,
+ null /* anyOfPermissions */,
+ null /* permissionEnforcementFlag */,
+ false /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -412,7 +549,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT)
}, true),
- null
+ null /* anyOfPermissions */,
+ null /* permissionEnforcementFlag */,
+ false /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -428,7 +567,9 @@ public abstract class ForegroundServiceTypePolicy {
new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE)
}, true),
- null
+ null /* anyOfPermissions */,
+ FGS_TYPE_PERM_ENFORCEMENT_FLAG_SPECIAL_USE /* permissionEnforcementFlag */,
+ true /* permissionEnforcementFlagDefaultValue */
);
/**
@@ -512,6 +653,14 @@ public abstract class ForegroundServiceTypePolicy {
@NonNull String packageName, int callerUid, int callerPid, boolean allowWhileInUse,
@NonNull ForegroundServiceTypePolicyInfo policy);
+ /**
+ * Run the given {@code policyFunctor} on the matching policy, if the flag is known
+ * to the policy.
+ *
+ * @hide
+ */
+ public abstract void updatePermissionEnforcementFlagIfNecessary(@NonNull String flag);
+
@GuardedBy("sLock")
private static ForegroundServiceTypePolicy sDefaultForegroundServiceTypePolicy = null;
@@ -575,11 +724,31 @@ public abstract class ForegroundServiceTypePolicy {
final @Nullable ForegroundServiceTypePermissions mAnyOfPermissions;
/**
+ * A permission enforcement flag, unlike the {@link #FGS_TYPE_PERMISSION_CHANGE_ID},
+ * here it applies to all apps using this FGS type.
+ */
+ final @Nullable String mPermissionEnforcementFlag;
+
+ /**
+ * The default value to {@link #mPermissionEnforcementFlag}.
+ */
+ final boolean mPermissionEnforcementFlagDefaultValue;
+
+ /**
* A customized check for the permissions.
*/
@Nullable ForegroundServiceTypePermission mCustomPermission;
/**
+ * The value of the permission enforcement flag, will be updated by the system.
+ * If the value is {@code false}, the FGS permission check will be ignored.
+ *
+ * <p>This value could be updated via the DeviceConfig flag specified
+ * in the {@link #mPermissionEnforcementFlag}.</p>
+ */
+ volatile boolean mPermissionEnforcementFlagValue;
+
+ /**
* Not a real change id, but a place holder.
*/
private static final long INVALID_CHANGE_ID = 0L;
@@ -599,12 +768,17 @@ public abstract class ForegroundServiceTypePolicy {
public ForegroundServiceTypePolicyInfo(@ForegroundServiceType int type,
long deprecationChangeId, long disabledChangeId,
@Nullable ForegroundServiceTypePermissions allOfPermissions,
- @Nullable ForegroundServiceTypePermissions anyOfPermissions) {
+ @Nullable ForegroundServiceTypePermissions anyOfPermissions,
+ @Nullable String permissionEnforcementFlag,
+ boolean permissionEnforcementFlagDefaultValue) {
mType = type;
mDeprecationChangeId = deprecationChangeId;
mDisabledChangeId = disabledChangeId;
mAllOfPermissions = allOfPermissions;
mAnyOfPermissions = anyOfPermissions;
+ mPermissionEnforcementFlag = permissionEnforcementFlag;
+ mPermissionEnforcementFlagDefaultValue = permissionEnforcementFlagDefaultValue;
+ mPermissionEnforcementFlagValue = permissionEnforcementFlagDefaultValue;
}
/**
@@ -650,6 +824,17 @@ public abstract class ForegroundServiceTypePolicy {
return sb;
}
+ private void updatePermissionEnforcementFlagIfNecessary(@NonNull String flagName) {
+ if (mPermissionEnforcementFlag == null
+ || !TextUtils.equals(flagName, mPermissionEnforcementFlag)) {
+ return;
+ }
+ mPermissionEnforcementFlagValue = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ mPermissionEnforcementFlag,
+ mPermissionEnforcementFlagDefaultValue);
+ }
+
/**
* @hide
*/
@@ -745,6 +930,15 @@ public abstract class ForegroundServiceTypePolicy {
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
platformCompat.clearOverrideForTest(changeId, packageName);
}
+
+ /**
+ * For test only.
+ *
+ * @return The permission enforcement flag.
+ */
+ public @Nullable String getPermissionEnforcementFlagForTest() {
+ return mPermissionEnforcementFlag;
+ }
}
/**
@@ -991,6 +1185,12 @@ public abstract class ForegroundServiceTypePolicy {
new SparseArray<>();
/**
+ * The map between permission enforcement flag to its permission policy info.
+ */
+ private final ArrayMap<String, ForegroundServiceTypePolicyInfo>
+ mPermissionEnforcementToPolicyInfoMap = new ArrayMap<>();
+
+ /**
* Constructor
*/
public DefaultForegroundServiceTypePolicy() {
@@ -1022,10 +1222,15 @@ public abstract class ForegroundServiceTypePolicy {
FGS_TYPE_POLICY_SYSTEM_EXEMPTED);
mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
FGS_TYPE_POLICY_SHORT_SERVICE);
- mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT,
- FGS_TYPE_POLICY_FILE_MANAGEMENT);
+ // TODO (b/271950506): revisit it in the next release.
+ // Hide the file management type for now. If anyone uses it, will default to "none".
mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SPECIAL_USE,
FGS_TYPE_POLICY_SPECIAL_USE);
+ for (int i = 0, size = mForegroundServiceTypePolicies.size(); i < size; i++) {
+ final ForegroundServiceTypePolicyInfo info =
+ mForegroundServiceTypePolicies.valueAt(i);
+ mPermissionEnforcementToPolicyInfoMap.put(info.mPermissionEnforcementFlag, info);
+ }
}
@Override
@@ -1078,8 +1283,8 @@ public abstract class ForegroundServiceTypePolicy {
}
}
if (permissionResult != PERMISSION_GRANTED) {
- return (CompatChanges.isChangeEnabled(
- FGS_TYPE_PERMISSION_CHANGE_ID, callerUid))
+ return policy.mPermissionEnforcementFlagValue
+ && (CompatChanges.isChangeEnabled(FGS_TYPE_PERMISSION_CHANGE_ID, callerUid))
? FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED
: FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE;
}
@@ -1089,5 +1294,14 @@ public abstract class ForegroundServiceTypePolicy {
}
return FGS_TYPE_POLICY_CHECK_OK;
}
+
+ @Override
+ public void updatePermissionEnforcementFlagIfNecessary(@NonNull String flagName) {
+ final ForegroundServiceTypePolicyInfo info =
+ mPermissionEnforcementToPolicyInfoMap.get(flagName);
+ if (info != null) {
+ info.updatePermissionEnforcementFlagIfNecessary(flagName);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 24c9e0f55ab9..0b22f36958d1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -640,6 +640,7 @@ public final class ActiveServices {
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
setAllowListWhileInUsePermissionInFgs();
initSystemExemptedFgsTypePermission();
+ initMediaProjectFgsTypeCustomPermission();
}
private AppStateTracker getAppStateTracker() {
@@ -2580,6 +2581,39 @@ public final class ActiveServices {
}
}
+ /**
+ * A custom permission checker for the "mediaProjection" FGS type:
+ * if the app has been granted the permission to start a media projection via
+ * the {@link android.media.project.MediaProjectionManager#createScreenCaptureIntent()},
+ * it'll get the permission to start a foreground service with type "mediaProjection".
+ */
+ private class MediaProjectionFgsTypeCustomPermission extends ForegroundServiceTypePermission {
+ MediaProjectionFgsTypeCustomPermission() {
+ super("Media projection screen capture permission");
+ }
+
+ @Override
+ public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
+ @NonNull String packageName, boolean allowWhileInUse) {
+ return mAm.isAllowedMediaProjectionNoOpCheck(callerUid)
+ ? PERMISSION_GRANTED : PERMISSION_DENIED;
+ }
+ }
+
+ /**
+ * Set a custom permission checker for the "mediaProjection" FGS type.
+ */
+ private void initMediaProjectFgsTypeCustomPermission() {
+ final ForegroundServiceTypePolicy policy = ForegroundServiceTypePolicy.getDefaultPolicy();
+ final ForegroundServiceTypePolicyInfo policyInfo =
+ policy.getForegroundServiceTypePolicyInfo(
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+ if (policyInfo != null) {
+ policyInfo.setCustomPermission(new MediaProjectionFgsTypeCustomPermission());
+ }
+ }
+
ServiceNotificationPolicy applyForegroundServiceNotificationLocked(Notification notification,
final String tag, final int id, final String pkg, final int userId) {
// By nature of the FGS API, all FGS notifications have a null tag
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 9e95e5fb0a40..569600482873 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -25,6 +25,7 @@ import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROA
import android.annotation.NonNull;
import android.app.ActivityThread;
+import android.app.ForegroundServiceTypePolicy;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -1196,6 +1197,7 @@ final class ActivityManagerConstants extends ContentObserver {
updateUseTieredCachedAdj();
break;
default:
+ updateFGSPermissionEnforcementFlagsIfNecessary(name);
break;
}
}
@@ -1951,6 +1953,11 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME);
}
+ private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
+ ForegroundServiceTypePolicy.getDefaultPolicy()
+ .updatePermissionEnforcementFlagIfNecessary(name);
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 10450f032ffb..fdd55a8406ce 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -38,6 +38,8 @@ import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.StopUserOnSwitch;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
+import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
@@ -178,6 +180,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.BindServiceEventListener;
import android.app.ActivityManagerInternal.BroadcastEventListener;
import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
+import android.app.ActivityManagerInternal.MediaProjectionTokenEvent;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.ActivityThread;
import android.app.AnrController;
@@ -1508,6 +1511,17 @@ public class ActivityManagerService extends IActivityManager.Stub
final AppRestrictionController mAppRestrictionController;
+ /**
+ * The collection of the MediaProjection tokens per UID, for the apps that are allowed to
+ * start FGS with the type "mediaProjection"; this permission is granted via the request over
+ * the call to {@link android.media.project.MediaProjectionManager#createScreenCaptureIntent()}.
+ *
+ * <p>Note, the "token" here is actually an instance of
+ * {@link android.media.projection.IMediaProjection}.</p>
+ */
+ @GuardedBy("mMediaProjectionTokenMap")
+ private final SparseArray<ArraySet<IBinder>> mMediaProjectionTokenMap = new SparseArray();
+
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
@@ -18737,6 +18751,12 @@ public class ActivityManagerService extends IActivityManager.Stub
int uid, int pid) {
ActivityManagerService.this.logFgsApiEnd(apiType, uid, pid);
}
+
+ @Override
+ public void notifyMediaProjectionEvent(int uid, @NonNull IBinder projectionToken,
+ @MediaProjectionTokenEvent int event) {
+ ActivityManagerService.this.notifyMediaProjectionEvent(uid, projectionToken, event);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
@@ -19970,4 +19990,41 @@ public class ActivityManagerService extends IActivityManager.Stub
return invalidValue;
}
}
+
+ private void notifyMediaProjectionEvent(int uid, @NonNull IBinder projectionToken,
+ @MediaProjectionTokenEvent int event) {
+ synchronized (mMediaProjectionTokenMap) {
+ final int index = mMediaProjectionTokenMap.indexOfKey(uid);
+ ArraySet<IBinder> tokens;
+ if (event == MEDIA_PROJECTION_TOKEN_EVENT_CREATED) {
+ if (index < 0) {
+ tokens = new ArraySet();
+ mMediaProjectionTokenMap.put(uid, tokens);
+ } else {
+ tokens = mMediaProjectionTokenMap.valueAt(index);
+ }
+ tokens.add(projectionToken);
+ } else if (event == MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED && index >= 0) {
+ tokens = mMediaProjectionTokenMap.valueAt(index);
+ tokens.remove(projectionToken);
+ if (tokens.isEmpty()) {
+ mMediaProjectionTokenMap.removeAt(index);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return {@code true} if the MediaProjectionManagerService has created a media projection
+ * for the given {@code uid} because the user has granted the permission;
+ * it doesn't necessarily mean it has started the projection.
+ *
+ * <p>It doesn't check the {@link AppOpsManager#OP_PROJECT_MEDIA}.</p>
+ */
+ boolean isAllowedMediaProjectionNoOpCheck(int uid) {
+ synchronized (mMediaProjectionTokenMap) {
+ final int index = mMediaProjectionTokenMap.indexOfKey(uid);
+ return index >= 0 && !mMediaProjectionTokenMap.valueAt(index).isEmpty();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 77b9abed0d41..48326188e215 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -16,6 +16,9 @@
package com.android.server.media.projection;
+import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
+import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -484,6 +487,9 @@ public final class MediaProjectionManagerService extends SystemService
userHandle = new UserHandle(UserHandle.getUserId(uid));
mTargetSdkVersion = targetSdkVersion;
mIsPrivileged = isPrivileged;
+ // TODO(b/267740338): Add unit test.
+ mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
+ MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
}
@Override // Binder call
@@ -630,6 +636,9 @@ public final class MediaProjectionManagerService extends SystemService
mToken = null;
unregisterCallback(mCallback);
mCallback = null;
+ // TODO(b/267740338): Add unit test.
+ mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
+ MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED);
}
}