詳解Android進(jìn)程?;畹姆椒?/h1>
更新時(shí)間:2017年03月06日 09:46:02 作者:lianghe
本篇文章主要介紹了Android進(jìn)程?;?,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
關(guān)于 Android 平臺(tái)的進(jìn)程?;钸@一塊,想必是所有 Android 開(kāi)發(fā)者矚目的內(nèi)容之一。你到網(wǎng)上搜 Android 進(jìn)程保活,可以搜出各種各樣神乎其技的做法,絕大多數(shù)都是極其不靠譜。前段時(shí)間,Github還出現(xiàn)了一個(gè)很火的“黑科技”進(jìn)程?;顜?kù),聲稱(chēng)可以做到進(jìn)程永生不死。
懷著學(xué)習(xí)和膜拜的心情進(jìn)去Github圍觀,結(jié)果發(fā)現(xiàn)很多人提了 Issue 說(shuō)各種各樣的機(jī)子無(wú)法成功?;睢?/p>
看到這里,我瞬間就放心了。坦白的講,我是真心不希望有這種黑科技存在的,它只會(huì)滋生更多的流氓應(yīng)用,拖垮我大 Android 平臺(tái)的流暢性。
扯了這么多,接下來(lái)就直接進(jìn)入本文的正題,談?wù)勱P(guān)于進(jìn)程?;畹闹R(shí)。提前聲明以下四點(diǎn)
- 本文是本人開(kāi)發(fā) Android 至今綜合各方資料所得
- 不以節(jié)能來(lái)維持進(jìn)程保活的手段,都是耍流氓
- 本文不是教你做永生不死的進(jìn)程,如果指望實(shí)現(xiàn)進(jìn)程永生不死,請(qǐng)忽略本文
- 本文有錯(cuò)誤的地方,歡迎留下評(píng)論互相探討(拍磚請(qǐng)輕拍)
?;钍侄?/strong>
當(dāng)前業(yè)界的Android進(jìn)程?;钍侄沃饕譃?黑、白、灰 三種,其大致的實(shí)現(xiàn)思路如下:
黑色?;睿翰煌腶pp進(jìn)程,用廣播相互喚醒(包括利用系統(tǒng)提供的廣播進(jìn)行喚醒)
白色?;睿?jiǎn)?dòng)前臺(tái)Service
灰色?;睿豪孟到y(tǒng)的漏洞啟動(dòng)前臺(tái)Service
黑色保活
所謂黑色?;睿褪抢貌煌腶pp進(jìn)程使用廣播來(lái)進(jìn)行相互喚醒。舉個(gè)3個(gè)比較常見(jiàn)的場(chǎng)景:
場(chǎng)景1:開(kāi)機(jī),網(wǎng)絡(luò)切換、拍照、拍視頻時(shí)候,利用系統(tǒng)產(chǎn)生的廣播喚醒a(bǔ)pp
場(chǎng)景2:接入第三方SDK也會(huì)喚醒相應(yīng)的app進(jìn)程,如微信sdk會(huì)喚醒微信,支付寶sdk會(huì)喚醒支付寶。由此發(fā)散開(kāi)去,就會(huì)直接觸發(fā)了下面的 場(chǎng)景3
場(chǎng)景3:假如你手機(jī)里裝了支付寶、淘寶、天貓、UC等阿里系的app,那么你打開(kāi)任意一個(gè)阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。(只是拿阿里打個(gè)比方,其實(shí)BAT系都差不多)
沒(méi)錯(cuò),我們的Android手機(jī)就是一步一步的被上面這些場(chǎng)景給拖卡機(jī)的。
針對(duì)場(chǎng)景1,估計(jì)Google已經(jīng)開(kāi)始意識(shí)到這些問(wèn)題,所以在最新的Android N取消了 ACTION_NEW_PICTURE(拍照),ACTION_NEW_VIDEO(拍視頻),CONNECTIVITY_ACTION(網(wǎng)絡(luò)切換)等三種廣播,無(wú)疑給了很多app沉重的打擊。我猜他們的心情是下面這樣的
而開(kāi)機(jī)廣播的話(huà),記得有一些定制ROM的廠商早已經(jīng)將其去掉。
針對(duì)場(chǎng)景2和場(chǎng)景3,因?yàn)檎{(diào)用SDK喚醒a(bǔ)pp進(jìn)程屬于正常行為,此處不討論。但是在借助LBE分析app之間的喚醒路徑的時(shí)候,發(fā)現(xiàn)了兩個(gè)問(wèn)題:
1.很多推送SDK也存在喚醒a(bǔ)pp的功能
2.app之間的喚醒路徑真是多,且錯(cuò)綜復(fù)雜
我把自己使用的手機(jī)測(cè)試結(jié)果給大家圍觀一下(我的手機(jī)是小米4C,刷了原生的Android5.1系統(tǒng),且已經(jīng)獲得Root權(quán)限才能查看這些喚醒路徑)

15組相互喚醒路徑

全部喚醒路徑
我們直接點(diǎn)開(kāi) 簡(jiǎn)書(shū) 的喚醒路徑進(jìn)行查看

簡(jiǎn)書(shū)喚醒路徑
可以看到以上3條喚醒路徑,但是涵蓋的喚醒應(yīng)用總數(shù)卻達(dá)到了23+43+28款,數(shù)目真心驚人。請(qǐng)注意,這只是我手機(jī)上一款app的喚醒路徑而已,到了這里是不是有點(diǎn)細(xì)思極恐。
當(dāng)然,這里依然存在一個(gè)疑問(wèn),就是LBE分析這些喚醒路徑和互相喚醒的應(yīng)用是基于什么思路,我們不得而知。所以我們也無(wú)法確定其分析結(jié)果是否準(zhǔn)確,如果有LBE的童鞋看到此文章,不知可否告知一下思路呢?但是,手機(jī)打開(kāi)一個(gè)app就喚醒一大批,我自己可是親身體驗(yàn)到這種酸爽的......

白色保活
白色?;钍侄畏浅:?jiǎn)單,就是調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification,用來(lái)讓用戶(hù)知道有這樣一個(gè)app在運(yùn)行著,哪怕當(dāng)前的app退到了后臺(tái)。如下方的LBE和QQ音樂(lè)這樣:

