[工具篇]Android系统首次开机分析-----BootChart工具

以开发的android设备W机器为参考分析,该机器是基于高通平台Android 7.0开发,User版本开机时间平均约为85S左右。

这里记录下个人最近对android系统开机时间的分析手段以及开机流程理解。

BootChart工具

Bootchart是一个用于linux启动过程性能分析的开源软件工具,在系统启动过程自动收集CPU占用率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。Android5.1之前已自带bootchart,但缺省时不被编译,需要显式指定编译。5.1之后的不用编译boot.img,该工具默认已经编入系统中。

Android系统中已有一份bootchart的c实现,位于system/core/init/bootchart.cpp中,入口函数为bootchart_init();如果在该方法执行前设定了采样时间,则会记录android开机的各个进程的启动时间。

bootchart_init()函数是在init.rc脚本中调用,代码如下:

on post-fs-data       ---------------------/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

系统默认是不会设置采样时间的,用户可以通过adb shell 'echo 240 > /data/bootchart/start'命令设定,写入start节点值为240(即采样时间为240s,可以自行选择时间数值),just for example.

设定采样时间

列出工具使用中几个坑

    坑1、由于bootchart程序运行时是通过读取/data/bootchart/start这个节点值来确定采样时间,在系统进行恢复出厂设置时,设备会清除data分区,前面方式设置的时间节点“/data/bootchart/start”同样是会被清理的,so 如果按照这样的常规设置,我们是无法通过该工具记录恢复出厂设置的开机时间的。

    坑2、想使用该工具获取首次开机时间,毫不犹豫,我修改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

+ write/data/bootchart/start 240

    bootchart_init

      然后使用命令make bootimage重新编译boot,将生成的boot.image成功flash到机器中,so easy,以为可以获取到首次开机时间图,但是确实空空如也,需要查看代码分析。

忽略N个过程,这里需要关注的是,android系统在首次开机时或者进行reset恢复出厂设置时,是会首先进行全盘加密,即FDE(full-disk encryption.)操作,可以查看链接全盘加密(https://source.android.com/security/encryption/)。在这个过程中,vold会将vold.decrypt设为trigger_restart_min_framework,装载tmpfs临时分区,并且会执行class_start main,即重启main组内的服务,当加密成功后,会装载/data

然后,vold会将vold.decrypt属性设为trigger_restart_framework。这会使init.rc再次启动main类中的服务,并启动late_start类中的服务(这是设备启动后首次启动这些服务)。这个启动过程中post-fs-data会触发两次,bootchart_init()函数触发两次,initj进程一直占用/data/bootchart/proc_stat.log,进程kill失败,会导致开机一直进入不到launcher界面,开机失败问题。

经过前面的分析,为了能使bootchart正常工作,可以在/data正常挂载后,触发trigger_restart_framework。这时写入采样时间并且调用bootchart_init()。代码修改如下:

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

.......................

on property:vold.decrypt=trigger_restart_framework

    # A/B update verifier that marks a successful boot.

    exec - root cache -- /system/bin/update_verifier trigger_restart_framework

+  write /data/bootchart/start 360

+  bootchart_init

    class_start main

    class_start late_start

这种修改方式在userdebug版本中测试正常。


数据采集与分析

     开机后,采集的数据信息会自动收集到/data/bootchart目录下,包含如下5个文件:

header,kernel_pacct,proc_diskstats.log,proc_ps.log,proc_stat.log

接着,可以将以上文件打包放到pc机上,以便利用bootchart工具分析采集到的数据(其中codebase为自己源码所在根目录):

./codebase/system/core/init/grab-bootchart.sh



 在6.0中Google更加贴心了,grap-bootchart.sh在5.1的基础上又调用bootchart工具解析生成的压缩包,生成图片,最后又用命令将图片打开。我们在userdebug时可能感觉不到grap-bootchart.sh的好处,因为我们可以手动pull文件,压缩,解析,查看图片。但是如果在user版本上,我们虽然可以在data/bootchart下新建文件,如果你要想用命令将里面的文件pull出来,就报出文件夹不存在的命令,这时如果使用该脚本就没有问题,最终生成开机图片。

最后生成的分析结果如下(请放大查看),截图是以userdebug版本实验的,可以清晰看到每个进程的执行时间:


对比正常开机的时间,这是机器开机后,按电源键reboot重启后抓取的时间,这次启动完成大约在75s左右


对比两个bootchart图

android 7.0代码还添加了新功能,执行compare-bootcharts.py脚本可以对比获取的两个bootchart的进程启动结束时间点,从而得到对应进程之间的耗时差距.

当我们使用grab-bootchart.sh脚本获取对应的bootcahrt图时,会在PC的/tmp/android-bootchart目录下留下bootchart.tgz压缩包.然后将所要比较的两个bootchart的压缩包放在两个不同的目录base_bootchart_dir,

exp_bootchart_dir.执行如下命令:

system/core/init/compare-bootcharts.py base_bootchart_dir exp_bootchart_dir

就可以得到如下信息:


可以看到zygote进程在首次开机时间和之后的正常开机相比启动时间延迟了38s,即android上层启动晚了38s时间,这是需要抓取event log来同时分析延迟原因。搜索boot_progress关键字:


前面已经分析过,在机器首次开机时,是会首先进行全盘加密,即FDE(full-disk encryption.)操作,这个过程是会先后触发trigger_restart_min_framework和trigger_restart_framework,即 

  class_start main的服务会启动两次,zygote属于main类服务,可以查看init.zygote32.rc脚本,

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

    class main

而通过bootchart工具得到的zygote进程开始时间点,是第二次启动的时间,因为第一次zygote启动后,进程后来是会被kill掉,重新启动,此时能找到的zygote进程pid只是第二次的。

    但是可以参考第一次启动时间为boot_progress_start大约为51s,boot_progress_pms_ready时间为81s,由于是采集的userdebug版本,该时间可以说是开机速度不慢了。

     这里,自己用秒表采集过W机器的user版本首次开机时间,记录大约是80s左右,应该说速度相对不慢。

这里主要介绍了最近对bootchart工具的使用,已便于分析系统启动过程的耗时点,为优化启动过程提供指导意义.

你可能感兴趣的:([工具篇]Android系统首次开机分析-----BootChart工具)