https://source.android.com/devices/tech/perf/boot-times
优化启动时间 | Android 开源项目 | Android Open Source Project (google.cn)
本文档提供了有关改进特定 Android 设备的启动时间的合作伙伴指南。启动时间是系统性能的重要组成部分,因为用户必须等待启动完成后才能使用设备。对于较常进行冷启动的汽车等设备而言,较短的启动时间至关重要(没有人喜欢在等待几十秒后才能输入导航目的地)。
Android 8.0 支持一系列组件的多项改进,因而可以缩短启动时间。下表对这些性能改进(在 Google Pixel 和 Pixel XL 设备上测得)进行了总结。
组件 改进 引导加载程序
- 通过移除 UART 日志节省了 1.6 秒
- 通过从 GZIP 更改为 LZ4 节省了 0.4 秒
设备内核
- 通过移除不使用的内核配置和减少驱动程序大小节省了 0.3 秒
- 通过 dm-verity 预提取优化节省了 0.3 秒
- 通过移除驱动程序中不必要的等待/测试,节省了 0.15 秒
- 通过移除 CONFIG_CC_OPTIMIZE_FOR_SIZE,节省了 0.12 秒
I/O 调整
- 正常启动时间节省了 2 秒
- 首次启动时间节省了 25 秒
init.*.rc
- 通过并行运行 init 命令节省了 1.5 秒
- 通过及早启动 zygote 节省了 0.25 秒
- 通过 cpuset 调整节省了 0.22 秒
启动动画
- 在未触发 fsck 的情况下,启动动画的开始时间提前了 2 秒,而触发 fsck 时启动动画则大得多
- 通过立即关闭启动动画在 Pixel XL 上节省了 5 秒
SELinux 政策 通过 genfscon 节省了 0.2 秒 优化引导加载程序
请遵循以下做法优化引导加载程序以缩短启动时间:
- 对于日志记录:
- 停止向 UART 写入日志,因为如果日志记录很多,可能需要很长时间来处理。(在 Google Pixel 设备上,我们发现这会使引导加载程序的速度减慢 1.5 秒)。
- 仅记录错误情况,并考虑将其他信息存储到具有单独检索机制的内存中。
- 对于内核解压缩,请考虑为当代硬件使用 LZ4 而非 GZIP(例如补丁)。请注意,不同的内核压缩选项具有不同的加载和解压缩时间,对于特定硬件,某些选项可能比其他选项更适合。
- 检查进入去抖动/特殊模式过程中是否有不必要的等待时间,并最大限度地减少此类时间。
- 将在引导加载程序中花费的启动时间以命令行的形式传递到内核。
- 检查 CPU 时钟并考虑内核加载和初始化 I/O 并行进行(需要多核支持)。
优化 I/O 效率
提高 I/O 效率对缩短启动时间来说至关重要,对任何不必要内容的读取都应推迟到启动之后再进行(在 Google Pixel 上,启动时大约要读取 1.2GB 的数据)。
调整文件系统
当从头开始读取某个文件或依序读取块时,预读的 Linux 内核便会启动,这就需要调整专门用于启动的 I/O 调度程序参数(与普通应用的工作负载特性不同)。
支持无缝 (A/B) 更新的设备在首次启动时会极大地受益于文件系统调整(例如,Google Pixel 的启动时间缩短了 20 秒)。例如,我们为 Google Pixel 调整了以下参数:
on late-fs # boot time fs tune # boot time fs tune # 关闭了硬盘的统计记录功能,有助于减少开机的延迟 write /sys/block/sda/queue/iostats 0 # 将磁盘调度器设置为CFQ(Completely Fair Queueing),公平的磁盘I/O调度算法,试图平衡所有进程的磁盘访问 write /sys/block/sda/queue/scheduler cfq #关闭了磁盘休眠功能,磁盘在空闲时不会进入低功耗模式 write /sys/block/sda/queue/iosched/slice_idle 0 #预读取值为2048KB,磁盘驱动器会在每次读取操作时预先读取2048KB的数据,以提高后续读取操作的性能 write /sys/block/sda/queue/read_ahead_kb 2048 #磁盘请求队列管理着对磁盘的I/O请求。当一个应用程序请求数据时,这个请求会被加入到队列中。磁盘控制器会按照某种策略(比如CFQ)来处理这些请求,nr_requests 参数决定了队列中可以同时存储的最大请求数量, 这个数跟硬件相关,要在实践中调整 write /sys/block/sda/queue/nr_requests 256 #映射设备预读取值也相应的改为2048KB 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 #一旦系统启动完成,将读取ahead值减小到512KB,其他的也相应复原 write /sys/block/sda/queue/read_ahead_kb 512 ...其他
- 使用内核配置 DM_VERITY_HASH_PREFETCH_MIN_SIZE(默认大小为 128)来启用 dm-verity 哈希预提取大小。Verity模式是设备映射器的一种模式,它提供了数据完整性和校验和功能,通常用于映射加密或校验过的数据。在Verity模式下,数据块和校验和块是分离开的。校验和块包含了用于验证数据块完整性的信息。当系统读取数据时,设备映射器可以使用预取(prefetch)机制来提前加载数据块和相关的校验和块,以减少读取延迟。DM_VERITY_HASH_PREFETCH_MIN_SIZE 参数控制了预取的最小块大小,这意味着设备映射器至少会预取这么多大小的数据块和校验和块。这个参数的设置可能会影响系统的性能,特别是对于需要频繁读取小块数据的场景。如果设置得太小,可能会导致预取效率不高;如果设置得太大,可能会增加预取数据的大小,从而增加内存使用和潜在的延迟。
- 为了提升文件系统稳定性及取消每次启动时的强制检查,请在 BoardConfig.mk 中设置 TARGET_USES_MKE2FS,以使用新的 ext4 生成工具。在 ext4 文件系统中,日志记录(journaling)是一个关键特性,它确保了文件系统的原子性写操作和一致性。 ext4 的日志记录允许更新操作在写入磁盘之前被记录下来,如果系统在更新过程中发生故障,未写入磁盘的数据可以通过日志恢复。mke2fs 工具在创建 ext4 文件系统时,会根据指定的参数生成超级块和块组描述表,同时也会创建必要的日志文件(通常是 .journal 文件)。如果文件系统在创建时没有指定开启日志记录,那么这个 ext4 文件系统将是一个传统的 ext4 文件系统,不会包含日志文件,这种情况下,文件系统可能需要在每次启动时进行强制检查,以确保文件系统的完整性
分析 I/O
如需了解启动过程中的 I/O 活动,请使用内核 ftrace 数据(systrace 也使用这些数据):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE需要在系统启动时传递给内核,以便启用特定的 ftrace 事件跟踪。trace_event=block 表示跟踪块设备的 I/O 事件,而 ext4 指定了要跟踪的文件系统类型。BOARD_KERNEL_CMDLINE 是一个宏,它在板级配置文件BoardConfig.mk或BoardConfigCommon.mk中定义
如需针对每个文件细分文件访问权限,请对内核进行以下更改(仅限开发版内核;请勿在正式版内核中应用这些更改):
diff --git a/fs/open.c b/fs/open.c index 1651f35..a808093 100644 --- a/fs/open.c +++ b/fs/open.c @@ -981,6 +981,25 @@ } EXPORT_SYMBOL(file_open_root); +static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd) +{ + char *buf; + char *fname; + + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + fname = d_path(&filp-<f_path, buf, PAGE_SIZE); + + if (IS_ERR(fname)) + goto out; + + trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n", + current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino); +out: + kfree(buf); +} + long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; @@ -1003,6 +1022,7 @@ } else { fsnotify_open(f); fd_install(fd, f); + _trace_do_sys_open(f, flags, mode, fd);使用以下脚本来帮助分析启动性能。
system/extras/boottime_tools/bootanalyze/bootanalyze.py
:负责衡量启动时间,并详细分析启动过程中的重要步骤。system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
:提供每个文件的访问信息。检测启动过程中读取文件的速度,如果某个文件的读取速度远低于其他文件,则可能表明该文件所在的存储设备或文件系统存在性能问题。分析文件系统的读取模式,比如是否进行了大量的随机读取或顺序读取,以及是否发生了磁盘寻址的磨损。识别启动过程中读取耗时的文件,开发者可以定位系统启动的瓶颈,并采取措施优化,比如通过优化文件系统布局、使用更快的高速存储设备或改进文件加载策略。详细列出启动过程中每个文件的读取时间,以及可能影响启动速度的慢速 I/O 操作。system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
提供系统级细分信息。收集和分析系统启动过程中涉及的所有 I/O 操作,包括文件系统的读写操作、内存操作等。检测每个 I/O 操作的耗时,并识别出耗时较长的操作。分析 I/O 操作的模式,包括操作的频率、大小和访问类型(例如顺序访问与随机访问), 有助于理解文件系统的性能特征和潜在问题。生成一个报告,列出所有检测到的 I/O 操作,包括操作的类型、耗时、涉及的文件或内存区域等。优化 init.*.rc
Init 是从内核到框架建立之前的衔接过程,设备通常会在不同的 init 阶段花费几秒钟时间。
并行运行任务
虽然当前的 Android init 差不多算是一种单线程进程,但您仍然可以并行执行一些任务。
- 在 Shell 脚本服务中执行缓慢命令,然后通过等待特定属性,在稍后加入。Android 8.0 通过新的
wait_for_property
命令支持该用例。- 识别 init 中的缓慢操作。系统会记录 init 命令 exec/wait_for_prop 或任何所需时间较长的操作(在 Android 8.0 中,指所需时间超过 50 毫秒的任何命令)。例如:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms查看此日志可能会发现可以改进的机会。
- 启动服务并及早启用关键路径中的外围设备。例如,有些 SOC 需要先启动安全相关服务,然后再启动 SurfaceFlinger。在 ServiceManager 返回“wait for service”(等待服务)时查看系统日志 - 这通常表明必须先启动依赖服务。
- 移除 init.*.rc 中所有未使用的服务和命令。只要是早期阶段的 init 中没有使用的服务和命令,都应推迟到启动完成后再使用。
注意:“属性”服务是 init 进程的一部分,因此,在启动期间调用
setproperty
可能会导致较长时间的延迟(如果 init 忙于执行内置命令)。尽量将 setproperty 调用放在 init 进程完成主要初始化工作之后进行;只有必要的属性才应该在启动期间设置,以减少对 init 进程的干扰;让属性设置工作由专门的服务来处理;异步批量调用setproperty
使用调度程序调整
使用调度程序调整,以便及早启动设备。以下是取自 Google Pixel 的示例:
on init # boottime stune #系统在空闲时更倾向于使用低功耗模式 write /dev/stune/schedtune.prefer_idle 1 #调度器性能提升的级别为100,最大 write /dev/stune/schedtune.boost 100 on property:sys.boot_completed=1 # reset stune 启动结束后恢复 write /dev/stune/schedtune.prefer_idle 0 write /dev/stune/schedtune.boost 0 # or just disable EAS during boot 禁用了能量感知调度器(EAS),即开机时不考虑优化电源使用 on init write /sys/kernel/debug/sched_features NO_ENERGY_AWARE on property:sys.boot_completed=1 write /sys/kernel/debug/sched_features ENERGY_AWARE部分服务在启动过程中可能需要进行优先级提升。例如:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...及早启动 zygote
采用文件级加密的设备可以在 zygote-start 触发器的早期阶段启动 zygote(默认情况下,zygote 会在 main 类中启动,比 zygote-start 晚得多)。这样做时,请确保允许 zygote 在所有 CPU 中运行(因为错误的 cpuset 设置可能会强制 zygote 在特定 CPU 中运行)。
停用节电设置
在设备启动期间,可以停用 UFS 和/或 CPU 调节器等组件的节电设置。
请注意:为了提高效率,应在充电器模式下启用节电设置。
on init # Disable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0 write /sys/module/lpm_levels/parameters/sleep_disabled Y on property:sys.boot_completed=1 # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/module/lpm_levels/parameters/sleep_disabled N on charger # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/class/typec/port0/port_type sink write /sys/module/lpm_levels/parameters/sleep_disabled N推迟非关键初始化
非关键初始化(如 ZRAM)可以推迟到 boot_complete。
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}优化启动动画
请按照以下提示来优化启动动画。
配置为及早启动
Android 8.0 支持在装载 userdata 分区之前及早启动动画。然而,即使 Android 8.0 中使用了新的 ext4 工具链,系统也会出于安全原因定期触发 fsck,导致启动 bootanimation 服务时出现延迟。
为了使 bootanimation 及早启动,请将 fstab 装载分为以下两个阶段:
- 在早期阶段,仅装载不需要运行检查的分区(例如
system/
和vendor/
),然后启动启动动画服务及其依赖项(例如 servicemanager 和 surfaceflinger)。- 在第二个阶段,装载需要运行检查的分区(例如
data/
)。启动动画将会更快速地启动(且启动时间恒定),不受 fsck 影响。
在Android 8.0及更高版本中,文件系统检查(fsck)通常在设备启动时由内核根据预定的策略触发。Linux内核负责管理文件系统的完整性,并且会在检测到文件系统可能存在不一致的情况下自动运行fsck。
Android设备上的ext4文件系统(常见的移动设备文件系统类型)包含一个“挂载计数”机制。每次文件系统被挂载时,这个计数器会增加;当系统重启或关闭时,计数器会检查是否达到预设的阈值(例如,每n次挂载执行一次fsck)。如果满足条件,内核会在下一次启动时强制进行文件系统检查以确保其一致性。
此外,在特定情况下,如设备突然断电导致非正常关机后,内核在下次启动时也会默认运行fsck来修复可能存在的任何损坏。
具体的触发逻辑代码位置,它并不在Android系统的用户空间部分,而是在Linux内核的ext4文件系统驱动程序内部实现。相关的设置和配置参数可以在设备的启动脚本(比如init.rc等)中找到,实际的fsck调度逻辑则是在内核源码中定义和执行的。
以下是一个示例,展示了init.rc中用于挂载文件系统的部分内容:
on boot # 假设有一个ext4类型的/data分区 service fs_mount_data /system/bin/mount -t ext4 /dev/block/bootdevice/by-name/data /data -o defaults,discard,noatime,nofail class main user root group root critical onrestart write /sys/fs/some/path/reboot_reason "data_fs_mount_failure" # 在实际场景下,如果需要控制fsck,则可能通过fstab或类似机制设置
上述示例中的
/dev/block/bootdevice/by-name/data
是设备上的一个分区,当系统启动时,它会被挂载到/data
目录下。这里的“nofail”选项意味着即使文件系统存在错误也不会阻止启动过程,但是否进行fsck检查则由内核根据其内部策略决定。实际上,对于fsck的调度,通常是在Linux系统的
/etc/fstab
文件中配置的,而不是在init.rc里。在/etc/fstab
中,可以为每个分区指定一个fs_passno值,该值决定了在启动时哪个分区优先进行fsck检查。例如:/dev/block/bootdevice/by-name/data /data ext4 noatime 0 2
在这个fstab条目中,最后的数字"2"就是fs_passno,表示在启动时对这个文件系统进行第二次(相对较低优先级)的fsck检查。数字0代表跳过fsck,而1则是最高优先级,将在所有其他文件系统之前进行检查。
干净利落地结束
在收到退出信号后,bootanimation 会播放最后一部分,而这一部分的长度会延长启动时间。快速启动的系统不需要很长的动画,如果启动动画很长,在很大程度上就体现不出所做的任何改进。我们建议缩短循环播放和结尾的时间。
优化 SELinux
请按照以下提示优化 SELinux 以缩短启动时间。
- 使用简洁的正则表达式 (regex)。在为
file_contexts
中的sys/devices
匹配 SELinux 政策时,格式糟糕的正则表达式可能会导致大量开销。例如,正则表达式/sys/devices/.*abc.*(/.*)?
错误地强制扫描包含“abc”的所有/sys/devices
子目录,导致/sys/devices/abc
和/sys/devices/xyz/abc
都成为匹配项。如果将此正则表达式修正为/sys/devices/[^/]*abc[^/]*(/.*)?
,只有/sys/devices/abc
会成为匹配项。[^/]*
表示匹配零个或多个不包含斜杠/
的字符。这样就确保了"abc"前面不会有任何路径分隔符。abc
是要匹配的固定字符串。- 另一个
[^/]*
与第一个相同,确保"abc"后面也不会立即跟一个斜杠,从而避免匹配像/sys/devices/xyz/abc
这样的深层目录。(/.*)?
是一个可选的捕获组,它表示之后可以有一个斜杠/
和任意数量的其他字符。问号?
表示这部分零次或一次出现即可,这意味着它可以匹配到“abc”后面有无子目录的情况。- 将标签移动到 genfscon。这一现有的 SELinux 功能会将文件匹配前缀传递到 SELinux 二进制文件的内核中,而内核会将这些前缀应用于内核生成的文件系统。这也有助于修复错误标记的内核创建的文件,从而防止用户空间进程之间可能出现的竞态条件(试图在重新标记之前访问这些文件)。
工具和方法
请使用以下工具来帮助您收集用于优化目标的数据。
bootchart
bootchart 可为整个系统提供所有进程的 CPU 和 I/O 负载细分。该工具不需要重建系统映像,可以用作进入 systrace 之前的快速健全性检查。
如需启用 bootchart,请运行以下命令:
adb shell 'touch /data/bootchart/enabled'
adb reboot
在设备启动后,提取启动图表:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh完成后,请删除
如果 bootchart 不起作用,并且您看到说明/data/bootchart/enabled
以防止每次都收集日期数据。bootchart.png
不存在的错误消息,请执行以下操作:
- 运行以下命令:
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
- 更新
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
以指向pybootchartgui
的本地副本(位于~/Documents/bootchart/pybootchartgui.py
)Systrace
systrace 允许在启动期间收集内核和 Android 跟踪记录。systrace 的可视化可以帮助分析启动过程中的具体问题。(不过,如果要查看整个启动过程中的平均数量或累计数量,直接查看内核跟踪记录更为方便。)
如需在启动过程中启用 systrace,请执行以下操作:
这将启用跟踪功能(默认处于停用状态)。
如果是详细的 I/O 分析,还要添加块以及 ext4 和 f2fs。
- 在
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- 在设备专属
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
注意:Chrome 无法处理过大的文件。请考虑使用
tail
、head
或grep
分割boot_trace
文件,以获得必要的部分。由于事件过多,I/O 分析通常需要直接分析捕获的boot_trace
。
使用 tail 获取文件末尾的部分: 如果你对启动过程结束阶段的事件感兴趣,可以使用
tail
命令显示文件的最后几行或指定行数的内容。# 显示 boot_trace 文件最后100行 tail -n 100 boot_trace # 或者,如果想实时监控文件末尾的新内容(例如日志实时更新) tail -f boot_trace
使用 head 获取文件开头的部分: 如果你想查看启动过程初期的事件,可以使用
head
命令。# 显示 boot_trace 文件开始的100行 head -n 100 boot_trace
分割大文件: 如果需要对文件进行分割,可以使用split命令。这通常在文件太大,不适合使用文本编辑器查看时使用。例如:
split -l 1000 boot_trace boot_trace_
这将按行数分割boot_trace文件,每个输出文件将包含1000行,并以boot_trace_为前缀使用 grep 过滤包含特定关键词的行: 若要从文件中提取包含特定关键字的日志条目,可使用
grep
命令。# 提取包含 'I/O' 关键字的所有行 grep 'I/O' boot_trace # 或者只提取启动过程中与某个服务相关的行,比如名为 'systemd' 的服务 grep 'systemd' boot_trace # 若要仅显示匹配行及其前后各两行上下文 grep -C 2 'keyword' boot_trace
结合使用上述命令进行更精细的筛选: 如果要处理整个文件但仅针对某段时间窗口或者某些特定事件,可以组合这些命令。
# 举个例子,假设你知道你关注的是启动后5分钟内的 I/O 活动 # 假设 boot_trace 中每行前面都有一个时间戳格式为 [YYYY-MM-DD HH:MM:SS] # 首先找到这个时间窗口: start_time="2023-01-18 10:00:00" end_time="2023-01-18 10:05:00" # 然后用 awk 来过滤这个时间段内的行,并进一步通过 grep 查找 I/O 相关事件 awk -v s="$start_time" -v e="$end_time" '$0 >= s && $0 <= e' boot_trace | grep 'I/O' # 或者如果你知道时间戳在每一行的固定位置,可以用 sed 和 grep 结合: sed -n "/$start_time/,/$end_time/p" boot_trace | grep 'I/O'
[DESCRIPTION]
启动时间优化
从模块中剥离调试符号
请确保从模块中剥离调试符号,方法与在正式版设备上从内核中剥离调试符号类似。从模块中剥离调试符号有助于减少以下过程耗用的时间,从而缩短启动时间:
- 从闪存中读取二进制文件。
- 解压缩 ramdisk。
- 加载模块。
从模块中剥离调试符号可在启动过程中节省几秒钟时间。
在 Android 平台 build 中,符号剥离默认处于启用状态,但若要明确启用此功能,则需要在 device/vendor/device 下的设备专用 config 中设置
BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES
。对内核和 ramdisk 使用 LZ4 压缩
Gzip 生成的压缩输出比 LZ4 小,但 LZ4 的解压缩速度比 Gzip 快。对于内核和模块而言,使用 Gzip 减少的绝对存储大小相比使用 LZ4 节省的解压缩时间而言,并没有明显的优势。
Android 平台 build 已通过
BOARD_RAMDISK_USE_LZ4
添加了对 LZ4 ramdisk 压缩的支持。您可以在设备专用 config 中设置此选项。内核压缩可通过内核 defconfig 设置。切换到 LZ4 会使启动时间快 500 到 1000 毫秒。
避免在驱动程序中进行过多的日志记录
在 ARM64 和 ARM32 中,如果函数调用与调用点之间的距离超过了特定的距离,就需要借助跳转表(称为过程连接表或 PLT)才能对完整的跳转地址进行编码。由于模块是动态加载的,因此系统需要在模块加载期间对这些跳转表进行修复。需要重定位的调用称为重定位条目,带有 ELF 格式的显式加数(简称为 RELA)条目。
Linux 内核会在分配 PLT 时执行一些内存大小优化(例如缓存命中优化)。采用此上游提交时,优化方案的复杂度为 O(N^2),其中 N 代表
R_AARCH64_JUMP26
或R_AARCH64_CALL26
类型的 RELA 的数量。因此,减少这两种类型的 RELA 将有助于缩短模块加载时间。常见的会增加
R_AARCH64_CALL26
或R_AARCH64_JUMP26
RELA 数量的编码模式就是在驱动程序中进行过多的日志记录。通常,每次调用printk()
或任何其他日志记录方案都会添加一个CALL26
/JUMP26
RELA 条目。请注意,在上游提交的提交文本中,即使进行了优化,加载这六个模块也需要 250 毫秒左右,这是因为这六个模块是日志记录最多的前六个模块。减少日志记录可以节省约 100 - 300 毫秒的启动时间,具体取决于现有日志记录的过度程度。
选择性地启用异步探测
加载模块时,如果已从 DT(设备树)填充了模块所支持的设备并将其添加到了驱动程序核心中,则会在
module_init()
调用的上下文中完成设备探测。在module_init()
的上下文中完成设备探测时,模块加载要等到探测完成后才能完成。由于模块加载在很大程度上是序列化的,因此探测时间相对较长的设备会使启动变慢。为避免启动变慢,可以为需要花费一定时间来探测其设备的模块启用异步探测。为所有模块都启用异步探测可能没有好处,因为创建线程分支并启动探测所需的时间可能与探测设备所需的时间一样长。
通过慢总线(例如 I2C)连接的设备、在其探测功能中执行固件加载的设备,以及执行大量硬件初始化的设备都可能导致启动变慢。识别这种情况发生的最好办法就是收集每个驱动程序的探测时间并对其进行排序。其方法有
使用内核跟踪工具: Linux内核提供了
ftrace
等跟踪机制,可以用来分析整个系统范围内的函数调用和执行时间。例如,可以通过动态启用特定的probe函数跟踪点,收集所有驱动程序的探测时间。# 启用 probe 跟踪点(需要在内核编译时开启 ftrace 功能) echo function > /sys/kernel/debug/tracing/current_tracer echo my_driver_probe > /sys/kernel/debug/tracing/set_event # 重启系统以开始跟踪 reboot # 系统启动后,在适当的时间点停止追踪并查看结果 cat /sys/kernel/debug/tracing/trace
使用 BPF (Berkeley Packet Filter): 利用 eBPF 技术,编写一个用户态程序,通过加载 eBPF 程序到内核来监控特定的内核函数调用(如
device_add()
和driver_probe_done()
),并记录探测时间。BPF 可以实现细粒度的跟踪,并且不会显著影响系统性能。定制内核构建: 如果具备内核修改权限,可以在内核的设备模型层添加全局的探测时间统计功能,这样无需修改每个驱动的源码也能获得探测时间信息。不过这种方法需要对内核有较深的理解和一定的开发工作量。
启动日志分析: 分析系统的启动日志(dmesg 输出),虽然它可能不如直接测量探测时间准确,但可以根据驱动加载的顺序和时间戳粗略估计各驱动的探测耗时。
若要为模块启用异步探测,仅在驱动程序代码中设置 PROBE_PREFER_ASYNCHRONOUS 标志是不够的。对于模块,您还需要在内核命令行中添加
module_name.async_probe=1
,或者在使用modprobe
或insmod
加载模块时将async_probe=1
作为模块参数传递。举例:
kernel /boot/vmlinuz-linux root=/dev/sda1 ro module=module_name
.async_probe=1 ...modprobe module_name async_probe=1 insmod module_name.so async_probe=1
启用异步探测可以节省约 100 - 500 毫秒的启动时间,具体取决于您的硬件/驱动程序。
尽早探测 CPUfreq 驱动程序
越早探测 CPUfreq 驱动程序,有助于在启动过程中越早将 CPU 频率调节到最大值(或某些温度限制下的最大值)。CPU 越快,启动速度就越快。这条准则也适用于控制 DRAM、内存和互连频率的
devfreq
驱动程序。对于模块,加载顺序可能取决于驱动程序的
initcall
级别以及编译或连接顺序。请使用别名MODULE_SOFTDEP()
确保cpufreq
驱动程序是最先加载的几个模块之一。除了尽早加载模块之外,还需要确保要探测 CPUfreq 驱动程序的所有依赖项也已经探测。例如,如果您需要一个时钟或调节器句柄来控制 CPU 频率,请确保先对这二者进行探测。或者,如果 CPU 在启动过程中可能会变得过热,则可能需要先加载温度相关驱动程序,再加载 CPUfreq 驱动程序。因此,请尽量确保尽早探测 CPUfreq 和相关的 devfreq 驱动程序。
提早探测 CPUfreq 驱动程序带来的时间节省可能非常小,也可能非常大,具体取决于探测时间有多早以及引导加载程序让 CPU 处于的频率。
将模块移至第二阶段 init、vendor 或 vendor_dlkm 分区
由于第一阶段 init 过程是序列化的,因此并行化启动过程的机会并不多。如果一个模块在完成第一阶段 init 时用不到,请将模块放入 vendor 或
vendor_dlkm
分区,从而将其移至第二阶段 init。第一阶段 init 不需要探测多个设备才能进入第二阶段 init。正常启动流程只需要控制台和闪存功能。
加载以下基本驱动程序:
- watchdog
- reset
- cpufreq
对于恢复模式 (Recovery mode) 和用户空间
fastbootd
模式,第一阶段 init 需要探测和显示更多设备(例如 USB)。请在第一阶段 ramdisk 和 vendor 或vendor_dlkm
分区中保存这些模块的副本。这样一来,便可在第一阶段 init 中加载这些模块来执行恢复或fastbootd
启动流程。不过,在正常启动流程中,请勿在第一阶段 init 中加载恢复模式 (Recovery mode) 模块。恢复模式 (Recovery mode) 模块可以推迟到第二阶段 init 进行加载,以缩短启动时间。第一阶段 init 中不需要的所有其他模块都应移至 vendor 或vendor_dlkm
分区。给定一个叶设备(例如 UFS 或串行设备)列表,dev needs.sh 脚本会查找依赖项或提供方(例如,时钟、调节器或
gpio
)需要探测的所有驱动程序、设备和模块。将模块移至第二阶段 init 可通过以下方式缩短启动时间:
- 缩减 Ramdisk 大小。
- 这在引导加载程序加载 ramdisk(序列化启动步骤)时可以加快闪存读取速度。
- 这在内核解压缩 ramdisk(序列化启动步骤)时可以加快解压缩速度。
- 第二阶段 init 是并行运行的,模块加载与第二阶段 init 中的工作同步进行,因而可以省去单独加载模块的时间。
将模块移至第二阶段可以节省 500 - 1000 毫秒的启动时间,具体取决于可以将多少个模块移至第二阶段 init。
模块加载逻辑
最新的 Android build 具有板级配置,用于控制将哪些模块复制到每个阶段,以及加载哪些模块。本部分重点介绍以下子集:
BOARD_VENDOR_RAMDISK_KERNEL_MODULES
:要复制到 ramdisk 的模块列表。BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
:要在第一阶段 init 中加载的模块列表。BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD
:从 ramdisk 中选择 recovery 或fastbootd
时要加载的模块列表。BOARD_VENDOR_KERNEL_MODULES
:要复制到 vendor 或vendor_dlkm
分区中的/vendor/lib/modules/
目录下的模块列表。BOARD_VENDOR_KERNEL_MODULES_LOAD
:要在第二阶段 init 中加载的模块列表。ramdisk 中的启动和恢复模块也必须复制到 vendor 或
vendor_dlkm
分区中的/vendor/lib/modules
下。将这些模块复制到 vendor 分区,可以确保这些模块在第二阶段 init 过程中可见,这对于调试和为 bug 报告收集modinfo
很有用。只要尽量缩减启动模块集的大小,就可以最大限度地减少复制内容在 vendor 或
vendor_dlkm
分区中占用的空间。请确保供应商的modules.list
文件在/vendor/lib/modules
中提供经过过滤的模块列表,该列表可确保启动时间不会受到二次加载模块(这是一个成本高昂的过程)的影响。请确保将所有恢复模式 (Recovery mode) 模块作为一个组进行加载。加载恢复模式 (Recovery mode) 模块可以在恢复模式 (Recovery mode) 下完成,也可以在每个启动流程的第二阶段 init 开始时进行。
可以使用设备
Board.Config.mk
文件执行这些操作,如以下示例所示:# All kernel modules KERNEL_MODULES := $(wildcard $(KERNEL_MODULE_DIR)/*.ko) KERNEL_MODULES_LOAD := $(strip $(shell cat $(KERNEL_MODULE_DIR)/modules.load) # First stage ramdisk modules BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m)) # Recovery ramdisk modules RECOVERY_KERNEL_MODULES_FILTER := $(foreach m,$(RECOVERY_KERNEL_MODULES),%/$(m)) BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \ $(filter $(BOOT_KERNEL_MODULES_FILTER) \ $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES)) # ALL modules land in /vendor/lib/modules so they could be rmmod/insmod'd, # and modules.list actually limits us to the ones we intend to load. BOARD_VENDOR_KERNEL_MODULES := $(KERNEL_MODULES) # To limit /vendor/lib/modules to just the ones loaded, use: # BOARD_VENDOR_KERNEL_MODULES := $(filter-out \ # $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES)) # Group set of /vendor/lib/modules loading order to recovery modules first, # then remainder, subtracting both recovery and boot modules which are loaded # already. BOARD_VENDOR_KERNEL_MODULES_LOAD := \ $(filter-out $(BOOT_KERNEL_MODULES_FILTER), \ $(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))) BOARD_VENDOR_KERNEL_MODULES_LOAD += \ $(filter-out $(BOOT_KERNEL_MODULES_FILTER) \ $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)) # NB: Load order governed by modules.load and not by $(BOOT_KERNEL_MODULES) BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD := \ $(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)) # Group set of /vendor/lib/modules loading order to boot modules first, # then the remainder of recovery modules. BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD := \ $(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)) BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += \ $(filter-out $(BOOT_KERNEL_MODULES_FILTER), \ $(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
此示例展示了要在板级配置文件本地指定的
BOOT_KERNEL_MODULES
和RECOVERY_KERNEL_MODULES
的子集,这样会更易于管理。上述脚本会从所选的可用内核模块中查找并填充每个子集模块,而将其余的模块留到第二阶段 init。对于第二阶段 init,建议以服务的形式运行模块加载,以免它阻止启动流程。请使用 Shell 脚本来管理模块加载,以便在必要时可以报告(或忽略)其他逻辑,如错误处理和缓解,或模块加载完成。
可以忽略用户 build 中不存在的调试模块加载失败情况。如需忽略此失败情况,请设置
vendor.device.modules.ready
属性,使其触发init rc
脚本启动流程的后续阶段,以继续执行到启动屏幕。如果您在/vendor/etc/init.insmod.sh
中有以下代码,请参考以下脚本示例:#!/vendor/bin/sh . . . if [ $# -eq 1 ]; then cfg_file=$1 else # Set property even if there is no insmod config # to unblock early-boot trigger setprop vendor.common.modules.ready setprop vendor.device.modules.ready exit 1 fi if [ -f $cfg_file ]; then while IFS="|" read -r action arg do case $action in "insmod") insmod $arg ;; "setprop") setprop $arg 1 ;; "enable") echo 1 > $arg ;; "modprobe") modprobe -a -d /vendor/lib/modules $arg ;; . . . esac done < $cfg_file fi
在硬件 rc 文件中,可通过以下代码指定
one shot
服务:service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg class main user root group root system Disabled oneshot
在模块从第一阶段移至第二阶段后,可以进行其他优化。可以使用 modprobe blocklist 功能来拆分第二阶段启动流程,以纳入非必要模块的延迟模块加载。可以将特定 HAL 专用模块的加载推迟到相应 HAL 启动时才进行。
为了让用户明显感觉到启动时间的缩短,可以在模块加载服务中专门选择更适合在启动屏幕之后加载的模块。例如,可以将视频解码器模块或 Wi-Fi 模块明确推迟到 init 启动流程结束(例如,Android 属性信号
sys.boot_complete
)之后再加载。请确保延迟加载的模块所对应的 HAL 在内核驱动程序不存在的情况下阻塞足够长的时间。或者,也可以在启动流程的 rc 脚本中使用 init 的
wait<file>[<timeout>]
命令,以等待选定的sysfs
条目表明驱动程序模块已完成探测操作。例如,等待显示驱动程序在恢复或fastbootd
启动流程的后台完成加载,然后再显示菜单图形。在引导加载程序中将 CPU 频率初始化为合理的值
由于启动循环测试期间的温度或电源问题,并非所有 SoC/产品都能够以最高频率启动 CPU。但是,请确保引导加载程序在保证安全的前提下,为 SoC/产品的所有在线 CPU 设置尽可能高的频率。这一点非常重要,因为对于完全模块化的内核,init ramdisk 解压缩会在 CPUfreq 驱动程序加载之前进行。因此,如果引导加载程序将 CPU 频率保持在较低水平,ramdisk 解压缩的时间就可能会比静态编译内核还长(在针对 ramdisk 大小差异进行调整之后),因为在执行 CPU 密集型工作(解压缩)时,CPU 频率会非常低。此原则同样适用于内存/互连频率。
在引导加载程序中初始化大 CPU 的 CPU 频率
在加载
CPUfreq
驱动程序之前,内核不知道大小 CPU 各自的频率,因此不会根据当前频率调节 CPU 的调度容量。只要小 CPU 上的负载足够高,内核就会将线程迁移到大 CPU。因此,请确保引导加载程序为大小 CPU 设置的频率应使大 CPU 的性能至少不低于小 CPU。例如,如果在相同频率下,大 CPU 的性能是小 CPU 的 2 倍,但引导加载程序将小 CPU 的频率设置为 1.5 GHz,而将大 CPU 的频率设置为 300 MHz,那么当内核将线程移至大 CPU 时,启动性能就会下降。在本例中,如果以 750 MHz 的频率启动大 CPU 是安全的,那么即使您不打算明确使用该频率,也应这样做。
驱动程序不应在第一阶段 init 中加载固件
可能会有一些不可避免的情况,必须要在第一阶段 init 执行过程中加载固件。但一般而言,驱动程序不应在第一阶段 init 执行过程中加载任何固件,尤其是在设备探测上下文中。如果第一阶段 ramdisk 中没有固件,在第一阶段 init 中加载固件就会导致整个启动过程停滞。即使第一阶段 ramdisk 中有固件,也会导致不必要的延迟。
开关机、重启时间优化:
开机性能优化:是用功能和其它因素多方面平衡的结果,片面追求单方面的性能没有太大意义;
有些产品设计开机动画非常酷炫,动画图片过多、高帧率会影响开机速度,这时就需要看是开机速度优先还是体验优先;
[SOLUTION]
1.zygote,预加载class、resources;加载的多了,会影响开机时间;
/sdcard/mtklog/bootprof
12450.516490 : 860-system_server : Android:PMS_READY
13136.536031 : 506-main : Zygote:Preload 4715 classes in 495ms
13263.841416 : 506-main : Zygote:Preload 64 obtain resources in 42ms
13271.525031 : 506-main : Zygote:Preload 41 resources in 6ms
13639.574263 : 860-system_server : AMS:systemReady
13645.305493 : 860-system_server : AMS:AMS_READY
/frameworks/base/config/preloaded-classes,因为少加载类会影响APP启动速度,开机过程会涉及到APP启动,此地没有优化空间;
/frameworks/base/core/res/会被打包成:framework-res.apk,确保没有冗余的资源图片,可以挨个检查图片、XML是否在系统中有用到;
2.开机动画进程bootanimation或者mtkbootanimation,走android比走movie流程占用内存资源要少些,开机会快些,测试大概快上百毫秒;
开机动画分两种情况:
(1)播放mp3,需要等到mp3播放完动画才能退出,开机才能完成;所以mp3文件不能过长,最好不要超过system_server启动时间;
system_server启动时间查看如下:
/sdcard/mtklog/bootprof
10367.726870 : 860-system_server : Android:SysServerInit_START
……
14137.026648 : 860-system_server : Android:SysServerInit_END
(2)不播放mp3,不会影响开机时间;
bootanimation.zip中图片越少越好;
3.
不建议更改,修改风险较大,除非对开机速度有特别严苛的要求才修改:
/frameworks/base/services/java/com/android/server/SystemServer.java
比如:DropBoxManagerService和调试相关,可以异步加载或者直接阉割掉:
比如:PinnerService没有配置相关则可以去除;
其他Service可以挨个排查;
4.
system_server特定的服务导致开机变慢,比如:指纹系统;
非必要的服务可以放在system_server进程外启动;
5.kernel init 时间长,需要先看一下客户的版本上init.rc文件相对Driveronly版本是否有添加新的init,这些是否都是必须添加的。
在uartlog 中,需要查关键字-----[ cut here ]------------ ,找到在kernel init 过程中,频繁打出的这些call stack,看这些call stack,排查一下贵司所客制化的点。
6.在uartlog中排查驱动设备初始化是否有完成或延时较长
7.因为对apk进行dex2oat导致的开机慢问题确认
7.1、如果是刷机后第一次:
可以在sys_log.boot里面check 这两个log的时间,如果时间较长的话,就会有相关的dex的耗时,然后可以打开DEBUG_DEXOPT的log,进一步check是哪个apk在进行dex2oat
3364 01-01 00:01:17.923181 1008 1008 I SystemServer: UpdatePackagesIfNeeded
4825 01-01 00:01:28.833169 1008 1008 I SystemServer: PerformFstrimIfNeeded
7.2、非第一次开机log:
bootprof文件中包含PMS:performDexOpt,说明在编译时没有打开dex2oat选项;
/sdcard/mtklog/mobile/../bootprof
49643.453733 : 777-system_server : Android:PMS_READY
50662.038197 : 777-system_server : PMS:performDexOpt:com.mediatek.ims
50958.422582 : 434-main : Zygote:Preload 4715 classes in 957ms
51027.330659 : 777-system_server : PMS:performDexOpt:com.google.android.ext.services
51175.849890 : 434-main : Zygote:Preload 64 obtain resources in 89ms
51191.674429 : 434-main : Zygote:Preload 41 resources in 15ms
52011.623200 : 777-system_server : PMS:performDexOpt:com.android.providers.telephony
53090.475818 : 777-system_server : PMS:performDexOpt:com.valmul.defcontainer
53500.331742 : 777-system_server : PMS:performDexOpt:com.google.android.ext.shared
53759.386897 : 777-system_server : PMS:performDexOpt:com.figoglobal.gpsinitialization
55253.543054 : 777-system_server : PMS:performDexOpt:com.android.mms.service
55263.628131 : 777-system_server : PMS:performDexOpt:com.mediatek.wfo.impl
55270.579900 : 777-system_server : PMS:performDexOpt:com.android.defcontainer
55276.243746 : 777-system_server : PMS:performDexOpt:com.android.providers.settings
55278.248439 : 777-system_server : PMS:performDexOpt:com.android.inputdevices
55282.328746 : 777-system_server : PMS:performDexOpt:com.android.server.telecom
55294.016439 : 777-system_server : PMS:performDexOpt:com.android.dialer
55310.146285 : 777-system_server : PMS:performDexOpt:com.google.android.packageinstaller
56816.388981 : 777-system_server : PMS:performDexOpt:com.android.proxyhandler
56822.447212 : 777-system_server : PMS:performDexOpt:com.android.settings
56839.445365 : 777-system_server : PMS:performDexOpt:com.android.phone
56857.746212 : 777-system_server : PMS:performDexOpt:com.android.shell
56866.477442 : 777-system_server : PMS:performDexOpt:com.android.location.fused
56871.597365 : 777-system_server : PMS:performDexOpt:com.android.systemui
56890.546827 : 777-system_server : PMS:performDexOpt:com.mediatek.mtklogger
56902.493673 : 777-system_server : PMS:performDexOpt:com.mediatek.dataprotection
57298.609059 : 777-system_server : PMS:performDexOpt:com.google.android.inputmethod.latin
61557.196915 : 777-system_server : PMS:performDexOpt:com.android.fmradio
61565.777377 : 777-system_server : PMS:performDexOpt:com.mediatek.gba
61571.754300 : 777-system_server : PMS:performDexOpt:com.google.android.youtube
75712.856180 : 777-system_server : PMS:performDexOpt:com.google.android.googlequicksearchbox
99753.523929 : 777-system_server : PMS:performDexOpt:com.mediatek.camera
99774.462545 : 777-system_server : PMS:performDexOpt:com.android.providers.calendar
99784.232852 : 777-system_server : PMS:performDexOpt:com.android.providers.media
99789.938160 : 777-system_server : PMS:performDexOpt:com.google.android.apps.docs.editors.docs
114430.013733 : 777-system_server : PMS:performDexOpt:com.google.android.onetimeinitializer
114811.085504 : 777-system_server : PMS:performDexOpt:com.mediatek.location.lppe.main
115139.649966 : 777-system_server : PMS:performDexOpt:com.android.wallpapercropper
115144.646197 : 777-system_server : PMS:performDexOpt:com.android.protips
115150.169581 : 777-system_server : PMS:performDexOpt:com.android.documentsui
115166.986274 : 777-system_server : PMS:performDexOpt:com.android.externalstorage
115171.057197 : 777-system_server : PMS:performDexOpt:com.mediatek.ygps
115177.234966 : 777-system_server : PMS:performDexOpt:com.android.htmlviewer
115181.287581 : 777-system_server : PMS:performDexOpt:com.android.companiondevicemanager
115187.204274 : 777-system_server : PMS:performDexOpt:com.google.android.apps.docs.editors.sheets
130281.575156 : 777-system_server : PMS:performDexOpt:com.android.providers.downloads
130297.580156 : 777-system_server : PMS:performDexOpt:com.google.android.apps.messaging
136510.900478 : 777-system_server : PMS:performDexOpt:com.android.writeimei
136517.015402 : 777-system_server : PMS:performDexOpt:com.mediatek.engineermode
136533.084478 : 777-system_server : PMS:performDexOpt:com.otaupdater.client.pci
139099.409869 : 777-system_server : PMS:performDexOpt:com.google.android.apps.genie.geniewidget
141841.039414 : 777-system_server : PMS:performDexOpt:com.mediatek.omacp
141852.033722 : 777-system_server : PMS:performDexOpt:com.google.android.configupdater
143942.007804 : 777-system_server : PMS:performDexOpt:com.android.providers.downloads.ui
143950.975881 : 777-system_server : PMS:performDexOpt:com.android.vending
153350.969057 : 777-system_server : PMS:performDexOpt:com.android.pacprocessor
153357.482442 : 777-system_server : PMS:performDexOpt:com.android.certinstaller
153362.990057 : 777-system_server : PMS:performDexOpt:com.android.carrierconfig
153367.606672 : 777-system_server : PMS:performDexOpt:com.google.android.marvin.talkback
154832.208599 : 777-system_server : PMS:performDexOpt:com.google.android.apps.work.oobconfig
160397.116228 : 777-system_server : PMS:performDexOpt:com.android.egg
160407.464382 : 777-system_server : PMS:performDexOpt:com.android.mtp
160414.571766 : 777-system_server : PMS:performDexOpt:com.android.nfc
160427.387843 : 777-system_server : PMS:performDexOpt:com.android.stk
160435.046920 : 777-system_server : PMS:performDexOpt:com.android.launcher3
160447.006074 : 777-system_server : PMS:performDexOpt:com.android.backupconfirm
160452.568689 : 777-system_server : PMS:performDexOpt:com.mediatek.bluetooth.dtt
160465.013843 : 777-system_server : PMS:performDexOpt:com.google.android.deskclock
162244.236617 : 777-system_server : PMS:performDexOpt:com.android.statementservice
162251.229540 : 777-system_server : PMS:performDexOpt:com.google.android.gm
172015.771409 : 777-system_server : PMS:performDexOpt:com.google.android.apps.tachyon
176043.776419 : 777-system_server : PMS:performDexOpt:com.mediatek.mdmlsample
176051.331573 : 777-system_server : PMS:performDexOpt:com.mediatek.providers.drm
176056.306573 : 777-system_server : PMS:performDexOpt:com.google.android.setupwizard
177954.596039 : 777-system_server : PMS:performDexOpt:com.android.sharedstoragebackup
177960.795346 : 777-system_server : PMS:performDexOpt:com.mediatek.batterywarning
178219.600347 : 777-system_server : PMS:performDexOpt:com.google.android.music
187542.735908 : 777-system_server : PMS:performDexOpt:com.android.printspooler
187556.019446 : 777-system_server : PMS:performDexOpt:com.android.dreams.basic
187560.172908 : 777-system_server : PMS:performDexOpt:com.android.bips
187565.581754 : 777-system_server : PMS:performDexOpt:com.example
187844.819832 : 777-system_server : PMS:performDexOpt:com.mediatek.duraspeed
187854.295601 : 777-system_server : PMS:performDexOpt:com.android.musicfx
187859.364370 : 777-system_server : PMS:performDexOpt:com.google.android.apps.docs
195943.050389 : 777-system_server : PMS:performDexOpt:com.google.android.apps.maps
221750.079451 : 777-system_server : PMS:performDexOpt:com.google.android.apps.plus
230560.679933 : 777-system_server : PMS:performDexOpt:com.android.cellbroadcastreceiver
230576.272087 : 777-system_server : PMS:performDexOpt:com.google.android.webview
230830.527934 : 777-system_server : PMS:performDexOpt:com.google.android.contacts
234057.796942 : 777-system_server : PMS:performDexOpt:com.mediatek.nlpservice
234310.225942 : 777-system_server : PMS:performDexOpt:com.google.android.syncadapters.contacts
235439.648484 : 777-system_server : PMS:performDexOpt:com.android.facelock
236278.940486 : 777-system_server : PMS:performDexOpt:com.android.keychain
236285.839716 : 777-system_server : PMS:performDexOpt:com.google.android.calculator
237256.699719 : 777-system_server : PMS:performDexOpt:com.android.chrome
247269.808050 : 777-system_server : PMS:performDexOpt:com.google.android.gms
291173.412385 : 777-system_server : PMS:performDexOpt:com.google.android.gsf
291889.272310 : 777-system_server : PMS:performDexOpt:com.google.android.ims
294370.807931 : 777-system_server : PMS:performDexOpt:com.google.android.tag
294895.197548 : 777-system_server : PMS:performDexOpt:com.google.android.tts
296506.454398 : 777-system_server : PMS:performDexOpt:com.google.android.gmsintegration
296517.176552 : 777-system_server : PMS:performDexOpt:com.android.calllogbackup
296520.955705 : 777-system_server : PMS:performDexOpt:com.google.android.partnersetup
297375.172707 : 777-system_server : PMS:performDexOpt:com.valmedia.fdelux
299746.301790 : 777-system_server : PMS:performDexOpt:com.google.android.videos
305182.171495 : 777-system_server : PMS:performDexOpt:com.android.carrierdefaultapp
305190.510726 : 777-system_server : PMS:performDexOpt:com.google.android.feedback
305740.677035 : 777-system_server : PMS:performDexOpt:com.google.android.printservice.recommendation
306011.271036 : 777-system_server : PMS:performDexOpt:com.google.android.apps.photos
319736.751530 : 777-system_server : PMS:performDexOpt:com.google.android.calendar
324612.068619 : 777-system_server : PMS:performDexOpt:com.android.managedprovisioning
324623.492234 : 777-system_server : PMS:performDexOpt:com.mediatek.calendarimporter
324631.520311 : 777-system_server : PMS:performDexOpt:com.mediatek.thermalmanager
324959.254850 : 777-system_server : PMS:performDexOpt:com.mediatek.callrecorder
324964.480081 : 777-system_server : PMS:performDexOpt:com.mediatek.webview
327421.028548 : 777-system_server : PMS:performDexOpt:com.android.providers.partnerbookmarks
327429.625548 : 777-system_server : PMS:performDexOpt:com.mediatek.factorymode
327437.938548 : 777-system_server : PMS:performDexOpt:com.mtk.telephony
327691.050318 : 777-system_server : PMS:performDexOpt:com.baidu.map.location
328728.378167 : 777-system_server : PMS:performDexOpt:com.google.android.apps.translate
332677.203715 : 777-system_server : PMS:performDexOpt:com.google.android.backuptransport
332928.584946 : 777-system_server : PMS:performDexOpt:com.android.storagemanager
332944.970254 : 777-system_server : PMS:performDexOpt:com.android.bookmarkprovider
332949.513254 : 777-system_server : PMS:performDexOpt:com.google.android.inputmethod.pinyin
335415.889952 : 777-system_server : PMS:performDexOpt:com.mediatek.mdmconfig
335425.267183 : 777-system_server : PMS:performDexOpt:com.google.android.apps.books
341578.219044 : 777-system_server : PMS:performDexOpt:com.mediatek.lbs.em2.ui
341986.969814 : 777-system_server : PMS:performDexOpt:com.android.vpndialogs
341993.090198 : 777-system_server : PMS:performDexOpt:com.google.android.keep
346305.760132 : 777-system_server : PMS:performDexOpt:com.android.wallpaperbackup
346314.091670 : 777-system_server : PMS:performDexOpt:com.android.providers.blockednumber
346323.088055 : 777-system_server : PMS:performDexOpt:com.android.providers.userdictionary
346327.427440 : 777-system_server : PMS:performDexOpt:com.android.emergency
346342.475132 : 777-system_server : PMS:performDexOpt:com.android.bluetoothmidiservice
346346.436670 : 777-system_server : PMS:performDexOpt:com.mediatek.location.mtknlp
346351.760286 : 777-system_server : PMS:performDexOpt:com.mediatek.filemanager
346359.031132 : 777-system_server : PMS:performDexOpt:com.mediatek.sensorhub.ui
346363.830824 : 777-system_server : PMS:performDexOpt:com.google.android.play.games
350019.136756 : 777-system_server : PMS:performDexOpt:com.google.android.apps.magazines
357144.564619 : 777-system_server : PMS:performDexOpt:com.android.bluetooth
357162.350619 : 777-system_server : PMS:performDexOpt:com.android.wallpaperpicker
357168.592542 : 777-system_server : PMS:performDexOpt:com.android.providers.contacts
357180.100773 : 777-system_server : PMS:performDexOpt:com.android.captiveportallogin
357184.506389 : 777-system_server : PMS:performDexOpt:com.mediatek.mtklogger.proxy
362317.530247 : 777-system_server : AMS:systemReady
362327.296170 : 777-system_server : AMS:AMS_READY
7.3,若确认为dex2oat导致的问题可以按照下面修改
在/device和/build目录下,修改下面的宏,具体下面3个宏的位置可以在代码中搜索一下:
build/core/dex_preopt.mk
WITH_DEXPREOPT := true
WITH_DEXPREOPT_PIC := true
DONT_DEXPREOPT_PREBUILTS := false //或者注释掉
8.
尽量少把APP设置为persist;
优化每一个有源码的persist APP;使他们启动尽可能快;
com.android.systemui(PersistAP)
com.mediatek.ims(PersistAP)
com.android.phone(PersistAP)
com.android.settings
精简apk包;
(1)删除没有用到的,图片、资源文件、没有用到的jar包文件、不需要使用的so文件;
(2)预置自己的APP,假如设备只会加载drawable-xxhdpi中的资源,那么可以在drawable包重复的资源可以直接删除;
(3)预置自己的APP,假如设置只支持英文,values-da、values-fa这样的多语言支持资源都可以删除;
(4)apk中只保留和系统适配的so文件,比如:armv7和arm64的so文件;
Application的onCreate方法中不要有耗时的代码段;
通过修改--compiler-filter为speed、quick、speed-profile来提高apk的启动速度;speed模式优化的类较多,这时优化后的vdex、odex的文件较大,应用启动过程包括映射apk文件的过程,文件偏大导致有一定的时间损耗;但speed模式优化后,Java类执行更快;所以这个需要针对具体的应用多次验证,没有普适性;
[FAQ20644] Android O、N版本修改dex2oat编译选项,减少占用ROM空间或者加快安装速度
9.定频定核,调高CPU频率,会带来一定的功耗:
以6763的O1版本代码为例:
/system/core/rootdir/init.rc
on early-init
#mtk begin
write /proc/ppm/policy/ut_fix_core_num "4 4"
write /proc/ppm/policy/ut_fix_freq_idx "0 0"
#mtk end
on property:sys.boot_completed=1
bootchart stop
#mtk begin
write /proc/ppm/policy/ut_fix_core_num "-1 -1"
write /proc/ppm/policy/ut_fix_freq_idx "-1 -1"
#mtk end
10.
客制化进程的启动速度关注一下,是否有影响开机速度的;
11.
PackageManagerService
scanDirTracedLI
(1)减少预置APP的数量(对开机速度会有较为明显的提升);
(2)删除没有必要的apk包;
(3)单线程scan分区里面的apk并不一定能充分使用IO资源,尝试改为多线程异步scan;
(部分手机厂商有做出此种修改,且效果较为明显,但修改需谨慎);
(4)精简系统,把系统中用不到的apk包、有重复功能的apk移除(比如:我司代码默认包含有计算器APP,如果贵司有自己单独的计算器APP则可以移除我司apk),这样既可以使系统有更大的剩余存储空间又可以减少scan的时间,加快开机;
12.关机时间优化:
以MTK6763为例:
[ro.mediatek.version.branch]: [alps-mp-o1.mp1]
可以把下面这个时间改为1s(贵司可以自己测试找一个最优值),然后关机音频控制在1s(否则音频播放不完整),或者关机时不播放铃声,把这个值设置为10ms;
/frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
149 // Shutdown Animation
150 private static final int MIN_SHUTDOWN_ANIMATION_PLAY_TIME = 1 * 1000;
13.
关机时间长的另外一个原因有可能是后台应用乱跑;尤其国内一些有保活的APP,在后台都在积极抢占CPU,在手机系统资源紧张时对系统的性能影响是非常大的;手机使用过程中,适当的限制后台进程的数量,会一定程度提高系统性能和更快的关机;
还有些APP一直保持有1个像素的悬浮窗,使自己一直为可见进程,可见进程能更多的占用系统资源,手机系统可以增加悬浮窗的权限管控开关只有获取到了才允许悬浮,可以更加合理的非配系统资源。文章来源:https://www.toymoban.com/news/detail-611699.html
谷歌官方开机优化资料:
https://source.android.com/devices/tech/perf/boot-times文章来源地址https://www.toymoban.com/news/detail-611699.html
到了这里,关于ANDROID开机优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!