Merge "Allow FGS started from MediaButtonReceiver to have while-in-use permissions." into rvc-qpr-dev

This commit is contained in:
Hui Yu
2021-03-24 17:41:39 +00:00
committed by Android (Google) Code Review
8 changed files with 183 additions and 7 deletions

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

@@ -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 {

View File

@@ -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 "

View File

@@ -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);

View File

@@ -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: