Android 平臺(tái)側(cè)性能優(yōu)化之應(yīng)用啟動(dòng)[問題已解決]

上一篇文章Android 平臺(tái)側(cè)性能優(yōu)化之應(yīng)用啟動(dòng)采用多個(gè)命令分析了平臺(tái)的cpu/memory等方面對(duì)Email啟動(dòng)慢照成的影響。很遺憾花了許多精力,但依然沒有找出問題所在,這個(gè)坑終于填平了。手動(dòng)撒花_
回頭看來,問題其實(shí)很簡(jiǎn)單,一開始走錯(cuò)方向,導(dǎo)致花了許多精力,不過這個(gè)過程也同樣積累了不少知識(shí)。
本篇文章記錄填坑的過程,重新?lián)Q個(gè)角度分析。

曙光出現(xiàn):

同事在分析另外一個(gè)I/O讀取慢的問題時(shí)發(fā)現(xiàn)我們的設(shè)備是被加密的,得知這個(gè)消息后,我的內(nèi)心是激動(dòng)的。一度以為找到了問題的root cause.

adb shell getprop ro.crypto.state

用上述命令查看問題機(jī)的加密狀態(tài),返回encrypted,果然是已經(jīng)默認(rèn)加密了。感覺曙光出現(xiàn)了,我們的設(shè)備加密時(shí)將/data分區(qū)也進(jìn)行了加密,而應(yīng)用啟動(dòng)的文件正是放在/data分區(qū)下的。按理來講加密后的/data分區(qū)讀寫速度肯定弱于未加密狀態(tài)。問題會(huì)不會(huì)跟此相關(guān)呢?
我們采用的是高通8909平臺(tái)芯片,找到對(duì)應(yīng)的fstab.qcom文件。修改如下:


- /dev/block/bootdevice/by-name/userdata       /data        ext4    nosuid,nodev,barrier=1,noauto_da_alloc,discard      wait,check,forceencrypt=footer
+ /dev/block/bootdevice/by-name/userdata       /data        ext4    nosuid,nodev,barrier=1,noauto_da_alloc,discard      wait,check,encryptable=footer

關(guān)鍵就是修改這一句forceencrypt=footer===>encryptable=footer
forceencrypt表示強(qiáng)制加密,我們改成encryptable意味著加密是讓用戶主動(dòng)去選擇的。

懷著胸有成竹的心情驗(yàn)證修改后的版本。發(fā)現(xiàn)根本沒有起任何作用。whats's the fuck!說不過去啊。
滿以為找到突破口了,結(jié)果希望的火焰還是被無情的澆滅了。

還是IO速度

自己寫了一個(gè)test apk,專門測(cè)試平臺(tái)emcc的讀寫速度。測(cè)試問題機(jī)Log如下:

03-24 20:05:52.126 30578 30727 D Sunny-Test: start call writeData--->
03-24 20:05:52.144 30578 30727 D Sunny-Test-Utils: befWriteTime=93676689579157
03-24 20:05:52.144 30578 30727 D Sunny-Test-Utils: NewBufTime use time--->392292
03-24 20:06:12.656 30578 30727 D Sunny-Test-Utils: initBufData use time--->20512314888
03-24 20:06:12.656 30578 30727 D Sunny-Test-Utils: total create BufData use time--->20512707180
03-24 20:06:12.695 30578 30727 D Sunny-Test-Utils: aftWriteTime=93697240995816
03-24 20:06:12.695 30578 30727 D Sunny-Test-Utils: delta=20551416659
03-24 20:06:12.696 30578 30727 D Sunny-Test: start call writeData--->
03-24 20:06:12.710 30578 30727 D Sunny-Test-Utils: befWriteTime=93697255657795
03-24 20:06:12.710 30578 30727 D Sunny-Test-Utils: NewBufTime use time--->551198
03-24 20:06:33.188 30578 30727 D Sunny-Test-Utils: initBufData use time--->20477974992
03-24 20:06:33.188 30578 30727 D Sunny-Test-Utils: total create BufData use time--->20478526190
03-24 20:06:33.227 30578 30727 D Sunny-Test-Utils: aftWriteTime=93717772564923
03-24 20:06:33.227 30578 30727 D Sunny-Test-Utils: delta=20516907128

在測(cè)試參考機(jī)Log如下:

03-24 06:03:42.766 18541 18576 D Sunny-Test: start call writeData--->
03-24 06:03:42.780 18541 18576 D Sunny-Test-Utils: befWriteTime=7136372545141
03-24 06:03:42.787 18541 18576 D Sunny-Test-Utils: NewBufTime use time--->6635938
03-24 06:03:45.272 18541 18576 D Sunny-Test-Utils: initBufData use time--->2485714686
03-24 06:03:45.272 18541 18576 D Sunny-Test-Utils: total create BufData use time--->2492350624
03-24 06:03:45.359 18541 18576 D Sunny-Test-Utils: aftWriteTime=7138951725036
03-24 06:03:45.359 18541 18576 D Sunny-Test-Utils: delta=2579179895
03-24 06:03:45.360 18541 18576 D Sunny-Test: start call writeData--->
03-24 06:03:45.371 18541 18576 D Sunny-Test-Utils: befWriteTime=7138963657484
03-24 06:03:45.371 18541 18576 D Sunny-Test-Utils: NewBufTime use time--->387188
03-24 06:03:47.898 18541 18576 D Sunny-Test-Utils: initBufData use time--->2526351301
03-24 06:03:47.898 18541 18576 D Sunny-Test-Utils: total create BufData use time--->2526738489
03-24 06:03:47.983 18541 18576 D Sunny-Test-Utils: aftWriteTime=7141575492639
03-24 06:03:47.983 18541 18576 D Sunny-Test-Utils: delta=2611835155

可以看到
問題機(jī)寫入耗時(shí):Sunny-Test-Utils: delta=20516907128
參考機(jī)寫入耗時(shí):Sunny-Test-Utils: delta=2611835155
參考機(jī)比問題機(jī)寫入速度快了一個(gè)數(shù)量級(jí)。再用其他的工具測(cè)試I/O讀寫速度,同樣發(fā)現(xiàn)參考機(jī)比問題機(jī)快。但知道這個(gè)還是沒有辦法解決問題,也沒法量化I/O差異到底會(huì)對(duì)Email的啟動(dòng)速度影響多大。
問題到這一度陷入窘境,迷失了分析方向。是時(shí)候祭出systrace工具了。

插播 systrace 使用簡(jiǎn)介

systrace位于<sdk>/platform-tools/systrace目錄下。
我們主要分析Email的性能問題,因此可以用命令:

python systrace.py --app=com.tct.email gfx view sched dalvik -o email_launch.html

來抓取trace log分析啟動(dòng)過程。systrace 支持的trace類型可以通過:

python systrace.py -l

查看,用Android N下的systrace工具輸出結(jié)果如下:

systrace.py -l 輸出結(jié)果

輸入上述命令,然后啟動(dòng)Email,待主界面展示出來后,根據(jù)提示輸入回車鍵,此時(shí)systrace工具開始生成報(bào)告。

生成systrace過程

Tips:
systrace.py位于SDK/platform-tools/systrace目錄下。抓取時(shí)最好用系統(tǒng)對(duì)應(yīng)的SDK工具抓取。同時(shí)如果有源碼,也可以用源碼的external/chromium-trace/catapult/systrace/systrace/systrace.py 抓取。同樣注意抓取systrace的手機(jī)跟源碼版本一直。

然后打開chrome,在地址欄里輸入

chrome://tracing/

load systrace界面

點(diǎn)擊Load 按鈕,載入email_launch.html文件。顯示入下圖:

systrace 主界面

查看systrace主要用到4個(gè)快捷鍵:

W 放大視圖
S 縮小視圖
A 右移視圖
D 左移視圖

systrace 報(bào)告分析

為了排除apk版本差異的干擾,將同版本的apk分別安裝到問題機(jī)跟參考機(jī)上。然后對(duì)比systrace報(bào)告。
先用TestActivityLaunchTime.py測(cè)試問題機(jī)以及參考機(jī)的啟動(dòng)時(shí)間。腳本獲取地址:https://github.com/guanglixiang/Android_Performance/blob/master/TestActivityLaunchTime.py
問題機(jī):

**************************************************
Test APK version info is:
versionCode=317022801 minSdk=17 targetSdk=24
    versionName=v7.0.4.1.0312.0_0228
**************************************************
1 lunch time is 875
2 lunch time is 884
3 lunch time is 897
4 lunch time is 873
5 lunch time is 862
5 launch time average is 878

