Android开机速度优化 Android 开机时间优化
本文轉自谷歌? ?Android開發者官網
?
要優化開機時間。首要的是了解Android 的整個啟動過程。下圖是谷歌提供的一張開機啟動流程圖:
?
?
開機的具體流程分析,后續會有專門文章說明。這里不再詳述說。從上圖可以看出。開機啟動主要分為了 uboot 啟動 kernel 啟動 然后是system啟動。uboot的啟動時間幾乎很短,優化的難度大且危險性較高。不建議進行優化。下面將列出印度項目優化的過程:
關閉 kernel打印
此過程大概能提升8s-10s的時間。設置方法比較多。可以uboot環境變量中設置。kernel 打印print.c 中設置。也可以在mk 中通過cmd設置。但目的都是一樣:使loglevel=0這個配置生效
清理kernel 配置
主要是清理.config配置,將系統中不需要用的config 配置為N。
全系統app odex 預優化
系統mk 配置 WITH_DEXPREOPT := true 。這樣app編譯會生產 oat文件夾。此操作會加大固件大小,但是可以打打降低開機時間。
裁減驅動文件
將kernel跟系統需要家長的驅動ko文件裁減到最低。例如amlogic 一般會配置 multiWifi,這樣會編譯amlogic已經調試且支持的所有驅動文件。可以修改為,板子貼什么wifi模塊,只配置對應的wifi模塊驅動。
?
ATV不需要Netflix 的項目,也可以移除Netflix 的相關編譯。
?
如下內容。是優化開機時間的實際操作及效果:
?
優化開機時間時間
啟動時間是系統性能的重要組成部分,因為用戶必須等待啟動完成后才能使用設備。對于較常進行冷啟動的汽車等設備而言,較短的啟動時間至關重要(沒有人喜歡在等待幾十秒后才能輸入導航目的地)。
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 并行進行(需要多核支持)。
優化內核
請按照以下提示優化內核以縮短啟動時間。
最大限度地減少設備 defconfig
最大限度地減少內核配置可以減小內核大小,從而更快速地進行加載、解壓縮、初始化并縮小受攻擊面。要優化設備 defconfig,請執行以下操作:
- 識別未使用的驅動程序。查看?/dev?和?/sys?目錄,并查找帶有常規 SELinux 標簽的節點(這種標簽表示相應節點未配置為可由用戶空間訪問)。如果找到此類節點,請將其移除。
- 取消設置未使用的配置。查看由內核版本生成的 .config 文件,以明確取消設置所有已默認啟用但并未使用的配置。例如,我們從 Google Pixel 中移除了以下未使用的配置:
CONFIG_ANDROID_LOGGER=y
CONFIG_IMX134=y
CONFIG_IMX132=y
CONFIG_OV9724=y
CONFIG_OV5648=y
CONFIG_GC0339=y
CONFIG_OV8825=y
CONFIG_OV8865=y
CONFIG_s5k4e1=y
CONFIG_OV12830=y
CONFIG_USB_EHCI_HCD=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
CONFIG_IKCONFIG=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_TI_DRV2667=y
CONFIG_CHR_DEV_SCH=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SDHCI_MSM_ICE=y
CONFIG_MMC_CQ_HCI=y
CONFIG_MSDOS_FS=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_EEPROM_AT24=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_HBTP_INPUT=y
# CONFIG_VGA_ARB is not set
CONFIG_USB_MON=y
CONFIG_USB_STORAGE_DATAFAB=y
CONFIG_USB_STORAGE_FREECOM=y
CONFIG_USB_STORAGE_ISD200=y
CONFIG_USB_STORAGE_USBAT=y
CONFIG_USB_STORAGE_SDDR09=y
CONFIG_USB_STORAGE_SDDR55=y
CONFIG_USB_STORAGE_JUMPSHOT=y
CONFIG_USB_STORAGE_ALAUDA=y
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_SW_SYNC_USER=y
CONFIG_SEEMP_CORE=y
CONFIG_MSM_SMEM_LOGGING=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
CONFIG_MOBICORE_DRIVER=y
# CONFIG_DEBUG_PREEMPT is not set
- 移除導致每次啟動時運行不必要測試的配置。雖然此類配置(即 CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST)在開發過程中很有用,但應從正式版內核中移除。
最大限度地減小驅動程序大小
如果未使用相應功能,則可以移除設備內核中的某些驅動程序,以便進一步減小內核大小。例如,如果 WLAN 通過 PCIe 連接,則不會用到 SDIO 支持,因此應在編譯時將其移除。有關詳情,請參閱 Google Pixel 內核:網絡:無線:CNSS:添加選項以停用 SDIO 支持。
移除針對大小的編譯器優化
移除 CONFIG_CC_OPTIMIZE_FOR_SIZE 的內核配置。此標記是在最初假設較小的代碼大小會產生熱緩存命中(因此速度更快)時引入的。然而,隨著現代移動 SoC 變得更加強大,這一假設不再成立。
此外,移除此標記可以使編譯器針對未初始化的變量發出警告,當存在 CONFIG_CC_OPTIMIZE_FOR_SIZE 標記時,這一功能在 Linux 內核中是停用的(僅這一項更改就已幫助我們在某些 Android 設備驅動程序中發現了很多有意義的錯誤)。
延遲初始化
很多進程都在設備啟動期間啟動,但只有關鍵路徑 (bootloader > kernel > init > file system mount > zygote > system server) 中的組件才會直接影響啟動時間。在內核啟動期間執行?initcall?來識別啟動速度緩慢且對啟動 init 進程不重要的外設/組件,然后通過將這些外設/組件移入可加載的內核模塊將其延遲到啟動過程的后期來啟動。移入異步設備/驅動程序探測還有助于并行啟動內核 > init 重要路徑中啟動速度緩慢的組件。
BoardConfig-common.mk:
? ? BOARD_KERNEL_CMDLINE += initcall_debug ignore_loglevel
?
driver:
? ? .probe_type = PROBE_PREFER_ASYNCHRONOUS,
注意:必須添加?EPROBEDEFER?支持來妥善解決驅動程序依賴問題。
優化 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
? ? write /sys/block/sda/queue/scheduler cfq
? ? write /sys/block/sda/queue/iosched/slice_idle 0
? ? write /sys/block/sda/queue/read_ahead_kb 2048
? ? 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
? ? ...
其他
- 使用內核配置 DM_VERITY_HASH_PREFETCH_MIN_SIZE(默認大小為 128)來啟用 dm-verity 哈希預提取大小。
- 為了提升文件系統穩定性及取消每次啟動時的強制檢查,請在 BoardConfig.mk 中設置 TARGET_USES_MKE2FS,以使用新的 ext4 生成工具。
分析 I/O
要了解啟動過程中的 I/O 活動,請使用內核 ftrace 數據(systrace 也使用該數據):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
要針對每個文件細分文件訪問權限,請對內核進行以下更改(僅限開發版內核;請勿在正式版內核中應用這些更改):
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:提供每個文件的訪問信息。
- system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace:提供系統級細分信息。
優化 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 忙于執行內置命令)。
使用調度程序調整
使用調度程序調整,以便及早啟動設備。以下是取自 Google Pixel 的示例:
on init
? ? # update cpusets now that processors are up
? ? write /dev/cpuset/top-app/cpus 0-3
? ? write /dev/cpuset/foreground/cpus 0-3
? ? write /dev/cpuset/foreground/boost/cpus 0-3
? ? write /dev/cpuset/background/cpus 0-3
? ? write /dev/cpuset/system-background/cpus 0-3
? ? # set default schedTune value for foreground/top-app (only affects EAS)
? ? write /dev/stune/foreground/schedtune.prefer_idle 1
? ? write /dev/stune/top-app/schedtune.boost 10
? ? write /dev/stune/top-app/schedtune.prefer_idle 1
部分服務在啟動過程中可能需要進行優先級提升。例如:
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 支持在裝載用戶數據分區之前,及早啟動動畫。然而,即使 Android 8.0 中使用了新的 ext4 工具鏈,系統也會出于安全原因定期觸發 fsck,導致啟動 bootanimation 服務時出現延遲。
為了使 bootanimation 及早啟動,請將 fstab 裝載分為以下兩個階段:
- 在早期階段,僅裝載不需要運行檢查的分區(例如?system/?和?vendor/),然后啟動啟動動畫服務及其依賴項(例如 servicemanager 和 surfaceflinger)。
- 在第二個階段,裝載需要運行檢查的分區(例如?data/)。
啟動動畫將會更快速地啟動(且啟動時間恒定),不受 fsck 影響。
干凈利落地結束
在收到退出信號后,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?會成為匹配項。
- 將標簽移動到?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
完成后,請刪除?/data/bootchart/enabled?以防止每次都收集日期數據。
systrace
systrace 允許在啟動期間收集內核和 Android 跟蹤記錄。 systrace 的可視化可以幫助分析啟動過程中的具體問題。(不過,要查看整個啟動過程中的平均數量或累計數量,直接查看內核跟蹤記錄更為方便)。
要在啟動過程中啟用 systrace,請執行以下操作:
- 在?frameworks/native/atrace/atrace.rc?中,將
write /sys/kernel/debug/tracing/tracing_on 0
更改為:
#write /sys/kernel/debug/tracing/tracing_on 0
這將啟用跟蹤功能(默認處于停用狀態)。
- 在?device.mk?文件中,添加下面這行內容:
PRODUCT_PROPERTY_OVERRIDES += ? ?debug.atrace.tags.enableflags=802922
- 在設備?BoardConfig.mk?文件中,添加以下內容:
BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
要獲得詳細的 I/O 分析,還需要添加塊和 ext4。
- 在設備專用的?init.rc?文件中,進行以下更改:
- on property:sys.boot_completed=1(這會在啟動完成后停止跟蹤)
- write /d/tracing/tracing_on 0
- write /d/tracing/events/ext4/enable 0
- write /d/tracing/events/block/enable 0
在設備啟動后,獲取跟蹤記錄:
adb root && adb shell "cat /d/tracing/trace" < boot_trace ./external/chromium-trace/catapult/tracing/bin/trace2html boot_trace --output boot_trace.html
注意:Chrome 無法處理過大的文件。請考慮使用?tail、head?或?grep?分割?boot_trace?文件,以獲得必要的部分。由于事件過多,I/O 分析通常需要直接分析獲取的?boot_trace。
?
?
總結
以上是生活随笔為你收集整理的Android开机速度优化 Android 开机时间优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ffmpeg生成各种背景色的视频
- 下一篇: 电气施工和安装日记