一、 开机各个阶段分析
1、Bootloader 阶段
Bootloader 阶段 该阶段分为(preloader 和Ik 阶段)
从按电源键振动到 kernel 开始启动,这部分高通平台暂无好的方法确认时间,可以从总时间推算大概时间。MTK 项目可以从bootprof 确认

2、kernel 阶段
1.Linux boot -> init first stage started!
主要耗时为电池驱动以及 TP 初始化部分
MTK 项目可从bootprof 中看到各驱动初始化时间,高通平台暂无法确认
2.init first stage started! -> boot_progress_stat
系统进入用户空间,标志着kemel 启动完成
主要是内核访问根文件系统来启动init 进程,包括 apexd、加载 sepolicy (Coldboot)、挂载各个分区
kerne_log:

若以上阶段有差异可联系测试单独给bsp提单确认
3、Android 阶段
在eventlog中搜索boot_progress |sf_stop| wm_boot_animation_done关键字分析日志,粒度较大,只能定位出大概的耗时流程,之后还需分析流程内部具体的耗时情况。开机各流程内部也有相应的日志,可以进行更加细致的分析。

每个阶段如下表所示:
| 阶段 | 描述 |
| boot_progress_start | 系统进入用户空间,标志着kernel启动完成 |
| boot_progress_preload_start | Zygote启动 |
| boot_progress_preload_end | Zygote结束 |
| boot_progress_system_run | SystemServer ready,开始启动Android系统服务 |
| boot_progress_pms_start | PMS开始扫描安装的应用 |
| boot_progress_pms_system_scan_start | PMS先行扫描/system目录下的安装包 |
| boot_progress_pms_data_scan_start | PMS扫描/data目录下的安装包 |
| boot_progress_pms_scan_end | PMS扫描结束 |
| boot_progress_pms_ready | PMS就绪 |
| boot_progress_ams_ready | AMS就绪 |
| boot_progress_enable_screen | AMS启动完成后开始激活屏幕,从此以后屏幕才能响应用户的触摸,它在WindowManagerService发出退出开机动画的时间节点之前 |
| sf_stop_bootanim | SF设置service.bootanim.exit属性值为1,标志系统要结束开机动画了 |
| wm_boot_animation_done | 开机动画结束,这一步用户能直观感受到开机结束 |
开机流程Trace如下图所示:

1.boot_progress_start
系统进入用户空间,标志着kernel启动完成
/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
}
2.boot_progress_preload_start
Zygote启动
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String[] argv){
if(!enableLazyPreload){
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd();
}
}
trace

3.boot_progress_system_run
SystemServer ready,开始启动Android系统服务,如PMS、AMS等
/frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
Slog.i(TAG, "Entered the Android system server!");
final long uptimeMillis = SystemClock.elapsedRealtime();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
if (!mRuntimeRestart){
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START,uptimeMillis);
}
}
trace

4.boot_progress_pms_start
PMS开始扫描安装的应用
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis()
);
}
一般情况下该阶段耗时差异不大 50ms 之内若耗时差异较大
1请确认 BootAnimation 进程是否跑小核心详情见<开机时间checklist>
2耗时主要差异在 read user settings
trace


5.boot_progress_pms_system_scan_start
PMS先行扫描/system目录下的安装包
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);
}

6.boot_progress_pms_data_scan_start
PMS扫描/data目录下的安装包
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
final long systemScanTime = SystemClock.uptimeMillis() - startTime;
final int systemPackagesCount = mPackages.size();
Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ " ms, packageCount: " + systemPackagesCount
+ " , timePerPackage: "
+ (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ " , cached: " + cachedSystemApps);
if (mIsUpgrade && systemPackagesCount > 0) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
systemScanTime / systemPackagesCount);
}
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
}

7.boot_progress_pms_scan_end
PMS扫描结束
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
该阶段差异小,可忽略
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
mPackageUsage.read(mSettings.mPackages);
mCompilerStats.read();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
}
8.boot_progress_pms_ready
PMS就绪
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
t.traceBegin("write settings");
mSettings.writeLPr();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
}
startWifi R/Q差异,verifyclass比Q多

9.boot_progress_ams_ready
AMS就绪
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
t.traceEnd();
EventLog.writeBootProgressAmsReady(SystemClock.uptimeMillis());
}
trace

