summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMing-Shin Lu <lumark@google.com>2022-01-10 12:14:51 +0800
committerMing-Shin Lu <lumark@google.com>2022-01-14 12:49:13 +0000
commit29de30597b65c9111418278d04f03c35eb37d700 (patch)
tree605022d40a6316f8947cfd68bd21106ec5f9ee24
parent54fed092f842043cd0414c14a7d4e1f353f0cee9 (diff)
downloadbase-29de30597b65c9111418278d04f03c35eb37d700.tar.gz
Fix IME shrunk by WindowTokenClient mis-detach
As CL[1] introduced WindowTokenClient for WindowProviderService (aka the parent class of InputMethodService starts from CL[2]) as a token that IME context can associate with the windowContainer of the InputMethod window in server side. Like the activity context, IME context can adopt configuration/resources update when the IME window changed by display/window changes. And, the IME context caller can also create another type of context with wrapping IME context (i.e. calling createDisplayContext to create a display context), that makes this context can be mixed the window token of WindowProviderService since it's the base context. However, the finalization of the context mixed WindowTokenClient will detach the token when the attached context type is non-window context, this action will mis-detach the token when it managed by WindowProviderService. So like SoftKeyboard previously using createDisplayContext in CL[3] to workaround context resources issues, will in-directly expose this mis-detach token issue as the above. Beside, the handling of WindowTokenClient#{onConfigurationChange, onWindowTokenRemoved} does not thread-safe since this is called from IPC. As the result, the fix is to ignore the check in ContextImpl#finalize to not detach the token when it managed by WindowProviderService, also make sure to post to the main handler when received onConfigurationChanged/onWindowTokenRemoved in WindowTokenClient. Note that this fix could help to resolve "The Window Context should have been attached to a DisplayArea." exception if the token has been detached as the above case that happens before the next WindowProviderService#attachToWindowToken invoked. [1]: I64a1614f32d097785915f6105b1813a929e0fe32 [2]: Ie565e30ed5dd3f2cfe27355a6dded76dc3adc14b [3]: Ic592a1d2fb2da149220c8b503b522b3e864bcc77 Bug: 213118079 Bug: 211062619 Test: manual as steps: 1) adb install -r EditTextVariations.apk 2) adb install -r SoftKeyboard.apk 3) adb shell ime enable com.example.android.softkeyboard/.SoftKeyboard 4) adb shell ime set com.example.android.softkeyboard/.SoftKeyboard5 5) Enable screen auto-rotation 6) Launch EditTextVariations from launcher's shortcut 7) Tap the first EditText field to show IME 8) Rotate the device to the landscape mode 9) Expect the IME should not be shrunk Change-Id: I7beb7a122af93e596239a36db62073233cea0726
-rw-r--r--core/java/android/app/ContextImpl.java11
-rw-r--r--core/java/android/window/WindowTokenClient.java34
2 files changed, 32 insertions, 13 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index db3c7d9bcb02..30e088f15ff6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -311,6 +311,14 @@ class ContextImpl extends Context {
@ContextType
private int mContextType;
+ /**
+ * {@code true} to indicate that the {@link Context} owns the {@link #getWindowContextToken()}
+ * and is responsible for detaching the token when the Context is released.
+ *
+ * @see #finalize()
+ */
+ private boolean mOwnsToken = false;
+
@GuardedBy("mSync")
private File mDatabasesDir;
@GuardedBy("mSync")
@@ -2979,7 +2987,7 @@ class ContextImpl extends Context {
// WindowContainer. We should detach from WindowContainer when the Context is finalized
// if this Context is not a WindowContext. WindowContext finalization is handled in
// WindowContext class.
- if (mToken instanceof WindowTokenClient && mContextType != CONTEXT_TYPE_WINDOW_CONTEXT) {
+ if (mToken instanceof WindowTokenClient && mOwnsToken) {
((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded();
}
super.finalize();
@@ -3010,6 +3018,7 @@ class ContextImpl extends Context {
token.attachContext(context);
token.attachToDisplayContent(displayId);
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
+ context.mOwnsToken = true;
return context;
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index b331a9e81e27..1ba63f5fca3c 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -20,9 +20,10 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
+import android.annotation.BinderThread;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.app.IWindowToken;
import android.app.ResourcesManager;
import android.content.Context;
@@ -31,7 +32,9 @@ import android.inputmethodservice.AbstractInputMethodService;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.IWindowManager;
@@ -72,6 +75,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
private boolean mAttachToWindowContainer;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
/**
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
* can only attach one {@link Context}.
@@ -133,7 +138,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
if (configuration == null) {
return false;
}
- onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
+ mHandler.post(() -> onConfigurationChanged(configuration, displayId,
+ false /* shouldReportConfigChange */));
mAttachToWindowContainer = true;
return true;
} catch (RemoteException e) {
@@ -180,9 +186,11 @@ public class WindowTokenClient extends IWindowToken.Stub {
* @param newConfig the updated {@link Configuration}
* @param newDisplayId the updated {@link android.view.Display} ID
*/
+ @BinderThread
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
- onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
+ mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId,
+ true /* shouldReportConfigChange */));
}
// TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
@@ -193,6 +201,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
* Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control
* whether to dispatch configuration update or not.
*/
+ @MainThread
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public void onConfigurationChanged(Configuration newConfig, int newDisplayId,
boolean shouldReportConfigChange) {
@@ -218,8 +227,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
if (shouldReportConfigChange && context instanceof WindowContext) {
final WindowContext windowContext = (WindowContext) context;
- ActivityThread.currentActivityThread().getHandler().post(
- () -> windowContext.dispatchConfigurationChanged(newConfig));
+ windowContext.dispatchConfigurationChanged(newConfig);
}
// Dispatch onConfigurationChanged only if there's a significant public change to
@@ -233,8 +241,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
if (shouldReportConfigChange && diff != 0
&& context instanceof WindowProviderService) {
final WindowProviderService windowProviderService = (WindowProviderService) context;
- ActivityThread.currentActivityThread().getHandler().post(
- () -> windowProviderService.onConfigurationChanged(newConfig));
+ windowProviderService.onConfigurationChanged(newConfig);
}
freeTextLayoutCachesIfNeeded(diff);
if (mShouldDumpConfigForIme) {
@@ -256,12 +263,15 @@ public class WindowTokenClient extends IWindowToken.Stub {
}
}
+ @BinderThread
@Override
public void onWindowTokenRemoved() {
- final Context context = mContextRef.get();
- if (context != null) {
- context.destroy();
- mContextRef.clear();
- }
+ mHandler.post(() -> {
+ final Context context = mContextRef.get();
+ if (context != null) {
+ context.destroy();
+ mContextRef.clear();
+ }
+ });
}
}