1 /* 2 * Copyright (C) 2024 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 @file:OptIn(InternalComposeTracingApi::class) 18 19 package com.android.systemui.compose 20 21 import android.os.Trace 22 import android.util.Log 23 import androidx.compose.runtime.Composer 24 import androidx.compose.runtime.CompositionTracer 25 import androidx.compose.runtime.InternalComposeTracingApi 26 import com.android.systemui.CoreStartable 27 import com.android.systemui.dagger.SysUISingleton 28 import com.android.systemui.statusbar.commandline.Command 29 import com.android.systemui.statusbar.commandline.CommandRegistry 30 import com.android.systemui.statusbar.commandline.ParseableCommand 31 import java.io.PrintWriter 32 import javax.inject.Inject 33 34 private const val TAG = "ComposeTracingStartable" 35 private const val COMMAND_NAME = "composition-tracing" 36 private const val SUBCOMMAND_ENABLE = "enable" 37 private const val SUBCOMMAND_DISABLE = "disable" 38 39 /** 40 * Sets up a [Command] to enable or disable Composition tracing. 41 * 42 * Usage: 43 * ``` 44 * adb shell cmd statusbar composition-tracing [enable|disable] 45 * ${ANDROID_BUILD_TOP}/external/perfetto/tools/record_android_trace -c ${ANDROID_BUILD_TOP}/prebuilts/tools/linux-x86_64/perfetto/configs/trace_config_detailed.textproto 46 * ``` 47 */ 48 @SysUISingleton 49 class ComposeTracingStartable @Inject constructor(private val commandRegistry: CommandRegistry) : 50 CoreStartable { 51 @OptIn(InternalComposeTracingApi::class) startnull52 override fun start() { 53 Log.i(TAG, "Set up Compose tracing command") 54 commandRegistry.registerCommand(COMMAND_NAME) { CompositionTracingCommand() } 55 } 56 } 57 58 private class CompositionTracingCommand : ParseableCommand(COMMAND_NAME) { 59 val enable by subCommand(EnableCommand()) 60 val disable by subCommand(DisableCommand()) 61 executenull62 override fun execute(pw: PrintWriter) { 63 if ((enable != null) xor (disable != null)) { 64 enable?.execute(pw) 65 disable?.execute(pw) 66 } else { 67 help(pw) 68 } 69 } 70 } 71 72 private class EnableCommand : ParseableCommand(SUBCOMMAND_ENABLE) { executenull73 override fun execute(pw: PrintWriter) { 74 val msg = "Enabled Composition tracing" 75 Log.i(TAG, msg) 76 pw.println(msg) 77 enableCompositionTracing() 78 } 79 enableCompositionTracingnull80 private fun enableCompositionTracing() { 81 Composer.setTracer( 82 object : CompositionTracer { 83 override fun traceEventStart(key: Int, dirty1: Int, dirty2: Int, info: String) { 84 Trace.traceBegin(Trace.TRACE_TAG_APP, info) 85 } 86 87 override fun traceEventEnd() = Trace.traceEnd(Trace.TRACE_TAG_APP) 88 89 override fun isTraceInProgress(): Boolean = Trace.isEnabled() 90 } 91 ) 92 } 93 } 94 95 private class DisableCommand : ParseableCommand(SUBCOMMAND_DISABLE) { executenull96 override fun execute(pw: PrintWriter) { 97 val msg = "Disabled Composition tracing" 98 Log.i(TAG, msg) 99 pw.println(msg) 100 disableCompositionTracing() 101 } 102 disableCompositionTracingnull103 private fun disableCompositionTracing() { 104 Composer.setTracer(null) 105 } 106 } 107