需要对比基线测试的情况;

Kernel log: adb shell dmesg

Event log: adb shell logcat –b events

Logcat log: adb shell logcat

lk boottime测试:(只适合LE)

adb shell dmesg

搜索关键字:

[0.424253] KPI: Boot loader start count = 35880

[0.424265] KPI: Boot loader end count = 73583

[0.424271] KPI: Boot loader display count = 48572

[0.424277] KPI: Boot loader load kernel count = 3318

[0.424285] KPI: Kernel MPM timestamp = 94543

[0.424290] KPI: Kernel MPM clock frequency = 32768

Boot loader time calculation

  • Hw_count = 94543

  • Frequency = 32768

  • Kernel timestamp = 0.424285

  • Boot loader time = (Hw_count/Frequency) – Kernel timestamp

  • Boot loader time = (94543/32768) – 0.424285 = 2.460938388671875 sec

Total boot up time = Boot loader time + HLOS boot up time (from boot_progress_enable_screen)

kernel阶段的log:(demsg.log)

The following are the kernel Init stages:-

  • First stage: Kernel driver initialization takes place

  • Second stage: File system mount takes place`

    grep "init:"

    [ 0.954087] init: init first stage started!

    [ 8.398016] init: init second stage started!

init阶段的log:(logcat_event.log)

搜索关键字:boot_progress


boot_progress|bootAnimation:|wm_boot_animation_done boot_progress_start: 6914 标志着kernel启动完成。Zygote开始启动 此时界面还是现实开机静态图片
BootAnimation: BootAnimationStartTiming start time: 15202ms 界面开始开机动画
boot_progress_preload_start: 9509 Zygote开始加载资源
boot_progress_preload_end: 12251 Zygote加载资源结束
boot_progress_system_run: 12619 SystemServer开始启动
boot_progress_pms_start: 13424 PMS开始启动
boot_progress_pms_system_scan_start: 13482 PMS扫描/system目录下的安装包
boot_progress_pms_data_scan_start: 15598 PMS扫描/data目录下的安装包
boot_progress_pms_scan_end: 15633 PMS扫描结束
boot_progress_pms_ready: 16225 PMS初始化完毕
boot_progress_ams_ready: 22036 AMS就绪
android.intent.category.HOME: 先启动“Android正在启动” FallbackHome。
boot_progress_enable_screen: 24814 AMS启动完成后开始激活屏幕,从此以后

注意这里的boot_progress不包含bootloader的时间

boot_progress_enable_screen代表完整的开机日志。

看完event.log之后,可以大致推算出耗时点,如果是SystemServer耗时,可以在android.log里面看每个服务的启动时间推算卡在哪个服务,搜索关键字“SystemServer”即可。

service-start stage

logcat中搜索关键字:init:

[ 0.954087] init: init first stage started!

[ 0.975432] init: Loading module /lib/modules/qcom-cpufreq-hw.ko with args ''

[ 1.033704] init: Loaded kernel module /lib/modules/qcom-cpufreq-hw.ko

[ 1.033866] init: Loading module /lib/modules/sched-walt.ko with args ''

[ 1.050295] init: Loaded kernel module /lib/modules/sched-walt.ko

[ 1.051146] init: Loading module /lib/modules/minidump.ko with args ''

[ 1.056404] init: Loaded kernel module /lib/modules/minidump.ko

[ 1.056556] init: Loading module /lib/modules/msm_rtb.ko with args 'filter=0x237 filter=0x237'

[ 1.065098] init: Loaded kernel module /lib/modules/msm_rtb.ko

[ 1.065552] init: Loading module /lib/modules/qcom_ipc_logging.ko with args ''

[ 5.581554] sdhci_msm 4744000.sdhci: mmc0: CQE init: success

[ 6.283528] init: [libfs_mgr] Created logical partition scratch on device /dev/block/dm-6

[ 7.091009] init: [libfs_mgr] __mount(source=/dev/block/dm-6,target=/mnt/scratch,type=f2fs)=0: Success

[ 7.156231] init: [libfs_mgr] __mount(source=/dev/block/dm-6,target=/mnt/scratch,type=f2fs)=0: Success

[ 7.171745] init: [libfs_mgr] __mount(target=/system,flag=MS_PRIVATE)=-1: Invalid argument

[ 7.193904] init: [libfs_mgr] __mount(source=overlay,target=/system,type=overlay,upperdir=/mnt/scratch/overlay/system/upper)=0

[ 7.223198] init: [libfs_mgr] __mount(source=overlay,target=/system_ext,type=overlay,upperdir=/mnt/scratch/overlay/system_ext/upper)=0

[ 7.252759] init: [libfs_mgr] __mount(source=overlay,target=/product,type=overlay,upperdir=/mnt/scratch/overlay/product/upper)=0

[ 7.281241] init: [libfs_mgr] __mount(source=overlay,target=/vendor,type=overlay,upperdir=/mnt/scratch/overlay/vendor/upper)=0

[ 7.309920] init: [libfs_mgr] __mount(source=overlay,target=/vendor_dlkm,type=overlay,upperdir=/mnt/scratch/overlay/vendor_dlkm/upper)=0

[ 7.340022] init: [libfs_mgr] __mount(source=overlay,target=/system_dlkm,type=overlay,upperdir=/mnt/scratch/overlay/system_dlkm/upper)=0

[ 7.413005] printk: init: 181 output lines suppressed due to ratelimiting

[ 7.587287] init: [libfstab] Using Android DT directory /proc/device-tree/firmware/android/

[ 7.597363] init: [libfstab] dt_fstab: Skip disabled entry for partition vendor

[ 7.605818] init: [libfstab] dt_fstab: Skip disabled entry for partition system

[ 7.625867] init: Opening SELinux policy

[ 7.652166] init: Loading SELinux policy

[ 8.398016] init: init second stage started!

[ 8.669245] init: [libfstab] Using Android DT directory /proc/device-tree/firmware/android/

[ 8.705971] init: Overriding previous property 'ro.logd.size':'1M' with new value '1048576'

[ 8.716936] audit: type=1107 audit(484.615:7): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=u:r:init:s0 msg='avc: denied { set } for property=persist.backup.ntpServer pid=1 uid=0 gid=0 scontext=u:r:vendor_init:s0 tcontext=u:object_r:default_prop:s0 tclass=property_service permissive=1'

[ 8.717393] init: Overriding previous property 'dalvik.vm.heapstartsize':'32m' with new value '8m'

[ 8.754074] init: Overriding previous property 'dalvik.vm.heapsize':'256m' with new value '128m'

使用 bootchart 分析开机启动时间

bootchart 是一个能对 GNU/Linux boot 过程进行性能分析并把结果直观化的开源工具,在系统启动过程中自动收集 CPU 占用率、磁盘吞吐率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。BootChart 包含数据收集工具和图像产生工具,数据收集工具在原始的 BootChart 中是独立的 shell 程序,但在 Android 中,数据收集工具被集成到了 init 程序中。

在 Android 中会通过一个叫 do_bootchart_start 的函数来判断是否抓取 bootchar 数据

// system/core/init/bootchart.cpp
static Result<Success> do_bootchart_start() {
// We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
std::string start;
// 只要存在/data/bootchart/enabled文件,即抓取 bootchart 数据
if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
LOG(VERBOSE) << "Not bootcharting";
return Success();
} g_bootcharting_thread = new std::thread(bootchart_thread_main);
return Success();
}

所以我们只要创建一个 /data/bootchart/enabled 即可开启 bootchar 数据的抓取。

system/core/init/README.md

android 12: https://android-review.googlesource.com/c/platform/system/sepolicy/+/1888457

adb shell touch /data/bootchart/enabled
adb reboot

接着我们准备用于生成 bootchart 图的分析软件 pybootchartgui:

# 下载 pybootchartgui
sudo apt install python-is-python3
cd ~/Documents
git clone https://github.com/xrmx/bootchart.git
cd bootchart/pybootchartgui
mv main.py.in main.py
# 建立
sudo ln -s ~/Project/bootchart-master/pybootchartgui.py /usr/bin/pybootchartgui

回到 Android 源码目录下执行:

system/core/init/grab-bootchart.sh
parsing '/tmp/android-bootchart/bootchart.tgz'
parsing 'header'
parsing 'proc_stat.log'
parsing 'proc_ps.log'
parsing 'proc_diskstats.log'
merged 0 logger processes
pruned 47 process, 0 exploders, 2 threads, and 1 runs
bootchart written to 'bootchart.png'
Clean up /tmp/android-bootchart/ and ./bootchart.png when done

在源码目录下就生成了 bootchart.png 图:

从生成的图片可以更加直观详细的看到开机耗时以及硬件使用情况.

抓取 trace 文件分析开机启动时间

修改 frameworks/native/cmds/atrace/atrace.rc 中 service boottrace 的内容:

service boottrace /system/bin/atrace --async_start -b 30720 gfx input view webview wm am sm audio video binder_lock binder_driver camera hal res dalvik rs bionic power pm ss database network adb vibrator aidl sched
disabled
oneshot

接着重新编译源码,启动虚拟机。

打开抓取 boottrace 的属性开关

adb  shell setprop persist.debug.atrace.boottrace 0

生成和拉取 boottrace 文件

adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
adb pull /data/local/tmp/boot_trace

自此,我们就得到了启动阶段的 trace 文件,可以通过 perfetto 工具打开并分析它了。

开机启动优化

开启启动优化可以分为两类:

  • 程序异常,导致开机时间加长或无法开机
  • 正常开机时间的基础上加快开机速度

第一种情况,很多时候是某个模块的魔改导致的,我们的主要任务是找到这个模块,一般通过上一节介绍的三种开机时间分析的手段就可以很容易的找到了。

更多的时候是第二种情况,Android 启动可以优化的阶段主要有:

  • Bootloader
  • Kernel
  • Framework

我们主要关注 Framework 阶段的优化,常见的优化手段有:

在 Zygote 进程启动后,加载自定义的驱动,启动自定义的进程

zygote 是在 late-init 阶段启动

on late-init
trigger early-fs
trigger fs
trigger post-fs
trigger late-fs
trigger post-fs-data
trigger load_persist_props_action
# zygote 启动
trigger zygote-start
trigger firmware_mounts_complete
trigger early-boot
trigger boot

加载自定义的驱动,启动自定义的进程两类操作,我们可以放到 early-boot 或者 boot 阶段启动,这样可以让 Zygote 进程今早的启动,加快系统的启动。

on boot
insmod /vendor/lib/modules/btusb.ko
start xxxx
# .....

调整 Zygote 启动参数

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance

这里改动了两个地方 --enable-lazy-preloadtask_profiles ProcessCapacityHigh MaxPerformance

添加了 --enable-lazy-preload 参数,在开机阶段不会执行 preload 预加载操作。在开机后,通过 system-server 发送指令给 zygote 做资源加载操作,在发送指令前,system-server 会加载一部分自己使用的类,会和 zygote 中存在相同的一部分备份,所有会多耗费一些内存。

task_profiles ProcessCapacityHigh MaxPerformance 会让内核使用尽可能多的资源来启动 Zygote。

开机阶段 CPU 开启性能模式

# cpu 开启性能模式
on early-init
write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance # 开机完成后,CPU 频率变成自适应
on property:sys.boot_completed=1
write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor schedutil

读写 IO 调整

可以通过调整事先预读数据的 Kb 数以及默认 IO 请求队列的长度来加快 IO 的读写以提高开机速度

# on late-fs
# # boot time fs tune
# write /sys/block/mmcblk0/queue/iostats 0
# # 增大事先预读数据的 Kb 数
# write /sys/block/mmcblk0/queue/read_ahead_kb 2048
# # 默认 IO 请求队列的长度
# write /sys/block/mmcblk0/queue/nr_requests 256 # on property:sys.boot_completed=1
# # end boot time fs tune
# write /sys/block/mmcblk0/queue/read_ahead_kb 128 on late-fs
# boot time fs tune
write /sys/block/sda/queue/iostats 0
write /sys/block/sda/queue/scheduler cfq
write /sys/block/sda/queue/iosched/slice_idle 0
# 增大事先预读数据的 Kb 数
write /sys/block/sda/queue/read_ahead_kb 2048
# IO 请求队列的长度
write /sys/block/sda/queue/nr_requests 256
write /sys/block/dm-0/queue/read_ahead_kb 2048
write /sys/block/dm-1/queue/read_ahead_kb 2048 on property:sys.boot_completed=1
# end boot time fs tune
write /sys/block/sda/queue/read_ahead_kb 512

移除没有用的模块

主要是修改 SystemServer,删除一些用不到的服务,比如有的产品是电视、音响,就不会用到电话,指纹、定位、打印等相关的模块。

一般可裁剪的模块有:

TelecomLoaderService
TelephonyRegistry
StatusBarManagerService
SearchManagerService
SerialService
FingerprintService
CameraService
MmsService

延时启动 persist app

修改 startPersistentApps 方法,延时启动 persist app

void startPersistentApps(int matchFlags) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return; synchronized (this) {
try {
final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
mHandler.postDelayed(() -> {
addAppLocked(app, null, false, null /* ABI override */,
ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
}, 1000);
}
}
} catch (RemoteException ex) {
}
}
}

精简 preload 的 classes

可以根据产品的类型修改 frameworks/base/config/preloaded-classes 文件,来删减一些用不到的 preload classes

常见可删除的预加载 classes 有:

// 生物识别
android.hardware.biometrics // 人脸识别
android.hardware.face // 打印服务
android.hardware.fingerprint
android.print. // 部分定位相关, 还有GPS定位相关
android.hardware.location
com.android.internal.location.GpsNetInitiatedHandler
android.location.Gnss* // 手机通话相关
android.telephony.
android.telecom.
com.android.i18n.phonenumbers.
com.android.ims
android.hardware.radio // nfc相关
android.nfc.

如果需要再做一些大的裁剪,可以使用 frameworks\base\config\generate-preloaded-classes.sh 脚本来重新生成 preloaded-classes

android启动时间测试的更多相关文章

  1. 利用 Traceview 精准定位启动时间测试的异常方法 (工具开源)

    机智的防爬虫标识原创博客地址:http://www.cnblogs.com/alexkn/p/7095855.html博客求关注: http://www.cnblogs.com/alexkn 1.启动 ...

  2. 移动性能测试 | 持续集成中的 Android 稳定性测试

    前言 谈到Android稳定测试,大多数会联想到使用monkey工具来做测试.google官方提供了monkey工具,可以很快速点击被应用,之前我有一篇帖子提到了monkey工具的使用,详见: htt ...

  3. Android开源测试框架学习

    近期因工作需要,分析了一些Android的测试框架,在这也分享下整理完的资料. Android测试大致分三大块: 代码层测试 用户操作模拟,功能测试 安装部署及稳定性测试 代码层测试 对于一般java ...

  4. Android ui 测试课堂笔记

    开始接触Android ui测试了,笔记如下 模拟器 Genemotion , the fastest android simulator in the world Android ui 测试工具 S ...

  5. Android压力测试工具——Monkey

    Android压力测试工具——Monkey Monkey是运行在模拟器上和真机设备上的一段程序,它会产生用户事件的一系列伪随机流,比如点击.触摸.手势,还有很多系统级别的事件.Monkey通常是用来做 ...

  6. Android渗透测试Android渗透测试入门教程大学霸

    Android渗透测试Android渗透测试入门教程大学霸 第1章  Android渗透测试 Android是一种基于Linux的自由及开放源代码的操作系统,主要用于移动设备,如智能手机.平板等.目前 ...

  7. 监听Android CTS测试项解决方案(一)

    前言: 首先这里需要详细叙述一下标题中"监听Android CTS测试项解决方案"的需求.这里的需求是指我们需要精确的监听到当前CTS测试正在测试的测试项. 因为我们知道CTS认证 ...

  8. Android测试(一):在Android中测试App

    原文:https://developer.android.com/training/testing/index.html 测试你的App是开发过程中的重要组成部分.通过对应用程序持续的运行测试,你可以 ...

  9. Google+ 团队的 Android UI 测试

    https://github.com/bboyfeiyu/android-tech-frontier/tree/master/android-blog/Google%2B%20%E5%9B%A2%E9 ...

  10. [转]Android开源测试框架学习

    近期因工作需要,分析了一些Android的测试框架,在这也分享下整理完的资料. Android测试大致分三大块: 代码层测试 用户操作模拟,功能测试 安装部署及稳定性测试 代码层测试 对于一般java ...

随机推荐

  1. 自写Json转换工具

    前面写了简单的API测试工具ApiTools,返回的json有时需要做很多转换,于是开发了这个工具. 功能包括 1.json字符串转为表格,可以直观的展示,也可以复制,并支持转换后的表格点击列头进行排 ...

  2. onnxruntime无法使用GPU加速 加速失败 解决方法【非常详细】

    onnx 无法使用GPU加速 加速失败 解决方法[非常详细] 应该是自目前以来最详细的加速失败解决方法GPU加速,收集了各方的资料.引用资料见后文 硬件配置: GPU CUDA版本:12.2 客户架构 ...

  3. 【JavaWeb】HttpClient

    需要的依赖: <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <de ...

  4. 【Project】JS的Map对象前后交互问题

    这是我在项目中写的一个Map对象: let map = new Map(); for (let i = 0; i < type_checked_value.length; i++) { let ...

  5. 深度学习框架 MindSpore —— 华为出品的AI计算框架, docker 安装

    深度学习框架  MindSpore  --   华为出品的AI计算框架 官网地址: https://www.mindspore.cn/ 源代码地址: https://gitee.com/devilma ...

  6. 【转载】【转载视频】 如何成为好的IT技术面试官

    在外网找到了一个IT技术面试官的面试心得,感觉还不错,挺有借鉴的,这里mark一下. 地址: https://www.youtube.com/watch?v=yFMmkoqDPlM ========= ...

  7. 告别Hugging Face模型下载难题:掌握高效下载策略,畅享无缝开发体验

    告别Hugging Face模型下载难题:掌握高效下载策略,畅享无缝开发体验 Huggingface国内开源镜像:https://hf-mirror.com/ 里面总结了很多下载的方法,下面进行一一讲 ...

  8. spring声明事务失效问题

    问题:      在项目开发中遇到了一个spring事务失效的问题,检查配置文档,都没有问题,其他的类中的方法都能进行事务管理,而这个类中的方法却不行. 分析      查看代码发现三个问题: 原因1 ...

  9. T113s工业套件简述

    T113s工业套件简述 提示 T113开发交流QQ群:120575746 此开发板的任何问题都可以在我们的论坛交流讨论 https://forums.100ask.net/c/aw/ 硬件简述​ 10 ...

  10. MySQL编译安装-麒麟V10 x86

    环境信息 操作系统: Kylin Linux Advanced Server V10 (Sword) 架构:X86 MySQL版本:5.7.44 编译 安装必要的依赖库和编译工具 sudo yum g ...