Merge "Add proto-based client side dumping for IME tracing"
This commit is contained in:
114
core/java/android/util/imetracing/ImeTracing.java
Normal file
114
core/java/android/util/imetracing/ImeTracing.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.ShellCommand;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.view.IInputMethodManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* 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";
|
||||
|
||||
private static ImeTracing sInstance;
|
||||
static boolean sEnabled = false;
|
||||
IInputMethodManager mService;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to start proto dump to {@link ImeTracingServerImpl} when called from a
|
||||
* server process and to {@link ImeTracingClientImpl} when called from a client process.
|
||||
*/
|
||||
public abstract void triggerDump();
|
||||
|
||||
/**
|
||||
* @param proto dump to be added to the buffer
|
||||
*/
|
||||
public abstract void addToBuffer(ProtoOutputStream proto);
|
||||
|
||||
/**
|
||||
* @param shell The shell command to process
|
||||
* @return {@code 0} if the command was successfully processed, {@code -1} otherwise
|
||||
*/
|
||||
public abstract int onShellCommand(ShellCommand shell);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
private static boolean isSystemProcess() {
|
||||
return ActivityThread.isSystem();
|
||||
}
|
||||
}
|
||||
71
core/java/android/util/imetracing/ImeTracingClientImpl.java
Normal file
71
core/java/android/util/imetracing/ImeTracingClientImpl.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.os.RemoteException;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.ShellCommand;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
class ImeTracingClientImpl extends ImeTracing {
|
||||
|
||||
private boolean mDumpInProgress;
|
||||
private final Object mDumpInProgressLock = new Object();
|
||||
|
||||
ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
|
||||
sEnabled = mService.isImeTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToBuffer(ProtoOutputStream proto) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onShellCommand(ShellCommand shell) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerDump() {
|
||||
if (isAvailable() && isEnabled()) {
|
||||
boolean doDump = false;
|
||||
synchronized (mDumpInProgressLock) {
|
||||
if (!mDumpInProgress) {
|
||||
mDumpInProgress = true;
|
||||
doDump = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDump) {
|
||||
try {
|
||||
ProtoOutputStream proto = new ProtoOutputStream();
|
||||
InputMethodManager.dumpProto(proto);
|
||||
mService.startProtoDump(proto.getBytes());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception while sending ime-related client dump to server", e);
|
||||
} finally {
|
||||
mDumpInProgress = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
154
core/java/android/util/imetracing/ImeTracingServerImpl.java
Normal file
154
core/java/android/util/imetracing/ImeTracingServerImpl.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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 static android.os.Build.IS_USER;
|
||||
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER;
|
||||
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_H;
|
||||
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_L;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.ShellCommand;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.TraceBuffer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
class ImeTracingServerImpl extends ImeTracing {
|
||||
private static final String TRACE_FILENAME = "/data/misc/wmtrace/ime_trace.pb";
|
||||
private static final int BUFFER_CAPACITY = 4096 * 1024;
|
||||
|
||||
// Needed for winscope to auto-detect the dump type. Explained further in
|
||||
// core.proto.android.view.inputmethod.inputmethodeditortrace.proto
|
||||
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
|
||||
|
||||
private final TraceBuffer mBuffer;
|
||||
private final File mTraceFile;
|
||||
private final Object mEnabledLock = new Object();
|
||||
|
||||
ImeTracingServerImpl() throws ServiceNotFoundException {
|
||||
mBuffer = new TraceBuffer<>(BUFFER_CAPACITY);
|
||||
mTraceFile = new File(TRACE_FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* The provided dump is added to the current dump buffer {@link ImeTracingServerImpl#mBuffer}.
|
||||
*
|
||||
* @param proto dump to be added to the buffer
|
||||
*/
|
||||
@Override
|
||||
public void addToBuffer(ProtoOutputStream proto) {
|
||||
if (isAvailable() && isEnabled()) {
|
||||
mBuffer.add(proto);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
|
||||
*
|
||||
* @param shell The shell command to process
|
||||
* @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
|
||||
*/
|
||||
@Override
|
||||
public int onShellCommand(ShellCommand shell) {
|
||||
PrintWriter pw = shell.getOutPrintWriter();
|
||||
String cmd = shell.getNextArgRequired();
|
||||
switch (cmd) {
|
||||
case "start":
|
||||
startTrace(pw);
|
||||
return 0;
|
||||
case "stop":
|
||||
stopTrace(pw);
|
||||
return 0;
|
||||
default:
|
||||
pw.println("Unknown command: " + cmd);
|
||||
pw.println("Input method trace options:");
|
||||
pw.println(" start: Start tracing");
|
||||
pw.println(" stop: Stop tracing");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerDump() {
|
||||
if (isAvailable() && isEnabled()) {
|
||||
try {
|
||||
mService.startProtoDump(null);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception while triggering proto dump", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTraceToFileLocked() {
|
||||
try {
|
||||
ProtoOutputStream proto = new ProtoOutputStream();
|
||||
proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
|
||||
mBuffer.writeTraceToFile(mTraceFile, proto);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to write buffer to file", e);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mEnabledLock")
|
||||
private void startTrace(PrintWriter pw) {
|
||||
if (IS_USER) {
|
||||
Log.w(TAG, "Warn: Tracing is not supported on user builds.");
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mEnabledLock) {
|
||||
if (isAvailable() && isEnabled()) {
|
||||
Log.w(TAG, "Warn: Tracing is already started.");
|
||||
return;
|
||||
}
|
||||
|
||||
pw.println("Starting tracing to " + mTraceFile + ".");
|
||||
sEnabled = true;
|
||||
mBuffer.resetBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mEnabledLock")
|
||||
private void stopTrace(PrintWriter pw) {
|
||||
if (IS_USER) {
|
||||
Log.w(TAG, "Warn: Tracing is not supported on user builds.");
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mEnabledLock) {
|
||||
if (!isAvailable() || !isEnabled()) {
|
||||
Log.w(TAG, "Warn: Tracing is not available or not started.");
|
||||
return;
|
||||
}
|
||||
|
||||
pw.println("Stopping tracing and writing traces to " + mTraceFile + ".");
|
||||
sEnabled = false;
|
||||
writeTraceToFileLocked();
|
||||
mBuffer.resetBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user