diff options
| author | 2017-07-06 14:28:59 -0700 | |
|---|---|---|
| committer | 2017-07-19 19:31:28 -0700 | |
| commit | 71587649836d8e97c2ca00d968fc95293b59b0d3 (patch) | |
| tree | a64eebf2c25d3ef21d6e73af802ce716da25f561 | |
| parent | d16aeddbd197701b387dcedf2719b7cd09455bfc (diff) | |
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
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 4 | ||||
| -rw-r--r-- | data/etc/privapp-permissions-platform.xml | 1 | ||||
| -rw-r--r-- | packages/Shell/AndroidManifest.xml | 1 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityRecord.java | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityStackSupervisor.java | 51 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityStarter.java | 25 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/TaskRecord.java | 3 |
8 files changed, 70 insertions, 18 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index cc414bca05b0..82ab6ea5b413 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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"; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 54282b9a5a22..1d6957cf6e74 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1855,6 +1855,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 --> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index a79376ca774c..1a5cbd5df3f7 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -266,6 +266,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"/> diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index e6d9a9a39280..244677508894 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -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" /> diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 4a573691b656..1ed1ea67aa4b 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1181,7 +1181,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo */ boolean canBeLaunchedOnDisplay(int displayId) { return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId, - supportsResizeableMultiWindow()); + supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info); } /** diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 90d9149a2f66..fcdb91fa8ad5 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -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()) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index a31c33e4ab91..c10c3bd379e1 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1841,13 +1841,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) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 96d857354f1a..b77681907f63 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -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 */); } /** |