Introduce getWindowContextToken

Also consolidate UI context related flags to ContextType.

Bug: 171280916
Test: atest ContextTest ContextAccessTest
Test: atest WindowContextTest WindowContextTests \
            WindowMetricsTest WindowMetricsTests
Test atest InputMethodServiceStrictModeTest \
           InputMethodMenuControllerTest
Test atest InputMethodServiceTest#testGetDisplay
           StrictModeTest#testIncorrectContextuse_*

Change-Id: I7f3a7f951c664d4c329059942e688ee3a625b992
This commit is contained in:
Charles Chen
2020-10-21 15:24:28 +08:00
parent 108951ecb3
commit 468a11afdd
8 changed files with 137 additions and 46 deletions

View File

@@ -258,14 +258,48 @@ class ContextImpl extends Context {
private ContentCaptureOptions mContentCaptureOptions = null;
private final Object mSync = new Object();
/**
* Whether this is created from {@link #createSystemContext(ActivityThread)} or
* {@link #createSystemUiContext(ContextImpl, int)} or any {@link Context} that system UI uses.
* Indicates this {@link Context} can not handle UI components properly and is not associated
* with a {@link Display} instance.
*/
private boolean mIsSystemOrSystemUiContext;
private boolean mIsUiContext;
private boolean mIsAssociatedWithDisplay;
private static final int CONTEXT_TYPE_NON_UI = 0;
/**
* Indicates this {@link Context} is associated with a {@link Display} instance but should not
* be handled UI components properly because it doesn't receive configuration changes
* regardless of display property updates.
*/
private static final int CONTEXT_TYPE_DISPLAY_CONTEXT = 1;
/**
* Indicates this {@link Context} is an {@link Activity} or {@link Activity} derived
* {@link Context}.
*/
private static final int CONTEXT_TYPE_ACTIVITY = 2;
/**
* Indicates this {@link Context} is a {@link WindowContext} or {@link WindowContext} derived
* {@link Context}.
*/
private static final int CONTEXT_TYPE_WINDOW_CONTEXT = 3;
// TODO(b/170369943): Remove after WindowContext migration
/**
* Indicates this {@link Context} is created from {@link #createSystemContext(ActivityThread)}
* or {@link #createSystemUiContext(ContextImpl, int)} or any {@link Context} that system UI
* uses.
*/
private static final int CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI = 4;
@IntDef(prefix = "CONTEXT_TYPE_", value = {
CONTEXT_TYPE_NON_UI,
CONTEXT_TYPE_DISPLAY_CONTEXT,
CONTEXT_TYPE_ACTIVITY,
CONTEXT_TYPE_WINDOW_CONTEXT,
CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
})
@Retention(RetentionPolicy.SOURCE)
private @interface ContextType {}
@ContextType
private int mContextType;
@GuardedBy("mSync")
private File mDatabasesDir;
@@ -1912,7 +1946,7 @@ class ContextImpl extends Context {
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
// Check incorrect Context usage.
if (isUiComponent(name) && !isSelfOrOuterUiContext()) {
if (isUiComponent(name) && !isUiContext()) {
final String errorMessage = "Tried to access visual service "
+ SystemServiceRegistry.getSystemServiceClassName(name)
+ " from a non-visual Context:" + getOuterContext();
@@ -1934,16 +1968,21 @@ class ContextImpl extends Context {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
// TODO(b/149463653): check if we still need this method after migrating IMS to WindowContext.
private boolean isSelfOrOuterUiContext() {
// We may override outer context's isUiContext
return isUiContext() || getOuterContext() != null && getOuterContext().isUiContext();
}
/** @hide */
@Override
public boolean isUiContext() {
return mIsSystemOrSystemUiContext || mIsUiContext;
switch (mContextType) {
case CONTEXT_TYPE_ACTIVITY:
case CONTEXT_TYPE_WINDOW_CONTEXT:
case CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI:
return true;
case CONTEXT_TYPE_DISPLAY_CONTEXT:
case CONTEXT_TYPE_NON_UI: {
return false;
}
default:
return false;
}
}
/**
@@ -2423,16 +2462,11 @@ class ContextImpl extends Context {
overrideConfig, display.getDisplayAdjustments().getCompatibilityInfo(),
mResources.getLoaders()));
context.mDisplay = display;
context.mIsAssociatedWithDisplay = true;
context.mContextType = CONTEXT_TYPE_DISPLAY_CONTEXT;
// Display contexts and any context derived from a display context should always override
// the display that would otherwise be inherited from mToken (or the global configuration if
// mToken is null).
context.mForceDisplayOverrideInResources = true;
// Note that even if a display context is derived from an UI context, it should not be
// treated as UI context because it does not handle configuration changes from the server
// side. If the context does need to handle configuration changes, please use
// Context#createWindowContext(int, Bundle).
context.mIsUiContext = false;
return context;
}
@@ -2449,11 +2483,10 @@ class ContextImpl extends Context {
ContextImpl createBaseWindowContext(IBinder token) {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
context.mIsAssociatedWithDisplay = true;
// Window contexts receive configurations directly from the server and as such do not
// need to override their display in ResourcesManager.
context.mForceDisplayOverrideInResources = false;
context.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
return context;
}
@@ -2520,7 +2553,7 @@ class ContextImpl extends Context {
@Override
public Display getDisplay() {
if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSelfOrOuterUiContext()) {
if (!isAssociatedWithDisplay()) {
throw new UnsupportedOperationException("Tried to obtain display from a Context not "
+ "associated with one. Only visual Contexts (such as Activity or one created "
+ "with Context#createWindowContext) or ones created with "
@@ -2531,6 +2564,19 @@ class ContextImpl extends Context {
return getDisplayNoVerify();
}
private boolean isAssociatedWithDisplay() {
switch (mContextType) {
case CONTEXT_TYPE_DISPLAY_CONTEXT:
case CONTEXT_TYPE_ACTIVITY:
case CONTEXT_TYPE_WINDOW_CONTEXT:
// TODO(b/170369943): Remove after WindowContext migration
case CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI:
return true;
default:
return false;
}
}
@Override
public Display getDisplayNoVerify() {
if (mDisplay == null) {
@@ -2550,7 +2596,9 @@ class ContextImpl extends Context {
@Override
public void updateDisplay(int displayId) {
mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources);
mIsAssociatedWithDisplay = true;
if (mContextType == CONTEXT_TYPE_NON_UI) {
mContextType = CONTEXT_TYPE_DISPLAY_CONTEXT;
}
}
@Override
@@ -2655,7 +2703,7 @@ class ContextImpl extends Context {
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
context.mIsSystemOrSystemUiContext = true;
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
return context;
}
@@ -2673,7 +2721,7 @@ class ContextImpl extends Context {
context.setResources(createResources(null, packageInfo, null, displayId, null,
packageInfo.getCompatibilityInfo(), null));
context.updateDisplay(displayId);
context.mIsSystemOrSystemUiContext = true;
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
return context;
}
@@ -2696,7 +2744,8 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
0, null, opPackageName);
context.setResources(packageInfo.getResources());
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
: CONTEXT_TYPE_NON_UI;
return context;
}
@@ -2724,9 +2773,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
activityInfo.splitName, activityToken, null, 0, classLoader, null);
context.mIsUiContext = true;
context.mIsAssociatedWithDisplay = true;
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -2757,7 +2804,7 @@ class ContextImpl extends Context {
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
@NonNull LoadedApk packageInfo, @Nullable String attributionTag,
@Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user,
@Nullable String splitName, @Nullable IBinder token, @Nullable UserHandle user,
int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
mOuterContext = this;
@@ -2774,7 +2821,7 @@ class ContextImpl extends Context {
}
mMainThread = mainThread;
mToken = activityToken;
mToken = token;
mFlags = flags;
if (user == null) {
@@ -2794,10 +2841,8 @@ class ContextImpl extends Context {
opPackageName = container.mOpPackageName;
setResources(container.mResources);
mDisplay = container.mDisplay;
mIsAssociatedWithDisplay = container.mIsAssociatedWithDisplay;
mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
mIsUiContext = container.isSelfOrOuterUiContext();
mContextType = container.mContextType;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
@@ -2847,8 +2892,13 @@ class ContextImpl extends Context {
}
@UnsupportedAppUsage
final void setOuterContext(Context context) {
final void setOuterContext(@NonNull Context context) {
mOuterContext = context;
// TODO(b/149463653): check if we still need this method after migrating IMS to
// WindowContext.
if (mOuterContext.isUiContext() && mContextType <= CONTEXT_TYPE_DISPLAY_CONTEXT) {
mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
}
}
@UnsupportedAppUsage
@@ -2859,7 +2909,12 @@ class ContextImpl extends Context {
@Override
@UnsupportedAppUsage
public IBinder getActivityToken() {
return mToken;
return mContextType == CONTEXT_TYPE_ACTIVITY ? mToken : null;
}
@Override
public IBinder getWindowContextToken() {
return mContextType == CONTEXT_TYPE_WINDOW_CONTEXT ? mToken : null;
}
private void checkMode(int mode) {

View File

@@ -6114,12 +6114,42 @@ public abstract class Context {
public abstract boolean canLoadUnsafeResources();
/**
* Returns token if the {@link Context} is a {@link android.app.Activity}. Returns
* {@code null} otherwise.
*
* @hide
*/
@Nullable
public IBinder getActivityToken() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
/**
* Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
* {@code null} otherwise.
*
* @hide
*/
@Nullable
public IBinder getWindowContextToken() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
/**
* Returns the proper token of a {@link Context}.
*
* If the {@link Context} is an {@link android.app.Activity}, returns
* {@link #getActivityToken()}. If the {@lijnk Context} is a {@link android.app.WindowContext},
* returns {@link #getWindowContextToken()}. Returns {@code null}, otherwise.
*
* @hide
*/
@Nullable
public static IBinder getToken(@NonNull Context context) {
return context.getActivityToken() != null ? context.getActivityToken()
: context.getWindowContextToken();
}
/**
* @hide
*/

View File

@@ -1067,6 +1067,14 @@ public class ContextWrapper extends Context {
return mBase.getActivityToken();
}
/**
* @hide
*/
@Override
public IBinder getWindowContextToken() {
return mBase != null ? mBase.getWindowContextToken() : null;
}
/**
* @hide
*/

View File

@@ -250,8 +250,8 @@ public final class WindowManagerImpl implements WindowManager {
// Initialize params which used for obtaining all system insets.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
params.token = (mParentWindow != null) ? mParentWindow.getContext().getActivityToken()
: mContext.getActivityToken();
final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext;
params.token = Context.getToken(context);
params.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
params.setFitInsetsTypes(0);

View File

@@ -60,7 +60,7 @@ public class WindowContextTest {
final WindowContext windowContext = new WindowContext(context, TYPE_APPLICATION_OVERLAY,
null /* options */);
final IBinder token = windowContext.getActivityToken();
final IBinder token = windowContext.getWindowContextToken();
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
assertTrue("Token must be registered to WMS", wms.isWindowToken(token));

View File

@@ -1940,9 +1940,7 @@ public final class ActiveServices {
ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
if (token != null) {
activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
// TODO(b/171280916): Remove the check after we have another API get window context
// token than getActivityToken.
if (activity == null && !mAm.mWindowManager.isWindowToken(token)) {
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}

View File

@@ -227,7 +227,7 @@ public class InputMethodMenuController {
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
mSettingsContext = new ContextThemeWrapper(
windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings);
mSwitchingDialogToken = mSettingsContext.getActivityToken();
mSwitchingDialogToken = mSettingsContext.getWindowContextToken();
}
// TODO(b/159767464): register the listener to another display again if window token is not
// yet created.

View File

@@ -63,8 +63,8 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
mDisplayContent.getDisplayId());
assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mDisplayContent);
assertThat(contextOnDefaultDisplay.getActivityToken())
.isEqualTo(contextOnSecondaryDisplay.getActivityToken());
assertThat(contextOnDefaultDisplay.getWindowContextToken())
.isEqualTo(contextOnSecondaryDisplay.getWindowContextToken());
}
private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {