Android开机速度优化简单回顾
Android的開機(jī)速度,基本上沒人說(shuō)快的,通常移植完系統(tǒng)后,馬上要看的事情就是優(yōu)化開機(jī)時(shí)間,以下是簡(jiǎn)單回憶以下以前做優(yōu)化的那些事。
開機(jī)時(shí)間都花在哪?
優(yōu)化開機(jī)時(shí)間,通常做的首先是那有有沒有BUG,明顯不合理的先解決,由于開發(fā)階段穩(wěn)定性問題,一些地方可能延時(shí)加的大,或者頻率設(shè)的低,先記下來(lái),后面定期還會(huì)再看。這些先不看的話,一般拿到機(jī)器,我們統(tǒng)計(jì)開機(jī)時(shí)間,主要看如下幾個(gè)時(shí)間段分布:
內(nèi)核優(yōu)化
可以通過添加打印module init的log,來(lái)check每個(gè)module初始化時(shí)的時(shí)間。從而找到花費(fèi)時(shí)間比較多的module:
--- a/init/main.c +++ b/init/main.c @@ -785,7 +785,7 @@ int __init_or_module do_one_initcall(initcall_t fn)if (initcall_blacklisted(fn))return -EPERM;- if (initcall_debug) + if (1)ret = do_one_initcall_debug(fn);優(yōu)化方案:
這里我們主要關(guān)注的是第三個(gè),也是優(yōu)化的重點(diǎn)。這部分時(shí)間,具體都在干啥,瓶頸是哪,可以通過bootchart很清楚的看到。以下結(jié)合以前抓的圖,簡(jiǎn)要說(shuō)一下(圖是很久之前抓的,比較懶,沒有再跑一遍過程)
上圖中bootanim的退出時(shí)間沒有截出來(lái),實(shí)際圖是有的,大約是33s的時(shí)候結(jié)束。
這里分析時(shí),我們是分了幾個(gè)時(shí)間段:
以上,具體分析看每段時(shí)間:
第一點(diǎn)另外處理,具體分析打印看是否有異常,這個(gè)值一般是很小的,不合理要和BSP同事一起查一下原因。
第二個(gè)主要是init.rc執(zhí)行各種命令,這個(gè)可以通過在execute_one_command函數(shù)中統(tǒng)計(jì)測(cè)量 ,比如大于100ms的命令打印出來(lái),再分析定位原因,這里命令執(zhí)行時(shí)間長(zhǎng)基本算BUG,要和BSP工程師一起解決。
第三點(diǎn)主要zygote啟動(dòng)問題,主要慢的原因,是加載資源和類庫(kù),這個(gè)要讀nand,一般卡的時(shí)間比較長(zhǎng),圖中可以看到,zygote進(jìn)程一溜的小粉紅,說(shuō)明IO較多。這個(gè)preload過程消耗的時(shí)間,在logcat的log中,也會(huì)打印的,一般來(lái)說(shuō),都是在近10S左右。
第四個(gè),zygote初始化完后,會(huì)fork system_server。 system_server進(jìn)程啟動(dòng),耗時(shí)也是較長(zhǎng)的。根據(jù)以前統(tǒng)計(jì)分析的結(jié)果,這里的服務(wù)啟動(dòng),基本上都是花在packageManagerService的PackageScan中,這又是一個(gè)讀文件,卡在文件讀取中,時(shí)間長(zhǎng)短,和預(yù)制app及安裝的app數(shù)量有關(guān)
第五個(gè)時(shí)間,是基本都準(zhǔn)備ready后,啟動(dòng)launcher等應(yīng)用了,啟動(dòng)完成后,systemServer請(qǐng)求SurfaceFlinger殺了bootanimation,就啟動(dòng)完成了。
 以上時(shí)間中,主要要優(yōu)化的,還是第三步和第四步的IO慢問題,其他可優(yōu)化的不多。比如CPU,常開四核performance模式啟動(dòng),也并沒提升多少,一般我們就不管了這個(gè)了。
