diff options
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;      } |