灰色?;?/strong>
灰色?;?,這種保活手段是應(yīng)用范圍最廣泛。它是利用系統(tǒng)的漏洞來(lái)啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程,與普通的啟動(dòng)方式區(qū)別在于,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification,看起來(lái)就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣。這樣做帶來(lái)的好處就是,用戶(hù)無(wú)法察覺(jué)到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的。那么如何利用系統(tǒng)的漏洞呢,大致的實(shí)現(xiàn)思路和代碼如下:
思路一:API < 18,啟動(dòng)前臺(tái)Service時(shí)直接傳入new Notification();
思路二:API >= 18,同時(shí)啟動(dòng)兩個(gè)id相同的前臺(tái)Service,然后再將后啟動(dòng)的Service做stop處理;
public class GrayService extends Service {
private final static int GRAY_SERVICE_ID = 1001;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隱藏Notification上的圖標(biāo)
} else {
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
}
return super.onStartCommand(intent, flags, startId);
}
...
...
/**
* 給 API >= 18 的平臺(tái)上用的灰色?;钍侄?
*/
public static class GrayInnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(GRAY_SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
}
代碼大致就是這樣,能讓你神不知鬼不覺(jué)的啟動(dòng)著一個(gè)前臺(tái)Service。其實(shí)市面上很多app都用著這種灰色保活的手段,什么?你不信?好吧,我們來(lái)驗(yàn)證一下。流程很簡(jiǎn)單,打開(kāi)一個(gè)app,看下系統(tǒng)通知欄有沒(méi)有一個(gè) Notification,如果沒(méi)有,我們就進(jìn)入手機(jī)的adb shell模式,然后輸入下面的shell命令
dumpsys activity services PackageName
打印出指定包名的所有進(jìn)程中的Service信息,看下有沒(méi)有 isForeground=true 的關(guān)鍵信息。如果通知欄沒(méi)有看到屬于app的 Notification 且又看到 isForeground=true 則說(shuō)明了,此app利用了這種灰色?;畹氖侄?。
下面分別是我手機(jī)上微信、qq、支付寶、陌陌的測(cè)試結(jié)果,大家有興趣也可以自己驗(yàn)證一下。

微信

手Q

支付寶

陌陌
其實(shí)Google察覺(jué)到了此漏洞的存在,并逐步進(jìn)行封堵。這就是為什么這種保活方式分 API >= 18 和 API < 18 兩種情況,從Android5.0的ServiceRecord類(lèi)的postNotification函數(shù)源代碼中可以看到這樣的一行注釋

