Android系统中的进程管理:进程的优先级
本文是Android進(jìn)程管理系列文章的第二篇,會講解進(jìn)程管理中的優(yōu)先級管理。
進(jìn)程管理的第一篇文章:《進(jìn)程的創(chuàng)建》請?zhí)D(zhuǎn)至這里。
本文適合Android平臺的應(yīng)用程序開發(fā)者,也適合對于Android系統(tǒng)內(nèi)部實現(xiàn)感興趣的讀者。
前言
進(jìn)程的優(yōu)先級反應(yīng)了系統(tǒng)對于進(jìn)程重要性的判定。
在Android系統(tǒng)中,進(jìn)程的優(yōu)先級影響著以下三個因素:
- 當(dāng)內(nèi)存緊張時,系統(tǒng)對于進(jìn)程的回收策略
- 系統(tǒng)對于進(jìn)程的CPU調(diào)度策略
- 虛擬機(jī)對于進(jìn)程的內(nèi)存分配和垃圾回收策略
本文會主要講解系統(tǒng)對于進(jìn)程優(yōu)先級的判斷依據(jù)和計算方法。
在Processes and Threads?(如果你還沒有閱讀,請立即閱讀一下這篇文章)一文中,我們已經(jīng)了解到,系統(tǒng)對于進(jìn)程的優(yōu)先級有如下五個分類:
實際上這只是一個粗略的劃分。在系統(tǒng)的內(nèi)部實現(xiàn)中,優(yōu)先級遠(yuǎn)不止這么五種。
優(yōu)先級的依據(jù)
我們來簡單列一下應(yīng)用組件與進(jìn)程的相關(guān)信息:
- 每一個Android的應(yīng)用進(jìn)程中,都可能包含四大組件中的一個/種或者多個/種。
- 對于運(yùn)行中的Service和ContentProvider來說,可能有若干個客戶端進(jìn)程正在對其使用。
- 應(yīng)用進(jìn)程是由ActivityManagerService發(fā)送請求讓zygote創(chuàng)建的,并且ActivityManagerService中對于每一個運(yùn)行中的進(jìn)程都有一個ProcessRecord對象與之對應(yīng)。
ProcessRecord簡化圖如下所示:
在ProcessRecord中,詳細(xì)記錄了應(yīng)用組件的相關(guān)信息,相關(guān)代碼如下:
// all activities running in the process final ArrayList<ActivityRecord> activities = new ArrayList<>(); // all ServiceRecord running in this process final ArraySet<ServiceRecord> services = new ArraySet<>(); // services that are currently executing code (need to remain foreground). final ArraySet<ServiceRecord> executingServices = new ArraySet<>(); // All ConnectionRecord this process holds final ArraySet<ConnectionRecord> connections = new ArraySet<>(); // all IIntentReceivers that are registered from this process. final ArraySet<ReceiverList> receivers = new ArraySet<>(); // class (String) -> ContentProviderRecord final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>(); // All ContentProviderRecord process is using final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();這里的:
- activities?記錄了進(jìn)程中運(yùn)行的Activity
- services,executingServices?記錄了進(jìn)程中運(yùn)行的Service
- receivers?記錄了進(jìn)程中運(yùn)行的BroadcastReceiver
- pubProviders?記錄了進(jìn)程中運(yùn)行的ContentProvider
而:
- connections?記錄了對于Service連接
- conProviders?記錄了對于ContentProvider的連接
連接就是對于客戶端使用狀態(tài)的記錄,對于Service和ContentProvider是類似的,每有一個客戶端就需要記錄一個連接。連接的意義在于:連接的客戶端的進(jìn)程優(yōu)先級會影響被使用的Service和ContentProvider所在進(jìn)程的優(yōu)先級。?例如:當(dāng)一個后臺的Service正在被一個前臺的Activity使用,那么這個后臺的Service就需要設(shè)置一個較高的優(yōu)先級以便不會被回收。(否則后臺Service進(jìn)程一旦被回收,便會對前臺的Activity造成影響。)
而所有這些組件的狀態(tài)就是其所在進(jìn)程優(yōu)先級的決定性因素。?組件的狀態(tài)是指:
- Activity是否在前臺,用戶是否可見
- Service正在被哪些客戶端使用
- ContentProvider正在被哪些客戶端使用
- BroadcastReceiver是否正在接受廣播
優(yōu)先級的基礎(chǔ)
oom_score_adj
對于每一個運(yùn)行中的進(jìn)程,Linux內(nèi)核都通過proc文件系統(tǒng)暴露這樣一個文件來允許其他程序修改指定進(jìn)程的優(yōu)先級:
/proc/[pid]/oom_score_adj。(修改這個文件需要root權(quán)限)
這個文件允許的值的范圍是:-1000 ~ +1000之間。值越小,表示進(jìn)程越重要。
當(dāng)內(nèi)存非常緊張時,系統(tǒng)便會遍歷所有進(jìn)程,以確定哪個進(jìn)程需要被殺死以回收內(nèi)存,此時便會讀取oom_score_adj?這個文件的值。關(guān)于這個值的使用,在后面講解進(jìn)程回收的的時候,我們會詳細(xì)講解。
PS:在Linux 2.6.36之前的版本中,Linux 提供調(diào)整優(yōu)先級的文件是/proc/[pid]/oom_adj。這個文件允許的值的范圍是-17 ~ +15之間。數(shù)值越小表示進(jìn)程越重要。 這個文件在新版的Linux中已經(jīng)廢棄。
但你仍然可以使用這個文件,當(dāng)你修改這個文件的時候,內(nèi)核會直接進(jìn)行換算,將結(jié)果反映到oom_score_adj這個文件上。
Android早期版本的實現(xiàn)中也是依賴oom_adj這個文件。但是在新版本中,已經(jīng)切換到使用oom_score_adj這個文件。
ProcessRecord中下面這些屬性反應(yīng)了oom_score_adj的值:
int maxAdj; // Maximum OOM adjustment for this process int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process int curAdj; // Current OOM adjustment for this process int setAdj; // Last set OOM adjustment for this processmaxAdj?指定了該進(jìn)程允許的oom_score_adj最大值。這個屬性主要是給系統(tǒng)應(yīng)用和常駐內(nèi)存的進(jìn)程使用,這些進(jìn)程的優(yōu)先級的計算方法與應(yīng)用進(jìn)程的計算方法不一樣,通過設(shè)定maxAdj保證這些進(jìn)程一直擁有較高的優(yōu)先級(在后面”優(yōu)先級的算法“中,我們會看到對于這個屬性的使用)。
除此之外,還有四個屬性。
這其中,curXXX這一組記錄了這一次優(yōu)先級計算的結(jié)果。在計算完成之后,會將curXXX復(fù)制給對應(yīng)的setXXX這一組上進(jìn)行備份。 (下文的其他屬性也會看到curXXX和setXXX的形式,和這里的原理是一樣的。)
另外,xxxRawAdj記錄了沒有經(jīng)過限制的adj值,“沒有經(jīng)過限制”是指這其中的值可能是超過了oom_score_adj文件所允許的范圍(-1000 ~ 1000)。
為了便于管理,ProcessList.java中預(yù)定義了oom_score_adj的可能取值。
其實這里的預(yù)定義值也是對應(yīng)用進(jìn)程的一種分類,它們是:
static final int UNKNOWN_ADJ = 1001; // 未知進(jìn)程 static final int PREVIOUS_APP_ADJ = 700; // 前一個應(yīng)用 static final int HOME_APP_ADJ = 600; // 桌面進(jìn)程 static final int SERVICE_ADJ = 500; // 包含了Service的進(jìn)程 static final int HEAVY_WEIGHT_APP_ADJ = 400; // 重量級進(jìn)程 static final int BACKUP_APP_ADJ = 300; // 備份應(yīng)用進(jìn)程 static final int PERCEPTIBLE_APP_ADJ = 200; // 可感知的進(jìn)程 static final int VISIBLE_APP_ADJ = 100; // 可見進(jìn)程 static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1; static final int FOREGROUND_APP_ADJ = 0; // 前臺進(jìn)程 static final int PERSISTENT_SERVICE_ADJ = -700; // 常駐服務(wù)進(jìn)程 static final int PERSISTENT_PROC_ADJ = -800; // 常駐應(yīng)用進(jìn)程 static final int SYSTEM_ADJ = -900; // 系統(tǒng)進(jìn)程 static final int NATIVE_ADJ = -1000; // native系統(tǒng)進(jìn)程這里我們看到,FOREGROUND_APP_ADJ = 0,這個是前臺應(yīng)用進(jìn)程的優(yōu)先級。這是用戶正在交互的應(yīng)用,它們是很重要的,系統(tǒng)不應(yīng)當(dāng)把它們回收了。
FOREGROUND_APP_ADJ = 0是普通應(yīng)用程序能夠獲取到的最高優(yōu)先級。
而VISIBLE_APP_ADJ,PERCEPTIBLE_APP_ADJ,PREVIOUS_APP_ADJ這幾個級別的優(yōu)先級就逐步降低了。
VISIBLE_APP_ADJ是具有可見Activity進(jìn)程的優(yōu)先級:同一時刻,不一定只有一個Activity是可見的,如果前臺Activity設(shè)置了透明屬性,那么背后的Activity也是可見的。
PERCEPTIBLE_APP_ADJ是指用戶可感知的進(jìn)程,可感知的進(jìn)程包括:
- 進(jìn)程中包含了處于pause狀態(tài)或者正在pause的Activity
- 進(jìn)程中包含了正在stop的Activity
- 進(jìn)程中包含了前臺的Service
另外,PREVIOUS_APP_ADJ描述的是前一個應(yīng)用的優(yōu)先級。所謂“前一個應(yīng)用”是指:在啟動新的Activity時,如果新啟動的Activity是屬于一個新的進(jìn)程的,那么當(dāng)前即將被stop的Activity所在的進(jìn)程便會成為“前一個應(yīng)用”進(jìn)程。
而HEAVY_WEIGHT_APP_ADJ?描述的重量級進(jìn)程是指那些通過Manifest指明不能保存狀態(tài)的應(yīng)用進(jìn)程。
除此之外,Android系統(tǒng)中,有一些系統(tǒng)應(yīng)用會常駐內(nèi)存,這些應(yīng)用通常是系統(tǒng)實現(xiàn)的一部分,如果它們不存在,系統(tǒng)將處于比較奇怪的狀態(tài),例如SystemUI(狀態(tài)欄,Keyguard都處于這個應(yīng)用中)。
所以它們的優(yōu)先級比所有應(yīng)用進(jìn)程的優(yōu)先級更高:PERSISTENT_SERVICE_ADJ = -700,PERSISTENT_PROC_ADJ = -800。
另外,還有一些系統(tǒng)服務(wù)的實現(xiàn),如果這些系統(tǒng)服務(wù)不存在,系統(tǒng)將無法工作,所以這些應(yīng)用的優(yōu)先級最高,幾乎是任何任何時候都需要存在的:SYSTEM_ADJ = -900,NATIVE_ADJ = -1000。
Schedule Group
內(nèi)核負(fù)責(zé)了進(jìn)程的CPU調(diào)度,所有運(yùn)行中的進(jìn)程并非能平等的能獲取相等的時間片。在ProcessRecord中,通過Schedule Group來記錄進(jìn)程的調(diào)度組:
int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class它們可能的取值定義在ProcessList.java中:
// Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE static final int SCHED_GROUP_BACKGROUND = 0; // Activity manager's version of Process.THREAD_GROUP_DEFAULT static final int SCHED_GROUP_DEFAULT = 1; // Activity manager's version of Process.THREAD_GROUP_TOP_APP static final int SCHED_GROUP_TOP_APP = 2; // Activity manager's version of Process.THREAD_GROUP_TOP_APP // Disambiguate between actual top app and processes bound to the top app static final int SCHED_GROUP_TOP_APP_BOUND = 3;Process State
進(jìn)程的狀態(tài)會影響虛擬機(jī)對于進(jìn)程的內(nèi)存分配和垃圾回收策略,ProcessRecord中的下面這幾個屬性記錄了進(jìn)程的狀態(tài):
int curProcState; // Currently computed process state int repProcState; // Last reported process state int setProcState; // Last set process state in process tracker int pssProcState; // Currently requesting pss for這些屬性可能的取值定義在ActivityManager中,這些常量的名稱已經(jīng)說明了其作用:
public static final int PROCESS_STATE_NONEXISTENT = -1;public static final int PROCESS_STATE_PERSISTENT = 0;public static final int PROCESS_STATE_PERSISTENT_UI = 1;public static final int PROCESS_STATE_TOP = 2;public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;public static final int PROCESS_STATE_TOP_SLEEPING = 5;public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;public static final int PROCESS_STATE_BACKUP = 8;public static final int PROCESS_STATE_HEAVY_WEIGHT = 9;public static final int PROCESS_STATE_SERVICE = 10;public static final int PROCESS_STATE_RECEIVER = 11;public static final int PROCESS_STATE_HOME = 12;public static final int PROCESS_STATE_LAST_ACTIVITY = 13;public static final int PROCESS_STATE_CACHED_ACTIVITY = 14;public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;public static final int PROCESS_STATE_CACHED_EMPTY = 16;優(yōu)先級的更新
前文已經(jīng)提到,系統(tǒng)會對處于不同狀態(tài)的進(jìn)程設(shè)置不同的優(yōu)先級。但實際上,進(jìn)程的狀態(tài)是一直在變化中的。例如:用戶可以隨時會啟動一個新的Activity,或者將一個前臺的Activity切換到后臺。在這個時候,發(fā)生狀態(tài)變化的Activity的所在進(jìn)程的優(yōu)先級就需要進(jìn)行更新。
并且,Activity可能會使用其他的Service或者ContentProvider。當(dāng)Activity的進(jìn)程優(yōu)先級發(fā)生變化的時候,它所使用的Service或者ContentProvider的優(yōu)先級也應(yīng)當(dāng)發(fā)生變化。
ActivityManagerService中有如下兩個方法用來更新進(jìn)程的優(yōu)先級:
- final boolean updateOomAdjLocked(ProcessRecord app)
- final void updateOomAdjLocked()
第一個方法是針對指定的單個進(jìn)程更新優(yōu)先級。第二個是對所有進(jìn)程更新優(yōu)先級。
在下面的這些情況下,需要對指定的應(yīng)用進(jìn)程更新優(yōu)先級:
- 當(dāng)有一個新的進(jìn)程開始使用本進(jìn)程中的ContentProvider
- 當(dāng)本進(jìn)程中的一個Service被其他進(jìn)程bind或者unbind
- 當(dāng)本進(jìn)程中的Service的執(zhí)行完成或者退出了
- 當(dāng)本進(jìn)程中一個BroadcastReceiver正在接受廣播
- 當(dāng)本進(jìn)程中的BackUpAgent啟動或者退出了
final boolean updateOomAdjLocked(ProcessRecord app)?被調(diào)用的關(guān)系如下圖所示:
在有些情況下,系統(tǒng)需要對所有應(yīng)用進(jìn)程的優(yōu)先級進(jìn)行更新,譬如:
- 當(dāng)有一個新的進(jìn)程啟動時
- 當(dāng)有一個進(jìn)程退出時
- 當(dāng)系統(tǒng)在清理后臺進(jìn)程時
- 當(dāng)有一個進(jìn)程被標(biāo)記為前臺進(jìn)程時
- 當(dāng)有一個進(jìn)程進(jìn)入或者退出cached狀態(tài)時
- 當(dāng)系統(tǒng)鎖屏或者解鎖時
- 當(dāng)有一個Activity啟動或者退出時
- 當(dāng)系統(tǒng)正在處理一個廣播事件時
- 當(dāng)前臺Activity發(fā)生改變時
- 當(dāng)有一個Service啟動時
final void updateOomAdjLocked()?被調(diào)用的關(guān)系圖如下所示:?
優(yōu)先級的算法
ActivityManagerService中的computeOomAdjLocked方法負(fù)責(zé)計算進(jìn)程的優(yōu)先級,這個方法總計約700行,執(zhí)行流程主要包含如下10個步驟:
下面我們來詳細(xì)看其中的每一個步驟:
-
1.確認(rèn)該進(jìn)程是否是空進(jìn)程
空進(jìn)程中沒有任何組件,因此主線程也為null(ProcessRecord.thread描述了應(yīng)用進(jìn)程的主線程)。
如果是空進(jìn)程,則不需要再做后面的計算了。直接設(shè)置為ProcessList.CACHED_APP_MAX_ADJ級別即可。
-
2.確認(rèn)是否設(shè)置了maxAdj
上文已經(jīng)提到過,系統(tǒng)進(jìn)程或者Persistent進(jìn)程會通過設(shè)置maxAdj來保持其較高的優(yōu)先級,對于這類進(jìn)程不用按照普通進(jìn)程的算法進(jìn)行計算,直接按照maxAdj的值設(shè)置即可。
-
3.確認(rèn)進(jìn)程中是否有前臺優(yōu)先級的組件
前臺優(yōu)先級的組件是指:
a.前臺的Activity; b.正在接受廣播的Receiver; c.正在執(zhí)行任務(wù)的Service;
注:除此之外,還有Instrumentation被認(rèn)為是具有較高優(yōu)先級的。Instrumentation應(yīng)用是輔助測試用的,正常運(yùn)行的系統(tǒng)中不用考慮這種應(yīng)用。
假設(shè)進(jìn)程中包含了以上提到的前臺優(yōu)先級的任何一個組件,則直接設(shè)置進(jìn)程優(yōu)先級為FOREGROUND_APP_ADJ即可。因為這已經(jīng)是應(yīng)用程序能夠獲取的最高優(yōu)先級了。
-
4.確認(rèn)進(jìn)程中是否有較高優(yōu)先級的Activity
這里需要遍歷進(jìn)程中的所有Activity,找出其中優(yōu)先級最高的設(shè)置為進(jìn)程的優(yōu)先級。
即便Activity不是前臺Activity,但是處于下面這些狀態(tài)的Activity優(yōu)先級也是被認(rèn)為是較高優(yōu)先級的:
- 該Activity處于可見狀態(tài)
- 該Activity處于Pause正在Pause狀態(tài)
- 該Activity正在stop
-
5.確認(rèn)進(jìn)程中是否有前臺Service
通過startForeground啟動的Service被認(rèn)為是前臺Service。給予這類進(jìn)程PERCEPTIBLE_APP_ADJ級別的優(yōu)先級。
-
6.確認(rèn)是否是特殊類型進(jìn)程
特殊類型的進(jìn)程包括:重量級進(jìn)程,桌面進(jìn)程,前一個應(yīng)用進(jìn)程,正在執(zhí)行備份的進(jìn)程。 “重量級進(jìn)程”和“前一個應(yīng)用”進(jìn)程在上文中已經(jīng)說過了。而桌面就是指Android上的Launcher。
-
7.根據(jù)所有Service的客戶端計算優(yōu)先級
這里需要遍歷所有的Service,并且還需要遍歷每一個Service的所有連接。然后根據(jù)連接的關(guān)系確認(rèn)客戶端進(jìn)程的優(yōu)先級來確定當(dāng)前進(jìn)程的優(yōu)先級。
ConnectionRecord.binding.client即為客戶端進(jìn)程ProcessRecord,由此便可以知道客戶端進(jìn)程的優(yōu)先級。
-
8.根據(jù)所有Provider的客戶端確認(rèn)優(yōu)先級
這里與Service類似,需要遍歷所有的Provider,以及每一個Provider的所有連接。然后根據(jù)連接的關(guān)系確認(rèn)客戶端進(jìn)程的優(yōu)先級來確定當(dāng)前進(jìn)程的優(yōu)先級。
類似的,ContentProviderConnection.client為客戶端進(jìn)程的ProcessRecord。
- 9.收尾工作 收尾工作主要是根據(jù)進(jìn)程中的Service,Provider的一些特殊狀態(tài)做一些處理,另外還有針對空進(jìn)程以及設(shè)置了maxAdj的進(jìn)程做一些處理,這里就不貼出代碼了。
這里想專門說明一下的是,在這一步還會對Service進(jìn)程做ServiceB的區(qū)分。系統(tǒng)將Service進(jìn)程分為ServiceA和ServiceB。ServiceA是相對來說較新的Service,而ServiceB相對來說是比較“老舊”的,對用戶來說可能是不那么感興趣的,因此ServiceB的優(yōu)先級會相對低一些。
static final int SERVICE_B_ADJ = 800; static final int SERVICE_ADJ = 500;而ServiceB的標(biāo)準(zhǔn)是:app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);?即:所有Service進(jìn)程的前1/3為ServiceA,剩下為ServiceB。
if (adj == ProcessList.SERVICE_ADJ) {if (doingAll) {app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);mNewNumServiceProcs++;if (!app.serviceb) {if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL&& app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {app.serviceHighRam = true;app.serviceb = true;} else {mNewNumAServiceProcs++;}} else {app.serviceHighRam = false;}}if (app.serviceb) {adj = ProcessList.SERVICE_B_ADJ;} }app.curRawAdj = adj;- 10.保存結(jié)果 最終需要把本次的計算結(jié)果保存到ProcessRecord中:
優(yōu)先級的生效
優(yōu)先級的生效是指:將計算出來的優(yōu)先級真正應(yīng)用到系統(tǒng)中,applyOomAdjLocked?方法負(fù)責(zé)了此項工作。
前文中我們提到,優(yōu)先級意味著三個方面,這里的生效就對應(yīng)了這三個方面:
ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);?將計算出來的adj值寫入到procfs中,即:/proc/[pid]/oom_score_adj?這個文件中。
Process.setProcessGroup(app.pid, processGroup);?用來設(shè)置進(jìn)程的調(diào)度組。
app.thread.setProcessState(app.repProcState);?這個方法會最終調(diào)用到?VMRuntime.getRuntime().updateProcessState();將進(jìn)程的狀態(tài)設(shè)置到虛擬機(jī)中。
結(jié)束語
前言中我們提到,“優(yōu)先級反應(yīng)了系統(tǒng)對于進(jìn)程重要性的判定。”
那么,系統(tǒng)如何評價進(jìn)程的優(yōu)先級,便是系統(tǒng)本身一個很重要的特性。了解系統(tǒng)的這一特性對于我們開發(fā)應(yīng)用程序,以及對于應(yīng)用程序運(yùn)行的行為分析是很有意義的。
系統(tǒng)在判定優(yōu)先級的時候,應(yīng)當(dāng)做到公平公正,并且不能讓開發(fā)者有機(jī)可乘。
“公平公正”是指系統(tǒng)需要站在一個中間人的狀態(tài)下,不偏倚任何一個應(yīng)用,公正的將系統(tǒng)資源分配給真正需要的進(jìn)程。并且在系統(tǒng)資源緊張的時候,回收不重要的進(jìn)程。
通過上文的分析,我們看到,Android系統(tǒng)認(rèn)為“重要”的進(jìn)程主要有三類:
不過對于這一點是有改進(jìn)的空間的,例如,可以引入用戶習(xí)慣的分析:如果是用戶頻繁使用的應(yīng)用,可以給予這些應(yīng)用更高的優(yōu)先級以提升這些應(yīng)用的響應(yīng)速度。目前,國內(nèi)一些Android定制廠商已經(jīng)開始做這類功能的支持。
“不能讓開發(fā)者有機(jī)可乘”是指:系統(tǒng)對于進(jìn)程優(yōu)先級的判定的因素應(yīng)當(dāng)是不能被開發(fā)者利用的。因為一旦開發(fā)者可以利用,每個開發(fā)者都肯定會將自己的設(shè)置為高優(yōu)先級,來搶占更多的資源。
需要說明的是,Android在這個方面是存在缺陷的:在Android系統(tǒng)上,可以通過startForeground拿到前臺的優(yōu)先級的。后來Google也意識到這個問題,于是在API Level 18以上的版本上,調(diào)用startForeground這個API會在通知欄顯示一條通知以告知用戶。但是,這個改進(jìn)是有Bug的:開發(fā)者可以同時通過startForeground啟動兩個Service,指定同樣的通知id,然后退出其中一個,這樣應(yīng)用的不會在通知欄顯示通知圖標(biāo),并且拿到了前臺的優(yōu)先級。這個便是讓開發(fā)者“有機(jī)可乘”了。
由于筆者認(rèn)為這不是一個很好的行為,具體的做法不細(xì)說了,有興趣自己去網(wǎng)上搜索。
本文,我們詳細(xì)講解的Android中進(jìn)程優(yōu)先級的計算方法,在下一篇文章中,我們會專門講解與進(jìn)程回收相關(guān)的內(nèi)容,敬請期待。
參考資料與推薦讀物
Embedded Android: Porting, Extending, and Customizing
The proc filesystem
sched_setscheduler
原文: http://qiangbo.space/2016-11-23/AndroidAnatomy_Process_OomAdj/
總結(jié)
以上是生活随笔為你收集整理的Android系统中的进程管理:进程的优先级的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android开发架构规范
- 下一篇: Android系统中的进程管理:进程的创