Android Studio CPU 性能剖析器

///

一、性能优化工具基础

1.1 概述

  在Android开发中,开发者可通过"系统跟踪"观察Android设备的运行情况并生成跟踪报告,在此基础上进行分析优化。Android 平台提供了多种获取跟踪信息的工具:

  • Android Studio CPU 性能剖析器
  • Systrace 命令行工具
  • Perfetto 命令行工具
  • "系统跟踪"应用

  其中,Android Studio CPU Profiler性能剖析器可实时检查应用的 CPU 使用率和线程活动,此外还可以查看方法跟踪记录、函数跟踪记录和系统跟踪记录中的详细信息。与CPU Profiler功能类似的TraceView、DDMS已弃用。

  Systrace 是Android SDK Tools提供的旧版命令行工具,可记录短时间内的设备活动,并保存在压缩的文本文件中。该工具会生成一份html报告,其中汇总了 Android 内核中的数据,例如 CPU 调度程序、磁盘活动和应用线程。

  Perfetto 是 Android 10 中引入的全新平台级跟踪工具,与Systrace类似,同样会生成汇总了Android 内核数据(例如CPU 调度程序、磁盘活动和应用线程)的跟踪文件。与 Systrace 不同的是,跟踪文件会以 Perfetto 格式保存,它提供数据源超集,可让您以 protobuf 编码的二进制流形式记录任意长度的跟踪记录。

  "系统跟踪"应用是一款用于将设备活动保存到跟踪文件的 Android 工具。在搭载 Android 10(API 级别 29)或更高版本的设备上,跟踪文件会以 Perfetto 格式保存。在搭载较低版本 Android 系统的设备上,跟踪文件会以 Systrace 格式保存。

1.2 例子

  下面通过一个例子介绍如何用上面几种工具进行分析,例如在OpenCVActivity中点击"BC OPENCV BEFORE"按钮时,执行《Android OpenCV基础(三、图片处理)》中比较耗时的高斯滤波,代码如下:

public class OpenCVActivity  extends Activity implements View.OnClickListener {private ImageView imageView1;private Button button;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.open_cv_activity_layout);imageView1 = findViewById(R.id.opencv_sample_image_view);button = findViewById(R.id.opencv_sample_button);button.setOnClickListener(this);}@Overridepublic void onClick(View v) {if (v.getId() == R.id.opencv_sample_button) {Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time);// 高斯滤波Bitmap bitmap1 = OpenCVSample.blurBitmap(bitmap, 30);imageView1.setImageBitmap(bitmap1);Toast.makeText(this, "ok", Toast.LENGTH_SHORT).show();button.setText("BC OpenCV After");}}
}

  点击按钮后的执行效果如下图所示,后面几个小节介绍如何通过性能分析工具分析点击按钮后的方法执行情况。

二、性能剖析器

  Android Studio性能剖析器是Android Studio提供的一个可视化分析工具,可实时显示应用的 CPU、内存、网络和电池资源使用情况。Android Studio 3.0 及更高版本中的 Android Profiler 取代了 Android Monitor 工具。如下图所示,性能剖析器展示了四类信息:CPU、MEMORY、NETEORK、ENERGY,点击后可分别进入CPU性能分析,内存性能分析、网络性能分析、电池性能分析:
Android Studio CPU 性能剖析器_第1张图片
  其中在点击CPU时间轴后,进入的CPU Profiler常用来分析方法执行耗时情况。

2.1 CPU Profiler介绍

  CPU 性能分析器可以在APP运行时,实时检查应用的 CPU 使用率和线程活动,也可以检查记录的方法轨迹、函数轨迹和系统轨迹的详情。

2.1.1 使用方法

  CPU Profiler使用方式为:

  1. 在 Android Studio 中,依次选择 View > Tool Windows > Profiler,或点击工具栏中的 Profile 图标。
  2. 在Android Studio Profiler中新建session,选择需要分析的设备及app进程。
  3. 点击 CPU 时间轴上的任意位置以打开 CPU 性能分析器。
  4. 从 CPU 性能分析器的配置菜单中选择 System Trace(详细配置介绍见2.2小节),然后点击 Record。完成与应用的交互后,点击 Stop Sample Java Method右边的"record"按钮后,CPU Profiler会对之后的方法执行进行采样,完成与应用的交互后,点击"stop"停止记录,并将这段时间的方法执行按顺序展示出来
    Android Studio CPU 性能剖析器_第2张图片
  5. 结束记录后,CPU 性能分析器会展示这段时间内的方法调用,开发者也可以点击保存把跟踪记录保存为.trace 文件。

2.1.2 使用举例

  在例子1.2中,我们点击页面中的"BC OPENCV BEFORE"按钮,在执行结束后停止记录,方法采样记录如下所示:
Android Studio CPU 性能剖析器_第3张图片
  在Android studio Profiler中,按"w"键可放大查看(按"s"可缩小、"a"左移、"d"右移、"0"复位),放大后如下图所示:
Android Studio CPU 性能剖析器_第4张图片
  可以看到,点击方法"performClick()"内先执行了"blurBitmap()"方法,然后执行了"imageView1.setImageBitmap()"方法,后面在主线程中继续执行了"doTraversal()"来更新view,方法执行顺序符合预期,同时可以看到"blurBitmap()"执行耗时较长,是需要进行优化的。接着,点击"blurBitmap"可以看到该方法的耗时总结,如下图所示:
Android Studio CPU 性能剖析器_第5张图片

  另外,CPU Profiler可以查看线程的运行情况,在这个例子中onClick()方法总耗时1350ms,其中Running状态占744ms(对应blurBitmap耗时),Idle状态占602ms(对应sleep耗时)。
Android Studio CPU 性能剖析器_第6张图片

2.1.3 查看方法跟踪

  下面介绍,如何查看CPU Profiler收集到的方法跟踪结果。结合例子2.1.2中收集到的方法跟踪结果可见,对系统 API 的调用显示为橙色,对应用自有方法的调用显示为绿色,对第三方 API(包括 Java 语言 API)的调用显示为蓝色。此外,CPU 性能分析器中的轨迹视图提供了多种方法查看所记录的轨迹的信息(例如Top Down、Flame Chart、Bottom Up、Event视图),开发者可自行切换视图查看,这里不再详细介绍。

  通常情况下,方法跟踪信息可以帮助您找出应用中用时最多的方法,帮助您定位并针对性分析优化。但是,方法跟踪不适合用于识别卡顿,因为它们会因开销过大而导致出现假正例卡顿,且无法查看线程何时运行以及何时处于阻塞状态。