當(dāng)某一天 API >= 18 的方案也失效的時(shí)候,我們就又要另謀出路了。需要注意的是,使用灰色保活并不代表著你的Service就永生不死了,只能說(shuō)是提高了進(jìn)程的優(yōu)先級(jí)。如果你的app進(jìn)程占用了大量的內(nèi)存,按照回收進(jìn)程的策略,同樣會(huì)干掉你的app。感興趣于灰色?;钍侨绾卫孟到y(tǒng)漏洞不顯示 Notification 的童鞋,可以研究一下系統(tǒng)的 ServiceRecord、NotificationManagerService 等相關(guān)源代碼,因?yàn)椴皇潜疚牡闹攸c(diǎn),所以不做詳述。
嘮叨的分割線
到這里基本就介紹完了 黑、白、灰 三種實(shí)現(xiàn)方式,僅僅從代碼層面去講?;钍遣粔虻?,我希望能夠通過(guò)系統(tǒng)的進(jìn)程回收機(jī)制來(lái)理解?;?,這樣能夠讓我們更好的避免踩到進(jìn)程被殺的坑。
進(jìn)程回收機(jī)制
熟悉Android系統(tǒng)的童鞋都知道,系統(tǒng)出于體驗(yàn)和性能上的考慮,app在退到后臺(tái)時(shí)系統(tǒng)并不會(huì)真正的kill掉這個(gè)進(jìn)程,而是將其緩存起來(lái)。打開(kāi)的應(yīng)用越多,后臺(tái)緩存的進(jìn)程也越多。在系統(tǒng)內(nèi)存不足的情況下,系統(tǒng)開(kāi)始依據(jù)自身的一套進(jìn)程回收機(jī)制來(lái)判斷要kill掉哪些進(jìn)程,以騰出內(nèi)存來(lái)供給需要的app。這套殺進(jìn)程回收內(nèi)存的機(jī)制就叫 Low Memory Killer ,它是基于Linux內(nèi)核的 OOM Killer(Out-Of-Memory killer)機(jī)制誕生。
了解完 Low Memory Killer,再科普一下oom_adj。什么是oom_adj?它是linux內(nèi)核分配給每個(gè)系統(tǒng)進(jìn)程的一個(gè)值,代表進(jìn)程的優(yōu)先級(jí),進(jìn)程回收機(jī)制就是根據(jù)這個(gè)優(yōu)先級(jí)來(lái)決定是否進(jìn)行回收。對(duì)于oom_adj的作用,你只需要記住以下幾點(diǎn)即可:
- 進(jìn)程的oom_adj越大,表示此進(jìn)程優(yōu)先級(jí)越低,越容易被殺回收;越小,表示進(jìn)程優(yōu)先級(jí)越高,越不容易被殺回收
- 普通app進(jìn)程的oom_adj>=0,系統(tǒng)進(jìn)程的oom_adj才可能<0
那么我們?nèi)绾尾榭催M(jìn)程的oom_adj值呢,需要用到下面的兩個(gè)shell命令
ps | grep PackageName //獲取你指定的進(jìn)程信息

這里是以我寫(xiě)的demo代碼為例子,紅色圈中部分別為下面三個(gè)進(jìn)程的ID
- UI進(jìn)程:com.clock.daemon
- 普通后臺(tái)進(jìn)程:com.clock.daemon:bg
- 灰色?;钸M(jìn)程:com.clock.daemon:gray
當(dāng)然,這些進(jìn)程的id也可以通過(guò)AndroidStudio獲得

接著我們來(lái)再來(lái)獲取三個(gè)進(jìn)程的oom_adj
cat /proc/進(jìn)程ID/oom_adj

從上圖可以看到UI進(jìn)程和灰色?;頢ervice進(jìn)程的oom_adj=0,而普通后臺(tái)進(jìn)程oom_adj=15。到這里估計(jì)你也能明白,為什么普通的后臺(tái)進(jìn)程容易被回收,而前臺(tái)進(jìn)程則不容易被回收了吧。但明白這個(gè)還不夠,接著看下圖

