Merge "Fix potential failures in InputMethodService (2nd try)"
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 05daf63..a87b133 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -147,119 +147,146 @@
@MainThread
@Override
public void executeMessage(Message msg) {
- InputMethod inputMethod = mInputMethod.get();
- // Need a valid reference to the inputMethod for everything except a dump.
- if (inputMethod == null && msg.what != DO_DUMP) {
- Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
- return;
- }
-
+ final InputMethod inputMethod = mInputMethod.get();
+ final InputMethodServiceInternal target = mTarget.get();
switch (msg.what) {
case DO_DUMP: {
- InputMethodServiceInternal target = mTarget.get();
- if (target == null) {
- return;
- }
SomeArgs args = (SomeArgs)msg.obj;
- try {
- target.dump((FileDescriptor) args.arg1,
- (PrintWriter) args.arg2, (String[]) args.arg3);
- } catch (RuntimeException e) {
- ((PrintWriter)args.arg2).println("Exception: " + e);
- }
- synchronized (args.arg4) {
- ((CountDownLatch)args.arg4).countDown();
+ if (isValid(inputMethod, target, "DO_DUMP")) {
+ final FileDescriptor fd = (FileDescriptor) args.arg1;
+ final PrintWriter fout = (PrintWriter) args.arg2;
+ final String[] dumpArgs = (String[]) args.arg3;
+ final CountDownLatch latch = (CountDownLatch) args.arg4;
+ try {
+ target.dump(fd, fout, dumpArgs);
+ } catch (RuntimeException e) {
+ fout.println("Exception: " + e);
+ } finally {
+ latch.countDown();
+ }
}
args.recycle();
return;
}
case DO_INITIALIZE_INTERNAL:
- inputMethod.initializeInternal((IInputMethod.InitParams) msg.obj);
+ if (isValid(inputMethod, target, "DO_INITIALIZE_INTERNAL")) {
+ inputMethod.initializeInternal((IInputMethod.InitParams) msg.obj);
+ }
return;
case DO_SET_INPUT_CONTEXT: {
- inputMethod.bindInput((InputBinding)msg.obj);
+ if (isValid(inputMethod, target, "DO_SET_INPUT_CONTEXT")) {
+ inputMethod.bindInput((InputBinding) msg.obj);
+ }
return;
}
case DO_UNSET_INPUT_CONTEXT:
- inputMethod.unbindInput();
+ if (isValid(inputMethod, target, "DO_UNSET_INPUT_CONTEXT")) {
+ inputMethod.unbindInput();
+ }
return;
case DO_START_INPUT: {
final SomeArgs args = (SomeArgs) msg.obj;
- final InputConnection inputConnection = (InputConnection) args.arg1;
- final IInputMethod.StartInputParams params =
- (IInputMethod.StartInputParams) args.arg2;
- inputMethod.dispatchStartInput(inputConnection, params);
+ if (isValid(inputMethod, target, "DO_START_INPUT")) {
+ final InputConnection inputConnection = (InputConnection) args.arg1;
+ final IInputMethod.StartInputParams params =
+ (IInputMethod.StartInputParams) args.arg2;
+ inputMethod.dispatchStartInput(inputConnection, params);
+ }
args.recycle();
return;
}
case DO_ON_NAV_BUTTON_FLAGS_CHANGED:
- inputMethod.onNavButtonFlagsChanged(msg.arg1);
+ if (isValid(inputMethod, target, "DO_ON_NAV_BUTTON_FLAGS_CHANGED")) {
+ inputMethod.onNavButtonFlagsChanged(msg.arg1);
+ }
return;
case DO_CREATE_SESSION: {
SomeArgs args = (SomeArgs)msg.obj;
- inputMethod.createSession(new InputMethodSessionCallbackWrapper(
- mContext, (InputChannel) args.arg1,
- (IInputMethodSessionCallback) args.arg2));
+ if (isValid(inputMethod, target, "DO_CREATE_SESSION")) {
+ inputMethod.createSession(new InputMethodSessionCallbackWrapper(
+ mContext, (InputChannel) args.arg1,
+ (IInputMethodSessionCallback) args.arg2));
+ }
args.recycle();
return;
}
case DO_SET_SESSION_ENABLED:
- inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
- msg.arg1 != 0);
+ if (isValid(inputMethod, target, "DO_SET_SESSION_ENABLED")) {
+ inputMethod.setSessionEnabled((InputMethodSession) msg.obj, msg.arg1 != 0);
+ }
return;
case DO_SHOW_SOFT_INPUT: {
final SomeArgs args = (SomeArgs)msg.obj;
- inputMethod.showSoftInputWithToken(
- msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
+ if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
+ inputMethod.showSoftInputWithToken(
+ msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
+ }
args.recycle();
return;
}
case DO_HIDE_SOFT_INPUT: {
final SomeArgs args = (SomeArgs) msg.obj;
- inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
- (IBinder) args.arg1);
+ if (isValid(inputMethod, target, "DO_HIDE_SOFT_INPUT")) {
+ inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
+ (IBinder) args.arg1);
+ }
args.recycle();
return;
}
case DO_CHANGE_INPUTMETHOD_SUBTYPE:
- inputMethod.changeInputMethodSubtype((InputMethodSubtype)msg.obj);
+ if (isValid(inputMethod, target, "DO_CHANGE_INPUTMETHOD_SUBTYPE")) {
+ inputMethod.changeInputMethodSubtype((InputMethodSubtype) msg.obj);
+ }
return;
case DO_CREATE_INLINE_SUGGESTIONS_REQUEST: {
final SomeArgs args = (SomeArgs) msg.obj;
- inputMethod.onCreateInlineSuggestionsRequest(
- (InlineSuggestionsRequestInfo) args.arg1,
- (IInlineSuggestionsRequestCallback) args.arg2);
+ if (isValid(inputMethod, target, "DO_CREATE_INLINE_SUGGESTIONS_REQUEST")) {
+ inputMethod.onCreateInlineSuggestionsRequest(
+ (InlineSuggestionsRequestInfo) args.arg1,
+ (IInlineSuggestionsRequestCallback) args.arg2);
+ }
args.recycle();
return;
}
case DO_CAN_START_STYLUS_HANDWRITING: {
- inputMethod.canStartStylusHandwriting(msg.arg1);
+ if (isValid(inputMethod, target, "DO_CAN_START_STYLUS_HANDWRITING")) {
+ inputMethod.canStartStylusHandwriting(msg.arg1);
+ }
return;
}
case DO_UPDATE_TOOL_TYPE: {
- inputMethod.updateEditorToolType(msg.arg1);
+ if (isValid(inputMethod, target, "DO_UPDATE_TOOL_TYPE")) {
+ inputMethod.updateEditorToolType(msg.arg1);
+ }
return;
}
case DO_START_STYLUS_HANDWRITING: {
final SomeArgs args = (SomeArgs) msg.obj;
- inputMethod.startStylusHandwriting(msg.arg1, (InputChannel) args.arg1,
- (List<MotionEvent>) args.arg2);
+ if (isValid(inputMethod, target, "DO_START_STYLUS_HANDWRITING")) {
+ inputMethod.startStylusHandwriting(msg.arg1, (InputChannel) args.arg1,
+ (List<MotionEvent>) args.arg2);
+ }
args.recycle();
return;
}
case DO_INIT_INK_WINDOW: {
- inputMethod.initInkWindow();
+ if (isValid(inputMethod, target, "DO_INIT_INK_WINDOW")) {
+ inputMethod.initInkWindow();
+ }
return;
}
case DO_FINISH_STYLUS_HANDWRITING: {
- inputMethod.finishStylusHandwriting();
+ if (isValid(inputMethod, target, "DO_FINISH_STYLUS_HANDWRITING")) {
+ inputMethod.finishStylusHandwriting();
+ }
return;
}
case DO_REMOVE_STYLUS_HANDWRITING_WINDOW: {
- inputMethod.removeStylusHandwritingWindow();
+ if (isValid(inputMethod, target, "DO_REMOVE_STYLUS_HANDWRITING_WINDOW")) {
+ inputMethod.removeStylusHandwritingWindow();
+ }
return;
}
-
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -445,4 +472,15 @@
public void removeStylusHandwritingWindow() {
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_STYLUS_HANDWRITING_WINDOW));
}
+
+ private static boolean isValid(InputMethod inputMethod, InputMethodServiceInternal target,
+ String msg) {
+ if (inputMethod != null && target != null && !target.isServiceDestroyed()) {
+ return true;
+ } else {
+ Log.w(TAG, "Ignoring " + msg + ", InputMethod:" + inputMethod
+ + ", InputMethodServiceInternal:" + target);
+ return false;
+ }
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7436601..8b3451e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -700,11 +700,6 @@
@MainThread
@Override
public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
- if (mDestroyed) {
- Log.i(TAG, "The InputMethodService has already onDestroyed()."
- + "Ignore the initialization.");
- return;
- }
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
mConfigTracker.onInitialize(params.configChanges);
mPrivOps.set(params.privilegedOperations);
@@ -3938,6 +3933,14 @@
public void triggerServiceDump(String where, @Nullable byte[] icProto) {
ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isServiceDestroyed() {
+ return mDestroyed;
+ }
};
}
diff --git a/core/java/android/inputmethodservice/InputMethodServiceInternal.java b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
index f44f49d..c6612f6 100644
--- a/core/java/android/inputmethodservice/InputMethodServiceInternal.java
+++ b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
@@ -85,4 +85,11 @@
*/
default void triggerServiceDump(@NonNull String where, @Nullable byte[] icProto) {
}
+
+ /**
+ * @return {@code true} if {@link InputMethodService} is destroyed.
+ */
+ default boolean isServiceDestroyed() {
+ return false;
+ };
}