參考機(jī):

**************************************************
Test APK version info is:
versionCode=317022801 targetSdk=24
    versionName=v7.0.4.1.0312.0_0228
    versionCode=216030401 targetSdk=23
    versionName=v5.2.10.3.0214.0
**************************************************
1 lunch time is 806
2 lunch time is 773
3 lunch time is 782
4 lunch time is 777
5 lunch time is 835
5 launch time average is 794

這里看差距貌似不大,但多次測(cè)試總是發(fā)現(xiàn)參考機(jī)就是比問題機(jī)快那么一點(diǎn)點(diǎn)。從配置上來將問題機(jī)跟參考機(jī)配置差不多,并且問題機(jī)的內(nèi)存還比參考機(jī)大。為什么就是慢那么一點(diǎn)點(diǎn)呢。
下面嘗試通過systrace文件去找原因。
這里我用命令:

./systrace.py gfx input view wm am sm app res dalvik bionic pm database sched freq idle disk mmc load -t 5 -o vJ5E-no-encrypt-no-net_emailv7.html

分別抓取參考機(jī)和問題機(jī)的systrace。終于發(fā)現(xiàn)了問題所在。

參考機(jī)systrace
問題機(jī)systrace

從systrace對(duì)比非常明顯的看到參考機(jī)沒有bindApplication的過程,而問題機(jī)卻在這個(gè)過程中消耗了0.226s。
我們知道冷啟動(dòng)應(yīng)用都是需要走bindApplication過程的。
bindApplication過程會(huì):
1.創(chuàng)建應(yīng)用進(jìn)程
2.加載應(yīng)用dex執(zhí)行文件
3.獲取應(yīng)用資源文件
4.makeApplication,初始化JavaContextClassLoader。
相應(yīng)的熱啟動(dòng)是不需要走上述過程的。

為了驗(yàn)證上述分析。可以有個(gè)簡(jiǎn)單的方法,只要先啟動(dòng)Email,然后點(diǎn)擊menu清除最近的應(yīng)用,最后通過ps命令查看email進(jìn)程是否還存在。

清理應(yīng)用結(jié)果

透過上面的分析可以確定參考機(jī)的Email應(yīng)用一直都在后臺(tái)運(yùn)行。而測(cè)試測(cè)冷啟動(dòng)case時(shí)只是點(diǎn)擊menu鍵,然后清除所有應(yīng)用,在去啟動(dòng)Email。參考機(jī)的Email逃過了這一劫,清除的過程中,進(jìn)程并沒有被殺死。而問題機(jī)的Email就沒那么幸運(yùn)了,直接被殺的它媽都不認(rèn)識(shí)它了。

解決辦法

由于參考機(jī)將Email配置成了后臺(tái)一直運(yùn)行,相當(dāng)于拿問題機(jī)的冷啟動(dòng)耗時(shí)對(duì)比參考機(jī)的熱啟動(dòng)應(yīng)用耗時(shí)。想要達(dá)到參考機(jī)的啟動(dòng)速度,在平臺(tái)側(cè)可以也可以效仿參考機(jī)將Email配置成后臺(tái)一直運(yùn)行。
修改方法:
在frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

void kill(String reason, boolean noisy) {
    if("com.tct.email".equals(processName) 
        && !KILL_APP_REASON_PERMISSIONS_REVOKED.equals(reason)) {
                return;
    }
    //忽略其他code
}

但這種做法需要項(xiàng)目上根據(jù)需求做權(quán)衡。Email應(yīng)用本身會(huì)定時(shí)去check郵件列表,發(fā)起網(wǎng)絡(luò)請(qǐng)求,屬于高耗電程序。一直在后臺(tái)運(yùn)行會(huì)消耗電量。

寫在最后

Email問題陸陸續(xù)續(xù)的分析了兩周多,最開始一心要去從I/O速度上去分析個(gè)結(jié)果出來。沒有去想其它的可能。中間一度想放棄,打算將問題歸結(jié)到I/O,拋給底層同事去check。但心里始終不安,有空了就去想該問題。其實(shí)一開始也抓取過systrace,只是重點(diǎn)放在了分析I/O上,沒有跟參考機(jī)做對(duì)比。沒有對(duì)比就帶來了傷害啊TT

systrace是個(gè)好東西,有空打算專門寫篇針對(duì)該工具的文章。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容