美文网首页
Bootchart 分析之Android 7.1 版本Bug

Bootchart 分析之Android 7.1 版本Bug

作者: 花前月下的细说 | 来源:发表于2019-06-28 16:33 被阅读0次

    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 <timeout> option to boot with bootcharting
    activated for <timeout> 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

          本文链接:https://www.haomeiwen.com/subject/tudecctx.html