Merge "Log errors if RemoteInputConnection is used after IMS#onDestroy()"

This commit is contained in:
TreeHugger Robot
2021-09-13 16:48:09 +00:00
committed by Android (Google) Code Review

View File

@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -62,8 +63,29 @@ final class RemoteInputConnection implements InputConnection {
@NonNull
private final IInputContextInvoker mInvoker;
private static final class InputMethodServiceInternalHolder {
@NonNull
private final WeakReference<InputMethodServiceInternal> mServiceRef;
private InputMethodServiceInternalHolder(
@NonNull WeakReference<InputMethodServiceInternal> ims) {
mServiceRef = ims;
}
@AnyThread
@Nullable
public InputMethodServiceInternal getAndWarnIfNull() {
final InputMethodServiceInternal ims = mServiceRef.get();
if (ims == null) {
Log.e(TAG, "InputMethodService is already destroyed. InputConnection instances"
+ " cannot be used beyond InputMethodService lifetime.", new Throwable());
}
return ims;
}
}
@NonNull
private final WeakReference<InputMethodServiceInternal> mInputMethodService;
private final InputMethodServiceInternalHolder mImsInternal;
@MissingMethodFlags
private final int mMissingMethods;
@@ -81,7 +103,7 @@ final class RemoteInputConnection implements InputConnection {
@NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
IInputContext inputContext, @MissingMethodFlags int missingMethods,
@NonNull CancellationGroup cancellationGroup) {
mInputMethodService = inputMethodService;
mImsInternal = new InputMethodServiceInternalHolder(inputMethodService);
mInvoker = IInputContextInvoker.create(inputContext);
mMissingMethods = missingMethods;
mCancellationGroup = cancellationGroup;
@@ -101,11 +123,11 @@ final class RemoteInputConnection implements InputConnection {
final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(length,
flags, result);
inputMethodService.triggerServiceDump(TAG + "#getTextAfterCursor", icProto);
imsInternal.triggerServiceDump(TAG + "#getTextAfterCursor", icProto);
}
return result;
@@ -125,11 +147,11 @@ final class RemoteInputConnection implements InputConnection {
final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(length,
flags, result);
inputMethodService.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto);
imsInternal.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto);
}
return result;
@@ -149,11 +171,11 @@ final class RemoteInputConnection implements InputConnection {
final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
result);
inputMethodService.triggerServiceDump(TAG + "#getSelectedText", icProto);
imsInternal.triggerServiceDump(TAG + "#getSelectedText", icProto);
}
return result;
@@ -187,11 +209,11 @@ final class RemoteInputConnection implements InputConnection {
final SurroundingText result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
beforeLength, afterLength, flags, result);
inputMethodService.triggerServiceDump(TAG + "#getSurroundingText", icProto);
imsInternal.triggerServiceDump(TAG + "#getSurroundingText", icProto);
}
return result;
@@ -207,11 +229,11 @@ final class RemoteInputConnection implements InputConnection {
final int result = CompletableFutureUtil.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(
reqModes, result);
inputMethodService.triggerServiceDump(TAG + "#getCursorCapsMode", icProto);
imsInternal.triggerServiceDump(TAG + "#getCursorCapsMode", icProto);
}
return result;
@@ -227,11 +249,11 @@ final class RemoteInputConnection implements InputConnection {
final ExtractedText result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal != null && ImeTracing.getInstance().isEnabled()) {
final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(
request, flags, result);
inputMethodService.triggerServiceDump(TAG + "#getExtractedText", icProto);
imsInternal.triggerServiceDump(TAG + "#getExtractedText", icProto);
}
return result;
@@ -248,12 +270,11 @@ final class RemoteInputConnection implements InputConnection {
@AnyThread
private void notifyUserActionIfNecessary() {
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService == null) {
// This basically should not happen, because it's the the caller of this method.
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal == null) {
return;
}
inputMethodService.notifyUserActionIfNecessary();
imsInternal.notifyUserActionIfNecessary();
}
@AnyThread
@@ -400,12 +421,11 @@ final class RemoteInputConnection implements InputConnection {
}
if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService == null) {
// This basically should not happen, because it's the caller of this method.
final InputMethodServiceInternal imsInternal = mImsInternal.getAndWarnIfNull();
if (imsInternal == null) {
return false;
}
inputMethodService.exposeContent(inputContentInfo, this);
imsInternal.exposeContent(inputContentInfo, this);
}
final CompletableFuture<Boolean> value =