btrace(AKA RheaTrace) is a high performance Android trace tool which is based on Systrace

Last update: Jun 17, 2022

btrace

README 中文版

btrace(AKA RheaTrace) is a high performance Android trace tool which is based on Systrace, it support to define custom events automatically during building apk and using bhook to provider more native events like IO.

Key features

Support to define custom events automatically, inject Trace#beginSection(String) and Trace#endSection() into app methods during building apk.

Provider extra native events like IO to determine time-consuming reasons for methods conveniently.

Support to only capture trace events of main thread on demand.

Easily use, high stability, lower latency than systrace.

Getting started

Import rhea-gradle-plugin as a dependency in your main build.gradle in the root of your project.

buildscript {
    repositories {
        ...
        mavenCentral()
        ...
    }
    dependencies {
        classpath 'com.bytedance.btrace:rhea-gradle-plugin:1.0.1'
    }
}

allprojects {
    repositories {
        ...
        mavenCentral()
        ...
    }
}

Then "apply" the plugin and import dependencies by adding the following lines to your app/build.gradle.

dependencies {
    //rheatrace core lib
    implementation "com.bytedance.btrace:rhea-core:1.0.1"
}
...
rheaTrace {

   compilation {
      //for reducing apk size, you can use method id to trace custom events, default false.
      traceWithMethodID = false 
      //decide which methods you don't want trace, default null.
      traceFilterFilePath = "${project.rootDir}/rhea-trace/traceFilter.txt"
      //keep name of custom event with specific method id, default null.
      applyMethodMappingFilePath = "${project.rootDir}/rhea-trace/keep-method-id.txt"
  }

   runtime {
      //capture trace events of main thread only, default false.
      mainThreadOnly true 
      //start to capture trace events when launch app, default true.
      startWhenAppLaunch true
      //set a specified size of ring buffer which used to store atrace data in memory.
      atraceBufferSize "500000"
   }
}
...
apply plugin: 'com.bytedance.rhea-trace'

About rheaTrace , Learn more from the RheaTrace Gradle Config.

At last, check python version in your computer, RheaTrace only support python 2.7 because of systrace, and then config systrace environment into ~/.bash_profile file.

export PATH=${PATH}:/Users/${user_name}/Library/Android/sdk/platform-tools/systrace

Usage

Open terminal, change directory to RheaTrace/scripts/python/rheatrace, execute command below.

python rheatrace.py -v

Then you will see output below.

Current version is 1.0.1.

RheaTrace retains the Systrace command parameters, if you have used Systrace before, you will quickly learn how to use RheaTrace.

Syntax

To generate the HTML report for app, you need to run rheatrace from the command line using the following syntax:

python rheatrace.py [options] [categories]

For example, the following command calls rheatrace to record device activity and generate a HTML report named mynewtrace.html. This list of categories is a reasonable default list for most devices.

python rheatrace.py -a rhea.sample.android -t 5 -o ./output/mynewtrace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res

Global options

Global options Description
-h | --help Show the help message.
-l | --list-categories Lists the tracing categories available to your connected device.

Commands and command options

Commands and options Description
-o file Write the HTML trace report to the specified file. If you don't specify this option, rheatrace saves your report to the same directory as rheatrace.py and names it systrace.html.
-t N | --time=N Trace device activity for N seconds. If you don't specify this option, rheatrace prompts you to end the trace by pressing the Enter key from the command line.
-b N | --buf-size=N Use a trace buffer size of N kilobytes. This option lets you limit the total size of the data collected during a trace.
-k functions|--ktrace=functions Trace the activity of specific kernel functions, specified in a comma-separated list.
-a app-name|--app=app-name Enable tracing for specified app, this option must be set. The app must contain tracing instrumentation calls from the Trace class. You should specify this option whenever you profile your app—many libraries, such as RecyclerView, include tracing instrumentation calls that provide useful information when you enable app-level tracing.
--from-file=file-path Create an interactive HTML report from a file, such as TXT files that include raw trace data, instead of running a live trace.
-e device-serial|--serial=device-serial Conduct the trace on a specific connected device, identified by its device serial number.
categories Include tracing information for the system processes you specify, such as gfx for system processes that render graphics. You can run rheatrace with the -l command to see a list of services available to your connected device.

