/* * 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.util.imetracing; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; import android.util.proto.ProtoOutputStream; 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, * schedule trace and add new trace to buffer. Both the client and server side classes can use * it by getting an implementation through {@link ImeTracing#getInstance()}. * * @hide */ public abstract class ImeTracing { static final String TAG = "imeTracing"; public static final String PROTO_ARG = "--proto-com-android-imetracing"; /* Constants describing the component type that triggered a dump. */ public static final int IME_TRACING_FROM_CLIENT = 0; public static final int IME_TRACING_FROM_IMS = 1; public static final int IME_TRACING_FROM_IMMS = 2; private static ImeTracing sInstance; static boolean sEnabled = false; IInputMethodManager mService; protected boolean mDumpInProgress; protected final Object mDumpInProgressLock = new Object(); ImeTracing() throws ServiceNotFoundException { mService = IInputMethodManager.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); } /** * Returns an instance of {@link ImeTracingServerImpl} when called from a server side class * and an instance of {@link ImeTracingClientImpl} when called from a client side class. * Useful to schedule a dump for next frame or save a dump when certain methods are called. * * @return Instance of one of the children classes of {@link ImeTracing} */ public static ImeTracing getInstance() { if (sInstance == null) { try { sInstance = isSystemProcess() ? new ImeTracingServerImpl() : new ImeTracingClientImpl(); } catch (RemoteException | ServiceNotFoundException e) { Log.e(TAG, "Exception while creating ImeTracing instance", e); } } return sInstance; } /** * Transmits the information from client or InputMethodService side to the server, in order to * be stored persistently to the current IME tracing dump. * * @param protoDump client or service side information to be stored by the server * @param source where the information is coming from, refer to {@see #IME_TRACING_FROM_CLIENT} * and {@see #IME_TRACING_FROM_IMS} * @param where */ public void sendToService(byte[] protoDump, int source, String where) throws RemoteException { mService.startProtoDump(protoDump, source, where); } /** * @param proto dump to be added to the buffer */ public abstract void addToBuffer(ProtoOutputStream proto, int source); /** * Starts a proto dump of the client side information. * * @param where Place where the trace was triggered. * @param immInstance The {@link InputMethodManager} instance to dump. * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format. */ public abstract void triggerClientDump(String where, InputMethodManager immInstance, ProtoOutputStream icProto); /** * Starts a proto dump of the currently connected InputMethodService information. * * @param where Place where the trace was triggered. * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped. * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format. */ public abstract void triggerServiceDump(String where, AbstractInputMethodService service, ProtoOutputStream icProto); /** * Starts a proto dump of the InputMethodManagerService information. * * @param where Place where the trace was triggered. */ public abstract void triggerManagerServiceDump(String where); /** * Being called while taking a bugreport so that tracing files can be included in the bugreport * when the IME tracing is running. Does nothing otherwise. * * @param pw Print writer */ public void saveForBugreport(@Nullable PrintWriter pw) { // does nothing by default. } /** * Sets whether ime tracing is enabled. * * @param enabled Tells whether ime tracing should be enabled or disabled. */ public void setEnabled(boolean enabled) { sEnabled = enabled; } /** * @return {@code true} if dumping is enabled, {@code false} otherwise. */ public boolean isEnabled() { return sEnabled; } /** * @return {@code true} if tracing is available, {@code false} otherwise. */ public boolean isAvailable() { return mService != null; } /** * 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); 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(); } } }