Bootchart 分析之Android 7.1 版本Bug

Bootchart 是什么

Bootchart是一个用于Linux启动过程性能分析的开源软件工具

在Android中又是什么

Google已经在Android系统中默认集成了Bootchart 用来记录开机时间的
可查看开机耗时在什么位置,以便优化开机时间

Android5.1之前已自带bootchart,但缺省时不被编译,需要显式指定编译

5.1之后的都默认编译进了init中

谷歌介绍

system/core/init/readme.txt


Bootcharting
------------
This version of init contains code to perform "bootcharting": generating log
files that can be later processed by the tools provided by www.bootchart.org.

On the emulator, use the -bootchart  option to boot with bootcharting
activated for  seconds.

On a device, create /data/bootchart/start with a command like the following:

  adb shell 'echo $TIMEOUT > /data/bootchart/start'

Where the value of $TIMEOUT corresponds to the desired bootcharted period in
seconds. Bootcharting will stop after that many seconds have elapsed.
You can also stop the bootcharting at any moment by doing the following:

  adb shell 'echo 1 > /data/bootchart/stop'

Note that /data/bootchart/stop is deleted automatically by init at the end of
the bootcharting. This is not the case with /data/bootchart/start, so don't
forget to delete it when you're done collecting data.

The log files are written to /data/bootchart/. A script is provided to
retrieve them and create a bootchart.tgz file that can be used with the
bootchart command-line utility:

  sudo apt-get install pybootchartgui
  # grab-bootchart.sh uses $ANDROID_SERIAL.
  $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

One thing to watch for is that the bootchart will show init as if it started
running at 0s. You'll have to look at dmesg to work out when the kernel
actually started init.



system/core/init/grab-bootchart.sh

这个脚本是因为需要在Linux环境下打包这些数据并做可视化处理输出性能分析图表。为此Google已经给我们在源码/system/core/init/目录下写了一个grab-bootchart.sh脚本,专门用来处理这些数据并做可视化处理

中文通俗解释下谷歌翻译

可以使用下面的命名来打开Bootchart来收集开机性能数据(主要就是记录日志文件)

//在data/bootchart/目录中新建start文件
adb shell 'touch /data/bootchart/start'

/*
* 在start文件中写入采用时间timeout=120s
* 这里的时间可以自定义,通过查看源代码可知最长时间不能超过10*60 s
 */
adb shell 'echo 120 > /data/bootchart/start'

//在data/bootchart/目录中新建stop文件
adb shell 'touch /data/bootchart/stop'

//在stop文件中写入1标记,用于停止采集数据
adb shell 'echo 1 > /data/bootchart/stop'

设置了 start 后,重启即刻看到在 data/bootchart/ 目录下应该会有相应的收集文件

但 7.1 的这时候就出现了 Bug ,机器一直down 机,无法开机(后面有解决办法)

代码目录

system/core/init/bootchart.cpp

执行时机

system/core/rootdir/init.rc


on post-fs-data

    ...
    
    # Start bootcharting as soon as possible after the data partition is
    # mounted to collect more data.
    mkdir /data/bootchart 0755 shell shell
    bootchart_init

在 init.rc 执行的时,在挂载好了 data 分区时,就执行 bootchart_init

所以 bootchart_init 就是在 bootchart.cpp 中的入口函数了

bootchart.cpp 中的代码也很容易看懂大概原理

从 data/bootchart/start 中读取设置的时间,并根据代码中设置默认的检测间隔执行读取记录

读取相关文件,如 proc/pid/cmd   proc/pid/stat 等的信息,写入

data/bootchart/proc_stat.log
data/bootchart/proc_ps.log
data/bootchart/proc_diskstats.log
data/bootchart/header
data/bootchart/kernel_pacct

如果读取到 data/bootchart/stop = 1,即停止

大概就这样,但读取出来的文件,还需要配合工具查看分析,就不关注了~~

Bug解决办法

设置了 start 的时间后,重启,发现无法开机了...

经过一番百度,Google

有的Blog是说把 system/core/init/bootchart.cpp中的

stat.replace(open + 1, close - open - 1, full_name);

删除就好了

我试过,确实,可以开机了

但是又想了想,谷歌会没发现这个问题么?不至于吧

真相只有一个!

然后对比了谷歌7.0 8.1 甚至 9.0 的源代码,开启了漫长2个小时的地毯上搜索....

最终在 Google 的提交记录上找到相关修复提交


system/core/init/Android.mk


LOCAL_SANITIZE := integer

========》

LOCAL_SANITIZE := signed-integer-overflow

有梯子的可以直接看原生提交

https://android-review.googlesource.com/c/platform/system/core/+/445032/2/init/Android.mk#b97

虽然不知道这是什么,但从字面意思大概猜到是和内存溢出有关系吧

LOCAL_SANITIZE

然后再百度搜索一波 LOCAL_SANITIZE signed-integer-overflow

是什么

官方解释

Android 的构建系统还使用了 UBSan 的整数溢出检查功能。UBSan 还支持 unsigned-integer-overflow,这不是严格意义上的未定义行为,但它包含在擦除器中。在生成文件中,可以将 LOCAL_SANITIZE 设置为 signed-integer-overflow、unsigned-integer-overflow 或 combination flag integer,启用 signed-integer-overflow、unsigned-integer-overflow、integer-divide-by-zero、shift-base 和 shift-exponent,以启用这些行为。在 blueprint 文件中,可以将 Misc_undefined 设置为所需的标志,启用这些行为。这些 UBSan 目标,尤其是 unsigned-integer-overflow,广泛用于 mediaserver 组件中,以用来消除任何潜在的整数溢出漏洞

在 Android 中,当出现未定义的行为时,默认的做法是中止程序。但是,从 2016 年 10 月开始,Android 中的 UBSan 将提供一个可选的运行时库,其报告的错误信息将更加详细,包括出现的未定义行为类型、文件和源代码行信息

在 Android.mk 文件中,可通过以下方式启用该库:

LOCAL_SANITIZE:=unsigned-integer-overflow signed-integer-overflow
LOCAL_SANITIZE_DIAG:=unsigned-integer-overflow signed-integer-overflow

(⊙﹏⊙),看完了还是有点懵,不过也算了解多一点知识吧,行吧,记录完 溜~

你可能感兴趣的:(Bootchart 分析之Android 7.1 版本Bug)