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
This commit is contained in:
wilsonshih
2020-03-18 22:41:55 +08:00
parent c920673e5f
commit d0fc2ca51f
13 changed files with 104 additions and 29 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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

View File

@@ -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,

View File

@@ -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",

View File

@@ -664,7 +664,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
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 */);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> implements WindowManagerP
mLastTitle = title;
mWasExiting = mAnimatingExit;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
+ " u" + UserHandle.getUserId(mOwnerUid)
+ " u" + mShowUserId
+ " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}");
}
return mStringNameCache;

View File

@@ -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) {

View File

@@ -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 */);
}

View File

@@ -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...