Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac24994a authored by Ioana Stefan's avatar Ioana Stefan
Browse files

IME tracing integration with bugreport

IME tracing information is added to bugreport if tracing was
previously enabled. IME tracing is reenabled after data is
dumped in the bugreport.

InputMethodManagerService state information is also dumped
in proto format.

Bug: 167948910, 154348613
Test: start trace by calling "adb shell ime tracing start"
      create a bugreport by calling "adb bugreport"
      check info in the bugreport zip file or upload to Winscope
Change-Id: Ie87eb8423e2bb70f28c330983d45b95e2e07062d
parent 45296595
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.util.imetracing;

import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
import android.inputmethodservice.AbstractInputMethodService;
@@ -29,6 +30,8 @@ import android.view.inputmethod.InputMethodManager;

import com.android.internal.view.IInputMethodManager;

import java.io.PrintWriter;

/**
 *
 * An abstract class that declares the methods for ime trace related operations - enable trace,
@@ -147,7 +150,43 @@ public abstract class ImeTracing {
        return mService != null;
    }

    /**
     * Writes the current tracing data to the specific output proto file.
     */
    public abstract void writeTracesToFiles();

    /**
     * Starts a new IME trace if one is not already started.
     *
     * @param pw Print writer
     */
    public abstract void startTrace(@Nullable PrintWriter pw);

    /**
     * Stops the IME trace if one was previously started and writes the current buffers to disk.
     *
     * @param pw Print writer
     */
    public abstract void stopTrace(@Nullable PrintWriter pw);

    /**
     * Stops the IME trace if one was previously started.
     *
     * @param pw Print writer
     * @param writeToFile If the current buffer should be written to disk or not
     */
    public abstract void stopTrace(@Nullable PrintWriter pw, boolean writeToFile);

    private static boolean isSystemProcess() {
        return ActivityThread.isSystem();
    }

    protected void logAndPrintln(@Nullable PrintWriter pw, String msg) {
        Log.i(TAG, msg);
        if (pw != null) {
            pw.println(msg);
            pw.flush();
        }
    }

}
+18 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;

import java.io.PrintWriter;

/**
 * @hide
 */
@@ -94,4 +96,20 @@ class ImeTracingClientImpl extends ImeTracing {
    public void triggerManagerServiceDump(String where) {
        // Intentionally left empty, this is implemented in ImeTracingServerImpl
    }

    @Override
    public void writeTracesToFiles() {
    }

    @Override
    public void startTrace(PrintWriter pw) {
    }

    @Override
    public void stopTrace(PrintWriter pw) {
    }

    @Override
    public void stopTrace(PrintWriter pw, boolean writeToFile) {
    }
}
+25 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.util.imetracing;

import static android.os.Build.IS_USER;

import android.annotation.Nullable;
import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -163,6 +164,14 @@ class ImeTracingServerImpl extends ImeTracing {
        }
    }

    @GuardedBy("mEnabledLock")
    @Override
    public void writeTracesToFiles() {
        synchronized (mEnabledLock) {
            writeTracesToFilesLocked();
        }
    }

    private void writeTracesToFilesLocked() {
        try {
            ProtoOutputStream clientsProto = new ProtoOutputStream();
@@ -178,13 +187,16 @@ class ImeTracingServerImpl extends ImeTracing {
            immsProto.write(InputMethodManagerServiceTraceFileProto.MAGIC_NUMBER,
                    MAGIC_NUMBER_IMMS_VALUE);
            mBufferImms.writeTraceToFile(mTraceFileImms, immsProto);

            resetBuffers();
        } catch (IOException e) {
            Log.e(TAG, "Unable to write buffer to file", e);
        }
    }

    @GuardedBy("mEnabledLock")
    private void startTrace(PrintWriter pw) {
    @Override
    public void startTrace(@Nullable PrintWriter pw) {
        if (IS_USER) {
            Log.w(TAG, "Warn: Tracing is not supported on user builds.");
            return;
@@ -196,15 +208,21 @@ class ImeTracingServerImpl extends ImeTracing {
                return;
            }

            pw.println("Starting tracing in " + TRACE_DIRNAME + ": " + TRACE_FILENAME_CLIENTS
            logAndPrintln(pw, "Starting tracing in " + TRACE_DIRNAME + ": " + TRACE_FILENAME_CLIENTS
                    + ", " + TRACE_FILENAME_IMS + ", " + TRACE_FILENAME_IMMS);
            sEnabled = true;
            resetBuffers();
        }
    }

    @Override
    public void stopTrace(@Nullable PrintWriter pw) {
        stopTrace(pw, true /* writeToFile */);
    }

    @GuardedBy("mEnabledLock")
    private void stopTrace(PrintWriter pw) {
    @Override
    public void stopTrace(@Nullable PrintWriter pw, boolean writeToFile) {
        if (IS_USER) {
            Log.w(TAG, "Warn: Tracing is not supported on user builds.");
            return;
@@ -216,12 +234,13 @@ class ImeTracingServerImpl extends ImeTracing {
                return;
            }

            pw.println("Stopping tracing and writing traces in " + TRACE_DIRNAME + ": "
            logAndPrintln(pw, "Stopping tracing and writing traces in " + TRACE_DIRNAME + ": "
                    + TRACE_FILENAME_CLIENTS + ", " + TRACE_FILENAME_IMS + ", "
                    + TRACE_FILENAME_IMMS);
            sEnabled = false;
            if (writeToFile) {
                writeTracesToFilesLocked();
            resetBuffers();
            }
        }
    }

+35 −1
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@

package com.android.server.inputmethod;

import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
@@ -161,6 +163,7 @@ import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.inputmethod.UnbindReason;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
@@ -208,6 +211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        implements ServiceConnection, Handler.Callback {
    static final boolean DEBUG = false;
    static final String TAG = "InputMethodManagerService";
    public static final String PROTO_ARG = "--proto";

    @Retention(SOURCE)
    @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
@@ -1574,7 +1578,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        public void onStart() {
            LocalServices.addService(InputMethodManagerInternal.class,
                    new LocalServiceImpl(mService));
            publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
            publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
        }

        @Override
@@ -5094,8 +5099,37 @@ public class InputMethodManagerService extends IInputMethodManager.Stub

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        boolean asProto = false;
        for (int argIndex = 0; argIndex < args.length; argIndex++) {
            if (args[argIndex].equals(PROTO_ARG)) {
                asProto = true;
                break;
            }
        }

        if (asProto) {
            final ImeTracing imeTracing = ImeTracing.getInstance();
            if (imeTracing.isEnabled()) {
                imeTracing.stopTrace(null, false /* writeToFile */);
                BackgroundThread.getHandler().post(() -> {
                    imeTracing.writeTracesToFiles();
                    imeTracing.startTrace(null);
                });
            }
        }
        doDump(fd, pw, args, asProto);
    }

    private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;

        if (useProto) {
            final ProtoOutputStream proto = new ProtoOutputStream(fd);
            dumpDebug(proto, InputMethodManagerServiceTraceProto.INPUT_METHOD_MANAGER_SERVICE);
            proto.flush();
            return;
        }

        IInputMethod method;
        ClientState client;
        ClientState focusedWindowClient;