2.2 CPU 记录配置

  2.1.1小节在步骤4中提到,Android Studio CPU Profiler提供了四种可选的记录配置,如下图所示,开发者可根据需要选择合适的配置。
Android Studio CPU 性能剖析器_第7张图片
  下面结合1.2中的例子,介绍四种配置的记录结果。

2.2.1 采样JAVA方法(Sample JAVA Methods)

  在CPU Profiler中选择"Sample JAVA Methods"后并点击"Record"按钮,CPU Profiler开始记录方法执行顺序,然后我们点击"1.2例子中APP上的blur按钮"完成需要分析的操作,接着点击CPU Profiler中的"Stop"按钮停止采集,最终得到如下记录结果:

  局部放大后如下图所示,可以看到部分耗时很短的方法未被采样,这是因为这种记录方式是间隔采样,再次采样时一些耗时很短的方法已经执行结束所以就没被记录下来。
Android Studio CPU 性能剖析器_第8张图片

2.2.2 跟踪JAVA方法(Trace JAVA Methods)

  同样地,在CPU Profiler中选择"Trace JAVA Methods",最终得到如下记录结果:
Android Studio CPU 性能剖析器_第9张图片
局部放大后,如下图所示,可以看到部分耗时很短的方法也被跟踪;
Android Studio CPU 性能剖析器_第10张图片

2.2.3 采样C/C++方法(Sample C/C++ Functions)

  同样地,在CPU Profiler中选择"Sample C/C++ Functions",最终得到如下记录结果,可以看到成功采集到了例子中"com_bc_sample_OpenCVSample_blurBitmap"的native方法调用:

2.2.4 跟踪系统调用(Trace System Calls)

  同样地,在CPU Profiler中选择"Trace System Calls",最终得到如下记录结果,可以看到SurfaceFlinger、VSYNC、RenderThread、app进程(com.bc.sample)的系统调用等信息:
Android Studio CPU 性能剖析器_第11张图片

2.3 CPU记录配置总结

  (1)Sample JAVA Methods不能采集耗时很短的方法,而Trace JAVA Methods可以采集耗时很短的方法;

  (2)Sample JAVA Methods和Trace JAVA Method会带来性能损耗,在DEMO中,Sample JAVA Methods和Trace JAVA Method记录到的方法执行耗时差别不大,但在大型APP中,Sample JAVA Methods收集到的方法执行耗时偏长,Trace JAVA Methods收集到的方法执行耗时比实际执行耗时更长,而且执行Trace JAVA Methods时APP卡顿比较明显;

  (3)Sample C/C++ Functions只能采集native层方法;

  (4)Trace System Calls可以采集SurfaceFlinger、VSYNC、RenderThread、app进程的系统调用等信息。

2.4 trace文件

  CPU 性能分析器可以把跟踪记录保存为.trace 文件。此外,开发者也可以自己保存trace文件,用CPU 性能分析器打开trace文件来查看函数调用。除了CPU 性能分析器外,以下几种方法也可以生成trace文件。

2.4.1 Debug API

  Android系统还提供了Debug类来跟踪方法执行顺序,并输出一个trace文件,开发者可使用Android Studio Profiler来查看trace文件。通过这种方式,开发者可以更精确地控制设备何时开始和停止记录跟踪信息。

  在执行Debug API开始跟踪后,方法执行速度会比实际执行速度慢很多,且默认情况下Debug的缓存空间限制是8MB(支持开发者配置更大的参数),因此DebugAPI专为时间间隔较短或难以手动启动/停止记录的场景而设计。

  Debug类通过startMethodTracing()和stopMethodTracing()结合使用,方法如下:

public void onClick(View v) {if (v.getId() == R.id.opencv_sample_button) {// 开始方法跟踪,默认参数为空,也可以传入指定路径// 默认输出路径是'/sdcard/Android/data/[application_pacake_name]/files/dmtrace.trace'Debug.startMethodTracing();Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time);Bitmap bitmap1 = OpenCVSample.blurBitmap(bitmap, 30);imageView1.setImageBitmap(bitmap1);Thread.sleep(500);button.setText("BC OpenCV After");// 结束方法跟踪Debug.stopMethodTracing();}}

2.4.2 adb命令

  对于APP冷启动场景,还可以使用 adb am 命令记录方法跟踪,如下所示:

# 1.打开com.bc.example.MainActivity 并开始方法跟踪
# --sampling 100表示方法采样间隔
adb shell am start -n com.bc.example/com.bc.example.MainActivity --start-profiler /data/local/tmp/bc—sample.trace --sampling 100# 2.Activity启动后,输入以下命令停止跟踪
adb shell am profile stop # 3.把手机上的trace文件pull出来
adb pull /data/local/tmp/bc—sample.trace ./

2.4.3 simpleperf

  simpleperf也提供了冷启动方法跟踪的方法如下所示,暂不详细介绍。

# Start simpleperf recording, then start the Activity to profile.
$ ./app_profiler.py -p simpleperf.example.cpp -a .MainActivity# We can also start the Activity on the device manually.
# 1. Make sure the application isn't running or one of the recent apps.
# 2. Start simpleperf recording.
$ ./app_profiler.py -p simpleperf.example.cpp
# 3. Start the app manually on the device.

三、Systrace 命令行工具

  Systrace是一个Python脚本,是Android SDK tools提供的旧版本分析工具(在Android platform tools 33.0.1版本中已经移除systrace,建议用Studio 性能分析器、gpuinspector.dev 或 Perfetto 取代)。它记录了一段时间内的设备活动(包括CPU调度、磁盘操作、应用线程等信息),并产生一个HTML格式的Systrace报告,可以帮助开发者分析系统瓶颈,改进性能。

  systrace.py实际上是多种其他工具的封装容器:它是 atrace 的主机端封装容器。atrace 是用于控制用户空间跟踪和设置 ftrace 的设备端可执行文件,也是 Linux 内核中的主要跟踪机制。systrace 在主机端通过adb使用 atrace 来启用跟踪,然后读取 ftrace 缓冲区并生成易于查看的HTML。

3.1 使用方法

  Systrace 工具位于/Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py,使用方法如下:

# 使用方式为:python systrace.py [options] [categories]
# 其中,[options] 表示参数,可选的参数有:
#        -a 进程名
#        -b 跟踪缓冲区大小,单位KB
#        -o 输出文件名字
#        -t 跟踪设备活动 N,可不指定,用Enter键结束跟踪
# [categories]表示需要trace的类别,可选的跟踪信息有:
#       sched - CPU Scheduling;CPU 调度信息,例如线程调度、锁信息等;
#        load - CPU Load
#        view - View System;view绘制系统的相关信息,比如onMeasure,onLayout等,常用来分析卡顿
#        app - Application;应用的跟踪信息,如果设备不支持则不能收集APP的trace
#        gfx - Graphics;Graphic相关信息,包括SerfaceFlinger、VSYNC、Texture等,常用来分析卡顿
#       input - Input
#     webview - WebView
#          wm - Window Manager
#          am - Activity Manager
#          sm - Sync Manager
#       audio - Audio
#       video - Video
#      camera - Camera
#         hal - Hardware Modules
#         app - Application
#         res - Resource Loading
#      dalvik - Dalvik VM
#          rs - RenderScript
#      bionic - Bionic C Library
#       power - Power Management
#        freq - CPU Frequency
#        idle - CPU Idle
# 例如以下命令会生成名为my_systrace_report.html的跟踪文件
python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a com.bc.sample -b 16384 -o my_systrace_report.html app load view

  如下所示,在命令行运行Systrace后,可以按Enter键结束跟踪,结束后会将系统跟踪输出到html文件中。

➜ ~ python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a 
com.bc.example -b 16384 -o my_systrace_report.html app load view
These categories are unavailable: load
Starting tracing (stop with enter)
Tracing completed. Collecting output...
Outputting Systrace results...
Tracing complete, writing resultsWrote trace HTML file: file:///Users/bc/my_systrace_report.html

  打开结果html,可通过键盘WSAD放大缩小,左右移动来检查html,如下图所示:

Android Studio CPU 性能剖析器_第12张图片
  从上图可以看到,UI线程中只显示了系统方法调用情况,没有app中的方法调用,这是因为systrace默认只跟踪系统级别进程的信息,如果想跟踪自己APP相对系统事件的代码执行状态,需要在代码中增加自己的trace,即自定义事件(详见第5章节)。

3.2 查看Systrace报告

3.2.1 线程状态

  在3.2.3中生成html后,可通过键盘WSAD放大缩小,左右移动来检查html。点击UI thread、Render Thread等,可以看到线程的当前状态,如下所示:
Android Studio CPU 性能剖析器_第13张图片
  线程运行状态与颜色对应如下:

  • 绿色 : 运行中(Running)
  • 蓝色 : 可运行(Runnable)
  • 白色 : 休眠中(Sleep)
  • 橘色 : 不可中断的睡眠态 (Uninterruptible Sleep - IO Block)
  • 紫色 : 不可中断的睡眠态(Uninterruptible Sleep)

3.2.2 卡顿示例

  如下图所示,APP进程中’F’表示一帧,红色的’F’表示可能发生卡顿。因为在设备的渲染流程上,普遍采用了Double Buffer或Triple Buffer,所以App进程中的红色Frame并不一定代表有卡顿发生,需要结合SurfaceFlinger进程、BufferQueue的大小等一起分析,才能判断是否真正发生了卡顿。因篇幅较大,暂不深入介绍。
Android Studio CPU 性能剖析器_第14张图片

四、Perfetto

  Perfetto 是 Android 10 中引入的全新平台级跟踪工具,可用来从设备上收集多种性能跟踪数据(内核信息、用户空间信息、服务&内存使用信息)。Perfetto底层实现上:

  • 使用 ftrace 收集内核信息
  • 使用 atrace 收集服务和应用中的用户空间信息
  • 使用 heapprofd 收集服务和应用的本地内存使用情况信息

  Perfetto在Android 11上默认开启,如果要在Android 9 和Android 10上使用,请先输入如下命令,确保trace服务开启:

# Needed only on Android 9 (P) and 10 (Q) on non-Pixel phones. 
adb shell setprop persist.traced.enable 1

  下面继续介绍,官方提供了两种方式:命令行方式和UI方式来使用Perfetto。

4.1 命令行方式

  通过命令行方式,也有两种方法:

  1. 使用封装的tools/record_android_trace 脚本;
  2. 直接使用 /system/bin/perfetto命令;

4.1.1 record_android_trace脚本

  Perfetto官方建议使用record_android_trace脚本,这个脚本和直接运行’adb shell perfetto’命令功能一样,但是省去了设置输出文件路径等参数,并且在抓取结束后会自动用Chrome浏览器打开结果。

# 1.下载record_android_trace脚本
curl -O https://raw.githubusercontent.com/google/perfetto/master/tools/record_android_trace # 2.设置脚本执行权限
chmod u+x record_android_trace # 3.运行record_android_trace脚本
# See ./record_android_trace --help for more 
./record_android_trace -o trace_file.perfetto-trace -t 10s -b 32mb \ sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory app

  运行record_android_trace脚本后,perfecto会开始记录手机的运行信息,运行结束后,可以看到脚本会自动把结果保存到本地文件"trace_file.perfetto-trace"中,并自动用浏览器打开。结果如下图所示,与Systrace类似,可以看到设备的运行情况、APP进程的运行情况、APP内线程的状态等(如果想跟踪自己APP的方法执行顺序,详见第5章自定义事件):
Android Studio CPU 性能剖析器_第15张图片

4.1.2 Perfetto命令

# Perfetto命令使用方式如下:
➜  ~ adb shell perfetto [ --time TIMESPEC ] [ --buffer SIZE ] [ --size SIZE ][ ATRACE_CAT | FTRACE_GROUP/FTRACE_NAME | FTRACE_GROUP/* ]
# Perfetto的更多参数可以参考:https://developer.android.com/studio/command-line/perfetto?hl=zh-cn
# perfetto可选参数
➜  ~ adb shell perfetto --help
perfetto_cmd.cc:205      --background     -d      : Exits immediately and continues tracing inbackground--config         -c      : /path/to/trace/config/file or - for stdin--out            -o      : /path/to/out/trace/file or - for stdout--dropbox           TAG  : Upload trace into DropBox using tag TAG--no-guardrails          : Ignore guardrails triggered when using --dropbox(for testing).--txt                    : Parse config as pbtxt. Not for production use.Not a stable API.--reset-guardrails       : Resets the state of the guardails and exits(for testing).--query                  : Queries the service state and prints it ashuman-readable text.--query-raw              : Like --query, but prints raw proto-encoded bytesof tracing_service_state.proto.--help           -hlight configuration flags: (only when NOT using -c/--config)--time           -t      : Trace duration N[s,m,h] (default: 10s)--buffer         -b      : Ring buffer size N[mb,gb] (default: 32mb)--size           -s      : Max file size N[mb,gb] (default: in-memory ring-buffer only)ATRACE_CAT               : Record ATRACE_CAT (e.g. wm)FTRACE_GROUP/FTRACE_NAME : Record ftrace event (e.g. sched/sched_switch)FTRACE_GROUP/*           : Record all events in group (e.g. sched/*)statsd-specific flags:--alert-id           : ID of the alert that triggered this trace.--config-id          : ID of the triggering config.--config-uid         : UID of app which registered the config.--subscription-id    : ID of the subscription that triggered this trace.Detach mode. DISCOURAGED, read https://docs.perfetto.dev/#/detached-mode :--detach=key          : Detach from the tracing session with the given key.--attach=key [--stop] : Re-attach to the session (optionally stop tracing once reattached).--is_detached=key     : Check if the session can be re-attached (0:Yes, 2:No, 1:Error).

  例如在命令行输入如下信息:

# 1.命令行输入如下信息:
# 其中:dalvik app sched idle frep load view 表示perfetto使用atrace抓取的信息类型
# --time 5s表示:抓取时长5s
# --out 表示:perfetto运行的结果输出到该文件
> adb shell perfetto -o /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s \
sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory app# 开始运行后,可以看到命令行提示如下信息:
[032.653] perfetto_cmd.cc:792     Connected to the Perfetto traced service, TTL: 5s
[037.695] perfetto_cmd.cc:916     Wrote 4370324 bytes into /data/misc/perfetto-traces/trace# 2.运行结束后,可以输入如下命令,把perfecto结果从手机上拉到电脑上
> adb pull /data/misc/perfetto-traces/bc_perfetto_trace ./bc_perfetto_trace

  在把perfetto的trace结果保存到本地后,用chrome浏览器打开"https://ui.perfetto.dev "可视化界面操作,然后打开trace文件如下图所示:
Android Studio CPU 性能剖析器_第16张图片

4.2 UI界面

  Chrome浏览器打开"https://ui.perfetto.dev/#!/record "可视化界面操作,如右下所示可以看到底层也是通过"adb shell perfetto"实现抓取。
Android Studio CPU 性能剖析器_第17张图片

五、自定义事件

5.1 自定义JAVA事件

  在 Android 4.3(API 级别 18)及更高版本中,您可以在代码中使用 Trace 类来定义随后会出现在 Perfetto 和 Systrace 报告中的自定义事件。在自定义事件的起点和终点分别调用Trace.beginSection()Trace.endSection(),如以下代码段所示:

// 自定义事件的起点
Trace.beginSection("BC blurBitmap");
// ...省略部分代码,起点和终点间的代码会作为一个"BC blurBitmap"事件被统计
// 自定义事件的终点
Trace.endSection();
// 注意必须在同一个线程上调用这两个方法,不能在一个线程上调用 beginSection(),而在另一个线程上结束它

5.2 自定义native事件

  对于native代码,Android 6.0(API 级别 23)及更高版本提供了native跟踪 API trace.h头文件,在自定义事件的起点和终点分别调用ATrace_beginSection()ATrace_endSection(),如下所示:

    #include char *customEventName = new char[32];sprintf(customEventName, "User tapped %s button", buttonName);// 自定义事件起点ATrace_beginSection(customEventName);// 省略native代码...// 自定义事件终点ATrace_endSection(); 

5.3 自定义事件例子

  在1.2中的例子,自定义java事件(“BC blurBitmap”)如下所示:

public class OpenCVActivity2  extends Activity implements View.OnClickListener {private Bitmap blurBitmap(Bitmap bitmap) {// 自定义事件"BC blurBitmap"的起点Trace.beginSection("BC blurBitmap");Bitmap result = OpenCVSample.blurBitmap(bitmap, 30);// 自定义事件"BC blurBitmap"的终点Trace.endSection();return result;}@Overridepublic void onClick(View v) {if (v.getId() == R.id.opencv_sample_button) {Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time);Bitmap bitmap1 = blurBitmap(bitmap);imageView1.setImageBitmap(bitmap1);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}  
}

  在自定义事件后,在使用Systrace和Perfetto时就可以看到app内的自定义事件执行情况。

5.3.1 Systrace自定义事件

  运行Systrace时,注意需要加上"-a com.bc.example"才会生效:

➜ ~ python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a 
com.bc.example -b 16384 -o my_systrace_report.html app load view

  运行结果如下,可以看到方法跟踪的结果显示了自定义事件"BC blurBitmap"的运行情况:
Android Studio CPU 性能剖析器_第18张图片

5.3.2 Perfetto自定义事件

  (1)首先,本地新建一个文件’bc_example.cfg’用来存放Perfetto配置,如下所示:

buffers: {size_kb: 522240fill_policy: DISCARD
}
data_sources: {config {name: "linux.ftrace"ftrace_config {ftrace_events: "sched/sched_switch"atrace_categories: "dalvik"atrace_categories: "view"atrace_apps: "com.bc.example"}}
}
duration_ms: 10000

  (2)然后,运行4.1.1小节的record_android_trace脚本,并使用’-c’指定配置文件:

./record_android_trace -c bc_example.cfg -o trace_file.perfetto-trace

  运行后的结果如下图所示,同样可以看到自定义事件"BC blurBitmap"的运行情况:
Android Studio CPU 性能剖析器_第19张图片

5.3.3 常见问题

(1)部分手机Systrace抓到的trace看不到APP内的方法跟踪,这是因为部分手机不支持抓取app类型的trace信息,可以换个手机试下。另外,可以通过如下命令查看机器支持Systrace的类型:

python systrace.py -l

(2)实际开发中,每个方法中都手动加入Trace自定义事件比较麻烦,可以尝试开发一个gradle脚本来完成Trace插桩。

(3)使用Systrace抓APP的方法执行顺序,要求App必须是debuggable的,如果要在release包中开启自定义事件,需要用到反射打开Trace功能:

Class trace = Class.forName("android.os.Trace");
Method setAppTracingAllowed = trace.getDeclaredMethod("setAppTracingAllowed", boolean.class);
setAppTracingAllowed.invoke(null, true);

六、"系统跟踪"应用

  "系统跟踪"应用是Android手机上的一个功能,其原理类似于 Systrace 或 Perfetto 命令行。通过"系统跟踪"应用,开发者可以直接从测试设备本身录制跟踪记录,而无需插入设备并通过命令行操作。

  如下图所示,"系统跟踪"应用位于开发者选项 - 调试 - System Tracing下,或者也可以在打开"开发者选项"后通过如下命令行启动"系统跟踪"应用,但是国内很多设备都没有该功能应用,暂不详细介绍。

adb shell am start com.android.traceur/com.android.traceur.MainActivity

Android Studio CPU 性能剖析器_第20张图片
  在Android 10(API 级别 29)或更高版本的设备上,"系统跟踪"应用的跟踪文件会使用 ‘.perfetto-trace’ 文件扩展名保存到/data/local/traces/目录下,并可在 Perfetto 界面中打开。在较旧 Android 版本的设备上,跟踪文件会使用 ‘.ctrace’ 文件扩展名(表示 Systrace 格式)保存。之后就可以把perfetto或trace文件分别用对应工具打开进行分析优化。

七、工具选择

  1. CPU性能剖析器的方法跟踪信息可以帮助您找出应用中用时最多的方法,帮助您定位并针对性分析优化。使用比较方便,但是方法跟踪不适合用于识别卡顿,因为它们会因开销过大而导致出现假正例卡顿,且无法查看线程何时运行以及何时处于阻塞状态。
  2. Systrace和Perfetto性能损耗小,在结果页的展示上,Perfetto相比更Systrace体验更流畅一些。
  3. Perfetto支持SQL查询,方便开发者根据sql条件快速筛选出数据,开发者可以结合官方示例扩展开发自身业务需要的自动化分析脚本等。
  4. Perfetto只支持Android 10及更高版本的设备,且官方提供的脚本使用便捷,结果查找方便;建议Android 10 以上设备直接使用Perfetto。

///

Profiler是Android Studio内置的一个分析app性能的利器,是优化app必不可少的帮手。功能涵盖了方法执行,内存分配,流量使用,耗电量等诸多方面。
今天就从实战的角度聊一聊,如何使用Profiler分析方法执行时间。
Profiler位于底部工具栏

点开后是这样的:

点击左上角的加号,可以看到正在运行的项目的进程。

点击进程后,右侧开始滚动关于该进程的信息,第一行是cpu,第二行是内存,第三行是流量,第四行是耗电量。

分析方法执行时间,使用的是第一行cpu。点击第一行,就会进入cpu界面,这里详细列举了cpu的各项数据,如当前的线程数量,cpu的使用率。

不同的Android Studio版本,这里的内容可能会有些许不同。
选择Java Method Trace Recording,点击record记录方法执行流程。注意,记录时间太久会导致卡死,根据个人电脑配置,控制记录时间。
记录结束后,页面的左侧多出来一个记录文件,我们可以选择Export导出到其他位置,下次可以跳过记录过程,直接打开文件查看方法执行流程。

页面的右侧有两个区域。两个区域的内容是一样的,但是展示的形式略有不同,我把左侧称为图形区,右侧称为文字区。图中的图形区显示有正在运行4个线程

看到main线程,相信小伙伴就很熟悉了,如果我们打算排查掉帧卡顿的问题,就要从main线程入手,点击main线程,将main线程选中,此时mian线程将会展开,展开后可以看到记录过程中,java代码执行的所有方法以及执行时间。

项目中main线程执行的方法非常多,为了方便查看,务必使用以下快捷键进行操作,其实操作方式已经在前面的文字区展现出来了,就是下图红框内的文字,W放大,S缩小,A左移,D右移。

如果不用快捷键,想想该如何查看下图这个区域。在我没有掌握快捷键之前,想要查看一个非常微小的区域,经常选到人崩溃。

线程中倒三角的结构,同时展现了方法的调用结构和执行耗时。以上图举例:
首先调用了Handler的dispatchMessage,dispatchMessage的长度代表了方法相对执行耗时,紧邻dispatchMessage下方只有ActivityThreadH的handleMessage,说明dispatchMessage内部只执行了这一个方法,而紧邻handleMessage的下方则有handleProfilerControl和checkHandleMessagetTime两条,说明handleMessage调用了两个方法,对比两个方法条,handleProfilerControl的执行时间长于checkHandleMessagetTime。
前面提到图形区和文字区是对应的,如果上述对图形区的描述不够清晰,点击文字区的Top Down栏,下图框中的内容直观的展示了上述流程。

这种方式不仅可以分析自己的项目,也可以用来学习源码,查看系统源码和三方源码的执行流程。
如果我们只关心某个方法的耗时,可以在图中搜索栏进行搜索,图形区和文字区都会以高亮的形式,把找到的方法显示出来,非常方便定位问题。

以上是有关方法执行流程的,Top Down右侧的Flame Chart对整个记录过程中每个方法的执行耗时进行了汇总,呈正三角的形状,方法越靠近底部,耗时越长。

以上profiler的功能,搭配实时帧率检测,可以轻松发现和定位掉帧问题,提升app流畅度。

///

为什么需要android studio profiler

UE4提供的UnrealFrontend Profiler、Unreal Insights等工具也可以支持非shipping版本的移动端性能分析。但是分析工具本身还是或多或少的占用一部分性能。android studio profiler则完全不依赖UE4本身的分析,不影响APP性能,性能分析更为精准。缺点是性能数据的录制时间比较短,太长会卡死。

Profileable 是在 Android Q 中引入的清单配置。它可以指定设备用户能否通过 Android Studio、Simpleperf 和 Perfetto 等工具对此类应用进行性能分析

在 profileable 之前,大多数开发者只能对 Android 上的可调试应用进行性能分析,这会导致性能显著下降。这些性能下降可能会导致分析结果无效,尤其是当它们与时间有关时。

引入了 Profileable,以便开发者可以选择允许其应用向分析工具公开信息,同时导致的性能下降微乎其微。可分析 APK 实质上是一个清单文件中添加了一行  的发布版 APK。

如需构建可分析应用,您需要先构建发布版应用,然后更新其清单文件,将发布版应用转换为可分析应用。

准备

  1. 可调试包
    目前shipping 中设置了android:debuggable="false" 为可调式包,但缺少调试符号信息展示不全,此处注意。Dev包是可调式的。最好添加Profileable
  2. Android Studio
    版本可以用4.0以上版本,profiler有独立安装包可以直接启动在bin目录下
  3. AS DebugConfigurations->Debugger->Symbol Directories配置ue4的so目录\arm64\jni\arm64-v8a
  4. 手机开发者模式
  5. adb devices 测试手机电脑连接正常

录制

  1. 手机上打开应用
  2. 打开android studio profiler 选择手机调试的应用进程

Android Studio CPU 性能剖析器_第21张图片

看到如下界面

Android Studio CPU 性能剖析器_第22张图片

点击cpu

Android Studio CPU 性能剖析器_第23张图片

3. 选择Simpile C/C++ Functions,实时预览性能数据

Android Studio CPU 性能剖析器_第24张图片

4. 点击Record录制完成后点击stop

Android Studio CPU 性能剖析器_第25张图片

Android Studio CPU 性能剖析器_第26张图片

5. 自动生成Trace文件,可导出

数据分析

官网教程:

检查轨迹 | Android 开发者 | Android Developers​developer.android.google.cn/studio/profile/inspect-traces?hl=zh-cn​编辑

  1. as profiler CPU性能录制是按照线程处理的,所以先要选择线程,然后cpu时间线上选择一个时间范围

Android Studio CPU 性能剖析器_第27张图片

2. 时间线选择控制,选中一个时段方便观察具体每帧图表或汇总一段时间的图表

可以鼠标左键点击CPU时间线 选择一个时间范围,WSAD按键分别用来:缩小时间范围、放大时间范围、向左移东时间范围、右移动时间范围

3. Call Chart视图:可以看每帧的调用栈的具体耗时,发现具体卡顿点

Call Chart 它基本上就是一个调用栈的重新组织和可视化呈现;横轴就是时间线,用来展示方法开始与结束的确切时间,纵轴则自上而下展示了方法间调用和被调用的关系;

对应用自有函数的调用显示为绿色,对第三方 API(包括 Java 语言 API)的函数调用显示为蓝色。

点击CPU时间线可以看到选中的线程视图会展示出调用堆栈的可视化信息如下图:

Android Studio CPU 性能剖析器_第28张图片

鼠标悬浮可以看具体函数的调用时间,通过W可以进一步缩小时间范围观察每帧的调用。

4. Flame Chart火焰图:发现总耗时很长的调用链及其占比

Flame Chart 提供了一个调用栈的聚合信息(合并相同的调用栈)。它的横轴显示的是百分比数值。由于忽略了时间线信息,Flame Chart 可以展示每次调用消耗时间占用整个记录时长的百分比。在顶部展示的是被调用者,底部展示的是调用者。鼠标移动到火焰图上可以看到相关函数的总体调用耗时。

Android Studio CPU 性能剖析器_第29张图片

5. Top Down视图:耗时调用链的排序视图,观察其中每一步所消耗的精确时间

以 Flame Chart 为基础,从调用者开始,持续添加被调用者作为子节点,直到整个 Flame Chart 被遍历一遍,然后按照调用链的耗时长短从高到低进排序

Android Studio CPU 性能剖析器_第30张图片

6. Bottom Up视图:观察某个方法如何被调用,找到最耗时的方法调用

从底部开始构建,这样我们就能通过在节点上不断添加调用者来反向构建出树,每个独立节点都可以构建出一棵树。

Android Studio CPU 性能剖析器_第31张图片

图表生成原理

图表作用总结

Android Studio CPU 性能剖析器_第32张图片

官方教程:

检查轨迹 | Android 开发者 | Android Developers​developer.android.google.cn/studio/profile/inspect-traces?hl=zh-cn​编辑

Call Chart

Call Chart 横轴就是时间线,用来展示方法开始与结束的确切时间,纵轴则自上而下展示了方法间调用和被调用的关系。

Android Studio CPU 性能剖析器_第33张图片

Android Studio CPU 性能剖析器_第34张图片

Flame Chart

根据call char 聚合相同的调用堆栈

Android Studio CPU 性能剖析器_第35张图片

Android Studio CPU 性能剖析器_第36张图片

Top Down

以 Flame Chart 为基础,您只需要从调用者开始,持续添加被调用者作为子节点,直到整个 Flame Chart 被遍历一遍,您就获得了一个 Top Down Tree

Android Studio CPU 性能剖析器_第37张图片

构建步骤:

我们从 A 节点开始:

  • A 消耗了 1 秒钟来运行自己的代码,所以 Self Time 是 1;
  • 然后它消耗了 9 秒中去调用其他方法,这意味着它的 Children Time 是 9;
  • 这样就一共消耗了 10 秒钟,Total Time 是 10;
  • B 和 D 以此类推...
  • 值得注意的是,D 节点只是调用了 C,自己没做任何事,这种情况在方法封装时很常见。所以 D 的 Children Time 和 Total Time 都是 2。

对于每个节点,我们关注三个时间信息:

  • Self Time —— 运行自己的代码所消耗的时间;
  • Children Time —— 调用其他方法的时间;
  • Total Time —— 前面两者时间之和。

Bottom Up

Bottom Up Tree 从底部开始构建,这样我们就能通过在节点上不断添加调用者来反向构建出树。由于每个独立节点都可以构建出一棵树。

Android Studio CPU 性能剖析器_第38张图片

由于我们在构建基于 C 节点的 Bottom Up Tree,所以所有时间信息也都是基于 C 节点的。这时我们在计算 B 的 Self Time 时,应当计算 C 被 B 调用的时间,而不是 B 自身执行的时间,这里是 4 秒;对于 D 来说,则是 2 秒。

///

1 Systace
Systrace 是第一代系统级性能分析工具。在 Perfetto 出现之前,基本上是唯一的性能分析工具(DDMS 在 Android Studio 3.0 就被抛弃),它将 Android 系统和 App 的运行信息以图形化的方式展示出来,与 Log 相比,Systrace 的图像化方式更为直观;与 TraceView 相比,抓取 Systrace 时候的性能开销基本可以忽略,最大程度地减少观察者效应带来的影响。

1.1 Systrace 的设计思路
在系统的一些关键操作(比如 Touch 操作、Power 按钮、滑动操作等)、系统机制(input 分发、View 绘制、进程间通信、进程管理机制等)、软硬件信息(CPU 频率信息、CPU 调度信息、磁盘信息、内存信息等)的关键流程上,插入类似 Log 的信息,我们称之为 TracePoint(本质是 Ftrace 信息),通过这些 TracePoint 来展示一个核心操作过程的执行时间、某些变量的值等信息。然后 Android 系统把这些散布在各个进程中的 TracePoint 收集起来,写入到一个文件中。导出这个文件后,Systrace 通过解析这些 TracePoint 的信息,得到一段时间内整个系统的运行信息。
Android 系统中,一些重要的模块都已经默认插入了一些 TracePoint,通过 TraceTag 来分类,其中信息来源如下

Framework Java 层的 TracePoint 通过 android.os.Trace 类完成
Framework Native 层的 TracePoint 通过 ATrace 宏完成
App 开发者可以通过 android.os.Trace 类自定义 Trace
这样 Systrace 就可以把 Android 上下层的所有信息都收集起来并集中展示,对于 Android 开发者来说,Systrace 最大的作用就是把整个 Android 系统的运行状态,从黑盒变成了白盒。全局性和可视化使得 Systrace 成为 Android 开发者在分析复杂的性能问题的时候的首选。
一般抓到的 Systrace 文件如下

Systrace 已经很强大了,但 Google 并不满足,在此基础上提供了一个更加强大的工具 Pefetto。

2 新一代性能分析全栈工具 Perfetto
Perfetto 相比 Systrace 最大的改进是可以支持长时间数据抓取,这是得益于它有一个可在后台运行的服务,通过它实现了对收集上来的数据进行 Protobuf 的编码并存盘。从数据来源来看,核心原理与 Systrace 是一致的,也都是基于 Linux 内核的 Ftrace 机制实现了用户空间与内核空间关键事件的记录(ATRACE、CPU 调度)。Systrace 提供的功能 Perfetto 都支持,由此才说 Systrace 最终会被 Perfetto 替代。
Perfetto 所支持的数据类型、获取方法,以及分析方式上看也是前所未有的全面,它几乎支持所有的类型与方法。数据类型上通过 ATRACE 实现了 Trace 类型支持,通过可定制的节点读取机制实现了 Metric 类型的支持,在 UserDebug 版本上通过获取 Logd 数据实现了 Log 类型的支持。
开发者可以通过 Perfetto.dev 网页、命令行工具手动触发抓取与结束,通过设置中的开发者选项触发长时间抓取,甚至你可以通过框架中提供的 Perfetto Trigger API 来动态开启数据抓取,基本上涵盖了我们在项目上能遇到的所有的情境。
本文主要讨论如何在 Android 使用 Peffetto 来分析性能。提到 Android 的性能分析工具就不得不提 Android Studio 中的 Profiler。

3 Android Studio Profiler 工具
随着 Android Studio 的迭代、演进,到目前,Android Studio 有了自己的性能分析工具 Android Profiler,它是一个集合体,集成了多种性能分析工具于一体,让开发者可以在 Android Studio 做开发应用,也不用再下载其它工具就能让能做性能调优工作。
目前 Android Studio Profiler 已经集成了 4 类性能分析工具: CPU、Memory、Network、Battery,其中 CPU 相关性能分析工具为 CPU Profiler,也是本章的主角,它把 CPU 相关的性能分析工具都集成在了一起,开发者可以根据自己需求来选择使用哪一个。可能很多人都知道,谷歌已经开发了一些独立的 CPU 性能分析工具,如 Perfetto、Simpleperf、Java Method Trace 等,现在又出来一个 CPU Profiler,显然不可能去重复造轮子,CPU Profiler 目前做法就是:从这些已知的工具中获取数据,然后把数据解析成自己想要的样式,通过统一的界面展示出来。
CPU Profiler 集成了性能分析工具:Perfetto、Simpleperf、Java Method Trace,它自然而然具备了这些工具的全部或部分功能,如下:

System Trace Recording,它是用 Perfetto 抓取的信息,可用于分析进程函数耗时、调度、渲染等情况,除了在 Profiler 分析外,还可以将 Trace 导出文件后在 ui.perfetto.dev/上进行分析
Java Method Trace Recording,它是从虚拟机获取函数调用栈信息,用于分析 Java 函数调用和耗时情况
C/C++ Function Trace,它是用 Simpleperf 抓取的信息,Simpleperf 是从 CPU 的性能监控单元 PMU 硬件组件获取数据。 C/C++ Method Trace 只具备 Simpleperf 部分功能,用于分析 C/C++ 函数调用和耗时情况

由此可知,使用 Profiler CPU 中的 System Trace Recording 就是在使用 Perfetto
4 Android 中 System trace 信息的抓取
那么我们下面列举几个例子来看看如何使用 Perfetto 来抓取和分析性能问题

4.1 Android Studio 如何抓取 App 启动的 trace 信息
1.点击此应用的 Edit Configurations 按钮

2.修改配置


选择 Profiling
勾选 Start this recording on startup
CPU activity 选择 Trace System Calls
点击 Aplay
点击 Ok
3.点击 Profile 按钮

4.App 运行之后会立即开始抓取,点击 stop 按钮停止 recording

5.以下是抓取后的信息

稍后我们来看看如何根据展示出的 System trace recording 分析性能问题

4.2 Android Studio 如何抓取任何时候的 trace 信息
1.启动 profiler 后,在 CPU 区域,选择 System trace Recording,点击 Record 按钮

2.在 App 中点击或者滑动之后,点击 Stop 按钮,即可获取 system trace 信息


4.3 使用手机设备抓取 trace 信息
在 Android 9(Api 级别 28)或更高版本上有一个 System Tracing 的系统级应用。如

抓取之后的.perfetto-trace文件可以直接导入 Android Stuido 的 Profier 进行分析,也可在 ui.perfetto.dev/上进行分析。

抓取之后的.ctrace文件可以在 ui.perfetto.dev/上进行分析。

5 Android 中 System trace 信息的分析
5.1 CPU 性能剖析器窗口介绍


事件时间轴:显示应用中的 activity 在其生命周期内不断转换经历各种不同状态的过程,并指示用户与设备的交互,包括屏幕旋转事件。
CPU 时间轴:显示应用的实时 CPU 使用率(以占总可用 CPU 时间的百分比表示)以及应用当前使用的线程总数。此时间轴还会显示其他进程(如系统进程或其他应用)的 CPU 使用率,以便您可以将其与您应用的 CPU 使用率进行对比。可以通过沿时间轴的横轴方向移动鼠标来检查历史 CPU 使用率数据。
线程活动时间轴:列出属于应用进程的每个线程,并使用下面列出的颜色在时间轴上指示它们的活动。记录轨迹后,可以从此时间轴上选择一个线程,以在轨迹窗格中检查其数据。
绿色:表示线程处于活动状态或准备使用 CPU。也就是说,线程处于正在运行或可运行状态。
黄色:表示线程处于活动状态,但它正在等待一项 I/O 操作(如磁盘或网络 I/O),然后才能完成它的工作。
灰色:表示线程正在休眠且没有消耗任何 CPU 时间。 当线程需要访问尚不可用的资源时,就会出现这种情况。在这种情况下,要么线程主动进入休眠状态,要么内核将线程置于休眠状态,直到所需的资源可用。
5.2 CPU Trace Recording 窗口介绍


选定范围:确定需在跟踪数据窗格中检查所记录时间的哪一部分。可以用鼠标拖选需要观察的范围。
“Interaction”部分:沿着时间轴显示用户互动和应用生命周期事件。
“Threads”部分:沿时间轴针对每一个线程显示线程状态活动(例如运行、休眠等)和调用图表(在 System Trace 中则为跟踪事件图表)。
使用鼠标和键盘快捷键(WASD)在时间轴上选择范围。
双击线程名称,或在选中线程时按 Enter 键展开或折叠线程。
选择某个线程即可在“Analysis”窗格中查看更多信息。 按住 Shift 可选择多个线程。
“Analysis”窗格:显示所选择的时间范围和线程/方法调用的 trace 数据。在此窗格中,可以选择如何查看每个堆栈轨迹(使用“Analysis”标签页),以及如何测量执行时间(使用“Time reference”下拉菜单)。
“Analysis”窗格标签页:选择如何显示跟踪数据详细信息。
"Time reference"菜单:选择以下选项之一,以确定如何测量每次调用的时间信息(仅在Sample/Trace Java 方法中受支持):
Wall clock time:该时间信息表示实际经过的时间。
Thread time:该时间信息表示实际经过的时间减去线程没有占用 CPU 资源的那部分时间。对于任何给定的调用,其线程时间始终小于或等于其挂钟时间。使用线程时间可以更好地了解线程的实际 CPU 使用率中有多少是给定方法或函数占用的。
Filter:按函数、方法、类或软件包名称过滤跟踪数据。
5.3 在 Android 10 及更低版本上检测卡顿
Android 10(API 级别 29)及更低版本会在 CPU 性能分析器捕捉的系统轨迹的 Display 中显示相关的操作系统图形流水线信息。

Display 部分显示以下图形流水线信息:Frames、SurfaceFlinger、VSYNC 和 BufferQueue。

Frames:此部分显示应用中的界面线程和 RenderThread 轨迹事件。时长超过 16 毫秒的事件会以红色表示。
SurfaceFlinger:此部分显示 SurfaceFlinger 处理帧缓冲区的时间。SurfaceFlinger 是负责将缓冲区内容发送到显示屏的系统进程。
VSYNC:此部分显示 VSYNC,这是一个表示与 Display 流水线保持同步的信号。
BufferQueue:此部分显示有多少帧缓冲区在排队等待 SurfaceFlinger 使用。对于部署到搭载 Android 9(API 级别 28)或更高版本的设备的应用,此轨迹显示应用 surface BufferQueue 的缓冲区计数(0、1 或 2)。BufferQueue 可帮助您了解图像缓冲区在 Android 图形组件之间切换时的状态。例如,值 2 表示应用当前处于三重缓冲状态,这会导致额外的输入延迟。
如何检测卡顿
如需在 Android 10 或更低版本上检测卡顿,请执行以下操作:

1.查看 Display 中的 Frames 轨迹。红色帧是要调查的候选对象。

2.发现可能存在卡顿的帧后,请按 W,或在按住 Control 键的同时滚动鼠标滚轮,以便进行放大。继续放大,直到您看到界面线程和 RenderThread 中的轨迹事件。

Choreographer#doFrame 显示了界面线程何时调用 Choreographer 来协调动画、视图布局、图像绘制和相关进程。DrawFrames 会在 RenderThread 形成并向 GPU 发出实际绘制命令时显示。
3.如果发现某个轨迹事件特别长,可以进一步放大,以便找出可能导致呈现速度缓慢的原因。下图显示了界面线程中的 inflate,这意味着应用正在花时间 inflate 布局。当放大其中一个 inflate 事件时,可以确切了解每个界面组件花费的时间


6 总结
应用的性能问题主要分为两类:响应慢、不流畅。

响应慢问题常有:应用启动慢、页面跳转慢、列表加载慢、按钮响应慢等
不流畅问题常有:列表滑动不流畅、页面滑动不跟手、动画卡顿等
CPU Profiler 在这些场景中要如何使用呢?基本的思路是:首先就要抓 System Trace,先用System Trace 分析、定位问题,如果不能定位到问题,再借助 Java Method Trace 或 C/C++ Function Trace 进一步分析定位。
Android Studio 中的 CPU Profiler 最大优势是集成了各种子工具,在一个地方就能操作一切,对应用开发者来说是还是非常方便的

///

///

///

你可能感兴趣的:(Unity,&,Android,android,studio,gitee,android)