Android13 开机时间优化

前言

在实际应用场景中,特定领域对 Android 系统的启动时间有着极为严苛的要求,车载领域便是典型代表。想象一下,当车辆已经行驶出数公里之遥,车内的信息娱乐系统(IVI)却仍未完成启动,这无疑会给用户带来极大的不便与尴尬体验。因此,对 Android 启动时间进行优化,成为了一项极具重要性与紧迫性的工作。

本文将紧密结合笔者在相关领域的实际工作经验,深入且详尽地阐述与 Android 开机时间相关的各项内容。需要特别说明的是,本文所涉及的技术探讨与案例分析均基于 Android 13 版本展开,旨在为从事相关工作的技术人员提供具有针对性和实用性的参考与指导。

开机时间检测方法

logcat

当用户长按电源键启动设备后,需等待系统完成一系列初始化流程,其中包括 adb 进程的启动。通常,在屏幕出现 "Android" 字样这一标志性界面后,表明系统已初步完成关键启动阶段。此时,可执行以下命令来抓取开机过程中的 logcat 日志,以便后续分析启动性能及排查潜在问题:

shell 复制代码
adb logcat -b all > logcat.txt

打开logcat.txt,搜索logcat关键字 "boot_progress"、"sf_stop_bootanim"、"wm_boot_animation_done"

或者直接执行以下命令过滤logcat

shell 复制代码
adb logcat -b events | grep -E "boot_progress|sf_stop_bootanim|wm_boot_animation_done"

以下是对 Android 系统启动各阶段耗时的详细分析。通过相关数据监测,我们可以清晰地看到整个开机流程的总耗时情况:此次开机过程共计耗时 23.283 秒。在这段开机时长中,从用户按下电源键(power 键)开始,到系统完成关键进程 zygote 的启动,这一阶段耗时 7.646 秒。接下来,对各个启动阶段进行具体解释:

启动阶段 说明
boot_progress_start Linux kernel启动到Zygote进程启动的时间,包含从kernel启动到Init启动Zygote的时间
boot_progress_preload_start ART虚拟机启动耗时/Zygote开始启动
boot_progress_preload_end 虚拟机资源装载耗时/Zygote启动结束
boot_progress_system_run System Server进程启动耗时
boot_progress_pms_start Android一些在PMS前需要启动服务的启动耗时,package scan开始
boot_progress_pms_system_scan_start system目录开始scan时间点
boot_progress_pms_data_scan_start data目录开始scan时间点/system目录扫描耗时
boot_progress_pms_scan_end 扫描结束时间点/data目录扫描耗时
boot_progress_pms_ready PMS启动扫描包耗时
boot_progress_ams_ready PMS后的系统服务启动时间
boot_progress_enable_screen AMS启动完成后开始激活屏幕
sf_stop_bootanim surfaceflinger结束开机动画
wm_boot_animation_done 从enable_screen到animation_done包含壁纸和keyguard的绘制时间

需要特别留意的是,logcat 日志工具主要用于捕获和显示 Android 系统上层(应用层及框架层)运行过程中的日志信息。也就是说,当 zygote 进程成功启动后,系统进入上层框架及应用的初始化阶段,此时通过 logcat 可以记录并查看这一阶段的详细日志。然而,在开机过程中,kernel 层(内核层)的启动和初始化发生在 zygote 启动之前,这一阶段的耗时情况无法通过 logcat 直接观察和分析。kernel 层的启动涉及硬件驱动加载、内存管理初始化、进程调度机制建立等关键操作,其耗时对整体开机性能有着重要影响,但需要借助其他工具或方法来获取和分析这部分的耗时数据。

串口log和kernel log
  • 串口log可以使用串口线连接Android设备和PC,使用串口工具抓取log,常用的串口工具有很多,xshell、MobaXterm等。
  • kernel log是在开机后执行如下命令抓取:
shell 复制代码
adb shell dmesg > dmesg.txt

log里面搜关键字 "KPI" 、"first stage" 、"second stage" ,此关键字为kernel的各个启动阶段。

uart log和kernel log都可以显示整个开机过程时间。

左侧为启动时间轴,右侧为启动log。

bootchart

