1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.util.imetracing; 18 19 import android.annotation.Nullable; 20 import android.app.ActivityThread; 21 import android.content.Context; 22 import android.inputmethodservice.AbstractInputMethodService; 23 import android.os.RemoteException; 24 import android.os.ServiceManager; 25 import android.os.ServiceManager.ServiceNotFoundException; 26 import android.util.Log; 27 import android.util.proto.ProtoOutputStream; 28 import android.view.inputmethod.InputMethodManager; 29 30 import com.android.internal.view.IInputMethodManager; 31 32 import java.io.PrintWriter; 33 34 /** 35 * 36 * An abstract class that declares the methods for ime trace related operations - enable trace, 37 * schedule trace and add new trace to buffer. Both the client and server side classes can use 38 * it by getting an implementation through {@link ImeTracing#getInstance()}. 39 * 40 * @hide 41 */ 42 public abstract class ImeTracing { 43 44 static final String TAG = "imeTracing"; 45 public static final String PROTO_ARG = "--proto-com-android-imetracing"; 46 47 /* Constants describing the component type that triggered a dump. */ 48 public static final int IME_TRACING_FROM_CLIENT = 0; 49 public static final int IME_TRACING_FROM_IMS = 1; 50 public static final int IME_TRACING_FROM_IMMS = 2; 51 52 private static ImeTracing sInstance; 53 static boolean sEnabled = false; 54 IInputMethodManager mService; 55 56 protected boolean mDumpInProgress; 57 protected final Object mDumpInProgressLock = new Object(); 58 ImeTracing()59 ImeTracing() throws ServiceNotFoundException { 60 mService = IInputMethodManager.Stub.asInterface( 61 ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); 62 } 63 64 /** 65 * Returns an instance of {@link ImeTracingServerImpl} when called from a server side class 66 * and an instance of {@link ImeTracingClientImpl} when called from a client side class. 67 * Useful to schedule a dump for next frame or save a dump when certain methods are called. 68 * 69 * @return Instance of one of the children classes of {@link ImeTracing} 70 */ getInstance()71 public static ImeTracing getInstance() { 72 if (sInstance == null) { 73 try { 74 sInstance = isSystemProcess() 75 ? new ImeTracingServerImpl() : new ImeTracingClientImpl(); 76 } catch (RemoteException | ServiceNotFoundException e) { 77 Log.e(TAG, "Exception while creating ImeTracing instance", e); 78 } 79 } 80 return sInstance; 81 } 82 83 /** 84 * Transmits the information from client or InputMethodService side to the server, in order to 85 * be stored persistently to the current IME tracing dump. 86 * 87 * @param protoDump client or service side information to be stored by the server 88 * @param source where the information is coming from, refer to {@see #IME_TRACING_FROM_CLIENT} 89 * and {@see #IME_TRACING_FROM_IMS} 90 * @param where 91 */ sendToService(byte[] protoDump, int source, String where)92 public void sendToService(byte[] protoDump, int source, String where) throws RemoteException { 93 mService.startProtoDump(protoDump, source, where); 94 } 95 96 /** 97 * @param proto dump to be added to the buffer 98 */ addToBuffer(ProtoOutputStream proto, int source)99 public abstract void addToBuffer(ProtoOutputStream proto, int source); 100 101 /** 102 * Starts a proto dump of the client side information. 103 * 104 * @param where Place where the trace was triggered. 105 * @param immInstance The {@link InputMethodManager} instance to dump. 106 * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format. 107 */ triggerClientDump(String where, InputMethodManager immInstance, ProtoOutputStream icProto)108 public abstract void triggerClientDump(String where, InputMethodManager immInstance, 109 ProtoOutputStream icProto); 110 111 /** 112 * Starts a proto dump of the currently connected InputMethodService information. 113 * 114 * @param where Place where the trace was triggered. 115 * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped. 116 * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format. 117 */ triggerServiceDump(String where, AbstractInputMethodService service, ProtoOutputStream icProto)118 public abstract void triggerServiceDump(String where, AbstractInputMethodService service, 119 ProtoOutputStream icProto); 120 121 /** 122 * Starts a proto dump of the InputMethodManagerService information. 123 * 124 * @param where Place where the trace was triggered. 125 */ triggerManagerServiceDump(String where)126 public abstract void triggerManagerServiceDump(String where); 127 128 /** 129 * Being called while taking a bugreport so that tracing files can be included in the bugreport 130 * when the IME tracing is running. Does nothing otherwise. 131 * 132 * @param pw Print writer 133 */ saveForBugreport(@ullable PrintWriter pw)134 public void saveForBugreport(@Nullable PrintWriter pw) { 135 // does nothing by default. 136 } 137 138 /** 139 * Sets whether ime tracing is enabled. 140 * 141 * @param enabled Tells whether ime tracing should be enabled or disabled. 142 */ setEnabled(boolean enabled)143 public void setEnabled(boolean enabled) { 144 sEnabled = enabled; 145 } 146 147 /** 148 * @return {@code true} if dumping is enabled, {@code false} otherwise. 149 */ isEnabled()150 public boolean isEnabled() { 151 return sEnabled; 152 } 153 154 /** 155 * @return {@code true} if tracing is available, {@code false} otherwise. 156 */ isAvailable()157 public boolean isAvailable() { 158 return mService != null; 159 } 160 161 /** 162 * Starts a new IME trace if one is not already started. 163 * 164 * @param pw Print writer 165 */ startTrace(@ullable PrintWriter pw)166 public abstract void startTrace(@Nullable PrintWriter pw); 167 168 /** 169 * Stops the IME trace if one was previously started and writes the current buffers to disk. 170 * 171 * @param pw Print writer 172 */ stopTrace(@ullable PrintWriter pw)173 public abstract void stopTrace(@Nullable PrintWriter pw); 174 isSystemProcess()175 private static boolean isSystemProcess() { 176 return ActivityThread.isSystem(); 177 } 178 logAndPrintln(@ullable PrintWriter pw, String msg)179 protected void logAndPrintln(@Nullable PrintWriter pw, String msg) { 180 Log.i(TAG, msg); 181 if (pw != null) { 182 pw.println(msg); 183 pw.flush(); 184 } 185 } 186 187 } 188