• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.internal.inputmethod;
18 
19 import android.annotation.Nullable;
20 import android.app.ActivityThread;
21 import android.content.Context;
22 import android.os.RemoteException;
23 import android.os.ServiceManager;
24 import android.os.ServiceManager.ServiceNotFoundException;
25 import android.util.Log;
26 import android.util.proto.ProtoOutputStream;
27 import android.view.inputmethod.InputMethodManager;
28 
29 import com.android.internal.view.IInputMethodManager;
30 
31 import java.io.PrintWriter;
32 
33 /**
34  *
35  * An abstract class that declares the methods for ime trace related operations - enable trace,
36  * schedule trace and add new trace to buffer. Both the client and server side classes can use
37  * it by getting an implementation through {@link ImeTracing#getInstance()}.
38  */
39 public abstract class ImeTracing {
40 
41     static final String TAG = "imeTracing";
42     public static final String PROTO_ARG = "--proto-com-android-imetracing";
43 
44     /* Constants describing the component type that triggered a dump. */
45     public static final int IME_TRACING_FROM_CLIENT = 0;
46     public static final int IME_TRACING_FROM_IMS = 1;
47     public static final int IME_TRACING_FROM_IMMS = 2;
48 
49     private static ImeTracing sInstance;
50     static boolean sEnabled = false;
51     IInputMethodManager mService;
52 
53     protected boolean mDumpInProgress;
54     protected final Object mDumpInProgressLock = new Object();
55 
ImeTracing()56     ImeTracing() throws ServiceNotFoundException {
57         mService = IInputMethodManager.Stub.asInterface(
58                 ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
59     }
60 
61     /**
62      * Returns an instance of {@link ImeTracingServerImpl} when called from a server side class
63      * and an instance of {@link ImeTracingClientImpl} when called from a client side class.
64      * Useful to schedule a dump for next frame or save a dump when certain methods are called.
65      *
66      * @return Instance of one of the children classes of {@link ImeTracing}
67      */
getInstance()68     public static ImeTracing getInstance() {
69         if (sInstance == null) {
70             try {
71                 sInstance = isSystemProcess()
72                         ? new ImeTracingServerImpl() : new ImeTracingClientImpl();
73             } catch (RemoteException | ServiceNotFoundException e) {
74                 Log.e(TAG, "Exception while creating ImeTracing instance", e);
75             }
76         }
77         return sInstance;
78     }
79 
80     /**
81      * Transmits the information from client or InputMethodService side to the server, in order to
82      * be stored persistently to the current IME tracing dump.
83      *
84      * @param protoDump client or service side information to be stored by the server
85      * @param source where the information is coming from, refer to {@see #IME_TRACING_FROM_CLIENT}
86      * and {@see #IME_TRACING_FROM_IMS}
87      * @param where
88      */
sendToService(byte[] protoDump, int source, String where)89     public void sendToService(byte[] protoDump, int source, String where) throws RemoteException {
90         mService.startProtoDump(protoDump, source, where);
91     }
92 
93     /**
94      * Calling {@link IInputMethodManager#startImeTrace()}} to capture IME trace.
95      */
startImeTrace()96     public final void startImeTrace() {
97         try {
98             mService.startImeTrace();
99         } catch (RemoteException e) {
100             Log.e(TAG, "Could not start ime trace." + e);
101         }
102     }
103 
104     /**
105      * Calling {@link IInputMethodManager#stopImeTrace()} to stop IME trace.
106      */
stopImeTrace()107     public final void stopImeTrace() {
108         try {
109             mService.stopImeTrace();
110         } catch (RemoteException e) {
111             Log.e(TAG, "Could not stop ime trace." + e);
112         }
113     }
114 
115     /**
116      * @param proto dump to be added to the buffer
117      */
addToBuffer(ProtoOutputStream proto, int source)118     public abstract void addToBuffer(ProtoOutputStream proto, int source);
119 
120     /**
121      * Starts a proto dump of the client side information.
122      *
123      * @param where Place where the trace was triggered.
124      * @param immInstance The {@link InputMethodManager} instance to dump.
125      * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
126      */
triggerClientDump(String where, InputMethodManager immInstance, @Nullable byte[] icProto)127     public abstract void triggerClientDump(String where, InputMethodManager immInstance,
128             @Nullable byte[] icProto);
129 
130     /**
131      * A delegate for {@link #triggerServiceDump(String, ServiceDumper, byte[])}.
132      */
133     @FunctionalInterface
134     public interface ServiceDumper {
135         /**
136          * Dumps internal data into {@link ProtoOutputStream}.
137          *
138          * @param proto {@link ProtoOutputStream} to be dumped into.
139          * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto
140          *                format.
141          */
dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto)142         void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto);
143     }
144 
145     /**
146      * Starts a proto dump of the currently connected InputMethodService information.
147      *
148      * @param where Place where the trace was triggered.
149      * @param dumper {@link ServiceDumper} to be used to dump
150      *               {@link android.inputmethodservice.InputMethodService}.
151      * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
152      */
triggerServiceDump(String where, ServiceDumper dumper, @Nullable byte[] icProto)153     public abstract void triggerServiceDump(String where, ServiceDumper dumper,
154             @Nullable byte[] icProto);
155 
156     /**
157      * Starts a proto dump of the InputMethodManagerService information.
158      *
159      * @param where Place where the trace was triggered.
160      */
triggerManagerServiceDump(String where)161     public abstract void triggerManagerServiceDump(String where);
162 
163     /**
164      * Being called while taking a bugreport so that tracing files can be included in the bugreport
165      * when the IME tracing is running.  Does nothing otherwise.
166      *
167      * @param pw Print writer
168      */
saveForBugreport(@ullable PrintWriter pw)169     public void saveForBugreport(@Nullable PrintWriter pw) {
170         // does nothing by default.
171     }
172 
173     /**
174      * Sets whether ime tracing is enabled.
175      *
176      * @param enabled Tells whether ime tracing should be enabled or disabled.
177      */
setEnabled(boolean enabled)178     public void setEnabled(boolean enabled) {
179         sEnabled = enabled;
180     }
181 
182     /**
183      * @return {@code true} if dumping is enabled, {@code false} otherwise.
184      */
isEnabled()185     public boolean isEnabled() {
186         return sEnabled;
187     }
188 
189     /**
190      * @return {@code true} if tracing is available, {@code false} otherwise.
191      */
isAvailable()192     public boolean isAvailable() {
193         return mService != null;
194     }
195 
196     /**
197      * Starts a new IME trace if one is not already started.
198      *
199      * @param pw Print writer
200      */
startTrace(@ullable PrintWriter pw)201     public abstract void startTrace(@Nullable PrintWriter pw);
202 
203     /**
204      * Stops the IME trace if one was previously started and writes the current buffers to disk.
205      *
206      * @param pw Print writer
207      */
stopTrace(@ullable PrintWriter pw)208     public abstract void stopTrace(@Nullable PrintWriter pw);
209 
isSystemProcess()210     private static boolean isSystemProcess() {
211         return ActivityThread.isSystem();
212     }
213 
logAndPrintln(@ullable PrintWriter pw, String msg)214     protected void logAndPrintln(@Nullable PrintWriter pw, String msg) {
215         Log.i(TAG, msg);
216         if (pw != null) {
217             pw.println(msg);
218             pw.flush();
219         }
220     }
221 
222 }
223