Prevent view leak in handwriting delegation
We may leak view when calling acceptDelegation async, lets avoid using
view references to call the async method
Fix: 335731544
Test: atest StylusHandwritingTest
Flag: android.view.inputmethod.use_zero_jank_proxy
Change-Id: I494c1b8fe5abf5f15e97884be5ef37783517ad40
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 57d1b8d..ccec89b 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -496,9 +496,10 @@
if (delegatorPackageName == null) {
delegatorPackageName = view.getContext().getOpPackageName();
}
+ WeakReference<View> viewRef = new WeakReference<>(view);
Consumer<Boolean> consumer = delegationAccepted -> {
if (delegationAccepted) {
- onDelegationAccepted(view);
+ onDelegationAccepted(viewRef.get());
}
};
mImm.acceptStylusHandwritingDelegation(view, delegatorPackageName, view::post, consumer);
@@ -509,6 +510,10 @@
mState.mHandled = true;
mState.mShouldInitHandwriting = false;
}
+ if (view == null) {
+ // can be null if view was detached and was GCed.
+ return;
+ }
if (view instanceof TextView) {
((TextView) view).hideHint();
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2d4bb90..0c63e58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -129,6 +129,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -2630,13 +2631,17 @@
return false;
}
if (useDelegation) {
+ WeakReference<Executor> executorRef = new WeakReference<>(executor);
+ WeakReference<Consumer<Boolean>> callbackRef = new WeakReference<>(callback);
if (useCallback) {
IBooleanListener listener = new IBooleanListener.Stub() {
@Override
public void onResult(boolean value) {
- executor.execute(() -> {
- callback.accept(value);
- });
+ Executor executor = executorRef.get();
+ Consumer<Boolean> callback = callbackRef.get();
+ if (executor != null && callback != null) {
+ executor.execute(() -> callback.accept(value));
+ }
}
};
if (!IInputMethodManagerGlobalInvoker.acceptStylusHandwritingDelegationAsync(