DO NOT MERGE Add permission to launch activities on VD
1. Added permission ACTIVITY_EMBEDDING which allows apps to launch
activities on virtual displays.
2. Allow owner of display to launch activities from same app without
permission check to owned display.
3. Added permission checks for launching on secondary displays to
more target task/stack resolution paths in ActivityStarter.
Bug: 63117330
Test: android.server.cts.ActivityManagerDisplayTests
Test: go/wm-smoke
Change-Id: If169a77fb56241e06f7de20168dc38c4b0a217f5
(cherry picked from commit 7158764983)
This commit is contained in:
@@ -22,6 +22,7 @@ package android {
|
||||
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
|
||||
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
|
||||
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
|
||||
field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
|
||||
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
|
||||
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
|
||||
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
|
||||
|
||||
@@ -1859,6 +1859,10 @@
|
||||
<permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi @hide Allows an application to embed other activities -->
|
||||
<permission android:name="android.permission.ACTIVITY_EMBEDDING"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows an application to start any activity, regardless of permission
|
||||
protection or exported state.
|
||||
@hide -->
|
||||
|
||||
@@ -265,6 +265,7 @@ applications that come with the platform
|
||||
<permission name="android.permission.DELETE_CACHE_FILES"/>
|
||||
<permission name="android.permission.DELETE_PACKAGES"/>
|
||||
<permission name="android.permission.DUMP"/>
|
||||
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
|
||||
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
|
||||
<permission name="android.permission.GET_APP_OPS_STATS"/>
|
||||
<permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
|
||||
<uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
|
||||
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
|
||||
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
|
||||
|
||||
@@ -1184,7 +1184,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
||||
*/
|
||||
boolean canBeLaunchedOnDisplay(int displayId) {
|
||||
return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
|
||||
supportsResizeableMultiWindow());
|
||||
supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
|
||||
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
|
||||
import static android.Manifest.permission.START_ANY_ACTIVITY;
|
||||
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
|
||||
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
|
||||
@@ -491,9 +490,27 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
}
|
||||
|
||||
/** Check if placing task or activity on specified display is allowed. */
|
||||
boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable) {
|
||||
return displayId == DEFAULT_DISPLAY || (mService.mSupportsMultiDisplay
|
||||
&& (resizeable || displayConfigMatchesGlobal(displayId)));
|
||||
boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
|
||||
int callingUid, ActivityInfo activityInfo) {
|
||||
if (displayId == DEFAULT_DISPLAY) {
|
||||
// No restrictions for the default display.
|
||||
return true;
|
||||
}
|
||||
if (!mService.mSupportsMultiDisplay) {
|
||||
// Can't launch on secondary displays if feature is not supported.
|
||||
return false;
|
||||
}
|
||||
if (!resizeable && !displayConfigMatchesGlobal(displayId)) {
|
||||
// Can't apply wrong configuration to non-resizeable activities.
|
||||
return false;
|
||||
}
|
||||
if (!isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, displayId, activityInfo)) {
|
||||
// Can't place activities to a display that has restricted launch rules.
|
||||
// In this case the request should be made by explicitly adding target display id and
|
||||
// by caller with corresponding permissions. See #isCallerAllowedToLaunchOnDisplay().
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1679,8 +1696,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
// Check if someone tries to launch an activity on a private display with a different
|
||||
// owner.
|
||||
final int launchDisplayId = options.getLaunchDisplayId();
|
||||
if (launchDisplayId != INVALID_DISPLAY
|
||||
&& !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId)) {
|
||||
if (launchDisplayId != INVALID_DISPLAY && !isCallerAllowedToLaunchOnDisplay(callingPid,
|
||||
callingUid, launchDisplayId, aInfo)) {
|
||||
final String msg = "Permission Denial: starting " + intent.toString()
|
||||
+ " from " + callerApp + " (pid=" + callingPid
|
||||
+ ", uid=" + callingUid + ") with launchDisplayId="
|
||||
@@ -1694,17 +1711,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
}
|
||||
|
||||
/** Check if caller is allowed to launch activities on specified display. */
|
||||
boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId) {
|
||||
boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId,
|
||||
ActivityInfo aInfo) {
|
||||
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
|
||||
+ " callingPid=" + callingPid + " callingUid=" + callingUid);
|
||||
|
||||
if (callingPid == -1 && callingUid == -1) {
|
||||
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: no caller info, skip check");
|
||||
return true;
|
||||
}
|
||||
|
||||
final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(launchDisplayId);
|
||||
if (activityDisplay == null) {
|
||||
Slog.w(TAG, "Launch on display check: display not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the caller can manage activity stacks.
|
||||
// Check if the caller has enough privileges to embed activities and launch to private
|
||||
// displays.
|
||||
final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid,
|
||||
callingUid);
|
||||
if (startAnyPerm == PERMISSION_GRANTED) {
|
||||
@@ -1714,12 +1738,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
}
|
||||
|
||||
if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL
|
||||
&& activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID) {
|
||||
&& activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID
|
||||
&& activityDisplay.mDisplay.getOwnerUid() != aInfo.applicationInfo.uid) {
|
||||
// Limit launching on virtual displays, because their contents can be read from Surface
|
||||
// by apps that created them.
|
||||
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
|
||||
+ " disallow launch on virtual display for not-embedded activity");
|
||||
return false;
|
||||
if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
|
||||
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
|
||||
+ " disallow launch on virtual display for not-embedded activity.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activityDisplay.isPrivate()) {
|
||||
|
||||
@@ -1851,13 +1851,30 @@ class ActivityStarter {
|
||||
|
||||
final TaskRecord sourceTask = mSourceRecord.getTask();
|
||||
final ActivityStack sourceStack = mSourceRecord.getStack();
|
||||
// We only want to allow changing stack if the target task is not the top one,
|
||||
// otherwise we would move the launching task to the other side, rather than show
|
||||
// two side by side.
|
||||
final boolean moveStackAllowed = sourceStack.topTask() != sourceTask;
|
||||
// We only want to allow changing stack in two cases:
|
||||
// 1. If the target task is not the top one. Otherwise we would move the launching task to
|
||||
// the other side, rather than show two side by side.
|
||||
// 2. If activity is not allowed on target display.
|
||||
final int targetDisplayId = mTargetStack != null ? mTargetStack.mDisplayId
|
||||
: sourceStack.mDisplayId;
|
||||
final boolean moveStackAllowed = sourceStack.topTask() != sourceTask
|
||||
|| !mStartActivity.canBeLaunchedOnDisplay(targetDisplayId);
|
||||
if (moveStackAllowed) {
|
||||
mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.getTask(),
|
||||
mOptions);
|
||||
// If target stack is not found now - we can't just rely on the source stack, as it may
|
||||
// be not suitable. Let's check other displays.
|
||||
if (mTargetStack == null && targetDisplayId != sourceStack.mDisplayId) {
|
||||
// Can't use target display, lets find a stack on the source display.
|
||||
mTargetStack = mService.mStackSupervisor.getValidLaunchStackOnDisplay(
|
||||
sourceStack.mDisplayId, mStartActivity);
|
||||
}
|
||||
if (mTargetStack == null) {
|
||||
// There are no suitable stacks on the target and source display(s). Look on all
|
||||
// displays.
|
||||
mTargetStack = mService.mStackSupervisor.getNextValidLaunchStackLocked(
|
||||
mStartActivity, -1 /* currentFocus */);
|
||||
}
|
||||
}
|
||||
|
||||
if (mTargetStack == null) {
|
||||
|
||||
@@ -1582,7 +1582,8 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
|
||||
*/
|
||||
boolean canBeLaunchedOnDisplay(int displayId) {
|
||||
return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
|
||||
isResizeable(false /* checkSupportsPip */));
|
||||
isResizeable(false /* checkSupportsPip */), -1 /* don't check PID */,
|
||||
-1 /* don't check UID */, null /* activityInfo */);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user