咋優(yōu)化?
確定優(yōu)化方向后主要看怎么優(yōu)化這兩段耗時(shí)的地方:
1. Zygote的preload 資源和class
2. PackageManagerService的包掃描
這里的第一個(gè),最早之前有人直接是去掉preload或刪減,雖然可以加快一點(diǎn)開機(jī)速度,但是撿了芝麻丟了西瓜,根本不能這樣干~
我們最早做的實(shí)現(xiàn)方式,是將preload做并行處理,畢竟現(xiàn)在都是多核處理器了,而且是preload是加載后還要解析處理的,并行會(huì)有一定幅度提升。
對(duì)于包掃描,這個(gè)不好拆成并行任務(wù),不像preload那么簡(jiǎn)單干凈。考慮過將PackageManager的信息序列化后存起來(lái),下次開機(jī)就不掃了,不過看起來(lái)改動(dòng)有點(diǎn)大,不太好搞,也放棄了。
最后我們的實(shí)現(xiàn)的方式,就是linux上用的較多的readahead機(jī)制。具體實(shí)現(xiàn)細(xì)節(jié)就不展開說(shuō)了,原理就是:
1. 統(tǒng)計(jì)開機(jī)過程中,讀取的塊數(shù)據(jù)信息,記錄下來(lái)保存
2.再次開機(jī),通過記錄下來(lái)的塊數(shù)據(jù)讀取信息,直接起一個(gè)服務(wù),預(yù)先開始讀,zygote或packagemanagerservice要讀文件的時(shí)候,文件數(shù)據(jù)已經(jīng)在cache中了。
實(shí)際用下來(lái),這一招特別好,優(yōu)化非常明顯。以下是實(shí)現(xiàn)了一個(gè)readahead后的bootchart圖:
可以看到:
1. zygote和system_server都提速了
2. zygote和system_server的IO時(shí)間,都降低非常大
3. 主要IO時(shí)間,跑到readahead進(jìn)程中去了。
不過,以上實(shí)現(xiàn),還是有可優(yōu)化的地方:
1. readahead進(jìn)程可以再提前,在system分區(qū)掛載后立刻啟動(dòng),這樣zygote中的IO應(yīng)該可以再減小
2. 對(duì)system_server的IO,此時(shí)readahead已經(jīng)結(jié)束了,按理不應(yīng)該有了,這里還是有IO,這一般是后裝apk導(dǎo)致,這個(gè)可以把readahead做的更健壯一些,不要只學(xué)習(xí)開始的一兩次。
其他NB的優(yōu)化
另外還有一個(gè)很NB的技術(shù),就是STD。這個(gè)我們也搞過,花費(fèi)了大量的人力物力。STD開機(jī)時(shí)間,不算上uboot時(shí)間的話,基本都是在10S內(nèi),5~8S之間。不過這么NB的技術(shù),目前基本上也是廢棄了,用起來(lái)問題也挺多的:
1. 開機(jī)時(shí)間少了,關(guān)機(jī)時(shí)間拉長(zhǎng)。
??? 由于是STD(Suspend to Disk),關(guān)機(jī)時(shí)需要將內(nèi)存數(shù)據(jù)寫入nand,這塊也是挺麻煩的事情
 2. 穩(wěn)定性
??? 本身STD弄起來(lái)就比較復(fù)雜,BUG挺多的,另外使用STD,就相當(dāng)于永不關(guān)機(jī)了,這也太考驗(yàn)系統(tǒng)軟件的穩(wěn)定性了...
 3. 沒毛用
?? 一開始還能忽悠客戶,不過后來(lái)也沒人怎么關(guān)心這個(gè)feature了,平白給自己找活干,大家都不樂意使能它了
轉(zhuǎn)至:Android開機(jī)速度優(yōu)化簡(jiǎn)單回顧_freshui的專欄-CSDN博客_android 開機(jī)優(yōu)化
打開 bootchart 收集開機(jī)數(shù)據(jù)
1. adb shell 'touch /data/bootchart/enabled'首先使能 bootchart,bootchart 操作的前提是存在 enable 標(biāo)記,所以在你不需要收集數(shù)據(jù)的時(shí)候別忘了刪除這個(gè)標(biāo)記。2. - sudo apt-get install pybootchartgui- $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.shgrab-bootchart.sh 腳本是 Google 封裝的一系列操作的合集跟使用下面手動(dòng)操作的結(jié)果是一樣的。* 手動(dòng)操作1. (可選) echo $TIME_OUT > /data/bootchart/start添加 bootchart timeout 時(shí)間2. reboot 重啟3. 可以看到 bootchart 生成的數(shù)據(jù)文件和 log 都被保存在 /data/bootchart 路徑下4. tar -zcf boochart.tgz *5. 使用 adb pull 命令將文件拷貝出來(lái)Bug解決辦法
設(shè)置了 enabled后,重啟,發(fā)現(xiàn)無(wú)法開機(jī)了,從內(nèi)核log看一直在crash
經(jīng)過一番百度,Google
有的Blog是說(shuō)把 system/core/init/bootchart.cpp中的
stat.replace(open + 1, close - open - 1, full_name);刪除就好了
我試過,確實(shí),可以開機(jī)了
但是又想了想,谷歌會(huì)沒發(fā)現(xiàn)這個(gè)問題么?不至于吧
真相只有一個(gè)!
然后對(duì)比了谷歌7.0 8.1 甚至 9.0 的源代碼,開啟了漫長(zhǎng)2個(gè)小時(shí)的地毯上搜索....
最終在 Google 的提交記錄上找到相關(guān)修復(fù)提交
system/core/init/Android.mkLOCAL_SANITIZE := integer========》LOCAL_SANITIZE := signed-integer-overflow有梯子的可以直接看原生提交
https://android-review.googlesource.com/c/platform/system/core/+/445032/2/init/Android.mk#b97雖然不知道這是什么,但從字面意思大概猜到是和內(nèi)存溢出有關(guān)系吧
LOCAL_SANITIZE
然后再百度搜索一波 LOCAL_SANITIZE signed-integer-overflow
是什么
官方解釋
Android 的構(gòu)建系統(tǒng)還使用了 UBSan 的整數(shù)溢出檢查功能。UBSan 還支持 unsigned-integer-overflow,這不是嚴(yán)格意義上的未定義行為,但它包含在擦除器中。在生成文件中,可以將 LOCAL_SANITIZE 設(shè)置為 signed-integer-overflow、unsigned-integer-overflow 或 combination flag integer,啟用 signed-integer-overflow、unsigned-integer-overflow、integer-divide-by-zero、shift-base 和 shift-exponent,以啟用這些行為。在 blueprint 文件中,可以將 Misc_undefined 設(shè)置為所需的標(biāo)志,啟用這些行為。這些 UBSan 目標(biāo),尤其是 unsigned-integer-overflow,廣泛用于 mediaserver 組件中,以用來(lái)消除任何潛在的整數(shù)溢出漏洞
在 Android 中,當(dāng)出現(xiàn)未定義的行為時(shí),默認(rèn)的做法是中止程序。但是,從 2016 年 10 月開始,Android 中的 UBSan 將提供一個(gè)可選的運(yùn)行時(shí)庫(kù),其報(bào)告的錯(cuò)誤信息將更加詳細(xì),包括出現(xiàn)的未定義行為類型、文件和源代碼行信息
在 Android.mk 文件中,可通過以下方式啟用該庫(kù):
LOCAL_SANITIZE:=unsigned-integer-overflow signed-integer-overflow LOCAL_SANITIZE_DIAG:=unsigned-integer-overflow signed-integer-overflow在 Linux PC 機(jī)上生成 bootchart 圖表
PC 機(jī)安裝 bootchart 工具
sudo apt-get install bootchart sudo apt-get install pybootchartgui生成 bootchar 圖表
拷貝 bootchart.tgz 到 PC 中,并執(zhí)行下面的命令生成圖表
bootchart bootchart.tgz但很有可能會(huì)出現(xiàn)如下錯(cuò)誤?
那么就要更新編譯一下自己的bootchartgui工具
由于Ubuntu版本的pybootchartgui不能解析busybox上的bootchart數(shù)據(jù),所以這里出現(xiàn)了錯(cuò)誤,需要用另外一個(gè)版本bootchart2的工具來(lái)處理。用git下載bootchart2后需要執(zhí)行make后才能使用pybootchartgui:
git clone https://github.com/xrmx/bootchart.git下載完成之后,進(jìn)到目錄里面執(zhí)行make操作
然后執(zhí)行如下命令即可
python ./bootchart/pybootchartgui.py bootlog.tar.gz至此bootchart.png文件生成成功
https://elinux.org/images/a/a1/Abs2011_bird_readahead.pdf
總結(jié)
以上是生活随笔為你收集整理的Android开机速度优化简单回顾的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: android:completionth
 - 下一篇: LM2596 adj DC/DC 降压模