Merge changes from topic "shell-transition-bugreport" into udc-dev am: 42df3d41e8
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22707463 Change-Id: Ia57cc3fa6a5f2272464816c3a7ad009e5e9d9e29 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -103,6 +103,10 @@ public class TraceBuffer<P, S extends P, T extends P> {
|
|||||||
this(bufferCapacity, new ProtoOutputStreamProvider(), null);
|
this(bufferCapacity, new ProtoOutputStreamProvider(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TraceBuffer(int bufferCapacity, Consumer<T> protoDequeuedCallback) {
|
||||||
|
this(bufferCapacity, new ProtoOutputStreamProvider(), protoDequeuedCallback);
|
||||||
|
}
|
||||||
|
|
||||||
public TraceBuffer(int bufferCapacity, ProtoProvider protoProvider,
|
public TraceBuffer(int bufferCapacity, ProtoProvider protoProvider,
|
||||||
Consumer<T> protoDequeuedCallback) {
|
Consumer<T> protoDequeuedCallback) {
|
||||||
mBufferCapacity = bufferCapacity;
|
mBufferCapacity = bufferCapacity;
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ public class BugreportManagerTest {
|
|||||||
Paths.get("/data/misc/wmtrace/layers_trace.winscope"),
|
Paths.get("/data/misc/wmtrace/layers_trace.winscope"),
|
||||||
Paths.get("/data/misc/wmtrace/transactions_trace.winscope"),
|
Paths.get("/data/misc/wmtrace/transactions_trace.winscope"),
|
||||||
Paths.get("/data/misc/wmtrace/transition_trace.winscope"),
|
Paths.get("/data/misc/wmtrace/transition_trace.winscope"),
|
||||||
|
Paths.get("/data/misc/wmtrace/shell_transition_trace.winscope"),
|
||||||
};
|
};
|
||||||
private static final Path[] UI_TRACES_GENERATED_DURING_BUGREPORT = {
|
private static final Path[] UI_TRACES_GENERATED_DURING_BUGREPORT = {
|
||||||
Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"),
|
Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"),
|
||||||
|
|||||||
@@ -125,6 +125,34 @@ prebuilt_etc {
|
|||||||
|
|
||||||
// End ProtoLog
|
// End ProtoLog
|
||||||
|
|
||||||
|
gensrcs {
|
||||||
|
name: "wm-shell-protos",
|
||||||
|
|
||||||
|
tools: [
|
||||||
|
"aprotoc",
|
||||||
|
"protoc-gen-javastream",
|
||||||
|
"soong_zip",
|
||||||
|
],
|
||||||
|
|
||||||
|
tool_files: [
|
||||||
|
":libprotobuf-internal-protos",
|
||||||
|
],
|
||||||
|
|
||||||
|
cmd: "mkdir -p $(genDir)/$(in) " +
|
||||||
|
"&& $(location aprotoc) " +
|
||||||
|
" --plugin=$(location protoc-gen-javastream) " +
|
||||||
|
" --javastream_out=$(genDir)/$(in) " +
|
||||||
|
" -Iexternal/protobuf/src " +
|
||||||
|
" -I . " +
|
||||||
|
" $(in) " +
|
||||||
|
"&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
|
||||||
|
|
||||||
|
srcs: [
|
||||||
|
"proto/**/*.proto",
|
||||||
|
],
|
||||||
|
output_extension: "srcjar",
|
||||||
|
}
|
||||||
|
|
||||||
java_library {
|
java_library {
|
||||||
name: "WindowManager-Shell-proto",
|
name: "WindowManager-Shell-proto",
|
||||||
|
|
||||||
@@ -142,6 +170,7 @@ android_library {
|
|||||||
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
|
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
|
||||||
":wm_shell-sources-kt",
|
":wm_shell-sources-kt",
|
||||||
":wm_shell-aidls",
|
":wm_shell-aidls",
|
||||||
|
":wm-shell-protos",
|
||||||
],
|
],
|
||||||
resource_dirs: [
|
resource_dirs: [
|
||||||
"res",
|
"res",
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package com.android.wm.shell;
|
||||||
|
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
/* Represents a file full of transition entries.
|
||||||
|
Encoded, it should start with 0x09 0x57 0x4D 0x53 0x54 0x52 0x41 0x43 0x45 (.WMSTRACE), such
|
||||||
|
that it can be easily identified. */
|
||||||
|
message WmShellTransitionTraceProto {
|
||||||
|
/* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
|
||||||
|
(this is needed because enums have to be 32 bits and there's no nice way to put 64bit
|
||||||
|
constants into .proto files. */
|
||||||
|
enum MagicNumber {
|
||||||
|
INVALID = 0;
|
||||||
|
MAGIC_NUMBER_L = 0x54534D57; /* WMST (little-endian ASCII) */
|
||||||
|
MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be the first field, set to value in MagicNumber
|
||||||
|
required fixed64 magic_number = 1;
|
||||||
|
repeated Transition transitions = 2;
|
||||||
|
repeated HandlerMapping handlerMappings = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Transition {
|
||||||
|
required int32 id = 1;
|
||||||
|
optional int64 dispatch_time_ns = 2;
|
||||||
|
optional int32 handler = 3;
|
||||||
|
optional int64 merge_time_ns = 4;
|
||||||
|
optional int64 merge_request_time_ns = 5;
|
||||||
|
optional int32 merged_into = 6;
|
||||||
|
optional int64 abort_time_ns = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HandlerMapping {
|
||||||
|
required int32 id = 1;
|
||||||
|
required string name = 2;
|
||||||
|
}
|
||||||
@@ -544,13 +544,14 @@ public abstract class WMShellBaseModule {
|
|||||||
DisplayController displayController,
|
DisplayController displayController,
|
||||||
@ShellMainThread ShellExecutor mainExecutor,
|
@ShellMainThread ShellExecutor mainExecutor,
|
||||||
@ShellMainThread Handler mainHandler,
|
@ShellMainThread Handler mainHandler,
|
||||||
@ShellAnimationThread ShellExecutor animExecutor) {
|
@ShellAnimationThread ShellExecutor animExecutor,
|
||||||
|
ShellCommandHandler shellCommandHandler) {
|
||||||
if (!context.getResources().getBoolean(R.bool.config_registerShellTransitionsOnInit)) {
|
if (!context.getResources().getBoolean(R.bool.config_registerShellTransitionsOnInit)) {
|
||||||
// TODO(b/238217847): Force override shell init if registration is disabled
|
// TODO(b/238217847): Force override shell init if registration is disabled
|
||||||
shellInit = new ShellInit(mainExecutor);
|
shellInit = new ShellInit(mainExecutor);
|
||||||
}
|
}
|
||||||
return new Transitions(context, shellInit, shellController, organizer, pool,
|
return new Transitions(context, shellInit, shellController, organizer, pool,
|
||||||
displayController, mainExecutor, mainHandler, animExecutor);
|
displayController, mainExecutor, mainHandler, animExecutor, shellCommandHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
|
|||||||
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.wm.shell.transition;
|
||||||
|
|
||||||
|
import static android.os.Build.IS_USER;
|
||||||
|
|
||||||
|
import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
|
||||||
|
import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
|
||||||
|
import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.os.Trace;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.proto.ProtoOutputStream;
|
||||||
|
|
||||||
|
import com.android.internal.util.TraceBuffer;
|
||||||
|
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to collect and dump transition traces.
|
||||||
|
*/
|
||||||
|
public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
|
||||||
|
private static final int ALWAYS_ON_TRACING_CAPACITY = 15 * 1024; // 15 KB
|
||||||
|
private static final int ACTIVE_TRACING_BUFFER_CAPACITY = 5000 * 1024; // 5 MB
|
||||||
|
|
||||||
|
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
|
||||||
|
|
||||||
|
static final String WINSCOPE_EXT = ".winscope";
|
||||||
|
private static final String TRACE_FILE =
|
||||||
|
"/data/misc/wmtrace/shell_transition_trace" + WINSCOPE_EXT;
|
||||||
|
|
||||||
|
private final Object mEnabledLock = new Object();
|
||||||
|
private boolean mActiveTracingEnabled = false;
|
||||||
|
|
||||||
|
private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
|
||||||
|
(proto) -> handleOnEntryRemovedFromTrace(proto));
|
||||||
|
private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
|
||||||
|
|
||||||
|
private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
|
||||||
|
private final Map<Transitions.TransitionHandler, Integer> mHandlerUseCountInTrace =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry in the trace to log that a transition has been dispatched to a handler.
|
||||||
|
*
|
||||||
|
* @param transitionId The id of the transition being dispatched.
|
||||||
|
* @param handler The handler the transition is being dispatched to.
|
||||||
|
*/
|
||||||
|
public void logDispatched(int transitionId, Transitions.TransitionHandler handler) {
|
||||||
|
final int handlerId;
|
||||||
|
if (mHandlerIds.containsKey(handler)) {
|
||||||
|
handlerId = mHandlerIds.get(handler);
|
||||||
|
} else {
|
||||||
|
handlerId = mHandlerIds.size();
|
||||||
|
mHandlerIds.put(handler, handlerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoOutputStream outputStream = new ProtoOutputStream();
|
||||||
|
final long protoToken =
|
||||||
|
outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
|
||||||
|
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
|
||||||
|
SystemClock.elapsedRealtimeNanos());
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
|
||||||
|
|
||||||
|
outputStream.end(protoToken);
|
||||||
|
|
||||||
|
final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
|
||||||
|
mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
|
||||||
|
|
||||||
|
mRemovedFromTraceCallbacks.put(outputStream, () -> {
|
||||||
|
final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
|
||||||
|
mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
|
||||||
|
});
|
||||||
|
|
||||||
|
mTraceBuffer.add(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry in the trace to log that a request to merge a transition was made.
|
||||||
|
*
|
||||||
|
* @param mergeRequestedTransitionId The id of the transition we are requesting to be merged.
|
||||||
|
* @param playingTransitionId The id of the transition we was to merge the transition into.
|
||||||
|
*/
|
||||||
|
public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
|
||||||
|
ProtoOutputStream outputStream = new ProtoOutputStream();
|
||||||
|
final long protoToken =
|
||||||
|
outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
|
||||||
|
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
|
||||||
|
SystemClock.elapsedRealtimeNanos());
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
|
||||||
|
|
||||||
|
outputStream.end(protoToken);
|
||||||
|
|
||||||
|
mTraceBuffer.add(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry in the trace to log that a transition was merged by the handler.
|
||||||
|
*
|
||||||
|
* @param mergedTransitionId The id of the transition that was merged.
|
||||||
|
* @param playingTransitionId The id of the transition the transition was merged into.
|
||||||
|
*/
|
||||||
|
public void logMerged(int mergedTransitionId, int playingTransitionId) {
|
||||||
|
ProtoOutputStream outputStream = new ProtoOutputStream();
|
||||||
|
final long protoToken =
|
||||||
|
outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
|
||||||
|
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
|
||||||
|
outputStream.write(
|
||||||
|
com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
|
||||||
|
|
||||||
|
outputStream.end(protoToken);
|
||||||
|
|
||||||
|
mTraceBuffer.add(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an entry in the trace to log that a transition was aborted.
|
||||||
|
*
|
||||||
|
* @param transitionId The id of the transition that was aborted.
|
||||||
|
*/
|
||||||
|
public void logAborted(int transitionId) {
|
||||||
|
ProtoOutputStream outputStream = new ProtoOutputStream();
|
||||||
|
final long protoToken =
|
||||||
|
outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
|
||||||
|
|
||||||
|
outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
|
||||||
|
outputStream.write(
|
||||||
|
com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
|
||||||
|
|
||||||
|
outputStream.end(protoToken);
|
||||||
|
|
||||||
|
mTraceBuffer.add(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts collecting transitions for the trace.
|
||||||
|
* If called while a trace is already running, this will reset the trace.
|
||||||
|
*/
|
||||||
|
public void startTrace(@Nullable PrintWriter pw) {
|
||||||
|
if (IS_USER) {
|
||||||
|
LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trace.beginSection("Tracer#startTrace");
|
||||||
|
LogAndPrintln.i(pw, "Starting shell transition trace.");
|
||||||
|
synchronized (mEnabledLock) {
|
||||||
|
mActiveTracingEnabled = true;
|
||||||
|
mTraceBuffer.resetBuffer();
|
||||||
|
mTraceBuffer.setCapacity(ACTIVE_TRACING_BUFFER_CAPACITY);
|
||||||
|
}
|
||||||
|
Trace.endSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops collecting the transition trace and dump to trace to file.
|
||||||
|
*
|
||||||
|
* Dumps the trace to @link{TRACE_FILE}.
|
||||||
|
*/
|
||||||
|
public void stopTrace(@Nullable PrintWriter pw) {
|
||||||
|
stopTrace(pw, new File(TRACE_FILE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops collecting the transition trace and dump to trace to file.
|
||||||
|
* @param outputFile The file to dump the transition trace to.
|
||||||
|
*/
|
||||||
|
public void stopTrace(@Nullable PrintWriter pw, File outputFile) {
|
||||||
|
if (IS_USER) {
|
||||||
|
LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trace.beginSection("Tracer#stopTrace");
|
||||||
|
LogAndPrintln.i(pw, "Stopping shell transition trace.");
|
||||||
|
synchronized (mEnabledLock) {
|
||||||
|
mActiveTracingEnabled = false;
|
||||||
|
writeTraceToFileLocked(pw, outputFile);
|
||||||
|
mTraceBuffer.resetBuffer();
|
||||||
|
mTraceBuffer.setCapacity(ALWAYS_ON_TRACING_CAPACITY);
|
||||||
|
}
|
||||||
|
Trace.endSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Being called while taking a bugreport so that tracing files can be included in the bugreport.
|
||||||
|
*
|
||||||
|
* @param pw Print writer
|
||||||
|
*/
|
||||||
|
public void saveForBugreport(@Nullable PrintWriter pw) {
|
||||||
|
if (IS_USER) {
|
||||||
|
LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trace.beginSection("TransitionTracer#saveForBugreport");
|
||||||
|
synchronized (mEnabledLock) {
|
||||||
|
final File outputFile = new File(TRACE_FILE);
|
||||||
|
writeTraceToFileLocked(pw, outputFile);
|
||||||
|
}
|
||||||
|
Trace.endSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
|
||||||
|
Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
|
||||||
|
try {
|
||||||
|
ProtoOutputStream proto = new ProtoOutputStream();
|
||||||
|
proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
|
||||||
|
writeHandlerMappingToProto(proto);
|
||||||
|
int pid = android.os.Process.myPid();
|
||||||
|
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
|
||||||
|
+ " from process " + pid);
|
||||||
|
mTraceBuffer.writeTraceToFile(file, proto);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogAndPrintln.e(pw, "Unable to write buffer to file", e);
|
||||||
|
}
|
||||||
|
Trace.endSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
|
||||||
|
for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
|
||||||
|
final int count = mHandlerUseCountInTrace.get(handler);
|
||||||
|
if (count > 0) {
|
||||||
|
final long protoToken = outputStream.start(
|
||||||
|
com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
|
||||||
|
outputStream.write(com.android.wm.shell.HandlerMapping.ID,
|
||||||
|
mHandlerIds.get(handler));
|
||||||
|
outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
|
||||||
|
handler.getClass().getName());
|
||||||
|
outputStream.end(protoToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOnEntryRemovedFromTrace(Object proto) {
|
||||||
|
if (mRemovedFromTraceCallbacks.containsKey(proto)) {
|
||||||
|
mRemovedFromTraceCallbacks.get(proto).run();
|
||||||
|
mRemovedFromTraceCallbacks.remove(proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShellCommand(String[] args, PrintWriter pw) {
|
||||||
|
switch (args[0]) {
|
||||||
|
case "start": {
|
||||||
|
startTrace(pw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case "stop": {
|
||||||
|
stopTrace(pw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case "save-for-bugreport": {
|
||||||
|
saveForBugreport(pw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
pw.println("Invalid command: " + args[0]);
|
||||||
|
printShellCommandHelp(pw, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printShellCommandHelp(PrintWriter pw, String prefix) {
|
||||||
|
pw.println(prefix + "start");
|
||||||
|
pw.println(prefix + " Start tracing the transitions.");
|
||||||
|
pw.println(prefix + "stop");
|
||||||
|
pw.println(prefix + " Stop tracing the transitions.");
|
||||||
|
pw.println(prefix + "save-for-bugreport");
|
||||||
|
pw.println(prefix + " Flush in memory transition trace to file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LogAndPrintln {
|
||||||
|
private static final String LOG_TAG = "ShellTransitionTracer";
|
||||||
|
|
||||||
|
private static void i(@Nullable PrintWriter pw, String msg) {
|
||||||
|
Log.i(LOG_TAG, msg);
|
||||||
|
if (pw != null) {
|
||||||
|
pw.println(msg);
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void e(@Nullable PrintWriter pw, String msg) {
|
||||||
|
Log.e(LOG_TAG, msg);
|
||||||
|
if (pw != null) {
|
||||||
|
pw.println("ERROR: " + msg);
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void e(@Nullable PrintWriter pw, String msg, @NonNull Exception e) {
|
||||||
|
Log.e(LOG_TAG, msg, e);
|
||||||
|
if (pw != null) {
|
||||||
|
pw.println("ERROR: " + msg + " ::\n " + e);
|
||||||
|
pw.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,10 +74,12 @@ import com.android.wm.shell.common.ShellExecutor;
|
|||||||
import com.android.wm.shell.common.TransactionPool;
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
|
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||||
import com.android.wm.shell.sysui.ShellController;
|
import com.android.wm.shell.sysui.ShellController;
|
||||||
import com.android.wm.shell.sysui.ShellInit;
|
import com.android.wm.shell.sysui.ShellInit;
|
||||||
import com.android.wm.shell.util.TransitionUtil;
|
import com.android.wm.shell.util.TransitionUtil;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -106,7 +108,8 @@ import java.util.Arrays;
|
|||||||
* track, it will be marked as SYNC. This means that all currently active tracks must be flushed
|
* track, it will be marked as SYNC. This means that all currently active tracks must be flushed
|
||||||
* before the SYNC transition can play.
|
* before the SYNC transition can play.
|
||||||
*/
|
*/
|
||||||
public class Transitions implements RemoteCallable<Transitions> {
|
public class Transitions implements RemoteCallable<Transitions>,
|
||||||
|
ShellCommandHandler.ShellCommandActionHandler {
|
||||||
static final String TAG = "ShellTransitions";
|
static final String TAG = "ShellTransitions";
|
||||||
|
|
||||||
/** Set to {@code true} to enable shell transitions. */
|
/** Set to {@code true} to enable shell transitions. */
|
||||||
@@ -165,12 +168,15 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
private final ShellController mShellController;
|
private final ShellController mShellController;
|
||||||
private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
|
private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
|
||||||
private final SleepHandler mSleepHandler = new SleepHandler();
|
private final SleepHandler mSleepHandler = new SleepHandler();
|
||||||
|
private final Tracer mTracer = new Tracer();
|
||||||
private boolean mIsRegistered = false;
|
private boolean mIsRegistered = false;
|
||||||
|
|
||||||
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
|
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
|
||||||
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
|
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ShellCommandHandler mShellCommandHandler;
|
||||||
|
|
||||||
private final ArrayList<TransitionObserver> mObservers = new ArrayList<>();
|
private final ArrayList<TransitionObserver> mObservers = new ArrayList<>();
|
||||||
|
|
||||||
/** List of {@link Runnable} instances to run when the last active transition has finished. */
|
/** List of {@link Runnable} instances to run when the last active transition has finished. */
|
||||||
@@ -246,8 +252,23 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
@NonNull WindowOrganizer organizer,
|
@NonNull WindowOrganizer organizer,
|
||||||
@NonNull TransactionPool pool,
|
@NonNull TransactionPool pool,
|
||||||
@NonNull DisplayController displayController,
|
@NonNull DisplayController displayController,
|
||||||
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
|
@NonNull ShellExecutor mainExecutor,
|
||||||
|
@NonNull Handler mainHandler,
|
||||||
@NonNull ShellExecutor animExecutor) {
|
@NonNull ShellExecutor animExecutor) {
|
||||||
|
this(context, shellInit, shellController, organizer, pool, displayController, mainExecutor,
|
||||||
|
mainHandler, animExecutor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transitions(@NonNull Context context,
|
||||||
|
@NonNull ShellInit shellInit,
|
||||||
|
@NonNull ShellController shellController,
|
||||||
|
@NonNull WindowOrganizer organizer,
|
||||||
|
@NonNull TransactionPool pool,
|
||||||
|
@NonNull DisplayController displayController,
|
||||||
|
@NonNull ShellExecutor mainExecutor,
|
||||||
|
@NonNull Handler mainHandler,
|
||||||
|
@NonNull ShellExecutor animExecutor,
|
||||||
|
@Nullable ShellCommandHandler shellCommandHandler) {
|
||||||
mOrganizer = organizer;
|
mOrganizer = organizer;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
@@ -263,6 +284,7 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Default");
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Default");
|
||||||
// Next lowest priority is remote transitions.
|
// Next lowest priority is remote transitions.
|
||||||
mHandlers.add(mRemoteTransitionHandler);
|
mHandlers.add(mRemoteTransitionHandler);
|
||||||
|
mShellCommandHandler = shellCommandHandler;
|
||||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Remote");
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Remote");
|
||||||
shellInit.addInitCallback(this::onInit, this);
|
shellInit.addInitCallback(this::onInit, this);
|
||||||
}
|
}
|
||||||
@@ -294,6 +316,10 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
// Pre-load the instance.
|
// Pre-load the instance.
|
||||||
TransitionMetrics.getInstance();
|
TransitionMetrics.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mShellCommandHandler != null) {
|
||||||
|
mShellCommandHandler.addCommandCallback("transitions", this, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRegistered() {
|
public boolean isRegistered() {
|
||||||
@@ -766,6 +792,7 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s ready while"
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s ready while"
|
||||||
+ " %s is still animating. Notify the animating transition"
|
+ " %s is still animating. Notify the animating transition"
|
||||||
+ " in case they can be merged", ready, playing);
|
+ " in case they can be merged", ready, playing);
|
||||||
|
mTracer.logMergeRequested(ready.mInfo.getDebugId(), playing.mInfo.getDebugId());
|
||||||
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
|
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
|
||||||
playing.mToken, (wct, cb) -> onMerged(playing, ready));
|
playing.mToken, (wct, cb) -> onMerged(playing, ready));
|
||||||
}
|
}
|
||||||
@@ -799,6 +826,7 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
for (int i = 0; i < mObservers.size(); ++i) {
|
for (int i = 0; i < mObservers.size(); ++i) {
|
||||||
mObservers.get(i).onTransitionMerged(merged.mToken, playing.mToken);
|
mObservers.get(i).onTransitionMerged(merged.mToken, playing.mToken);
|
||||||
}
|
}
|
||||||
|
mTracer.logMerged(merged.mInfo.getDebugId(), playing.mInfo.getDebugId());
|
||||||
// See if we should merge another transition.
|
// See if we should merge another transition.
|
||||||
processReadyQueue(track);
|
processReadyQueue(track);
|
||||||
}
|
}
|
||||||
@@ -825,6 +853,8 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
// Otherwise give every other handler a chance
|
// Otherwise give every other handler a chance
|
||||||
active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
|
active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
|
||||||
active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
|
active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
|
||||||
|
|
||||||
|
mTracer.logDispatched(active.mInfo.getDebugId(), active.mHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -876,6 +906,8 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
transition.mFinishT.apply();
|
transition.mFinishT.apply();
|
||||||
transition.mAborted = true;
|
transition.mAborted = true;
|
||||||
|
|
||||||
|
mTracer.logAborted(transition.mInfo.getDebugId());
|
||||||
|
|
||||||
if (transition.mHandler != null) {
|
if (transition.mHandler != null) {
|
||||||
// Notifies to clean-up the aborted transition.
|
// Notifies to clean-up the aborted transition.
|
||||||
transition.mHandler.onTransitionConsumed(
|
transition.mHandler.onTransitionConsumed(
|
||||||
@@ -1350,4 +1382,26 @@ public class Transitions implements RemoteCallable<Transitions> {
|
|||||||
mMainExecutor.execute(() -> dispatchAnimScaleSetting(mTransitionAnimationScaleSetting));
|
mMainExecutor.execute(() -> dispatchAnimScaleSetting(mTransitionAnimationScaleSetting));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShellCommand(String[] args, PrintWriter pw) {
|
||||||
|
switch (args[0]) {
|
||||||
|
case "tracing": {
|
||||||
|
mTracer.onShellCommand(Arrays.copyOfRange(args, 1, args.length), pw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
pw.println("Invalid command: " + args[0]);
|
||||||
|
printShellCommandHelp(pw, "");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printShellCommandHelp(PrintWriter pw, String prefix) {
|
||||||
|
pw.println(prefix + "tracing");
|
||||||
|
mTracer.printShellCommandHelp(pw, prefix + " ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user