diff options
| author | 2017-01-21 00:59:16 +0000 | |
|---|---|---|
| committer | 2017-01-21 00:59:20 +0000 | |
| commit | 4cbec883f103b9c6bf553ef4f77df492287d30dc (patch) | |
| tree | 15fda5ae8f0f35d22bdb08acb6d0d0094c343951 | |
| parent | 3b8eaf3f3ca62a70b062adfd16a92e1c8d81df09 (diff) | |
| parent | fb1bf69d5d7fc8c45e3ddbb8916e21ae57432ff1 (diff) | |
Merge "Set permissions for launching on private displays"
12 files changed, 280 insertions, 53 deletions
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index aea125835748..3eb584483911 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -19,6 +19,8 @@ package android.hardware.display; import android.hardware.SensorManager; import android.os.Handler; import android.os.PowerManager; +import android.util.IntArray; +import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; @@ -147,6 +149,21 @@ public abstract class DisplayManagerInternal { public abstract void setDisplayOffsets(int displayId, int x, int y); /** + * Provide a list of UIDs that are present on the display and are allowed to access it. + * + * @param displayAccessUIDs Mapping displayId -> int array of UIDs. + */ + public abstract void setDisplayAccessUIDs(SparseArray<IntArray> displayAccessUIDs); + + /** + * Check if specified UID's content is present on display and should be granted access to it. + * + * @param uid UID to be checked. + * @param displayId id of the display where presence of the content is checked. + * */ + public abstract boolean isUidPresentOnDisplay(int uid, int displayId); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 374813458c90..bc4ae6d0fcf1 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -750,13 +750,14 @@ public interface WindowManagerPolicy { * @param windowFlags Window layout flags. * @param overrideConfig override configuration to consider when generating * context to for resources. + * @param displayId Id of the display to show the splash screen at. * * @return The starting surface. * */ public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig); + int logo, int windowFlags, Configuration overrideConfig, int displayId); /** * Prepare for a window being added to the window manager. You can throw an diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 6134d7530eee..a968e0bb2a47 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -149,6 +149,7 @@ final class ActivityRecord implements AppWindowContainerListener { AppWindowContainerController mWindowContainerController; final ActivityInfo info; // all about me final ApplicationInfo appInfo; // information about activity's app + final int launchedFromPid; // always the pid who started the activity. final int launchedFromUid; // always the uid who started the activity. final String launchedFromPackage; // always the package who started the activity. final int userId; // Which user is this running for? @@ -588,7 +589,7 @@ final class ActivityRecord implements AppWindowContainerListener { return ResolverActivity.class.getName().equals(realActivity.getClassName()); } - ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, + ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, @@ -598,6 +599,7 @@ final class ActivityRecord implements AppWindowContainerListener { service = _service; appToken = new Token(this); info = aInfo; + launchedFromPid = _launchedFromPid; launchedFromUid = _launchedFromUid; launchedFromPackage = _launchedFromPackage; userId = UserHandle.getUserId(aInfo.applicationInfo.uid); @@ -2192,9 +2194,11 @@ final class ActivityRecord implements AppWindowContainerListener { throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent + " resolvedType=" + resolvedType); } - final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid, - launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(), - null, null, 0, componentSpecified, false, stackSupervisor, null, null, null); + final ActivityRecord r = new ActivityRecord(service, null /* caller */, + 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, intent, resolvedType, + aInfo, service.getConfiguration(), null /* resultTo */, null /* resultWho */, + 0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */, + stackSupervisor, null /* container */, null /* options */, null /* sourceRecord */); r.persistentState = persistentState; r.taskDescription = taskDescription; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index cd11d21eda89..d7b3728e9803 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -105,6 +105,7 @@ import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.util.ArraySet; import android.util.EventLog; +import android.util.IntArray; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -195,6 +196,12 @@ final class ActivityStack extends ConfigurationContainer { return mActivityContainer.mActivityDisplay; } + @Override + void onParentChanged() { + super.onParentChanged(); + mStackSupervisor.updateUIDsPresentOnDisplay(); + } + enum ActivityState { INITIALIZING, RESUMED, @@ -680,6 +687,27 @@ final class ActivityStack extends ConfigurationContainer { return null; } + boolean isInStackLocked(TaskRecord task) { + return mTaskHistory.contains(task); + } + + /** Checks if there are tasks with specific UID in the stack. */ + boolean isUidPresent(int uid) { + for (TaskRecord task : mTaskHistory) { + if (task.effectiveUid == uid) { + return true; + } + } + return false; + } + + /** Get all UIDs that are present in the stack. */ + void getPresentUIDs(IntArray presentUIDs) { + for (TaskRecord task : mTaskHistory) { + presentUIDs.add(task.effectiveUid); + } + } + final boolean updateLRUListLocked(ActivityRecord r) { final boolean hadit = mLRUActivities.remove(r); mLRUActivities.add(r); @@ -4878,13 +4906,13 @@ final class ActivityStack extends ConfigurationContainer { final boolean toTop = position >= mTaskHistory.size(); final ActivityStack prevStack = preAddTask(task, reason, toTop); + mTaskHistory.add(position, task); task.setStack(this); if (toTop) { updateTaskReturnToForTopInsertion(task); } - mTaskHistory.add(position, task); updateTaskMovement(task, toTop); postAddTask(task, prevStack); @@ -4901,8 +4929,8 @@ final class ActivityStack extends ConfigurationContainer { final ActivityRecord topRunningActivity = task.topRunningActivityLocked(); final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity; - task.setStack(this); insertTaskAtPosition(task, index); + task.setStack(this); postAddTask(task, null /* prevStack */); if (wasResumed) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 1224abd6f9ea..14899b4d5256 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -125,6 +125,7 @@ import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.DisplayManagerInternal; import android.hardware.display.VirtualDisplay; import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; @@ -154,6 +155,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.EventLog; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -380,7 +382,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** Mapping from displayId to display current state */ private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>(); - InputManagerInternal mInputManagerInternal; + private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>(); + + private DisplayManagerInternal mDisplayManagerInternal; + private InputManagerInternal mInputManagerInternal; /** The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks * may be finished until there is only one entry left. If this is empty the system is not @@ -580,6 +585,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mDisplayManager = (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE); mDisplayManager.registerDisplayListener(this, null); + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); Display[] displays = mDisplayManager.getDisplays(); for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) { @@ -1452,7 +1458,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord resultRecord, ActivityStack resultStack, ActivityOptions options) { final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, callingUid); - if (startAnyPerm == PERMISSION_GRANTED) { + if (startAnyPerm == PERMISSION_GRANTED) { return true; } final int componentRestriction = getComponentRestrictionForCallingPackage( @@ -1519,25 +1525,76 @@ 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) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId); - if (activityDisplay != null - && (activityDisplay.mDisplay.getFlags() & FLAG_PRIVATE) != 0) { - if (activityDisplay.mDisplay.getOwnerUid() != callingUid) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchDisplayId=" - + launchDisplayId; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - } + if (launchDisplayId != INVALID_DISPLAY + && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId)) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchDisplayId=" + + launchDisplayId; + Slog.w(TAG, msg); + throw new SecurityException(msg); } } return true; } + /** Check if caller is allowed to launch activities on specified display. */ + boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId) { + if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId + + " callingPid=" + callingPid + " callingUid=" + callingUid); + + final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId); + if (activityDisplay == null) { + Slog.w(TAG, "Launch on display check: display not found"); + return false; + } + + if (!activityDisplay.isPrivate()) { + // Anyone can launch on a public display. + if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" + + " allow launch on public display"); + return true; + } + + // Check if the caller is the owner of the display. + if (activityDisplay.mDisplay.getOwnerUid() == callingUid) { + if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" + + " allow launch for owner of the display"); + return true; + } + + // Check if caller is present on display + if (activityDisplay.isUidPresent(callingUid)) { + if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" + + " allow launch for caller present on the display"); + return true; + } + + // Check if the caller can launch anything. + final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, + callingUid); + if (startAnyPerm == PERMISSION_GRANTED) { + if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" + + " allow launch any on display"); + return true; + } + + Slog.w(TAG, "Launch on display check: denied"); + return false; + } + + /** Update lists of UIDs that are present on displays and have access to them. */ + void updateUIDsPresentOnDisplay() { + mDisplayAccessUIDs.clear(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); + mDisplayAccessUIDs.append(activityDisplay.mDisplayId, activityDisplay.getPresentUIDs()); + } + // Store updated lists in DisplayManager. Callers from outside of AM should get them there. + mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs); + } + UserInfo getUserInfo(int userId) { final long identity = Binder.clearCallingIdentity(); try { @@ -4586,6 +4643,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord mVisibleBehindActivity; + /** Array of all UIDs that are present on the display. */ + private IntArray mDisplayAccessUIDs = new IntArray(); + ActivityDisplay() { } @@ -4648,6 +4708,28 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D protected ConfigurationContainer getParent() { return ActivityStackSupervisor.this; } + + boolean isPrivate() { + return (mDisplay.getFlags() & FLAG_PRIVATE) != 0; + } + + boolean isUidPresent(int uid) { + for (ActivityStack stack : mStacks) { + if (stack.isUidPresent(uid)) { + return true; + } + } + return false; + } + + /** Update and get all UIDs that are present on the display and have access to it. */ + private IntArray getPresentUIDs() { + mDisplayAccessUIDs.clear(); + for (ActivityStack stack : mStacks) { + stack.getPresentUIDs(mDisplayAccessUIDs); + } + return mDisplayAccessUIDs; + } } class VirtualActivityDisplay extends ActivityDisplay { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 46e004799a63..26d2ee2e1547 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -476,10 +476,10 @@ class ActivityStarter { aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); } - ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, - intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, - resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor, - container, options, sourceRecord); + ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid, + callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), + resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, + mSupervisor, container, options, sourceRecord); if (outActivity != null) { outActivity[0] = r; } @@ -1900,16 +1900,14 @@ class ActivityStarter { final ActivityStack currentStack = task != null ? task.getStack() : null; if (currentStack != null) { - if (currentStack.isOnHomeDisplay()) { - if (mSupervisor.mFocusedStack != currentStack) { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, - "computeStackFocus: Setting " + "focused stack to r=" + r - + " task=" + task); - } else { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, - "computeStackFocus: Focused stack already=" - + mSupervisor.mFocusedStack); - } + if (mSupervisor.mFocusedStack != currentStack) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, + "computeStackFocus: Setting " + "focused stack to r=" + r + + " task=" + task); + } else { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, + "computeStackFocus: Focused stack already=" + + mSupervisor.mFocusedStack); } return currentStack; } @@ -1926,13 +1924,7 @@ class ActivityStarter { // Same also applies to dynamic stacks, as they behave similar to fullscreen stack. // If the freeform or docked stack has focus, and the activity to be launched is resizeable, // we can also put it in the focused stack. - final int focusedStackId = mSupervisor.mFocusedStack.mStackId; - final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID - || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack()) - || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced()) - || isDynamicStack(focusedStackId); - if (canUseFocusedStack && (!newTask - || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { + if (canLaunchIntoFocusedStack(r, newTask)) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Have a focused stack=" + mSupervisor.mFocusedStack); return mSupervisor.mFocusedStack; @@ -1959,6 +1951,36 @@ class ActivityStarter { return stack; } + /** Check if provided activity record can launch in currently focused stack. */ + private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) { + // The fullscreen stack can contain any task regardless of if the task is resizeable + // or not. So, we let the task go in the fullscreen task if it is the focus stack. + // Same also applies to dynamic stacks, as they behave similar to fullscreen stack. + // If the freeform or docked stack has focus, and the activity to be launched is resizeable, + // we can also put it in the focused stack. + final ActivityStack focusedStack = mSupervisor.mFocusedStack; + final int focusedStackId = mSupervisor.mFocusedStack.mStackId; + final boolean canUseFocusedStack; + switch (focusedStackId) { + case FULLSCREEN_WORKSPACE_STACK_ID: + canUseFocusedStack = true; + break; + case DOCKED_STACK_ID: + canUseFocusedStack = r.canGoInDockedStack(); + break; + case FREEFORM_WORKSPACE_STACK_ID: + canUseFocusedStack = r.isResizeableOrForced(); + break; + default: + canUseFocusedStack = isDynamicStack(focusedStackId) + && mSupervisor.isCallerAllowedToLaunchOnDisplay(r.launchedFromPid, + r.launchedFromUid, focusedStack.mDisplayId); + } + + return canUseFocusedStack + && (!newTask || focusedStack.mActivityContainer.isEligibleForNewTasks()); + } + private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task, ActivityOptions aOptions) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index db6c0f72059d..e550ac88b0f1 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -741,8 +741,14 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta return mStack; } - /** Must be used for setting parent stack because it performs configuration updates. */ + /** + * Must be used for setting parent stack because it performs configuration updates. + * Must be called after adding task as a child to the stack. + */ void setStack(ActivityStack stack) { + if (stack != null && !stack.isInStackLocked(this)) { + throw new IllegalStateException("Task must be added as a Stack child first."); + } mStack = stack; onParentChanged(); } @@ -769,6 +775,12 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta return mStack; } + @Override + void onParentChanged() { + super.onParentChanged(); + mService.mStackSupervisor.updateUIDsPresentOnDisplay(); + } + // Close up recents linked list. void closeRecentsChain() { if (mPrevAffiliate != null) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 9c762cce7e0f..cd0779324194 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -48,6 +48,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.text.TextUtils; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.view.Display; @@ -230,6 +231,9 @@ public final class DisplayManagerService extends SystemService { // intended for use inside of the requestGlobalDisplayStateInternal function. private final ArrayList<Runnable> mTempDisplayStateWorkQueue = new ArrayList<Runnable>(); + // Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs. + private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>(); + public DisplayManagerService(Context context) { super(context); mContext = context; @@ -394,7 +398,8 @@ public final class DisplayManagerService extends SystemService { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display != null) { DisplayInfo info = display.getDisplayInfoLocked(); - if (info.hasAccess(callingUid)) { + if (info.hasAccess(callingUid) + || isUidPresentOnDisplayInternal(callingUid, displayId)) { return info; } } @@ -937,6 +942,25 @@ public final class DisplayManagerService extends SystemService { } } + // Updates the lists of UIDs that are present on displays. + private void setDisplayAccessUIDsInternal(SparseArray<IntArray> newDisplayAccessUIDs) { + synchronized (mSyncRoot) { + mDisplayAccessUIDs.clear(); + for (int i = newDisplayAccessUIDs.size() - 1; i >= 0; i--) { + mDisplayAccessUIDs.append(newDisplayAccessUIDs.keyAt(i), + newDisplayAccessUIDs.valueAt(i)); + } + } + } + + // Checks if provided UID's content is present on the display and UID has access to it. + private boolean isUidPresentOnDisplayInternal(int uid, int displayId) { + synchronized (mSyncRoot) { + final IntArray displayUIDs = mDisplayAccessUIDs.get(displayId); + return displayUIDs != null && displayUIDs.indexOf(uid) != -1; + } + } + private void clearViewportsLocked() { mDefaultViewport.valid = false; mExternalTouchViewport.valid = false; @@ -1647,5 +1671,15 @@ public final class DisplayManagerService extends SystemService { public void setDisplayOffsets(int displayId, int x, int y) { setDisplayOffsetsInternal(displayId, x, y); } + + @Override + public void setDisplayAccessUIDs(SparseArray<IntArray> newDisplayAccessUIDs) { + setDisplayAccessUIDsInternal(newDisplayAccessUIDs); + } + + @Override + public boolean isUidPresentOnDisplay(int uid, int displayId) { + return isUidPresentOnDisplayInternal(uid, displayId); + } } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 32b8c9bdd3f6..c25ad468cf09 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -19,6 +19,8 @@ package com.android.server.policy; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; +import static android.content.Context.DISPLAY_SERVICE; +import static android.content.Context.WINDOW_SERVICE; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -140,6 +142,7 @@ import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.hardware.display.DisplayManager; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; @@ -2254,8 +2257,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } lp.format = PixelFormat.TRANSLUCENT; lp.setTitle("PointerLocation"); - WindowManager wm = (WindowManager) - mContext.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE); lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; wm.addView(mPointerLocationView, lp); mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView); @@ -2265,7 +2267,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void disablePointerLocation() { if (mPointerLocationView != null) { mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView); - WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE); wm.removeView(mPointerLocationView); mPointerLocationView = null; } @@ -2826,7 +2828,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig) { + int logo, int windowFlags, Configuration overrideConfig, int displayId) { if (!SHOW_SPLASH_SCREENS) { return null; } @@ -2927,7 +2929,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { params.setTitle("Splash Screen " + packageName); - wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); + // Obtain proper context to launch on the right display. + final Context displayContext = getDisplayContext(context, displayId); + if (displayContext == null) { + // Can't show splash screen on requested display, so skip showing at all. + return null; + } + wm = (WindowManager) displayContext.getSystemService(WINDOW_SERVICE); view = win.getDecorView(); if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for " @@ -2957,6 +2965,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { return null; } + /** Obtain proper context for showing splash screen on the provided display. */ + private Context getDisplayContext(Context context, int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + // The default context fits. + return context; + } + + final DisplayManager dm = (DisplayManager) context.getSystemService(DISPLAY_SERVICE); + final Display targetDisplay = dm.getDisplay(displayId); + if (targetDisplay == null) { + // Failed to obtain the non-default display where splash screen should be shown, + // lets not show at all. + return null; + } + + return context.createDisplayContext(targetDisplay); + } + /** * Preflight adding a window to the system. * diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java index ee4209f4a6a8..4b14f867b381 100644 --- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java +++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java @@ -54,6 +54,6 @@ class SplashScreenStartingData extends StartingData { StartingSurface createStartingSurface(AppWindowToken atoken) { return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo, mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags, - mMergedOverrideConfiguration); + mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId()); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b0d22b58a869..9a6cd2cb41f8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1115,7 +1115,8 @@ public class WindowManagerService extends IWindowManager.Stub + displayId + ". Aborting."); return WindowManagerGlobal.ADD_INVALID_DISPLAY; } - if (!displayContent.hasAccess(session.mUid)) { + if (!displayContent.hasAccess(session.mUid) + && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) { Slog.w(TAG_WM, "Attempted to add window to a display for which the application " + "does not have access: " + displayId + ". Aborting."); return WindowManagerGlobal.ADD_INVALID_DISPLAY; diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index c0c8fb049415..269b71986e72 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -321,7 +321,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig) { + int logo, int windowFlags, Configuration overrideConfig, int displayId) { return null; } |