Extensive options

Global options Description
-r | --restart Before tracing app activities, force to stop the app and restart it.
-v | --version Check the current rheatrace version.
--advanced-sys-time | --advanced-sys-time How long in advance to open systrace, default value is 2 seconds.
--debug | --debug Whether to enable debug log output.

Easter Egg Feature

RheaTrace provides Gradle compilation configuration to change the tracking behavior of the App when it is running, but it needs to be repackaged every time, which work low efficiency. So we provide file configuration ways to change tracking behavior.

Create a Properties format file named rheatrace.config, the configurations that can be written are:

io=true
classLoad=true
memory=true
mainThreadOnly=true
atraceBufferSize=100000
startWhenAppLaunch=true

Then, push the file to the device directory sdcard/rhea-trace/${application package name}, and then restart the application to take effect.

options defaults description
io true Whether to enable tracking io native related methods.
classLoad fasle Whether to enable tracking class loading events, only supports Android 8.0 and above, and the app build type is debugable
memory fasle Whether to enable tracking memory access events, only supports Android 8.0 and above, and the app build type is debugable.
mainThreadOnly fasle Whether to capture trace events only on the main thread, if you only care about the main thread trace events, please set it to true.
atraceBufferSize 100000 Specify the size of the ring buffer to store atrace data in the memory. If its value is too small, the trace data will be incompletely written. If you capture multi-threaded trace data, it is recommended to set the value to about one million; the minimum value is 10,000. The maximum value is 5 million.
startWhenAppLaunch true Start to capture tracking events at the beginning of the app startup. If you do startup optimization, it is recommended to keep the value as true.

Known Issues

  1. RheaTrace only support python2.7, please check your python environment.
  2. RheaTrace does not currently support Windows.
  3. RheaTrace only support capture main process trace events.
  4. RheaTrace need read and write permissions of external storage, so you should grant the permission manually.
  5. if you can't open output file systrace.html directly, please using perfetto to load it.

Support

  1. Communicate on GitHub issues.
  2. Study the source code.
  3. Check wiki or FAQ for help.
  4. Contact us [email protected].
  5. Join QQ group chat.

Contributing

Contributing Guide

License

Apache License

GitHub

