Bootchart抓取 - Android源码分析及时间参数

本文针对Android系统Bootchart部分源码进行了分析,并给出了Android-5、6-7、8+版本的参数差异,解释了8+以上的时长无法手动控制的原因,并对bootchart源码进行了分析

研究背景

主要是网上的资料,关于如何控制采集bootchart时长的方法不一,且尝试过几种方法均无法控制后,遂看了下Android中bootchart源码,分析了生成header、proc_diskstats、proc_ps、proc_stat的过程。

已有的时长控制的方法:

  1. echo $TIME_OUT > /data/bootchart/start
    其中的 $TIME_OUT为时长,比如采集50s,echo 50 > /data/bootchart/start
  2. echo $TIME_OUT> /data/bootchart-start
    与方法1一致, $TIME_OUT为时长。

测试了下,针对我的手机+虚拟机,两种方法均无法控制时长,所以看了下Android源码,分析了下原因。

采集时长控制

通过查看Android源码,发现针对Android-5、6-7、8+版本中bootchart生成变化较多,针对差异较大的时长进行了分析。

Android 5

先上源码链接bootchart.cbootchart.h,挑出关于时间控制的源码。

  • 宏定义文件名
#define LOG_STARTFILE   "/data/bootchart-start"
  • 如果/data/bootchart-start文件中有数值,且不为0,设置timeout
buff[0] = 0;
proc_read( LOG_STARTFILE, buff, sizeof(buff) );
if (buff[0] != 0) {
    timeout = atoi(buff);
}
  • 如果/data/bootchart-start文件中timeout超过10*60,则设置timeout为10*60。再将timeout转化为具体的count,通过采集的index去跳出采集。
# define BOOTCHART_MAX_TIME_SEC        (10*60) /* max polling time in seconds */
# define BOOTCHART_POLLING_MS   200   /* polling period in ms */
if (timeout == 0)
    return 0;
if (timeout > BOOTCHART_MAX_TIME_SEC)
    timeout = BOOTCHART_MAX_TIME_SEC;
count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
  • 采集中停止采集
    可以通过向/data/bootchart-stop写入1即可,echo 1 > /data/bootchart-stop
#define LOG_STOPFILE    "/data/bootchart-stop"

/* called each time you want to perform a bootchart sampling op */
int  bootchart_step( void )
{
    do_log_file(log_stat,   "/proc/stat");
    do_log_file(log_disks,  "/proc/diskstats");
    do_log_procs(log_procs);
    /* we stop when /data/bootchart-stop contains 1 */
    {
        char  buff[2];
        if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') {
            return -1;
        }
    }
    return 0;
}

Android 6-7

这两个版本中关于bootchart的相对于Android 5有所变化,同样先上源码链接bootchart.cpp,以Android 7.1.0举例。

  • 宏定义文件名,控制逻辑与Android 5 类似。
#define LOG_ROOT        "/data/bootchart"

#define LOG_STARTFILE   LOG_ROOT"/start"
#define LOG_STOPFILE    LOG_ROOT"/stop"

Android 8+

Android 8+ 的源代码中去除了手动时长控制,查看源代码bootchart.cppreadme文档,可以发现主要是通过init.rc去控制运行、停止。

on post-fs-data
    # We chown/chmod /data again so because mount is run as root + defaults
    chown system system /data
    chmod 0771 /data

    # Start bootcharting as soon as possible after the data partition is
    # mounted to collect more data.
    mkdir /data/bootchart 0755 shell shell
    bootchart start
on property:sys.boot_completed=1
    bootchart stop
  • 启动
    默认在post-fs-data trigger触发器中去执行bootchart,依然是判断有/data/bootchart/enabled文件即可。
int do_bootchart(const std::vector<std::string>& args) {
  if (args[1] == "start") return do_bootchart_start();
  return do_bootchart_stop();
}
static int do_bootchart_start() {
  // We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
  std::string start;
  if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
    LOG(VERBOSE) << "Not bootcharting";
    return 0;
  }
  g_bootcharting_thread = new std::thread(bootchart_thread_main);
  return 0;
}
  • 停止
    sys.boot_completed=1时,即当系统的属性sys.boot_completed为1的时候(系统启动完成),会触发args[1] = stop,去停止bootchart采集。

Bootchart源代码分析

针对Android 12,对Bootchart源码进行分析,先上源码,bootchart.cppActivityManagerService.javaREADME.md

如何trigger

从readme中,关于Bootchart的描述如下:

/system/etc/init/hw/init.rc is the primary .rc file and is loaded by the init executable at the beginning of its execution. It is responsible for the initial set up of the system.

bootchart [start|stop]

Start/stop bootcharting. These are present in the default init.rc files, but bootcharting is only active if the file /data/bootchart/enabled exists; otherwise bootchart start/stop are no-ops.

可知,是通过init.rc中,去调起bootchart startbootchart stop的。

打开Android12模拟器下的 /system/etc/init/hw/init.rc文件,关于bootchart的流程如下:

  • 服务启动
    一旦/data分区挂载完毕后,立即去启动bootchart服务。
on post-fs-data

    mark_post_data

    # Start checkpoint before we touch data
    exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint

    # We chown/chmod /data again so because mount is run as root + defaults
    chown system system /data
    chmod 0771 /data
    # We restorecon /data in case the userdata partition has been reset.
    restorecon /data

    # Make sure we have the device encryption key.
    installkey /data

    # Start bootcharting as soon as possible after the data partition is
    # mounted to collect more data.
    mkdir /data/bootchart 0755 shell shell encryption=Require
    bootchart start
  • 服务结束
    系统启动完成后,停止采集bootchart。
on property:sys.boot_completed=1
   bootchart stop

所以系统的属性sys.boot_completed为啥时候为1?

参考Android系统启动之BOOT_COMPLETED广播

查看ActivityManagerService.java,关于trigger sys.boot_completed的代码如下:

final void finishBooting() {
       TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
               Trace.TRACE_TAG_ACTIVITY_MANAGER);
       t.traceBegin("FinishBooting");
       synchronized (this) {
           if (!mBootAnimationComplete) {
               mCallFinishBooting = true;
               return;
           }
           mCallFinishBooting = false;
       }
       // Let the ART runtime in zygote and system_server know that the boot completed.
       // Inform checkpointing systems of success
      // Tell anyone interested that we are done booting!
           SystemProperties.set("sys.boot_completed", "1");
           ......

mBootAnimationComplete即开机动画结束.

采集流程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值