Bootchart 是一款专为 Linux 系统启动过程性能分析而设计的开源工具软件。在系统启动期间,它能够自动且全面地收集关键数据,涵盖 CPU 占用率、磁盘吞吐率以及进程的详细信息等。收集完数据后,Bootchart 会以直观的图形化方式呈现分析结果。这种可视化展示极大地方便了用户,使他们无需深入钻研复杂的底层数据,就能轻松理解系统启动过程中的各项情况。

借助 Bootchart,用户可以极为直观地查看系统启动的完整流程,以及每个具体阶段所耗费的时间。基于这些清晰呈现的信息,用户能够深入剖析启动过程中的各个环节,精准定位可能存在的性能瓶颈或低效环节。进而,用户可以依据分析结果,有针对性地对系统启动过程进行优化,有效减少不必要的耗时操作,最终达到提高系统启动时间的目的。

  • 安装bootchart

Ubuntu16.04和18.04可通过一下命令安装

shell 复制代码
sudo apt-get install bootchart
sudo apt-get install pybootchartgui 

Ubuntu20.04上无法定位pybootchartgui

这时可以手动下载,然后放到python编译器搜寻的目录下。

下载地址:github.com/xrmx/bootchart/releases

下载好后解压

shell 复制代码
tar -zxvf bootchart-0.14.9.tar.gz

得到目录bootchart-0.14.9,进入到该目录

将图中的pybootchartgui 目录复制到 /usr/lib/python3.8/ 目录下

shell 复制代码
sudo cp -r /usr/lib/python3.8/bootchart-0.14.9/pybootchartgui/ /usr/lib/python3.8/

/usr/lib/python3.8/ 是python编译器搜寻的目录之一,完整的搜寻目录列表可通过以下命令查看

shell 复制代码
python3 -c "import sys;print(sys.path)"

因此,在实际操作中,我们可以将 pybootchartgui 目录复制到上述任意一个 Python 编译器能够搜索到的路径中。只要确保该目录在 Python 的模块搜索路径范围内,工具就能被正确调用。

不过,在完成复制操作后,有一个关键细节需要特别注意:必须将目录中的 main.py.in 文件重命名为 main.py。如果忽略这一步骤,运行工具时将会遇到错误提示。这一问题已在 GitHub 的 相关 issue中被提及和讨论,开发者可以通过查阅该 issue 了解更详细的问题背景和解决方案。重命名文件后,工具即可正常运行,为系统启动性能分析提供有力支持。

重命名命令

shell 复制代码
sudo mv /usr/lib/python3.8/pybootchartgui/main.py.in /usr/lib/python3.8/pybootchartgui/main.py

最后,我们需要将 bootchart 和 pybootchartgui 这两个文件复制到系统的 /usr/bin/ 目录下(相关文件可参考文末说明)。值得注意的是,这两个文件实际上是等效的,即它们具备相同的功能。这意味着,无论你是通过执行 bootchart 命令,还是 pybootchartgui 命令,最终都能成功生成 bootchart.png 这一可视化图表,用于分析系统启动过程。这样的设计为用户提供了更多的操作灵活性,方便根据个人习惯或实际需求选择合适的命令来执行任务。

生成bootchart.png开机图
  • 准备userdebug或者userroot设备
  • 开启bootchart
shell 复制代码
adb root 
adb shell
touch /data/bootchart/ enabled
  • 检查是否生成了enabled
shell 复制代码
# ls /data/bootchart/
enabled
  • 重启设备
shell 复制代码
adb reboot
  • 等待开机进入Launcher,查看 /data/bootchart/ 下是否有生成header文件,即bootchart日志是否生成
shell 复制代码
adb root
adb shell
ls /data/bootchart/
  • 拷贝 /data/bootchart/ 下的 4 个文件到本地
shell 复制代码
proc_diskstats.log
proc_ps.log
proc_stat.log
header
 
# Pull指令:
adb pull /data/bootchart/
  • 进入到 bootchart 目录(刚刚 pull 的文件夹),执行指令将这 4 个文件打包起来(在 bootchart 目录中打开终端)
shell 复制代码
tar -czf bootchart.tgz *
  • 执行指令,生成 bootchart.png 文件(./指代当前目录)
shell 复制代码
bootchart ./ bootchart.tgz
  • 拷贝 bootchart.png 到你需要的地方,双击查看
bootchart.png示例图