上面是我把a(bǔ)pp切換到后臺(tái),再進(jìn)行一次oom_adj的檢驗(yàn),你會(huì)發(fā)現(xiàn)UI進(jìn)程的值從0變成了6,而灰色?;畹腟ervice進(jìn)程則從0變成了1。這里可以觀察到,app退到后臺(tái)時(shí),其所有的進(jìn)程優(yōu)先級(jí)都會(huì)降低。但是UI進(jìn)程是降低最為明顯的,因?yàn)樗加玫膬?nèi)存資源最多,系統(tǒng)內(nèi)存不足的時(shí)候肯定優(yōu)先殺這些占用內(nèi)存高的進(jìn)程來(lái)騰出資源。所以,為了盡量避免后臺(tái)UI進(jìn)程被殺,需要盡可能的釋放一些不用的資源,尤其是圖片、音視頻之類(lèi)的。
從Android官方文檔中,我們也能看到優(yōu)先級(jí)從高到低列出了這些不同類(lèi)型的進(jìn)程:Foreground process、Visible process、Service process、Background process、Empty process。
總結(jié)(文末有福利)
絮絮叨叨寫(xiě)完了這么多,最后來(lái)做個(gè)小小的總結(jié)?;貧w到開(kāi)篇提到QQ進(jìn)程不死的問(wèn)題,我也曾認(rèn)為存在這樣一種技術(shù)。可惜我把手機(jī)root后,殺掉QQ進(jìn)程之后就再也起不來(lái)了。有些手機(jī)廠商把這些知名的app放入了自己的白名單中,保證了進(jìn)程不死來(lái)提高用戶(hù)體驗(yàn)(如微信、QQ、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通app一樣躲避不了被殺的命運(yùn),為了盡量避免被殺,還是老老實(shí)實(shí)去做好優(yōu)化工作吧。
所以,進(jìn)程?;畹母痉桨附K究還是回到了性能優(yōu)化上,進(jìn)程永生不死終究是個(gè)徹頭徹尾的偽命題!
補(bǔ)充更新
有童鞋問(wèn),在華為的機(jī)子上發(fā)現(xiàn)微信和手Q的UI進(jìn)程退到后臺(tái),oom_adj的值一點(diǎn)都沒(méi)有變,是不是有什么黑科技在其中。為此,我稍稍驗(yàn)證了一下,驗(yàn)證方式就是把demo工程的包名改成手機(jī)QQ的,編譯運(yùn)行在華為的機(jī)子上,發(fā)現(xiàn)我的進(jìn)程怎么殺也都是不死的,退到后臺(tái)oom_adj的值同樣不發(fā)生變化,而恢復(fù)原來(lái)的包名就不行了。所以,你懂的,手Q就在華為機(jī)子的白名單中。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
-
Android如何實(shí)現(xiàn)社交應(yīng)用中的評(píng)論與回復(fù)功能詳解
目前,各種App的社區(qū)或者用戶(hù)曬照片、發(fā)說(shuō)說(shuō)的地方,都提供了評(píng)論功能,為了更好地學(xué)習(xí),自己把這個(gè)功能實(shí)現(xiàn)了一下,下面這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)社交應(yīng)用中的評(píng)論與回復(fù)功能的相關(guān)資料,需要的朋友可以參考下 2018-07-07
-
Android JSON數(shù)據(jù)與實(shí)體類(lèi)之間的相互轉(zhuǎn)化(GSON的用法)
這篇文章主要介紹了Android JSON數(shù)據(jù)與實(shí)體類(lèi)之間的相互轉(zhuǎn)化(GSON的用法),非常具有實(shí)用價(jià)值,需要的朋友可以參考下。 2017-01-01
-
基于android樣式與主題(style&theme)的詳解
本篇文章是對(duì)android中的樣式與主題(style&theme)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下 2013-06-06
-
Android實(shí)現(xiàn)音樂(lè)播放進(jìn)度條傳遞信息的兩種方式(在service和activity中)
這篇文章主要介紹了Android:在service和activity之中,實(shí)現(xiàn)音樂(lè)播放進(jìn)度條傳遞信息的兩種方式,MediaPlayer做音樂(lè)播放器采坑以及解決辦法,需要的朋友可以參考下 2020-05-05
-
Android搜索框(SearchView)的功能和用法詳解
這篇文章主要為大家詳細(xì)介紹了Android搜索框SearchView的功能和用法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 2017-05-05
-
android 字體顏色選擇器(ColorPicker)介紹
本文將詳細(xì)介紹android 字體顏色選擇器(ColorPicker)需要了解更多的朋友可以參考下 2012-11-11
-
Android滑動(dòng)到頂部和底部時(shí)出現(xiàn)的陰影如何去掉
本文給大家介紹android滑動(dòng)到頂部和底部時(shí)出現(xiàn)的陰影去掉的解決方法,本文還涉及到listview各個(gè)屬性的用法介紹,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧 2016-10-10
最新評(píng)論
關(guān)于 Android 平臺(tái)的進(jìn)程?;钸@一塊,想必是所有 Android 開(kāi)發(fā)者矚目的內(nèi)容之一。你到網(wǎng)上搜 Android 進(jìn)程保活,可以搜出各種各樣神乎其技的做法,絕大多數(shù)都是極其不靠譜。前段時(shí)間,Github還出現(xiàn)了一個(gè)很火的“黑科技”進(jìn)程?;顜?kù),聲稱(chēng)可以做到進(jìn)程永生不死。
懷著學(xué)習(xí)和膜拜的心情進(jìn)去Github圍觀,結(jié)果發(fā)現(xiàn)很多人提了 Issue 說(shuō)各種各樣的機(jī)子無(wú)法成功?;睢?/p>
看到這里,我瞬間就放心了。坦白的講,我是真心不希望有這種黑科技存在的,它只會(huì)滋生更多的流氓應(yīng)用,拖垮我大 Android 平臺(tái)的流暢性。
扯了這么多,接下來(lái)就直接進(jìn)入本文的正題,談?wù)勱P(guān)于進(jìn)程?;畹闹R(shí)。提前聲明以下四點(diǎn)
- 本文是本人開(kāi)發(fā) Android 至今綜合各方資料所得
- 不以節(jié)能來(lái)維持進(jìn)程保活的手段,都是耍流氓
- 本文不是教你做永生不死的進(jìn)程,如果指望實(shí)現(xiàn)進(jìn)程永生不死,請(qǐng)忽略本文
- 本文有錯(cuò)誤的地方,歡迎留下評(píng)論互相探討(拍磚請(qǐng)輕拍)
?;钍侄?/strong>
當(dāng)前業(yè)界的Android進(jìn)程?;钍侄沃饕譃?黑、白、灰 三種,其大致的實(shí)現(xiàn)思路如下:
黑色?;睿翰煌腶pp進(jìn)程,用廣播相互喚醒(包括利用系統(tǒng)提供的廣播進(jìn)行喚醒)
白色?;睿?jiǎn)?dòng)前臺(tái)Service
灰色?;睿豪孟到y(tǒng)的漏洞啟動(dòng)前臺(tái)Service
黑色保活
所謂黑色?;睿褪抢貌煌腶pp進(jìn)程使用廣播來(lái)進(jìn)行相互喚醒。舉個(gè)3個(gè)比較常見(jiàn)的場(chǎng)景:
場(chǎng)景1:開(kāi)機(jī),網(wǎng)絡(luò)切換、拍照、拍視頻時(shí)候,利用系統(tǒng)產(chǎn)生的廣播喚醒a(bǔ)pp
場(chǎng)景2:接入第三方SDK也會(huì)喚醒相應(yīng)的app進(jìn)程,如微信sdk會(huì)喚醒微信,支付寶sdk會(huì)喚醒支付寶。由此發(fā)散開(kāi)去,就會(huì)直接觸發(fā)了下面的 場(chǎng)景3
場(chǎng)景3:假如你手機(jī)里裝了支付寶、淘寶、天貓、UC等阿里系的app,那么你打開(kāi)任意一個(gè)阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。(只是拿阿里打個(gè)比方,其實(shí)BAT系都差不多)
沒(méi)錯(cuò),我們的Android手機(jī)就是一步一步的被上面這些場(chǎng)景給拖卡機(jī)的。
針對(duì)場(chǎng)景1,估計(jì)Google已經(jīng)開(kāi)始意識(shí)到這些問(wèn)題,所以在最新的Android N取消了 ACTION_NEW_PICTURE(拍照),ACTION_NEW_VIDEO(拍視頻),CONNECTIVITY_ACTION(網(wǎng)絡(luò)切換)等三種廣播,無(wú)疑給了很多app沉重的打擊。我猜他們的心情是下面這樣的
而開(kāi)機(jī)廣播的話(huà),記得有一些定制ROM的廠商早已經(jīng)將其去掉。
針對(duì)場(chǎng)景2和場(chǎng)景3,因?yàn)檎{(diào)用SDK喚醒a(bǔ)pp進(jìn)程屬于正常行為,此處不討論。但是在借助LBE分析app之間的喚醒路徑的時(shí)候,發(fā)現(xiàn)了兩個(gè)問(wèn)題:
1.很多推送SDK也存在喚醒a(bǔ)pp的功能
2.app之間的喚醒路徑真是多,且錯(cuò)綜復(fù)雜
我把自己使用的手機(jī)測(cè)試結(jié)果給大家圍觀一下(我的手機(jī)是小米4C,刷了原生的Android5.1系統(tǒng),且已經(jīng)獲得Root權(quán)限才能查看這些喚醒路徑)
15組相互喚醒路徑
全部喚醒路徑
我們直接點(diǎn)開(kāi) 簡(jiǎn)書(shū) 的喚醒路徑進(jìn)行查看
簡(jiǎn)書(shū)喚醒路徑
可以看到以上3條喚醒路徑,但是涵蓋的喚醒應(yīng)用總數(shù)卻達(dá)到了23+43+28款,數(shù)目真心驚人。請(qǐng)注意,這只是我手機(jī)上一款app的喚醒路徑而已,到了這里是不是有點(diǎn)細(xì)思極恐。
當(dāng)然,這里依然存在一個(gè)疑問(wèn),就是LBE分析這些喚醒路徑和互相喚醒的應(yīng)用是基于什么思路,我們不得而知。所以我們也無(wú)法確定其分析結(jié)果是否準(zhǔn)確,如果有LBE的童鞋看到此文章,不知可否告知一下思路呢?但是,手機(jī)打開(kāi)一個(gè)app就喚醒一大批,我自己可是親身體驗(yàn)到這種酸爽的......
白色保活
白色?;钍侄畏浅:?jiǎn)單,就是調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification,用來(lái)讓用戶(hù)知道有這樣一個(gè)app在運(yùn)行著,哪怕當(dāng)前的app退到了后臺(tái)。如下方的LBE和QQ音樂(lè)這樣:
灰色?;?/strong>
灰色?;?,這種保活手段是應(yīng)用范圍最廣泛。它是利用系統(tǒng)的漏洞來(lái)啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程,與普通的啟動(dòng)方式區(qū)別在于,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification,看起來(lái)就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣。這樣做帶來(lái)的好處就是,用戶(hù)無(wú)法察覺(jué)到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的。那么如何利用系統(tǒng)的漏洞呢,大致的實(shí)現(xiàn)思路和代碼如下:
思路一:API < 18,啟動(dòng)前臺(tái)Service時(shí)直接傳入new Notification();
思路二:API >= 18,同時(shí)啟動(dòng)兩個(gè)id相同的前臺(tái)Service,然后再將后啟動(dòng)的Service做stop處理;
public class GrayService extends Service { private final static int GRAY_SERVICE_ID = 1001; @Override public int onStartCommand(Intent intent, int flags, int startId) { if (Build.VERSION.SDK_INT < 18) { startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隱藏Notification上的圖標(biāo) } else { Intent innerIntent = new Intent(this, GrayInnerService.class); startService(innerIntent); startForeground(GRAY_SERVICE_ID, new Notification()); } return super.onStartCommand(intent, flags, startId); } ... ... /** * 給 API >= 18 的平臺(tái)上用的灰色?;钍侄? */ public static class GrayInnerService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { startForeground(GRAY_SERVICE_ID, new Notification()); stopForeground(true); stopSelf(); return super.onStartCommand(intent, flags, startId); } } }
代碼大致就是這樣,能讓你神不知鬼不覺(jué)的啟動(dòng)著一個(gè)前臺(tái)Service。其實(shí)市面上很多app都用著這種灰色保活的手段,什么?你不信?好吧,我們來(lái)驗(yàn)證一下。流程很簡(jiǎn)單,打開(kāi)一個(gè)app,看下系統(tǒng)通知欄有沒(méi)有一個(gè) Notification,如果沒(méi)有,我們就進(jìn)入手機(jī)的adb shell模式,然后輸入下面的shell命令
dumpsys activity services PackageName
打印出指定包名的所有進(jìn)程中的Service信息,看下有沒(méi)有 isForeground=true 的關(guān)鍵信息。如果通知欄沒(méi)有看到屬于app的 Notification 且又看到 isForeground=true 則說(shuō)明了,此app利用了這種灰色?;畹氖侄?。
下面分別是我手機(jī)上微信、qq、支付寶、陌陌的測(cè)試結(jié)果,大家有興趣也可以自己驗(yàn)證一下。
微信
手Q
支付寶
陌陌
其實(shí)Google察覺(jué)到了此漏洞的存在,并逐步進(jìn)行封堵。這就是為什么這種保活方式分 API >= 18 和 API < 18 兩種情況,從Android5.0的ServiceRecord類(lèi)的postNotification函數(shù)源代碼中可以看到這樣的一行注釋
當(dāng)某一天 API >= 18 的方案也失效的時(shí)候,我們就又要另謀出路了。需要注意的是,使用灰色保活并不代表著你的Service就永生不死了,只能說(shuō)是提高了進(jìn)程的優(yōu)先級(jí)。如果你的app進(jìn)程占用了大量的內(nèi)存,按照回收進(jìn)程的策略,同樣會(huì)干掉你的app。感興趣于灰色?;钍侨绾卫孟到y(tǒng)漏洞不顯示 Notification 的童鞋,可以研究一下系統(tǒng)的 ServiceRecord、NotificationManagerService 等相關(guān)源代碼,因?yàn)椴皇潜疚牡闹攸c(diǎn),所以不做詳述。
嘮叨的分割線
到這里基本就介紹完了 黑、白、灰 三種實(shí)現(xiàn)方式,僅僅從代碼層面去講?;钍遣粔虻?,我希望能夠通過(guò)系統(tǒng)的進(jìn)程回收機(jī)制來(lái)理解?;?,這樣能夠讓我們更好的避免踩到進(jìn)程被殺的坑。
進(jìn)程回收機(jī)制
熟悉Android系統(tǒng)的童鞋都知道,系統(tǒng)出于體驗(yàn)和性能上的考慮,app在退到后臺(tái)時(shí)系統(tǒng)并不會(huì)真正的kill掉這個(gè)進(jìn)程,而是將其緩存起來(lái)。打開(kāi)的應(yīng)用越多,后臺(tái)緩存的進(jìn)程也越多。在系統(tǒng)內(nèi)存不足的情況下,系統(tǒng)開(kāi)始依據(jù)自身的一套進(jìn)程回收機(jī)制來(lái)判斷要kill掉哪些進(jìn)程,以騰出內(nèi)存來(lái)供給需要的app。這套殺進(jìn)程回收內(nèi)存的機(jī)制就叫 Low Memory Killer ,它是基于Linux內(nèi)核的 OOM Killer(Out-Of-Memory killer)機(jī)制誕生。
了解完 Low Memory Killer,再科普一下oom_adj。什么是oom_adj?它是linux內(nèi)核分配給每個(gè)系統(tǒng)進(jìn)程的一個(gè)值,代表進(jìn)程的優(yōu)先級(jí),進(jìn)程回收機(jī)制就是根據(jù)這個(gè)優(yōu)先級(jí)來(lái)決定是否進(jìn)行回收。對(duì)于oom_adj的作用,你只需要記住以下幾點(diǎn)即可:
- 進(jìn)程的oom_adj越大,表示此進(jìn)程優(yōu)先級(jí)越低,越容易被殺回收;越小,表示進(jìn)程優(yōu)先級(jí)越高,越不容易被殺回收
- 普通app進(jìn)程的oom_adj>=0,系統(tǒng)進(jìn)程的oom_adj才可能<0
那么我們?nèi)绾尾榭催M(jìn)程的oom_adj值呢,需要用到下面的兩個(gè)shell命令
ps | grep PackageName //獲取你指定的進(jìn)程信息
這里是以我寫(xiě)的demo代碼為例子,紅色圈中部分別為下面三個(gè)進(jìn)程的ID
- UI進(jìn)程:com.clock.daemon
- 普通后臺(tái)進(jìn)程:com.clock.daemon:bg
- 灰色?;钸M(jìn)程:com.clock.daemon:gray
當(dāng)然,這些進(jìn)程的id也可以通過(guò)AndroidStudio獲得
接著我們來(lái)再來(lái)獲取三個(gè)進(jìn)程的oom_adj
cat /proc/進(jìn)程ID/oom_adj
從上圖可以看到UI進(jìn)程和灰色?;頢ervice進(jìn)程的oom_adj=0,而普通后臺(tái)進(jìn)程oom_adj=15。到這里估計(jì)你也能明白,為什么普通的后臺(tái)進(jìn)程容易被回收,而前臺(tái)進(jìn)程則不容易被回收了吧。但明白這個(gè)還不夠,接著看下圖
上面是我把a(bǔ)pp切換到后臺(tái),再進(jìn)行一次oom_adj的檢驗(yàn),你會(huì)發(fā)現(xiàn)UI進(jìn)程的值從0變成了6,而灰色?;畹腟ervice進(jìn)程則從0變成了1。這里可以觀察到,app退到后臺(tái)時(shí),其所有的進(jìn)程優(yōu)先級(jí)都會(huì)降低。但是UI進(jìn)程是降低最為明顯的,因?yàn)樗加玫膬?nèi)存資源最多,系統(tǒng)內(nèi)存不足的時(shí)候肯定優(yōu)先殺這些占用內(nèi)存高的進(jìn)程來(lái)騰出資源。所以,為了盡量避免后臺(tái)UI進(jìn)程被殺,需要盡可能的釋放一些不用的資源,尤其是圖片、音視頻之類(lèi)的。
從Android官方文檔中,我們也能看到優(yōu)先級(jí)從高到低列出了這些不同類(lèi)型的進(jìn)程:Foreground process、Visible process、Service process、Background process、Empty process。
總結(jié)(文末有福利)
絮絮叨叨寫(xiě)完了這么多,最后來(lái)做個(gè)小小的總結(jié)?;貧w到開(kāi)篇提到QQ進(jìn)程不死的問(wèn)題,我也曾認(rèn)為存在這樣一種技術(shù)。可惜我把手機(jī)root后,殺掉QQ進(jìn)程之后就再也起不來(lái)了。有些手機(jī)廠商把這些知名的app放入了自己的白名單中,保證了進(jìn)程不死來(lái)提高用戶(hù)體驗(yàn)(如微信、QQ、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通app一樣躲避不了被殺的命運(yùn),為了盡量避免被殺,還是老老實(shí)實(shí)去做好優(yōu)化工作吧。
所以,進(jìn)程?;畹母痉桨附K究還是回到了性能優(yōu)化上,進(jìn)程永生不死終究是個(gè)徹頭徹尾的偽命題!
補(bǔ)充更新
有童鞋問(wèn),在華為的機(jī)子上發(fā)現(xiàn)微信和手Q的UI進(jìn)程退到后臺(tái),oom_adj的值一點(diǎn)都沒(méi)有變,是不是有什么黑科技在其中。為此,我稍稍驗(yàn)證了一下,驗(yàn)證方式就是把demo工程的包名改成手機(jī)QQ的,編譯運(yùn)行在華為的機(jī)子上,發(fā)現(xiàn)我的進(jìn)程怎么殺也都是不死的,退到后臺(tái)oom_adj的值同樣不發(fā)生變化,而恢復(fù)原來(lái)的包名就不行了。所以,你懂的,手Q就在華為機(jī)子的白名單中。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android如何實(shí)現(xiàn)社交應(yīng)用中的評(píng)論與回復(fù)功能詳解
目前,各種App的社區(qū)或者用戶(hù)曬照片、發(fā)說(shuō)說(shuō)的地方,都提供了評(píng)論功能,為了更好地學(xué)習(xí),自己把這個(gè)功能實(shí)現(xiàn)了一下,下面這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)社交應(yīng)用中的評(píng)論與回復(fù)功能的相關(guān)資料,需要的朋友可以參考下2018-07-07Android JSON數(shù)據(jù)與實(shí)體類(lèi)之間的相互轉(zhuǎn)化(GSON的用法)
這篇文章主要介紹了Android JSON數(shù)據(jù)與實(shí)體類(lèi)之間的相互轉(zhuǎn)化(GSON的用法),非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-01-01基于android樣式與主題(style&theme)的詳解
本篇文章是對(duì)android中的樣式與主題(style&theme)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android實(shí)現(xiàn)音樂(lè)播放進(jìn)度條傳遞信息的兩種方式(在service和activity中)
這篇文章主要介紹了Android:在service和activity之中,實(shí)現(xiàn)音樂(lè)播放進(jìn)度條傳遞信息的兩種方式,MediaPlayer做音樂(lè)播放器采坑以及解決辦法,需要的朋友可以參考下2020-05-05Android搜索框(SearchView)的功能和用法詳解
這篇文章主要為大家詳細(xì)介紹了Android搜索框SearchView的功能和用法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05android 字體顏色選擇器(ColorPicker)介紹
本文將詳細(xì)介紹android 字體顏色選擇器(ColorPicker)需要了解更多的朋友可以參考下2012-11-11Android滑動(dòng)到頂部和底部時(shí)出現(xiàn)的陰影如何去掉
本文給大家介紹android滑動(dòng)到頂部和底部時(shí)出現(xiàn)的陰影去掉的解決方法,本文還涉及到listview各個(gè)屬性的用法介紹,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-10-10