10.boot_progress_enable_screen
AMS启动完成后开始激活屏幕,从此以后屏幕才能响应用户的触摸,它在WindowManagerService发出退出开机动画的时间节点之前
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public void enableScreenAfterBoot(boolean booted) {
writeBootProgressEnableScreen(SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
synchronized (mGlobalLock) {
updateEventDispatchingLocked(booted);
}
}
11.sf_stop_bootanim
SF设置service.bootanim.exit属性值为1,标志系统要结束开机动画了
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::bootFinished()
{
property_set("service.bootanim.exit", "1");
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
12.wm_boot_animation_done
开机动画结束,这一步用户能直观感受到开机结束
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen() {
EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim");
}
可以将测试机与对比机抓取的此log数据制作成表格,制作成折线图,可以更加直观的观察到耗时异常的流程。

二、开机日志抓取
不同厂商可能暗码进入MTKLog的方式不同,打开MTKLog之后,重启手机,等开机后关闭Log
1、抓取流程:
MTKLog 拨号盘输入*#*#9646633#*#*-->EngineerMode-->log and Debugging-->DebugLoggerUI-->打开mobilelog-->重启-->停止抓取-->拉取adb pull /data/debuglogger
2、分析开机日志
Android的log系统是独立于Linux内核log系统的. Android系统把Log分为了四类,不同的类别记录不同的Log信息,默认通过logcat抓取的是main信息,开机日志主要看event.log跟kernel.log:
| Log名称 | 作用 | 获取命令 |
| system.log | 低级别的系统调试Log信息,包含CPU信息,大量系统服务输出的信息 | adb logcat –b system |
| main.log | 主要的Log信息,大部分应用级别的Log信息都在这里 | adb logcat –b main |
| event.log | 系统事件相关的Log信息,包含AMS与WMS输出的应用程序声明周期信息 | adb logcat –b event |
| kernel.log | 包含kernel打出的信息,LowMemoryKiller杀进程、内存碎片化或内存不足,mmc驱动异常都可以在这里找到。 | mtk log抓取 |
3、日志地址
抓取成功后有个boot_normal文件夹,开机过程跟开机结束后Log是分开的,在boot过程可以看到里面有相应过程的Log,如下所示:
1.APLog_2023_0814_135856__4

2.boot__normal

4、查看是否第一次开机
persist.sys.device_provisioned开机向导是否完成
persist.sys.device_first_boot是否第一次开机
三、开机trace抓取
1、MTK 平台
mtk 平台抓取开机 trace 可以不改代码,只需要 user root 版本即可
抓取非首次开机信息,需要 root 权限
1. 打开 google systrace: adb shell setprop persist.traced.enable 1
2.打开 mtk systrace工具设置: adb shell setprop persist.vendor.boot_trace 1
3.联网对时,普通重启两次,再打开 开机 log(#80#-其它-重启)
4.锁屏出现后,adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace,抓取trace
5.adb pull /data/local/tmp/boot_trace,关闭 log,导出log(/storage/ermulated/0/Android/data/com.oplus.logkit/files/Log 目录下对应时间1og)
注意:需要抓取init阶段的 trace需要修改对应项目的代码修改完代码跟高通抓取一样,需要验证代码之类的
打开抓取的开机trace如下所示:

如以上方式抓取不了,则需要在代码中修改:
2、代码修改
在 frameworks/native/cmds/atrace/atrace.rc 中,更改以下行:
write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
更改为:
#write /sys/kernel/debug/tracing/tracing_on 0 #write /sys/kernel/tracing/tracing_on 0
这将启用跟踪功能(默认处于停用状态)。
在 device.mk 文件中,添加以下行:
PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
在设备 BoardConfig.mk 文件中,添加以下行:
BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
如果是详细的 I/O 分析,还要添加块以及 ext4 和 f2fs。
在设备专属 init.rc 文件中,添加以下行:
on property:sys.boot_completed=1 // This stops tracing on boot complete write /d/tracing/tracing_on 0 write /d/tracing/events/ext4/enable 0 write /d/tracing/events/f2fs/enable 0 write /d/tracing/events/block/enable 0
在设备启动后,提取跟踪记录:
adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
adb pull /data/local/tmp/boot_trace
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
四、 开机速度优化实践
在Android S升级Android T的过程中,同一个项目的手机,在升级Android T之后,比之前的开机时间大概要多18秒左右。
首先在手机开机之后,查看boot_progress相关日志如下
07-15 04:13:35.244 I/boot_progress_start( 1059): 4040 07-15 04:13:35.934 I/boot_progress_preload_start( 1059): 4730 07-15 04:13:37.255 I/boot_progress_preload_end( 1059): 6051 07-15 04:13:37.636 I/boot_progress_system_run( 2221): 6432 07-15 04:13:38.260 I/boot_progress_pms_start( 2221): 7056 07-15 04:13:38.473 I/boot_progress_pms_system_scan_start( 2221): 7269 07-15 04:13:38.797 I/boot_progress_pms_data_scan_start( 2221): 7593 07-15 04:13:38.803 I/boot_progress_pms_scan_end( 2221): 7599 07-15 04:13:38.894 I/boot_progress_pms_ready( 2221): 7690 07-15 04:13:58.006 I/boot_progress_ams_ready( 2221): 26802 07-15 04:13:59.164 I/boot_progress_enable_screen( 2221): 27960
发现,在boot_progress_pms_ready到boot_progress_ams_ready之间,耗时近20秒,严重超时。
确定了大体的耗时异常点之后,我们抓取boottrace再进行进一步的分析。
由于PMS和AMS服务军运行再SystemServer进程当中,所以我们重点关注SystemServer进程的运行情况。

查看trace文件发现,主要是因为在启动AudioService的时候耗时较长。startService相关的日志也表明了这一点。

可见,启动AudioService耗时15.5秒左右。通过在AudioService相关的代码里面添加log,最终定位到为AudioService驱动在Android T上的问题。转交Audio模块处理之后,开机时间正常。
谷歌官方开机优化资料
https://source.android.com/devices/tech/perf/boot-times
五、开机时间拆解澄清
1、平台信息
| 项目信息 | 测试机 | 对比机1 | 对比机2 |
| Android版本 | 13 | 12 | 13 |
| 硬件平台 | mt6769 | mt6769 | mt6769 |
| 内存 | 4+128 | 4+128 | 4+128 |
| 网络制式 | LTE | WIFI | LTE |
2、测试差异
| 测试机 | 对比机1 | 差值 | |
| 开机时间 | 25.294s | 26.243s | -1s |
| 测试机 | 对比机2 | 差值 | |
| 开机时间 | 23.57s | 23.97s | -0.4s |
3、开机各阶段时间拆解
| prloader->kernel启动阶段 | 测试机(ms) | 对比机1(ms) | 差值(ms) |
| prloader | 1173 | 1099 | 74 |
| bl2_ext | 1233 | 1041 | 192 |
| lk | 1556 | 1555 | 1 |
| 阶段 | 测试机(ms) | 对比机1(ms) | 差值(ms) |
| boot_progress_start | 7504 | 7135 | |
| 1601 | 1347 | 254 | |
| boot_progress_preload_start | 9105 | 8482 | |
| 1756 | 1597 | 159 | |
| boot_progress_preload_end | 10861 | 10079 | |
| 832 | 1904 | -1072 | |
| boot_progress_system_run | 11693 | 11983 | |
| 1422 | 938 | 484 | |
| boot_progress_pms_start | 13115 | 12921 | |
| 322 | 280 | 42 | |
| boot_progress_pms_system_scan_start | 13437 | 13201 | |
| 702 | 886 | -184 | |
| boot_progress_pms_data_scan_start | 14139 | 14087 | |
| 113 | 268 | -155 | |
| boot_progress_pms_scan_end | 14252 | 14355 | |
| 181 | 227 | --46 | |
| boot_progress_pms_ready | 1443 | 14582 | |
| 2484 | 2597 | -113 | |
| boot_progress_ams_ready | 16917 | 17179 | |
| 3104 | 4268 | -1164 | |
| boot_progress_enable_screen | 20021 | 21447 | |
| 2545 | 2214 | 331 | |
| sf_stop_bootanim | 22566 | 23661 | -1095 |
对boot_progress_system_run->boot_progress_pms_start各阶段进一步拆解,各阶段耗时无异常
从拆解表查看,各阶段耗时无异常,Android13相比Android12,Preload classes较多,开机多耗时400ms左右
4、结论:
从分解结果看,测试机优于对比机,各阶段耗时正常,因为平台能力,达不到标准,予以澄清说明。
优化措施汇总:
1.解决开机时mtkcam-devicemgr:initialze一直在后台运行影响开机时间
2.优化lcd初始化时延
六、总结
1.先对开机时间进行拆解,然后根据差异大的过程进行拆解分析
2.MTK平台可以直接看 bootprof文件,查看整个开机时间以及对应做的事件
3.如果是preloader、lk、kernel阶段的耗时需要跟BSP确认
4.折解开机 log在event和 kemel里面获取对应时间
5.可以在Log里面搜索一些关键词(took duration)因为 Android是多进程有些in background即使消耗时间也可能不会影响开机时间




![Java并发编程(六)线程池[Executor体系]](https://img-blog.csdnimg.cn/c949d95312e44bc99e8a0d016a79a218.png)











![[PyTorch][chapter 50][创建自己的数据集 2]](https://img-blog.csdnimg.cn/b28ab32903b142b8ac5f78fb0ea35d87.png)