Bootchart 图能够以极为直观的可视化形式,清晰呈现整个开机过程中各个关键时间节点,让用户一目了然地了解系统从启动到完成初始化的各个阶段。同时,它还能精准展示 CPU 的使用率波动情况,以及磁盘在不同阶段的读写负载变化,帮助用户全面掌握系统启动期间的资源消耗状况,为深入分析和优化开机性能提供有力的数据支撑。

  • bootchart.png讲解

第一行:时间

第二行:Linux版本

第三行:odm release fingerprint

第三行:cpu架构

第四行:kernel配置选项

第五行:开机耗时

开机过程中,CPU的使用率、I/O状态、磁盘吞吐量、磁盘使用率

第一行:代表整个机器开机的时间,每一格代表1秒

第二行:代表init从长格子开始的位置开始启动

最后一行:开始zygote的启动,后面就是java 世界:system_server及app进程

kernel相关的启动部分,启动时间看下init什么时候启动的就知道了。

影响开机时间的Android启动流程

开机框架

引用Gityuan大佬的一张开机流程图

Android启动流程大体为:BootRom -> BootLoader -> Kernel -> Init -> Zygote -> SystemServer ->Launcher

Loader层
  • Boot ROM

当用户按下电源键后,设备的启动流程正式开始。此时,引导芯片(Boot ROM)中的固化代码会被激活,并从预定义的存储位置(通常是只读存储器 ROM)开始执行。这段初始代码负责完成最基本的硬件初始化工作,例如对 CPU、内存控制器等关键硬件进行自检和配置。随后,引导芯片会将存储设备中的引导程序(Bootloader)加载到系统内存(RAM)中,并跳转到该程序的入口点以执行后续操作。这一阶段是系统启动的基石,确保了硬件环境能够正确支持后续操作系统的加载与运行。

  • Boot Loader

此引导程序处于 Android 系统启动流程的前期阶段,承担着至关重要的基础初始化任务。它首先会对外部 RAM 进行全面检测,确保内存硬件能够正常工作且满足系统后续运行的容量需求。在此基础上,该引导程序会进一步执行网络参数配置、内存管理策略设置以及各类硬件参数的初始化工作,为 Android 操作系统的加载与稳定运行构建起可靠的硬件环境基础。

Kernel层

Kernel层是指Android内核层,到这里才刚刚开始进入Android系统。

  • 启动swapper进程(pid=0),该进程又称为idle进程,,系统初始化过程Kernel由无到有开创的第一个进程,,用于初始化进程管理、内存管理,加载Display、Camera Driver、Binder Driver等相关工作(图中kernel层蓝色区块)。
  • 启动kthreadd进程(pid=2),是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等一系列内核守护进程。kthreadd进程是所有内核进程的父进程。

Linux内核加载主要包括初始化kernel核心(内存初始化,打开中断,初始化进程表等)、初始化驱动、启动内核后台(daemons)线程、安装根(root)文件系统等。后续启动第一个用户级进程init(pid=1)。

Native层

Native层主要包括启动init进程(Android的第一个用户空间进程)、HAL层(硬件抽象层)以及开机动画等。init进程是所有用户进程的鼻祖。同时init进程也会孵化一系列用户进程,还会启动关键的服务以及孵化Zygote进程。

  • init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程。
  • init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务。
  • init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程,Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。
Framework层

Framework层分为Java frameword和C++ framework,分别由system_server进程和media_server进程负责启动和管理。

zygote本身是一个native的应用程序,刚开始的名字为"app_process",运行过程中,通过系统调用将自己名字改为zygote。在上图中的红色线,便是zygote fork出来的进程,所有的app进程都是由zygote fork产生的。

下面列举Zygote进程孵化的部分子进程:

进程名 解释
system_server Java framework的各种service都依赖此进程
com.android.phone 电话应用进程
android.process.acore 通讯录进程
android.process.media 多媒体应用进程
com.android.settings 设置进程
com.android.wifi wifi应用进程
  • zygote进程

由init进程通过解析init.rc文件后fork生成的,Zygote进程主要包含:

  • 加载ZygoteInit类,注册Zygote Socket服务端套接字
  • 加载虚拟机
  • preloadClasses
  • preloadResouces
  • system_server进程

由zygote进程fork而来,system_server是zygote孵化的第一个进程,system_server负责启动和管理整个java framework,包含ActivityManager、PowerManager等服务。

  • media_server进程

由init进程fork而来,负责启动和管理整个C++ framework,包含SurfaceFlinger、AudioFlinger、Camera Service等服务。

