Add InputConnection debug information

Add InputConnection information to IME tracing. This change adds
only information about the text associated with an
EditableInputConnection instance: editable text, selected text, text
before and after the cursor (for a preset length) and cursor caps mode.

Test: flash a device
      start IME tracing with `adb shell ime tracing start`
      stop IME tracing with `adb shell ime tracing stop`
      visualise the traces in Winscope and see the inputConnection information
Change-Id: I4dc6147fb7baa2cea413d2c44226e8c84c056c37
This commit is contained in:
Ioana Stefan
2020-11-02 16:57:07 +00:00
parent eb778956a4
commit c47b324d39
6 changed files with 133 additions and 3 deletions

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.inputmethod;
import android.annotation.NonNull;
import android.util.proto.ProtoOutputStream;
/** @hide */
public interface DumpableInputConnection {
/**
* Method used to dump state of InputConnection implementations of interest.
*
* @param proto Stream to write the state to
* @param fieldId FieldId of DumpableInputConnection as defined in the parent message
*/
void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
}

View File

@@ -22,6 +22,7 @@ import static android.util.imetracing.ImeTracing.PROTO_ARG;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
@@ -998,9 +999,9 @@ public final class InputMethodManager {
private final InputMethodManager mParentInputMethodManager;
private final WeakReference<View> mServedView;
ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn,
ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
InputMethodManager inputMethodManager, View servedView) {
super(mainLooper, conn);
super(icLooper, conn);
mParentInputMethodManager = inputMethodManager;
mServedView = new WeakReference<>(servedView);
}
@@ -1046,6 +1047,18 @@ public final class InputMethodManager {
+ " mServedView=" + mServedView.get()
+ "}";
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
// Check that the call is initiated in the main thread of the current InputConnection
// {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
// executed on this thread. Otherwise the messages are dispatched to the correct thread
// in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
// reasons.
if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
== getLooper()) {
((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
}
}
}
private static class ImeThreadFactory implements ThreadFactory {
@@ -2207,6 +2220,7 @@ public final class InputMethodManager {
* @hide
*/
public void notifyImeHidden(IBinder windowToken) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this);
synchronized (mH) {
try {
if (mCurMethod != null && mCurRootView != null
@@ -3312,6 +3326,9 @@ public final class InputMethodManager {
if (mImeInsetsConsumer != null) {
mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
}
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
}
}
}
}

View File

@@ -111,6 +111,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
}
protected Looper getLooper() {
synchronized (mMainLooper) {
return mMainLooper;
}
}
protected boolean isFinished() {
synchronized (mLock) {
return mFinished;

View File

@@ -16,21 +16,36 @@
package com.android.internal.widget;
import static android.view.inputmethod.InputConnectionProto.CURSOR_CAPS_MODE;
import static android.view.inputmethod.InputConnectionProto.EDITABLE_TEXT;
import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT;
import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_END;
import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_START;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
import android.text.method.KeyListener;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.widget.TextView;
public class EditableInputConnection extends BaseInputConnection {
/**
* Base class for an editable InputConnection instance. This is created by {@link TextView} or
* {@link EditText}.
*/
public class EditableInputConnection extends BaseInputConnection
implements DumpableInputConnection {
private static final boolean DEBUG = false;
private static final boolean DUMP_TEXT = false;
private static final String TAG = "EditableInputConnection";
private final TextView mTextView;
@@ -222,4 +237,28 @@ public class EditableInputConnection extends BaseInputConnection {
}
return true;
}
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();
CharSequence selectedText = getSelectedText(0 /* flags */);
if (DUMP_TEXT) {
if (editableText != null) {
proto.write(EDITABLE_TEXT, editableText.toString());
}
if (selectedText != null) {
proto.write(SELECTED_TEXT, selectedText.toString());
}
}
final Editable content = getEditable();
if (content != null) {
int start = Selection.getSelectionStart(content);
int end = Selection.getSelectionEnd(content);
proto.write(SELECTED_TEXT_START, start);
proto.write(SELECTED_TEXT_END, end);
}
proto.write(CURSOR_CAPS_MODE, getCursorCapsMode(0));
proto.end(token);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto2";
import "frameworks/base/core/proto/android/privacy.proto";
package android.view.inputmethod;
option java_multiple_files = true;
/**
* Represents a {@link android.view.inputmethod.InputConnection} object.
*/
message InputConnectionProto {
optional string editable_text = 1 [(.android.privacy).dest = DEST_LOCAL];
optional string selected_text = 2 [(.android.privacy).dest = DEST_LOCAL];
optional int32 selected_text_start = 3;
optional int32 selected_text_end = 4;
optional int32 cursor_caps_mode = 5;
}

View File

@@ -24,6 +24,7 @@ import "frameworks/base/core/proto/android/view/viewrootimpl.proto";
import "frameworks/base/core/proto/android/view/insetscontroller.proto";
import "frameworks/base/core/proto/android/view/imeinsetssourceconsumer.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
import "frameworks/base/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto";
@@ -70,6 +71,7 @@ message InputMethodClientsTraceProto {
optional ImeInsetsSourceConsumerProto ime_insets_source_consumer = 5;
optional EditorInfoProto editor_info = 6;
optional ImeFocusControllerProto ime_focus_controller = 7;
optional InputConnectionProto input_connection = 8;
}
}