Merge "Allow FGS started from MediaButtonReceiver to have while-in-use permissions." into rvc-qpr-dev
This commit is contained in:
@@ -440,4 +440,11 @@ public abstract class ActivityManagerInternal {
|
||||
* @return true if exists, false otherwise.
|
||||
*/
|
||||
public abstract boolean isPendingTopUid(int uid);
|
||||
|
||||
public abstract void tempAllowWhileInUsePermissionInFgs(int uid, long duration);
|
||||
|
||||
public abstract boolean isTempAllowlistedForFgsWhileInUse(int uid);
|
||||
|
||||
public abstract boolean canAllowWhileInUsePermissionInFgs(int pid, int uid,
|
||||
@NonNull String packageName);
|
||||
}
|
||||
|
||||
@@ -4878,17 +4878,20 @@ public final class ActiveServices {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (r.app != null) {
|
||||
if (r != null && r.app != null) {
|
||||
ActiveInstrumentation instr = r.app.getActiveInstrumentation();
|
||||
if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean hasAllowBackgroundActivityStartsToken = r.app != null
|
||||
? !r.app.mAllowBackgroundActivityStartsTokens.isEmpty() : false;
|
||||
if (hasAllowBackgroundActivityStartsToken) {
|
||||
return true;
|
||||
for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
|
||||
final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
|
||||
if (pr.uid == callingUid) {
|
||||
if (!pr.mAllowBackgroundActivityStartsTokens.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
|
||||
@@ -4907,6 +4910,10 @@ public final class ActiveServices {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mAm.mInternal.isTempAllowlistedForFgsWhileInUse(callingUid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final boolean isWhiteListedPackage =
|
||||
mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
|
||||
if (isWhiteListedPackage) {
|
||||
@@ -4920,4 +4927,10 @@ public final class ActiveServices {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
|
||||
String callingPackage) {
|
||||
return shouldAllowWhileInUsePermissionInFgsLocked(
|
||||
callingPackage, callingPid, callingUid, null, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,6 +1261,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this);
|
||||
|
||||
/**
|
||||
* List of uids that are allowed to have while-in-use permission when FGS is started from
|
||||
* background.
|
||||
*/
|
||||
private final FgsWhileInUseTempAllowList mFgsWhileInUseTempAllowList =
|
||||
new FgsWhileInUseTempAllowList();
|
||||
|
||||
/**
|
||||
* Information about and control over application operations
|
||||
*/
|
||||
@@ -19773,6 +19780,24 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
public boolean isPendingTopUid(int uid) {
|
||||
return mPendingStartActivityUids.isPendingTopUid(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tempAllowWhileInUsePermissionInFgs(int uid, long duration) {
|
||||
mFgsWhileInUseTempAllowList.add(uid, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTempAllowlistedForFgsWhileInUse(int uid) {
|
||||
return mFgsWhileInUseTempAllowList.isAllowed(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAllowWhileInUsePermissionInFgs(int pid, int uid,
|
||||
@NonNull String packageName) {
|
||||
synchronized (ActivityManagerService.this) {
|
||||
return mServices.canAllowWhileInUsePermissionInFgsLocked(pid, uid, packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
/**
|
||||
* List of uids that are allowed to have while-in-use permission when FGS is started
|
||||
* from background.
|
||||
*/
|
||||
final class FgsWhileInUseTempAllowList {
|
||||
/**
|
||||
* This list is supposed to have a small number of entries. If exceeds MAX_SIZE, log a warning
|
||||
* message.
|
||||
*/
|
||||
private static final int MAX_SIZE = 100;
|
||||
/**
|
||||
* The key is the UID, the value is expiration elapse time in ms of this temp-allowed UID.
|
||||
*/
|
||||
private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
void add(int uid, long durationMs) {
|
||||
synchronized (mLock) {
|
||||
if (durationMs <= 0) {
|
||||
Slog.e(TAG_AM, "FgsWhileInUseTempAllowList bad duration:" + durationMs
|
||||
+ " uid: " + uid);
|
||||
return;
|
||||
}
|
||||
// The temp allowlist should be a short list with only a few entries in it.
|
||||
final int size = mTempAllowListFgs.size();
|
||||
if (size > MAX_SIZE) {
|
||||
Slog.w(TAG_AM, "FgsWhileInUseTempAllowList length:" + size + " exceeds "
|
||||
+ MAX_SIZE);
|
||||
}
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
for (int index = mTempAllowListFgs.size() - 1; index >= 0; index--) {
|
||||
if (mTempAllowListFgs.valueAt(index) < now) {
|
||||
mTempAllowListFgs.removeAt(index);
|
||||
}
|
||||
}
|
||||
final long existingExpirationTime = mTempAllowListFgs.get(uid, -1);
|
||||
final long expirationTime = now + durationMs;
|
||||
if (existingExpirationTime == -1 || existingExpirationTime < expirationTime) {
|
||||
mTempAllowListFgs.put(uid, expirationTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isAllowed(int uid) {
|
||||
synchronized (mLock) {
|
||||
final int index = mTempAllowListFgs.indexOfKey(uid);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
} else if (mTempAllowListFgs.valueAt(index) < SystemClock.elapsedRealtime()) {
|
||||
mTempAllowListFgs.removeAt(index);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -583,6 +583,10 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
if (mActivityManagerInternal != null
|
||||
&& mActivityManagerInternal.isPendingTopUid(uid)) {
|
||||
return MODE_ALLOWED;
|
||||
} else if (mActivityManagerInternal != null
|
||||
&& mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(
|
||||
uid)) {
|
||||
return MODE_ALLOWED;
|
||||
} else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
|
||||
return MODE_ALLOWED;
|
||||
} else {
|
||||
@@ -592,6 +596,10 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
if (mActivityManagerInternal != null
|
||||
&& mActivityManagerInternal.isPendingTopUid(uid)) {
|
||||
return MODE_ALLOWED;
|
||||
} else if (mActivityManagerInternal != null
|
||||
&& mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(
|
||||
uid)) {
|
||||
return MODE_ALLOWED;
|
||||
} else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
|
||||
return MODE_ALLOWED;
|
||||
} else {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.media;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -196,6 +197,8 @@ final class MediaButtonReceiverHolder {
|
||||
// TODO: Find a way to also send PID/UID in secure way.
|
||||
mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
|
||||
|
||||
final BroadcastOptions options = BroadcastOptions.makeBasic();
|
||||
options.setBackgroundActivityStartsAllowed(true);
|
||||
if (mPendingIntent != null) {
|
||||
if (DEBUG_KEY_EVENT) {
|
||||
Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
|
||||
@@ -203,7 +206,8 @@ final class MediaButtonReceiverHolder {
|
||||
}
|
||||
try {
|
||||
mPendingIntent.send(
|
||||
context, resultCode, mediaButtonIntent, onFinishedListener, handler);
|
||||
context, resultCode, mediaButtonIntent, onFinishedListener, handler,
|
||||
/* requiredPermission= */null, options.toBundle());
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e);
|
||||
return false;
|
||||
@@ -226,7 +230,8 @@ final class MediaButtonReceiverHolder {
|
||||
break;
|
||||
default:
|
||||
// Legacy behavior for other cases.
|
||||
context.sendBroadcastAsUser(mediaButtonIntent, userHandle);
|
||||
context.sendBroadcastAsUser(mediaButtonIntent, userHandle,
|
||||
/* requiredPermission= */null, options.toBundle());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error sending media button to the restored intent "
|
||||
|
||||
@@ -986,6 +986,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
||||
public boolean sendMediaButton(String packageName, int pid, int uid,
|
||||
boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
|
||||
try {
|
||||
if (KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
|
||||
final String reason = "action=" + KeyEvent.actionToString(keyEvent.getAction())
|
||||
+ ";code=" + KeyEvent.keyCodeToString(keyEvent.getKeyCode());
|
||||
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||
pid, uid, packageName, reason);
|
||||
}
|
||||
if (asSystemService) {
|
||||
mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
|
||||
Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), sequenceId, cb);
|
||||
@@ -1003,6 +1009,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
||||
public boolean sendMediaButton(String packageName, int pid, int uid,
|
||||
boolean asSystemService, KeyEvent keyEvent) {
|
||||
try {
|
||||
if (KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
|
||||
final String reason = "action=" + KeyEvent.actionToString(keyEvent.getAction())
|
||||
+ ";code=" + KeyEvent.keyCodeToString(keyEvent.getKeyCode());
|
||||
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||
pid, uid, packageName, reason);
|
||||
}
|
||||
if (asSystemService) {
|
||||
mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
|
||||
Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), 0, null);
|
||||
|
||||
@@ -25,6 +25,7 @@ import static com.android.server.media.MediaKeyDispatcher.isSingleTapOverridden;
|
||||
import static com.android.server.media.MediaKeyDispatcher.isTripleTapOverridden;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.PendingIntent;
|
||||
@@ -114,6 +115,8 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
+ /* Buffer for delayed delivery of key event */ 50;
|
||||
private static final int MULTI_TAP_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
|
||||
|
||||
private static final int TEMP_ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS_DURATION_MS = 10_000;
|
||||
|
||||
private final Context mContext;
|
||||
private final SessionManagerImpl mSessionManagerImpl;
|
||||
private final MessageHandler mHandler = new MessageHandler();
|
||||
@@ -133,6 +136,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
|
||||
new ArrayList<>();
|
||||
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
private KeyguardManager mKeyguardManager;
|
||||
private AudioManagerInternal mAudioManagerInternal;
|
||||
private ContentResolver mContentResolver;
|
||||
@@ -168,6 +172,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
public void onStart() {
|
||||
publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
|
||||
Watchdog.getInstance().addMonitor(this);
|
||||
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
|
||||
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
|
||||
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
|
||||
mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(mContext);
|
||||
@@ -493,6 +498,25 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
throw new IllegalArgumentException("packageName is not owned by the calling process");
|
||||
}
|
||||
|
||||
void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
|
||||
int callingPid, int callingUid, String callingPackage, String reason) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
enforcePackageName(callingPackage, callingUid);
|
||||
if (targetUid != callingUid
|
||||
&& mActivityManagerInternal.canAllowWhileInUsePermissionInFgs(callingPid,
|
||||
callingUid, callingPackage)) {
|
||||
Log.d(TAG, "tempAllowlistTargetPkgIfPossible callingPackage:"
|
||||
+ callingPackage + " targetPackage:" + targetPackage
|
||||
+ " reason:" + reason);
|
||||
mActivityManagerInternal.tempAllowWhileInUsePermissionInFgs(targetUid,
|
||||
TEMP_ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS_DURATION_MS);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a caller's authorization to register an IRemoteControlDisplay.
|
||||
* Authorization is granted if one of the following is true:
|
||||
|
||||
Reference in New Issue
Block a user