app层
  • zygote进程孵化出的第一个app进程是Launcher,这是用户看到的桌面app。
  • zygote进程还会创建Browser,Phone,Email等app进程,每个app至少运行在一个进程上。
  • 所有的app进程都是由zygote进程fork生成的。

具体的启动过程,此文不便详述,都是代码分析,复杂且枯燥。

开机时间优化方案

以下均为framework层的优化,kernel层优化不在研究范围。

精简方向

精简初始化脚本:减少开机时的初始化时间。

高通平台关注以下.rc & .sh文件:

复制代码
init.rc  
init.target.rc  
init.qcom.rc  
init.sh
init.qcom.sh  
init.qcom.post_boot.sh
裁剪方向

移除非必须Apks、Features、Sensor等,减少PackageScan时间。

裁剪预置APK

针对具体应用场景,可以将没用的apk裁剪掉,比如automotive可以裁掉Launcher,因为automotive自带CarLauncher。

可通过如下命令查看设备中所有的apk:

shell 复制代码
adb shell pm list package -f

Android中的内置APK介绍见:Android主要应用和进程说明

裁剪方法:

diff 复制代码
diff --git /build/make/core/main.mk /build/make/core/main.mk
index a8f46c1..d9d507b 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1267,6 +1267,7 @@ define product-installed-files
   $(eval ### Filter out the overridden packages and executables before doing expansion) \
   $(eval _pif_overrides := $(call module-overrides,$(_pif_modules))) \
   $(eval _pif_modules := $(filter-out $(_pif_overrides), $(_pif_modules))) \
+  $(eval _pif_modules := $(filter-out $(modules_product_packages_remove), $(_pif_modules))) \
   $(eval _pif_modules := $(filter-out $(PRODUCT_PACKAGES_DEL), $(_pif_modules))) \
   $(eval ### Resolve the :32 :64 module name) \
   $(eval _pif_modules := $(sort $(call resolve-bitness-for-modules,TARGET,$(_pif_modules)))) \
@@ -1363,6 +1364,9 @@ else ifdef FULL_BUILD
	 endif
   endif
 
+  # App removal list
+  modules_product_packages_remove := $(PRODUCT_PACKAGES_REMOVE)
diff 复制代码
diff --git /build/make/core/product.mk /build/make/core/product.mk
index 90e960b..c556037 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -40,6 +40,9 @@ _product_list_vars += PRODUCT_PACKAGES_ENG
 _product_list_vars += PRODUCT_PACKAGES_TESTS
 _product_var_list += PRODUCT_PACKAGES_DEL
 
+# App removal list
+_product_list_vars+= PRODUCT_PACKAGES_REMOVE
+
 # The device that this product maps to.
 _product_single_value_vars += PRODUCT_DEVICE
 _product_single_value_vars += PRODUCT_MANUFACTURER
diff 复制代码
diff --git /device/qcom/{product}/{product}.mk /device/qcom/{product}/{product}.mk
index 163cac2..89a3078 100755
--- a/{product}.mk
+++ b/{product}.mk
@@ -60,6 +60,8 @@ PRODUCT_BUILD_USERDATA_IMAGE := true
+# App removal list
+PRODUCT_PACKAGES_REMOVE += \
+	Calendar \
+	Email \
+	SnapdragonMusic \
+	DeskClock \

注意: /device/qcom/{product}/{product}.mk 取决于厂商的产品名称

移除不需要的Features

针对具体应用场景,可以将没用的Features裁剪掉,比如automotive可以裁掉

可通过如下命令查看设备中所有的Features:

shell 复制代码
adb shell pm list features

裁剪方法:

diff 复制代码
diff --git /frameworks/native/data/etc/android.software.print.xml /frameworks/native/data/etc/android.software.print.xml
index 713a7f7..e76bb88 100644
--- /frameworks/native/data/etc/android.software.print.xml
+++ /frameworks/native/data/etc/android.software.print.xml
@@ -15,5 +15,5 @@
 -->
 
 <permissions>
-    <feature name="android.software.print" />
+<!--    <feature name="android.software.print" />-->
 </permissions>
禁用不需要的Sensors

针对具体应用场景,可以将没用的Sensor裁剪掉。

可通过如下命令查看设备中所有支持的Sensor:

shell 复制代码
adb shell dumpsys sensorservice
配置优化方向
优化PinnerService配置

PinnerService是用于锁定某些模块在内存中,避免这些模块被移出\移入内存从而提高程序的运行效率。优化目的是减少非首次开机启动Service的时间。

修改 /frameworks/base/core/res/res/values/config.xml ,添加如下配置:

xml 复制代码
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
... ...
   <!-- Default files to pin via Pinner Service -->
	<string-array translatable="false" name="config_defaultPinnerServiceFiles">
	 <item>"/system/framework/arm/boot-framework.art"</item>
	 <item>"/system/lib/libjavacrypto.so"</item>
	 <item>"/system/lib/libhidltransport.so"</item>
	 <item>"/system/framework/arm/boot-core-libart.oat"</item>
	 <item>"/system/framework/arm/boot-conscrypt.oat"</item>
	 <item>"/system/framework/arm/boot-core-libart.art"</item>
	 <item>"/system/framework/arm/boot-ext.art"</item>
	 <item>"/system/framework/arm/boot.art"</item>
	 <item>"/system/framework/arm/boot-framework.art"</item>
	</string-array>
... ...
 </resources>

注意:芯片商(例如高通)的代码可能会存在客制化,AOSP的位置可能会被覆盖,如果有,则以芯片商的代码为准。

使用32Bit程序

定义了32Bit的程序,机器在apk的使用及服务的申明都会有略微的精简,在设备启动时加载的资源会少,故加载时间会少。

修改方式:
/device/qcom/{product}/BoardConfig.mk

复制代码
TARGET_ARCH := arm
TARGET_ARCH_VARIANT := armv8-2a
TARGET_CPU_ABI := armeabi-v7a
TARGET_CPU_ABI2 := armeabi
TARGET_CPU_VARIANT := cortex-a9

#TARGET_2ND_ARCH := arm
#TARGET_2ND_ARCH_VARIANT := armv8-2a
#TARGET_2ND_CPU_ABI := armeabi-v7a
#TARGET_2ND_CPU_ABI2 := armeabi
#TARGET_2ND_CPU_VARIANT := cortex-a9

device/generic/art/armv8/armv8.mk

复制代码
# Force 32bits executables.
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote32
关闭默认开关

默认关闭功能开关,开机期间不再自动启动,加快开机进度。

主要修改 /frameworks/base/packages/SettingsProvider/res/values/defaults.xml

  • 1.关闭锁屏显示通知
xml 复制代码
     <!-- Default for Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
-    <integer name="def_lock_screen_show_notifications">1</integer>
+    <integer name="def_lock_screen_show_notifications">0</integer>
  • 2.关闭手势唤醒
xml 复制代码
     <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
-    <bool name="def_wake_gesture_enabled">true</bool>
+    <bool name="def_wake_gesture_enabled">false</bool>
  • 3.关闭双击唤醒
xml 复制代码
     <!-- Default state of tap to wake -->
-    <bool name="def_double_tap_to_wake">true</bool>
+    <bool name="def_double_tap_to_wake">false</bool>
  • 4.关闭充电振动
xml 复制代码
     <!-- Default for Settings.Secure.CHARGING_VIBRATION_ENABLED -->
-    <bool name="def_charging_vibration_enabled">true</bool>
+    <bool name="def_charging_vibration_enabled">false</bool>
  • 5.关闭充电提示音
xml 复制代码
     <!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED -->
-    <bool name="def_charging_sounds_enabled">true</bool>
+    <bool name="def_charging_sounds_enabled">false</bool>
  • 6.关闭蓝牙和wifi
xml 复制代码
<bool name="def_bluetooth_on">false</bool>
<bool name="def_wifi_display_on">false</bool>
  • 7.关闭自动旋转
xml 复制代码
<bool name="def_accelerometer_rotation">false</bool>
  • 8.关闭Wifi Debugging
xml 复制代码
<!-- Disable WiFi Debugging -->
<bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool>
删除开机动画

Animation的资源大小和播放时长一直是影响开机时间的重要因素之一,移除开机动画将有效地加快开机速度。

frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

cpp 复制代码
bool bootAnimationDisabled() {
	char value[PROPERTY_VALUE_MAX];
	//将获取结果改为1,则无法进入到开机动画流程中
	//property_get("debug.sf.nobootanimation", value, "0");
	property_get("debug.sf.nobootanimation", value, "1");
	if (atoi(value) > 0) {
		return true;
	}

	property_get("ro.boot.quiescent", value, "0");
	if (atoi(value) > 0) {
		// Only show the bootanimation for quiescent boots if this system property is set to enabled
		if (!property_get_bool("ro.bootanim.quiescent.enabled", false)) {
			return true;
		}
	}

	return false;
}
开机过程CPU满载

开机过程中让CPU火力全开,能有效减少开机时间

/device/qcom/common/rootdir/etc/init.qcom.rc

复制代码
 on early-init
+    write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu6/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor performance

注意:

  • init.qcom.rc是高通定制的init脚本,是开机时必然执行的。
  • 如果CPU原本就已经满载了,那么此修改则无效果。
  • 不同平台CPU的配置不尽相同。
移除SystemService

SystemServer进程启动后,会启动很多SystemService,根据实际场景,裁剪非必要的Service

frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
// Start services.
try {
	t.traceBegin("StartServices");
	startBootstrapServices(t);
	startCoreServices(t);
	startOtherServices(t);
	startApexServices(t);
} catch (Throwable ex) {
	Slog.e("System", "******************************************");
	Slog.e("System", "************ Failure starting system services", ex);
	throw ex;
} finally {
	t.traceEnd(); // StartServices
}

可裁剪的Service如下,仅供参考

复制代码
1.VibratorService          震动器服务  
2.ClipboardService         粘贴板服务  
3.FingerprintService       指纹  

4.BatteryService           电池服务,当电量不足时发广播  
5.AlarmManagerService      闹钟服务   
6.WallpaperManagerService  壁纸管理服务  
7.StatusBarManagerService  状态栏管理服务  

注意:

  • 从framework层的角度去看问题,我们会发现功能及服务的裁剪,是最直接、最有效地时间及空间优化方法,它可以做到时间与空间的两者兼顾。
  • 注意app与Service,Service与Service之间的耦合性,避免引起机器的异常,无法开机;
移除app源码

修改下面文件中的 PRODUCT_PACKAGES 字段的内容,将不需要的内置应用的名称删除,这样可以缩短 scan packages 的过程。

bash 复制代码
1.build/target/product/core.mk  
2.build/target/product/full_base.mk  
3.build/target/product/full_base_telephony.mk  
4.build/target/product/generic_no_telephony.mk  

同时,可以删除 /packages/apps/ 路径下不必要的 app 源码,这样可以缩短编译时间。

apk odex

apk odex优化就是以空间换时间,加快apk启动速度,缺点是会消耗内存。

/device/qcom/{product}/{product}.mk 加入 WITH_DEXPREOPT=true , 打开odex优化

Android.bp中添加

makefile 复制代码
android_app {
	dex_preopt: {
        enabled: true,
	},
}

Android.mk中添加

makefile 复制代码
LOCAL_DEX_PREOPT := true
PMS优化

Apk的扫描安装耗时是大头。通常采用多线程方案,针对Dir或者Dir中的package进行多线程扫描.

PMS多线程扫描apk,4线程改成8线程,注意,如果客户做了CPU绑核, Android所分配的CPU资源受到限制,导致改成8线程之后反向优化了。

frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java

java 复制代码
class ParallelPackageParser {

	private static final int QUEUE_CAPACITY = 30;
//    private static final int MAX_THREADS = 4;
	private static final int MAX_THREADS = 8;
	
	//省略部分代码
}
Zygote优化

Zygote主要是优化class和resource的预加载,可以减少部分不需要预加载的class和resource,具体优化哪些,根据实际需求来添加。

注意:并不是预加载越少越好,如果开机必须启动的进程所需要的class和resource在zygote阶段被优化了,那么也会在该进程自启动时也会去加载,这样优化就是无效的。

diff 复制代码
diff --git /frameworks/base/config/preloaded-classes /frameworks/base/config/preloaded-classes
index f2530519247..d6ac1e22e3f 100644
--- /frameworks/base/config/preloaded-classes
+++ /frameworks/base/config/preloaded-classes
@@ -806,7 +806,6 @@ android.app.VoiceInteractor$Request
 android.app.VoiceInteractor
 android.app.Vr2dDisplayProperties$1
 android.app.Vr2dDisplayProperties
-android.app.VrManager
 android.app.WaitResult$1
 android.app.WaitResult
 android.app.WallpaperColors$1
@@ -2471,12 +2470,6 @@ android.hardware.display.Time$1
 android.hardware.display.Time
 android.hardware.display.VirtualDisplayConfig$1
 android.hardware.display.VirtualDisplayConfig
-android.hardware.display.WifiDisplay$1
-android.hardware.display.WifiDisplay
-android.hardware.display.WifiDisplaySessionInfo$1
-android.hardware.display.WifiDisplaySessionInfo
-android.hardware.display.WifiDisplayStatus$1
-android.hardware.display.WifiDisplayStatus
 android.hardware.face.Face$1
 android.hardware.face.Face
 android.hardware.face.FaceManager$1
移除手势导航
diff 复制代码
diff --git /frameworks/base/packages/overlays/Android.mk /frameworks/base/packages/overlays/Android.mk
index 69641e69a9f..71f5fd00520 100644
--- /frameworks/base/packages/overlays/Android.mk
+++ /frameworks/base/packages/overlays/Android.mk
@@ -20,17 +20,8 @@ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_REQUIRED_MODULES := \
-	DisplayCutoutEmulationCornerOverlay \
-	DisplayCutoutEmulationDoubleOverlay \
-    DisplayCutoutEmulationHoleOverlay \
-	DisplayCutoutEmulationTallOverlay \
-	DisplayCutoutEmulationWaterfallOverlay \
	FontNotoSerifSourceOverlay \
	NavigationBarMode3ButtonOverlay \
-	NavigationBarModeGesturalOverlay \
-	NavigationBarModeGesturalOverlayNarrowBack \
-	NavigationBarModeGesturalOverlayWideBack \
-	NavigationBarModeGesturalOverlayExtraWideBack \
	preinstalled-packages-platform-overlays.xml
 
 include $(BUILD_PHONY_PACKAGE)
关闭壁纸服务

frameworks/base/core/res/res/values/config.xml

xml 复制代码
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
调整窗口动画渲染

frameworks/base/packages/SettingsProvider/res/values/defaults.xml

diff 复制代码
-    <fraction name="def_window_animation_scale">100%</fraction>
-    <fraction name="def_window_transition_scale">100%</fraction>
+    <fraction name="def_window_animation_scale">25%</fraction>
+    <fraction name="def_window_transition_scale">25%</fraction>

如果想关闭animaton,直接将数值改为0即可。

注意:芯片商可能会定制 defaults.xml ,所以在修改时请留意是否改全。

专项优化

针对实际项目,如果加了自定义的开机自启动项,那么可以抓trace,看看整个开机过程哪个启动项耗时较长

例如:

上图可以看到 avm_worker 存在耗时异常, 该进程为 android 侧的 360 环视功能, 可以找对应开发确认是否需要开机启动。

Google优化方案

详见:source.android.google.cn/docs/core/perf/boot-times?hl=zh-cn

实战总结

在 Android 开机时间优化中,Framework 层的优化空间有限。通过性能追踪工具可发现,单个系统服务的启动或大量 APK 的扫描,通常仅需几毫秒到几十毫秒。因此,即便关闭某些服务或裁剪部分 APK,优化效果也仅在毫秒级,难以察觉。不过,通过多种优化措施叠加,仍能累积出可见效果。相比之下,Kernel 层优化空间较大,优化幅度可达秒级。结合底层(Kernel)与上层(Framework)双向优化,最终可实现显著的开机提速效果。

bootchart安装包

链接: pan.baidu.com/s/1BKVd348fZV8xkYLj9hfTzA?pwd=253x 提取码: 253x

相关推荐
独自破碎E16 小时前
【BISHI9】田忌赛马
android·java·开发语言
代码s贝多芬的音符18 小时前
android 两个人脸对比 mlkit
android
darkb1rd20 小时前
五、PHP类型转换与类型安全
android·安全·php
gjxDaniel20 小时前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
csj5020 小时前
安卓基础之《(22)—高级控件(4)碎片Fragment》
android
峥嵘life21 小时前
Android16 【CTS】CtsMediaCodecTestCases等一些列Media测试存在Failed项
android·linux·学习
stevenzqzq21 小时前
Compose 中的状态可变性体系
android·compose
似霰1 天前
Linux timerfd 的基本使用
android·linux·c++
darling3311 天前
mysql 自动备份以及远程传输脚本,异地备份
android·数据库·mysql·adb
你刷碗1 天前
基于S32K144 CESc生成随机数
android·java·数据库