From d0fc2ca51fcf74c7f0a06a7cbda59384d2b20674 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 18 Mar 2020 22:41:55 +0800 Subject: [PATCH] Support addWindow as other user Support addWindow with the other userId which can be different from Uid. This can be used when client want to addView for secondary user. Example: 1. Create context with createContextAsUser or similar method. 2. Get WindowManager with this context. 3. WindowManager#addView Bug: 151414297 Test: atest WmTests WindowAddRemovePerfTest AddWindowAsUserTest Change-Id: I13e58d76b1f056f3829bc984c2b61496c8f8d535 --- core/java/android/view/IWindowSession.aidl | 5 ++++ core/java/android/view/ViewRootImpl.java | 16 ++++++++++-- .../android/view/WindowManagerGlobal.java | 5 ++-- core/java/android/view/WindowManagerImpl.java | 3 ++- .../android/view/WindowlessWindowManager.java | 14 +++++++++++ data/etc/services.core.protolog.json | 6 +++++ .../server/wm/RootWindowContainer.java | 2 +- .../java/com/android/server/wm/Session.java | 16 ++++++++++-- .../server/wm/WindowManagerService.java | 25 +++++++++++++++---- .../com/android/server/wm/WindowState.java | 23 +++++++++++------ .../server/wm/TestWindowManagerPolicy.java | 4 +-- .../android/server/wm/WindowTestUtils.java | 2 +- .../android/server/wm/WindowTestsBase.java | 12 +++++---- 13 files changed, 104 insertions(+), 29 deletions(-) diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 81bfcb07ab6d5..a0527b7434fc4 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -48,6 +48,11 @@ interface IWindowSession { out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); + int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs, + in int viewVisibility, in int layerStackId, in int userId, + out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, + out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, + out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, out Rect outStableInsets, out InsetsState insetsState); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 750b1eddd2229..bede614b2a07a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -111,6 +111,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; +import android.os.UserHandle; import android.sysprop.DisplayProperties; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; @@ -893,6 +894,14 @@ public final class ViewRootImpl implements ViewParent, * We have one child */ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { + setView(view, attrs, panelParentView, UserHandle.myUserId()); + } + + /** + * We have one child + */ + public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, + int userId) { synchronized (this) { if (mView == null) { mView = view; @@ -1001,8 +1010,8 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); adjustLayoutParamsForCompatibility(mWindowAttributes); - res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, - getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, + res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, + getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets, mTempControls); @@ -1075,6 +1084,9 @@ public final class ViewRootImpl implements ViewParent, throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified window type " + mWindowAttributes.type + " is not valid"); + case WindowManagerGlobal.ADD_INVALID_USER: + throw new WindowManager.BadTokenException("Unable to add Window " + + mWindow + " -- requested userId is not valid"); } throw new RuntimeException( "Unable to add window -- unknown error code " + res); diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 410d9afe73daa..6e1ad3724dae0 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -136,6 +136,7 @@ public final class WindowManagerGlobal { public static final int ADD_PERMISSION_DENIED = -8; public static final int ADD_INVALID_DISPLAY = -9; public static final int ADD_INVALID_TYPE = -10; + public static final int ADD_INVALID_USER = -11; @UnsupportedAppUsage private static WindowManagerGlobal sDefaultWindowManager; @@ -317,7 +318,7 @@ public final class WindowManagerGlobal { } public void addView(View view, ViewGroup.LayoutParams params, - Display display, Window parentWindow) { + Display display, Window parentWindow, int userId) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } @@ -394,7 +395,7 @@ public final class WindowManagerGlobal { // do this last because it fires off messages to start doing things try { - root.setView(view, wparams, panelParentView); + root.setView(view, wparams, panelParentView, userId); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 316a5f2c88d21..2975d5ee8e1c3 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -104,7 +104,8 @@ public final class WindowManagerImpl implements WindowManager { @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); - mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow); + mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, + mContext.getUserId()); } @Override diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 39ed4018c65c1..ec51301430861 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -130,6 +130,20 @@ public class WindowlessWindowManager implements IWindowSession { return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } + /** + * IWindowSession implementation. Currently this class doesn't need to support for multi-user. + */ + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return addToDisplay(window, seq, attrs, viewVisibility, displayId, + outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls); + } + @Override public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 07cf41560cf3e..19785588e5700 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1201,6 +1201,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "315395835": { + "message": "Trying to add window with invalid user=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, "342460966": { "message": "DRAG %s: pos=(%d,%d)", "level": "INFO", diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 80b8b58549669..61544cd31957e 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -664,7 +664,7 @@ class RootWindowContainer extends WindowContainer void setSecureSurfaceState(int userId, boolean disabled) { forAllWindows((w) -> { - if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) { + if (w.mHasSurface && userId == w.mShowUserId) { w.mWinAnimator.setSecureLocked(disabled); } }, true /* traverseTopToBottom */); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 7d8a56e6c468b..56147f216e73e 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -162,7 +162,19 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, - outInsetsState, outActiveControls); + outInsetsState, outActiveControls, UserHandle.getUserId(mUid)); + } + + + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, + outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls, userId); } @Override @@ -172,7 +184,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, new Rect() /* outFrame */, outContentInsets, outStableInsets, new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */, - outInsetsState, null); + outInsetsState, null, UserHandle.getUserId(mUid)); } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8d3a4f27a2572..05d471d36f9ed 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,6 +25,7 @@ import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; +import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; @@ -1357,7 +1358,8 @@ public class WindowManagerService extends IWindowManager.Stub LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, + int requestUserId) { int[] appOp = new int[1]; final boolean isRoundedCornerOverlay = (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; @@ -1426,6 +1428,20 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_INVALID_DISPLAY; } + int userId = UserHandle.getUserId(session.mUid); + if (requestUserId != userId) { + try { + mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId, + false /*allowAll*/, ALLOW_NON_FULL, null, null); + } catch (Exception exp) { + ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d", + requestUserId); + return WindowManagerGlobal.ADD_INVALID_USER; + } + // It's fine to use this userId + userId = requestUserId; + } + ActivityRecord activity = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token @@ -1514,7 +1530,7 @@ public class WindowManagerService extends IWindowManager.Stub } final WindowState win = new WindowState(this, session, client, token, parentWindow, - appOp[0], seq, attrs, viewVisibility, session.mUid, + appOp[0], seq, attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to @@ -1834,8 +1850,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { return true; } - if (DevicePolicyCache.getInstance().getScreenCaptureDisabled( - UserHandle.getUserId(w.mOwnerUid))) { + if (DevicePolicyCache.getInstance().getScreenCaptureDisabled(w.mShowUserId)) { return true; } return false; @@ -7389,7 +7404,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { WindowState window = mWindowMap.get(token); if (window != null) { - return UserHandle.getUserId(window.mOwnerUid); + return window.mShowUserId; } return UserHandle.USER_NULL; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5a76bac67d649..4d47523b627ca 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -191,7 +191,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; -import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.text.TextUtils; @@ -269,6 +268,12 @@ class WindowState extends WindowContainer implements WindowManagerP final int mAppOp; // UserId and appId of the owner. Don't display windows of non-current user. final int mOwnerUid; + /** + * Requested userId, if this is not equals with the userId from mOwnerUid, then this window is + * created for secondary user. + * Use this member instead of get userId from mOwnerUid while query for visibility. + */ + final int mShowUserId; /** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */ final boolean mOwnerCanAddInternalSystemWindow; final WindowId mWindowId; @@ -806,8 +811,9 @@ class WindowState extends WindowContainer implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) { - this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow) { + this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, showUserId, ownerCanAddInternalSystemWindow, new PowerManagerWrapper() { @Override public void wakeUp(long time, @WakeReason int reason, String details) { @@ -823,8 +829,8 @@ class WindowState extends WindowContainer implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow, - PowerManagerWrapper powerManagerWrapper) { + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) { super(service); mSession = s; mClient = c; @@ -832,6 +838,7 @@ class WindowState extends WindowContainer implements WindowManagerP mToken = token; mActivityRecord = mToken.asActivityRecord(); mOwnerUid = ownerId; + mShowUserId = showUserId; mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; mWindowId = new WindowId(this); mAttrs.copyFrom(a); @@ -3275,7 +3282,7 @@ class WindowState extends WindowContainer implements WindowManagerP } return win.showForAllUsers() - || mWmService.isCurrentProfile(UserHandle.getUserId(win.mOwnerUid)); + || mWmService.isCurrentProfile(win.mShowUserId); } private static void applyInsets(Region outRegion, Rect frame, Rect inset) { @@ -3795,7 +3802,7 @@ class WindowState extends WindowContainer implements WindowManagerP public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); - proto.write(USER_ID, UserHandle.getUserId(mOwnerUid)); + proto.write(USER_ID, mShowUserId); final CharSequence title = getWindowTag(); if (title != null) { proto.write(TITLE, title.toString()); @@ -3979,7 +3986,7 @@ class WindowState extends WindowContainer implements WindowManagerP mLastTitle = title; mWasExiting = mAnimatingExit; mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) - + " u" + UserHandle.getUserId(mOwnerUid) + + " u" + mShowUserId + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}"); } return mStringNameCache; diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 7a075a26cb31d..4a8e8dafb57db 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -120,8 +120,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { IWindow iWindow = mock(IWindow.class); doReturn(mock(IBinder.class)).when(iWindow).asBinder(); window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, activity, - "Starting window", 0 /* ownerId */, false /* internalWindows */, wm, - mock(Session.class), iWindow, mPowerManagerWrapper); + "Starting window", 0 /* ownerId */, 0 /* userId*/, false /* internalWindows */, + wm, mock(Session.class), iWindow, mPowerManagerWrapper); activity.startingWindow = window; } if (mRunnableWhenAddingSplashScreen != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 084216a9a543c..fc95556750f17 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -112,7 +112,7 @@ class WindowTestUtils { TestWindowState(WindowManagerService service, Session session, IWindow window, WindowManager.LayoutParams attrs, WindowToken token) { - super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, false /* ownerCanAddInternalSystemWindow */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 397f73c3e67cb..e561c13a4e994 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.content.Intent; +import android.os.UserHandle; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; @@ -296,12 +297,13 @@ class WindowTestsBase extends SystemServiceTestsBase { WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow) { - return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, - mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper()); + return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId), + ownerCanAddInternalSystemWindow, mWm, mMockSession, mIWindow, + mSystemServicesTestRule.getPowerManagerWrapper()); } static WindowState createWindow(WindowState parent, int type, WindowToken token, - String name, int ownerId, boolean ownerCanAddInternalSystemWindow, + String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow, WindowState.PowerManagerWrapper powerManagerWrapper) { synchronized (service.mGlobalLock) { @@ -309,8 +311,8 @@ class WindowTestsBase extends SystemServiceTestsBase { attrs.setTitle(name); final WindowState w = new WindowState(service, session, iWindow, token, parent, - OP_NONE, - 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, + OP_NONE, 0, attrs, VISIBLE, ownerId, userId, + ownerCanAddInternalSystemWindow, powerManagerWrapper); // TODO: Probably better to make this call in the WindowState ctor to avoid errors with // adding it to the token...