From eaf61d885e2921e7e829666d6b3cf23d37ebdd7e Mon Sep 17 00:00:00 2001 From: Pablo Gamito Date: Fri, 14 Apr 2023 15:32:20 +0000 Subject: [PATCH] Add shell side transition trace to bug reports Test: atest BugreportManagerTestCases Bug: 276701336 Bug: 277181336 Bug: 278691227 Change-Id: If53cce37f4787d4e03fbee4cbe5b2808719e011f --- .../tests/BugreportManagerTest.java | 1 + .../wm/shell/dagger/WMShellBaseModule.java | 5 +- .../android/wm/shell/transition/Tracer.java | 86 ++++++++++++++++++- .../wm/shell/transition/Transitions.java | 52 ++++++++++- 4 files changed, 139 insertions(+), 5 deletions(-) diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java index bf8c7c63590f9..72969f7d8b96a 100644 --- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java +++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java @@ -112,6 +112,7 @@ public class BugreportManagerTest { Paths.get("/data/misc/wmtrace/layers_trace.winscope"), Paths.get("/data/misc/wmtrace/transactions_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 = { Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 9808c591592fe..022901cacfc56 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -544,13 +544,14 @@ public abstract class WMShellBaseModule { DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler, - @ShellAnimationThread ShellExecutor animExecutor) { + @ShellAnimationThread ShellExecutor animExecutor, + ShellCommandHandler shellCommandHandler) { if (!context.getResources().getBoolean(R.bool.config_registerShellTransitionsOnInit)) { // TODO(b/238217847): Force override shell init if registration is disabled shellInit = new ShellInit(mainExecutor); } return new Transitions(context, shellInit, shellController, organizer, pool, - displayController, mainExecutor, mainHandler, animExecutor); + displayController, mainExecutor, mainHandler, animExecutor, shellCommandHandler); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java index 7753d174e68c9..9d7c39f1c90e3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java @@ -30,6 +30,7 @@ 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; @@ -40,8 +41,9 @@ import java.util.Map; /** * Helper class to collect and dump transition traces. */ -public class Tracer { +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; @@ -50,6 +52,7 @@ public class Tracer { "/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)); @@ -157,6 +160,54 @@ public class Tracer { 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. * @@ -213,6 +264,39 @@ public class Tracer { } } + @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"; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index c0a6c7bf95e52..8dbbe0cde3e97 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -74,10 +74,12 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; 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.ShellInit; import com.android.wm.shell.util.TransitionUtil; +import java.io.PrintWriter; import java.util.ArrayList; 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 * before the SYNC transition can play. */ -public class Transitions implements RemoteCallable { +public class Transitions implements RemoteCallable, + ShellCommandHandler.ShellCommandActionHandler { static final String TAG = "ShellTransitions"; /** Set to {@code true} to enable shell transitions. */ @@ -171,6 +174,9 @@ public class Transitions implements RemoteCallable { /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */ private final ArrayList mHandlers = new ArrayList<>(); + @Nullable + private final ShellCommandHandler mShellCommandHandler; + private final ArrayList mObservers = new ArrayList<>(); /** List of {@link Runnable} instances to run when the last active transition has finished. */ @@ -246,8 +252,23 @@ public class Transitions implements RemoteCallable { @NonNull WindowOrganizer organizer, @NonNull TransactionPool pool, @NonNull DisplayController displayController, - @NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler, + @NonNull ShellExecutor mainExecutor, + @NonNull Handler mainHandler, @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; mContext = context; mMainExecutor = mainExecutor; @@ -263,6 +284,7 @@ public class Transitions implements RemoteCallable { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Default"); // Next lowest priority is remote transitions. mHandlers.add(mRemoteTransitionHandler); + mShellCommandHandler = shellCommandHandler; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Remote"); shellInit.addInitCallback(this::onInit, this); } @@ -294,6 +316,10 @@ public class Transitions implements RemoteCallable { // Pre-load the instance. TransitionMetrics.getInstance(); } + + if (mShellCommandHandler != null) { + mShellCommandHandler.addCommandCallback("transitions", this, this); + } } public boolean isRegistered() { @@ -1373,4 +1399,26 @@ public class Transitions implements RemoteCallable { 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 + " "); + } }