https://github.com/bytedance/btrace
Comments
  • 1. Can't find merged manifest!

    andrid studio fox classpath 'com.android.tools.build:gradle:3.0.1' distributionUrl=https://services.gradle.org/distributions/gradle-4.1-bin.zip

    
    :app:javaPreCompileDebug UP-TO-DATE
    :app:compileDebugJavaWithJavac UP-TO-DATE
    :app:compileDebugNdk NO-SOURCE
    :app:compileDebugSources UP-TO-DATE
    :app:mergeDebugShaders UP-TO-DATE
    :app:compileDebugShaders UP-TO-DATE
    :app:generateDebugAssets UP-TO-DATE
    :app:mergeDebugAssets UP-TO-DATE
    :app:extractTryWithResourcesSupportJarDebug UP-TO-DATE
    :app:transformClassesWithStackFramesFixerForDebug UP-TO-DATE
    :app:transformClassesWithDesugarForDebug UP-TO-DATE
    :app:transformClassesWithRheaTraceForDebug FAILED
    :app:mergeDebugJniLibFolders UP-TO-DATE
    :app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE
    :app:processDebugJavaRes NO-SOURCE
    :app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE
    :app:validateSigningDebug
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':app:transformClassesWithRheaTraceForDebug'.
    > Can't find merged manifest!
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 0s
    

    不支持低版本插件?

    Reviewed by ff-frida at 2021-12-30 06:36
  • 2. Gradle project sync failed

    I have git cloned btrace and open it using Android Studio, Gradle 6.7.1. Then Gradle project sync failed with this message:

    A problem occurred configuring project ':app'. Could not create task ':app:minifyReleaseWithProguard'. Cannot query the value of this provider because it has no value available.

    What should I do to sync btrace with Gradle files successfully?

    Reviewed by Bingist at 2021-12-24 09:29
  • 3. 执行脚本报错:app 'rhea.sample.android' is not installed

    python rheatrace.py -a rhea.sample.android -t 5 -o ./output/mynewtrace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input
    2022-03-07 11:06:20,896 - rhea_trace - main_impl - WARNING: - app 'rhea.sample.android' is not installed, please check your inputs.

    Reviewed by liruchun333 at 2022-03-07 03:18
  • 4. Can't find systrace in environment path

    如图 正常-v可以用 但是第二天命令就不行了 是什么原因呢? 环境:Mac m1 Python 2.7.18 (default, Oct 2 2021, 04:20:38)

    [email protected] rheatrace % python rheatrace.py -v Current version is 1.0.1. [email protected] rheatrace % python rheatrace.py -a rhea.sample.android -t 5 -o ./output/mynewtrace.html sched freq Can't find systrace in environment path

    如下systrace 也是正常使用 python systrace.py --time=10 -o mynewtrace.html gfx

    Reviewed by ivalimmb at 2021-12-23 03:14
  • 5. At btrace Demo executed:

    Terminal print Error:

    (TimeoutThread-2-for-MainThread) Exception on WriteFile(192.168.3.239:5555, /d/tracing/events/android_fs/enable, 1, retries=3, timeout=30), attempt 2 of 4: AdbShellCommandFailedError("(device: 192.168.3.239:5555) shell command run via adb failed on the device:\n command: echo -n 1 > /d/tracing/events/android_fs/enable\n exit status: 1\n output:\n - /system/bin/sh: can't create /d/tracing/events/android_fs/enable: No such file or directory\n",)

    Reviewed by 13120241790 at 2021-12-22 05:31
  • 6. compatible with the version without special handling of throw events

    在一些程序中,会有一些代码在try cath逻辑中抛出异常,这是很常见的写法,比如由一个观察者统一处理异常,如下图: In some programs, there will be some code throwing exceptions in the try cath logic. This is a very common way of writing. For example, an observer handles exceptions uniformly, as shown in the following figure:

    private fun methodB(flag: Boolean): Boolean {
            val start = System.currentTimeMillis()
            try {
                var tmp: Long = 0
                for (i in 0 until 200 * 1000 * 1000) {
                    tmp += i
                }
                throw Exception()
            } catch (e: Exception) {
                e.printStackTrace()
                if (flag) {
                    var tmp: Long = 0
                    var i = 0
                    while (i < 200 * 1000 * 1000) {
                        tmp += i
                        i++
                    }
                    methodC()
                    Log.i(
                        TAG, String.format(
                            "methodB throw duration %s",
                            System.currentTimeMillis() - start
                        )
                    )
                    return false
                }
            }
            Log.i(
                TAG, String.format(
                    "methodB duration %s",
                    System.currentTimeMillis() - start
                )
            )
            return true
        }
    

    这会造成重复的对方法结束点插桩: This will cause repeated instrumentation of the end point of the method: image

    这样TraceView无法判断哪一个End事件为方法的结束点,造成方法识别错误: In this way, TraceView cannot determine which End event is the end point of the method, resulting in a method identification error: image 通过一个简单的算法可以解决这样的问题,保证保留的End事件是最后一个End事件,方法的Trace数据完整性是符合预期的: A simple algorithm can solve this problem, to ensure that the retained End event is the last End event, and the integrity of the trace data of the method is in line with expectations: image

    我的Demo程序是这样的,大家可以参考实验,在onWindowFocusChanged中(真正开发的时候可不能在主线程这么搞事情哟😄)执行了一个耗时方法,嵌套了两次方法B执行: My demo program is like this. You can refer to the experiment. In onWindowFocusChanged (you can't do this in the main thread when you are really developing 😄), a time-consuming method is executed, and the execution of method B is nested twice:

    override fun onWindowFocusChanged(hasFocus: Boolean) {
            DemoMethods.methodA()
            super.onWindowFocusChanged(hasFocus)
        }
    
    package rhea.sample.android.app
    
    import android.util.Log
    import java.lang.Exception
    
    object DemoMethods {
        private const val TAG = "DemoMethods"
        fun methodA() {
            val start = System.currentTimeMillis()
            var tmp: Long = 0
            for (i in 0 until 200 * 1000 * 1000) {
                tmp += i
            }
            methodB(false)
            methodB(true)
            var tmp2: Long = 0
            for (i in 0 until 200 * 1000 * 1000) {
                tmp2 += i
            }
            Log.i(
                TAG, String.format(
                    "methodA duration %s",
                    System.currentTimeMillis() - start
                )
            )
        }
    
        private fun methodB(flag: Boolean): Boolean {
            val start = System.currentTimeMillis()
            try {
                var tmp: Long = 0
                for (i in 0 until 200 * 1000 * 1000) {
                    tmp += i
                }
                throw Exception()
            } catch (e: Exception) {
                e.printStackTrace()
                if (flag) {
                    var tmp: Long = 0
                    var i = 0
                    while (i < 200 * 1000 * 1000) {
                        tmp += i
                        i++
                    }
                    methodC()
                    Log.i(
                        TAG, String.format(
                            "methodB throw duration %s",
                            System.currentTimeMillis() - start
                        )
                    )
                    return false
                }
            }
            Log.i(
                TAG, String.format(
                    "methodB duration %s",
                    System.currentTimeMillis() - start
                )
            )
            return true
        }
    
        private fun methodC() {
            val start = System.currentTimeMillis()
            var tmp: Long = 0
            for (i in 0 until 200 * 1000 * 1000) {
                tmp += i
            }
            Log.i(
                TAG, String.format(
                    "methodC duration %s",
                    System.currentTimeMillis() - start
                )
            )
        }
    }
    
    Reviewed by qkmaosjtu at 2021-12-24 06:48
  • 7. 多线程:rhea-atrace.gz hasn't 'TRACE_END'

    开启多线程记录情况下:输出trace文件时报错2022-06-07 20:29:23,587 - rhea_trace - unzip_rhea_original_file - WARNING: - sdcard/rhea-trace/XXX/rhea-atrace.gz hasn't 'TRACE_END' 查看原始文件rhea-atrace.gz最后一行没有 'TRACE_END',文件大小也比正常情况下,猜测是多线程情况下写文件出问题了,导致trace无法写入、最后的trace_end也无法写入。 希望作者帮忙看下

    Reviewed by zhaoshuyu at 2022-06-07 12:36
  • 8. 最新版platform-tools文件夹下没有systrace了

    今天在Ubuntu上升级了platform-tools版本之后,遇到了Can't find systrace in environment path的问题,仔细一看platform-tools目录下的systrace目录没有了。解决方法分享给各位:

    谷歌官方在22年3月发布的33.0.1版本的platform-tools包中移除了systrace,因此需要使用<=33.0.0的版本

    微信截图_20220607110213

    33.0.0版本下载地址: https://dl.google.com/android/repository/platform-tools_r33.0.0-linux.zip https://dl.google.com/android/repository/platform-tools_r33.0.0-darwin.zip

    转自:https://www.jianshu.com/p/626eaebaa6a8

    Reviewed by zhbzhbzhbz at 2022-06-07 04:34
  • 9. 写入外部存储失败的问题

    如果启动app没看到初始化日志,你可能没有实现 Application.attachBaseContext,导致插入初始化代码失败 : @OverRide protected void attachBaseContext(Context base) { super.attachBaseContext(base); }

    Reviewed by wesley666 at 2022-05-21 02:05
  • 10. Add script feature:start app by deeplink

    In some cases, I want to know the reason for the time-consuming when my app is started through deeplink, but the current script does not seem to support it very conveniently So I tried adding this feature and tested it locally

    Reviewed by learrn at 2022-05-17 06:22
A surgical debugging tool to uncover the layers under your app.
A surgical debugging tool to uncover the layers under your app.

Scalpel DEPRECATED! Android Studio 4.0's layout inspector now includes a live-updating 3D view. Use it! A surgical debugging tool to uncover the layer

Jun 13, 2022
A model-agnostic visual debugging tool for machine learning
A model-agnostic visual debugging tool for machine learning

Manifold This project is stable and being incubated for long-term support. Manifold is a model-agnostic visual debugging tool for machine learning. Un

Jun 9, 2022
Colored logcat script which only shows log entries for a specific application package.
Colored logcat script which only shows log entries for a specific application package.

PID Cat An update to Jeff Sharkey's excellent logcat color script which only shows log entries for processes from a specific application package. Duri

Jun 19, 2022
This app will show grid overlay over whole system which helps you to verify your excellent app design.
This app will show grid overlay over whole system which helps you to verify your excellent app design.

GridWichterle for Android This app will show grid overlay over whole system which helps you to verify your excellent app design. Download: What is the

Apr 3, 2022
Cordova plugin for Android Serial USB communication (easily connect an Arduino board to an Android device).

PR-DC cordova-plugin-serialusb Cordova plugin for Android Serial USB communication. This plugin makes a connection to the external board trivial, for

May 8, 2022
Stetho is a debug bridge for Android applications, enabling the powerful Chrome Developer Tools and much more.

Stetho Stetho is a sophisticated debug bridge for Android applications. When enabled, developers have access to the Chrome Developer Tools feature nat

Jun 17, 2022
A library for debugging android databases and shared preferences - Make Debugging Great Again
A library for debugging android databases and shared preferences - Make Debugging Great Again

Android Debug Database Android Debug Database is a powerful library for debugging databases and shared preferences in Android applications Android Deb

Jun 17, 2022
🔪Swiss-army knife for Android testing and development 🔪 ⛺
🔪Swiss-army knife for Android testing and development 🔪 ⛺

ADB Enhanced ADB-Enhanced is a Swiss-army knife for Android testing and development. A command-line interface to trigger various scenarios like screen

Jun 15, 2022
Under the Hood is a flexible and powerful Android debug view library. It uses a modular template system that can be easily extended to your needs, although coming with many useful elements built-in.
Under the Hood is a flexible and powerful Android debug view library. It uses a modular template system that can be easily extended to your needs, although coming with many useful elements built-in.

Under the Hood - Android App Debug View Library Under the Hood is a flexible and powerful Android debug view library. It uses a modular template syste

Apr 15, 2022
Android library to record the network calls through the interceptor mechanism of the http clients.
Android library to record the network calls through the interceptor mechanism of the http clients.

Android Snooper Introduction Android Snooper is a library which helps in debugging issues while running the applications on android devices. One of th

Jun 15, 2022
A Read-Eval-Print-Loop server for Android and SQLite

Android DebugPort Android DebugPort is a drop-in utility which allows you to write and execute code within your app's context, at runtime, and from th

Mar 29, 2022
traffic debugging library for android
traffic debugging library for android

TrafficMonitor About Display traffic per Activity.Observing traffic is used by TrafficStats API. OkHttp Interceptor observer is implementing. Demo Bai

Feb 4, 2022
Easy android exception tracer and handler.
Easy android exception tracer and handler.

Introduction Lup is a small android library that can help you to tracking bug that causes application stopped working (force close). Whiting this libr

Oct 12, 2021
Sources for the LiveBoot app for rooted Android devices

This is the sauce for the LiveBoot app. License Copyright © 2011-2020 Jorrit Chainfire Jongma This code is released under the GPLv3. LICENSE, COPYING.

Jun 9, 2022
android logcat
android logcat

android logcat

Apr 13, 2022
A local ADB shell for Android!

LADB A local ADB shell for Android! How does it work? LADB bundles an ADB server within the app libraries. Normally, this server cannot connect to the

Jun 23, 2022
Pluto: An on-device debugging framework for Android applications

Pluto is an on-device debugging framework for Android applications, which helps in the inspection of HTTP requests/responses, captures Crashes, and ANRs, and manipulates application data on the go.

Jun 15, 2022