249 lines
9.6 KiB
Java
249 lines
9.6 KiB
Java
/*
|
|
* 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 com.android.internal.inputmethod;
|
|
|
|
import static android.os.Build.IS_USER;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.os.SystemClock;
|
|
import android.util.Log;
|
|
import android.util.proto.ProtoOutputStream;
|
|
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto;
|
|
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodManagerServiceTraceFileProto;
|
|
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodServiceTraceFileProto;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
|
|
import com.android.internal.annotations.GuardedBy;
|
|
import com.android.internal.util.TraceBuffer;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
/**
|
|
* An implementation of {@link ImeTracing} for the system_server process.
|
|
*/
|
|
class ImeTracingServerImpl extends ImeTracing {
|
|
private static final String TRACE_DIRNAME = "/data/misc/wmtrace/";
|
|
private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.winscope";
|
|
private static final String TRACE_FILENAME_IMS = "ime_trace_service.winscope";
|
|
private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.winscope";
|
|
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.
|
|
// This magic number corresponds to InputMethodClientsTraceFileProto.
|
|
private static final long MAGIC_NUMBER_CLIENTS_VALUE =
|
|
((long) InputMethodClientsTraceFileProto.MAGIC_NUMBER_H << 32)
|
|
| InputMethodClientsTraceFileProto.MAGIC_NUMBER_L;
|
|
// This magic number corresponds to InputMethodServiceTraceFileProto.
|
|
private static final long MAGIC_NUMBER_IMS_VALUE =
|
|
((long) InputMethodServiceTraceFileProto.MAGIC_NUMBER_H << 32)
|
|
| InputMethodServiceTraceFileProto.MAGIC_NUMBER_L;
|
|
// This magic number corresponds to InputMethodManagerServiceTraceFileProto.
|
|
private static final long MAGIC_NUMBER_IMMS_VALUE =
|
|
((long) InputMethodManagerServiceTraceFileProto.MAGIC_NUMBER_H << 32)
|
|
| InputMethodManagerServiceTraceFileProto.MAGIC_NUMBER_L;
|
|
|
|
private final TraceBuffer mBufferClients;
|
|
private final File mTraceFileClients;
|
|
private final TraceBuffer mBufferIms;
|
|
private final File mTraceFileIms;
|
|
private final TraceBuffer mBufferImms;
|
|
private final File mTraceFileImms;
|
|
|
|
private final Object mEnabledLock = new Object();
|
|
|
|
ImeTracingServerImpl() {
|
|
mBufferClients = new TraceBuffer<>(BUFFER_CAPACITY);
|
|
mTraceFileClients = new File(TRACE_DIRNAME + TRACE_FILENAME_CLIENTS);
|
|
mBufferIms = new TraceBuffer<>(BUFFER_CAPACITY);
|
|
mTraceFileIms = new File(TRACE_DIRNAME + TRACE_FILENAME_IMS);
|
|
mBufferImms = new TraceBuffer<>(BUFFER_CAPACITY);
|
|
mTraceFileImms = new File(TRACE_DIRNAME + TRACE_FILENAME_IMMS);
|
|
}
|
|
|
|
/**
|
|
* The provided dump is added to the corresponding dump buffer:
|
|
* {@link ImeTracingServerImpl#mBufferClients} or {@link ImeTracingServerImpl#mBufferIms}.
|
|
*
|
|
* @param proto dump to be added to the buffer
|
|
*/
|
|
@Override
|
|
public void addToBuffer(ProtoOutputStream proto, int source) {
|
|
if (isAvailable() && isEnabled()) {
|
|
switch (source) {
|
|
case IME_TRACING_FROM_CLIENT:
|
|
mBufferClients.add(proto);
|
|
return;
|
|
case IME_TRACING_FROM_IMS:
|
|
mBufferIms.add(proto);
|
|
return;
|
|
case IME_TRACING_FROM_IMMS:
|
|
mBufferImms.add(proto);
|
|
return;
|
|
default:
|
|
// Source not recognised.
|
|
Log.w(TAG, "Request to add to buffer, but source not recognised.");
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void triggerClientDump(String where, InputMethodManager immInstance,
|
|
@Nullable byte[] icProto) {
|
|
// Intentionally left empty, this is implemented in ImeTracingClientImpl
|
|
}
|
|
|
|
@Override
|
|
public void triggerServiceDump(String where, ServiceDumper dumper, @Nullable byte[] icProto) {
|
|
// Intentionally left empty, this is implemented in ImeTracingClientImpl
|
|
}
|
|
|
|
@Override
|
|
public void triggerManagerServiceDump(String where, @NonNull ServiceDumper dumper) {
|
|
if (!isEnabled() || !isAvailable()) {
|
|
return;
|
|
}
|
|
|
|
synchronized (mDumpInProgressLock) {
|
|
if (mDumpInProgress) {
|
|
return;
|
|
}
|
|
mDumpInProgress = true;
|
|
}
|
|
|
|
try {
|
|
sendToService(null, IME_TRACING_FROM_IMMS, where);
|
|
} finally {
|
|
mDumpInProgress = false;
|
|
}
|
|
}
|
|
|
|
private void writeTracesToFilesLocked() {
|
|
try {
|
|
long timeOffsetNs =
|
|
TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis())
|
|
- SystemClock.elapsedRealtimeNanos();
|
|
|
|
ProtoOutputStream clientsProto = new ProtoOutputStream();
|
|
clientsProto.write(InputMethodClientsTraceFileProto.MAGIC_NUMBER,
|
|
MAGIC_NUMBER_CLIENTS_VALUE);
|
|
clientsProto.write(InputMethodClientsTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS,
|
|
timeOffsetNs);
|
|
mBufferClients.writeTraceToFile(mTraceFileClients, clientsProto);
|
|
|
|
ProtoOutputStream imsProto = new ProtoOutputStream();
|
|
imsProto.write(InputMethodServiceTraceFileProto.MAGIC_NUMBER,
|
|
MAGIC_NUMBER_IMS_VALUE);
|
|
imsProto.write(InputMethodServiceTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS,
|
|
timeOffsetNs);
|
|
mBufferIms.writeTraceToFile(mTraceFileIms, imsProto);
|
|
|
|
ProtoOutputStream immsProto = new ProtoOutputStream();
|
|
immsProto.write(InputMethodManagerServiceTraceFileProto.MAGIC_NUMBER,
|
|
MAGIC_NUMBER_IMMS_VALUE);
|
|
immsProto.write(
|
|
InputMethodManagerServiceTraceFileProto.REAL_TO_ELAPSED_TIME_OFFSET_NANOS,
|
|
timeOffsetNs);
|
|
mBufferImms.writeTraceToFile(mTraceFileImms, immsProto);
|
|
|
|
resetBuffers();
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Unable to write buffer to file", e);
|
|
}
|
|
}
|
|
|
|
@GuardedBy("mEnabledLock")
|
|
@Override
|
|
public void startTrace(@Nullable 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;
|
|
}
|
|
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
logAndPrintln(pw, "Stopping tracing and writing traces in " + TRACE_DIRNAME + ": "
|
|
+ TRACE_FILENAME_CLIENTS + ", " + TRACE_FILENAME_IMS + ", "
|
|
+ TRACE_FILENAME_IMMS);
|
|
sEnabled = false;
|
|
writeTracesToFilesLocked();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void saveForBugreport(@Nullable PrintWriter pw) {
|
|
if (IS_USER) {
|
|
return;
|
|
}
|
|
synchronized (mEnabledLock) {
|
|
if (!isAvailable() || !isEnabled()) {
|
|
return;
|
|
}
|
|
// Temporarily stop accepting logs from trace event providers. There is a small chance
|
|
// that we may drop some trace events while writing the file, but we currently need to
|
|
// live with that. Note that addToBuffer() also has a bug that it doesn't do
|
|
// read-acquire so flipping sEnabled here doesn't even guarantee that addToBuffer() will
|
|
// temporarily stop accepting incoming events...
|
|
// TODO(b/175761228): Implement atomic snapshot to avoid downtime.
|
|
// TODO(b/175761228): Fix synchronization around sEnabled.
|
|
sEnabled = false;
|
|
logAndPrintln(pw, "Writing traces in " + TRACE_DIRNAME + ": "
|
|
+ TRACE_FILENAME_CLIENTS + ", " + TRACE_FILENAME_IMS + ", "
|
|
+ TRACE_FILENAME_IMMS);
|
|
writeTracesToFilesLocked();
|
|
sEnabled = true;
|
|
}
|
|
}
|
|
|
|
private void resetBuffers() {
|
|
mBufferClients.resetBuffer();
|
|
mBufferIms.resetBuffer();
|
|
mBufferImms.resetBuffer();
|
|
}
|
|
}
|