編輯:關於Android編程
Anroid的殺進程策略是基於kernel裡的LowMemoryKiller模塊,LMK的實現在這裡不展開分析,大致的原理就是LMK注冊了內核的shrinker(lowmem_shrinker),內核線程kswapd,在linux回收內存分頁的時候,通過shrinker回調回來給LMK。LMK根據每個進程的oom_adj值,將大於某個阈值的進程都發送SIGKILL信號殺掉。oom_adj的阈值因內存情況不同而不同,具體的對應關系可以查看/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree這兩個文件。oom_adj的值從-17到16,值越小,代表越重要,越晚被殺,比如一個應用如果在前台的時候,oom_adj的值就會減到0。也就是說設為負值的那些應用,會比前台應用還晚被殺。於是,系統殺進程的策略就可以通過調整每個進程的oom_adj的值來實現。
oom_adj的值有如下類:
// 不可見的Activity static final int CACHED_APP_MAX_ADJ = 15; static final int CACHED_APP_MIN_ADJ = 9; / 比較老的Service static final int SERVICE_B_ADJ = 8; // 上一個應用,這樣在做任務切換,或者返回的時候,能夠快速載入 static final int PREVIOUS_APP_ADJ = 7; / 桌面 App static final int HOME_APP_ADJ = 6; / Service static final int SERVICE_ADJ = 5; // 重量級應用,早期版本可以在manifest裡加cantSaveState來聲明,新版已經注釋了,目前沒看到哪裡可以設置 static final int HEAVY_WEIGHT_APP_ADJ = 4; // 備份代理應用,manifest裡Application標簽裡可以聲明backAgent static final int BACKUP_APP_ADJ = 3; // 可感知的App,比如有Pause狀態的Activity,Stopping狀態的Activity,被一個可見的進程BindService的進程等 static final int PERCEPTIBLE_APP_ADJ = 2; // 前台可見的Activity, static final int VISIBLE_APP_ADJ = 1; / 前台App,包括Top App,Instrumentation Test App,正在接收broadcast的App,正在執行的Service等 static final int FOREGROUND_APP_ADJ = 0; / 被Persist App BindService的進程 static final int PERSISTENT_SERVICE_ADJ = -11; / 聲明了persist的進程 static final int PERSISTENT_PROC_ADJ = -12; // 系統進程,比如system server static final int SYSTEM_ADJ = -16; // 不被系統管的Native進程,比如/system/bin下運行的那些服務(surfaceflinger etc) static final int NATIVE_ADJ = -17;
oom_adj的值受很多因素影響:應用是否有activity,activity是否可見,是否有service,service是否被bind的其他進程的oom_adj等等。在Framework裡oom_adj的調整主要由ActivityManagerService這個類負責,任何可能會影響到進程oom_adj的值的情況,就會調用updateOomAdjLocked來更新各進程的oom_adj值,比如:
1,Activity切換
2,Service start/stop/bind
3,Broadcast分發處理
updateOomAdjLocked會遍歷當前進程列表,對每個進程ProcessRecord都調用computeOomAdjLocked來重新計算oom_adj,最後applyOomAdjLocked來使oom_adj生效。
我們看看updateOomAdjLocked的實現:
final void updateOomAdjLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final long now = SystemClock.uptimeMillis();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
final int N = mLruProcesses.size();
......
......
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
// 找到最早的一次service活動時間
if (mEnableBServicePropagation && app.serviceb
&& (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
numBServices++;
for (int s = app.services.size() - 1; s >= 0; s--) {
ServiceRecord sr = app.services.valueAt(s);
if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
+ " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
+ sr.lastActivity + " packageName = " + sr.packageName
+ " processName = " + sr.processName);
if (SystemClock.uptimeMillis() - sr.lastActivity
< mMinBServiceAgingTime) {
if (DEBUG_OOM_ADJ) {
Slog.d(TAG,"Not aged enough!!!");
}
continue;
}
if (serviceLastActivity == 0) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
} else if (sr.lastActivity < serviceLastActivity) {
serviceLastActivity = sr.lastActivity;
selectedAppRecord = app;
}
}
}
if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
"Identified app.processName = " + selectedAppRecord.processName
+ " app.pid = " + selectedAppRecord.pid);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
// 重新計算進程app的oom_adj
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
// If we haven't yet assigned the final cached adj
// to the process, do that now.
// 如果沒找到對應的oom_adj,那麼根據app的進程狀態,如果有activity存在,那麼oom_adj設為curCachedAdj,
// 否則就是empty進程,講oom_adj設為curEmptyAdj
if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
switch (app.curProcState) {
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
// This process is a cached process holding activities...
// assign it the next cached value for that type, and then
// step that cached level.
app.curRawAdj = curCachedAdj;
app.curAdj = app.modifyRawOomAdj(curCachedAdj);
if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+ " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
+ ")");
if (curCachedAdj != nextCachedAdj) {
stepCached++;
if (stepCached >= cachedFactor) {
stepCached = 0;
curCachedAdj = nextCachedAdj;
nextCachedAdj += 2;
if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
break;
default:
// For everything else, assign next empty cached process
// level and bump that up. Note that this means that
// long-running services that have dropped down to the
// cached level will be treated as empty (since their process
// state is still as a service), which is what we want.
app.curRawAdj = curEmptyAdj;
app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+ " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
+ ")");
if (curEmptyAdj != nextEmptyAdj) {
stepEmpty++;
if (stepEmpty >= emptyFactor) {
stepEmpty = 0;
curEmptyAdj = nextEmptyAdj;
nextEmptyAdj += 2;
if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
}
}
}
break;
}
}
// 調用applyOomAdjLocked使新的oom_adj生效
applyOomAdjLocked(app, true, now);
// Count the number of process types.
switch (app.curProcState) {
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
numCached++;
// 計算Cached進程個數,超過cachedProcessLimit即直接kill
if (numCached > cachedProcessLimit) {
app.kill("cached #" + numCached, true);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
// 計算empty進程個數,超過上限即kill
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
app.kill("empty for "
+ ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
/ 1000) + "s", true);
} else {
numEmpty++;
if (numEmpty > emptyProcessLimit) {
app.kill("empty #" + numEmpty, true);
}
}
break;
default:
mNumNonCachedProcs++;
break;
}
......
......
}
}
// 在低內存的情況下,把過老的service的oom_adj的值調大到CACHED_APP_MAX_ADJ,以便可以被優先殺死
if ((numBServices > mBServiceAppThreshold) && (true == mAllowLowerMemLevel)
&& (selectedAppRecord != null)) {
ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
ProcessList.CACHED_APP_MAX_ADJ);
selectedAppRecord.setAdj = selectedAppRecord.curAdj;
if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
+ " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
}
// finish所有後台的activity,這個有系統開關可以控制,Settings.Global.ALWAYS_FINISH_ACTIVITIES,也就是開發者選項裡的“不保留活動”,
// 也可以通過ActivityManagerNative的setAlwaysFinish來設置,這需要聲明權限android.Manifest.permission.SET_ALWAYS_FINISH
if (mAlwaysFinishActivities) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
}
......
......
}
系統將進程分三類:
一, empty process,沒有service,也沒有activity,空進程沒有執行邏輯,可以優先被殺,empty process有數量限制,超過限制之後就馬上被kill。
二, cached process,只有不可見的activity,這類進程優先級比empty高些,但也同樣可以被殺,用戶不會有太明顯的感知,表現就是返回到他的activity之後,
進程被重新被創建,Activity也會重新onCreate。
empty和cached進程的上限是ProcessList.MAX_CACHED_APPS=32個,而empty的上限是ProcessList.computeEmptyProcessLimit(ProcessList.MAX_CACHED_APPS),默認是16。
三,其他是第三類,包括有前台可見的Activity的進程,有前台Service的進程等。
三類進程數之和就等於LruProcesses隊列的大小。
private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
// This adjustment has already been computed.
return app.curRawAdj;
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
app.empty = false;
app.cached = false;
final int activitiesSize = app.activities.size();
// app最大的adj和前台app的adj一樣,說明是系統進程,adj就設為maxAdj
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.foregroundActivities = false;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
// is currently showing UI.
app.systemNoUi = true;
if (app == TOP_APP) {
app.systemNoUi = false;
} else if (activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.visible) {
app.systemNoUi = false;
}
}
}
if (!app.systemNoUi) {
app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
}
return (app.curAdj=app.maxAdj);
}
app.systemNoUi = false;
final int PROCESS_STATE_TOP = mTopProcessState;
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
int procState;
boolean foregroundActivities = false;
BroadcastQueue queue;
if (app == TOP_APP) { // App正在系統頂層,adj設為FOREGROUND_APP_ADJ
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_TOP;
if(app == mHomeProcess) {
mHomeKilled = false;
mHomeProcessName = mHomeProcess.processName;
}
} else if (app.instrumentationClass != null) { // App正執行Instrumentation,adj設為FOREGROUND_APP_ADJ
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
} else if ((queue = isReceivingBroadcast(app)) != null) { // App正在接收broadcast,adj設為FOREGROUND_APP_ADJ
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
// It's placed in a sched group based on the nature of the
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = (queue == mFgBroadcastQueue)
? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
} else if (app.executingServices.size() > 0) { // App的Service正在執行,adj設為FOREGROUND_APP_ADJ
// An app that is currently executing a service callback also
// counts as being in the foreground.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = app.execServicesFg ?
Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
} else {
// As far as we know the process is empty. We may change our mind later.
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
// At this point we don't actually know the adjustment. Use the cached adj
// value that the caller wants us to.
adj = cachedAdj;
procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
// 初始狀態cached和empty都設為true,根據進程的執行狀態再改
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
// 桌面App,既不是empty也不是cached,adj設為PERSISTENT_PROC_ADJ
if (mHomeKilled && app.processName.equals(mHomeProcessName)) {
adj = ProcessList.PERSISTENT_PROC_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
app.adjType = "top-activity";
}
}
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
// 遍歷非前台的activity
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.app != app) {
Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
+ app + "?!? Using " + r.app + " instead.");
continue;
}
if (r.visible) {
// 可見的Activity,如果Activity不在最頂層,而且被頂層完全擋住的時候visible狀態會被設為false,
// 如果是可見的,那麼adj設為VISIBLE_APP_ADJ,cached和empty也設為false
// App has a visible activity; only upgrade adjustment.
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "visible";
}
if (procState > PROCESS_STATE_TOP) {
procState = PROCESS_STATE_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
// Pause狀態的Activity,adj設為PERCEPTIBLE_APP_ADJ,cached和empty也設為false
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pausing";
}
if (procState > PROCESS_STATE_TOP) {
procState = PROCESS_STATE_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
} else if (r.state == ActivityState.STOPPING) {
// Stopping狀態的app,adj設為PERCEPTIBLE_APP_ADJ,cached和empty也設為false
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "stopping";
}
// For the process state, we will at this point consider the
// process to be cached. It will be cached either as an activity
// or empty depending on whether the activity is finishing. We do
// this so that we can treat the process as cached for purposes of
// memory trimming (determing current memory level, trim command to
// send to process) since there can be an arbitrary number of stopping
// processes and they should soon all go into the cached state.
if (!r.finishing) {
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
}
}
app.cached = false;
app.empty = false;
foregroundActivities = true;
} else {
// 進這個分支說明進程有不可見的Activity,adj會設為CACHED_APP_MIN_ADJ和CACHED_APP_MAX_ADJ之間的數
if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-act";
}
}
}
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
// 如果有前台的Service,adj設為PERCEPTIBLE_APP_ADJ,可通過ActivityManagerNative將Service設為foreground
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
app.cached = false;
app.adjType = "fg-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
if (app == mHeavyWeightProcess) {
if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
// We don't want to kill the current heavy-weight process.
adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "heavy";
}
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
}
}
if (app == mHomeProcess) {
// 如果桌面App,adj設為HOME_APP_ADJ
if (adj > ProcessList.HOME_APP_ADJ) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
adj = ProcessList.HOME_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "home";
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
}
}
// 如果是剛剛切換出去的App,adj設為PREVIOUS_APP_ADJ
if (app == mPreviousProcess && app.activities.size() > 0) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
// This was the previous process that showed UI to the user.
// We want to try to keep it around more aggressively, to give
// a good experience around switching between two apps.
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = "previous";
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
}
}
if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+ " reason=" + app.adjType);
// By default, we use the computed adjustment. It may be changed if
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
app.adjSeq = mAdjSeq;
app.curRawAdj = adj;
app.hasStartedServices = false;
// Backup App,adj設為BACKUP_APP_ADJ
if (mBackupTarget != null && app == mBackupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
adj = ProcessList.BACKUP_APP_ADJ;
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
app.adjType = "backup";
app.cached = false;
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
}
}
boolean mayBeTop = false;
// 如果App有Service,adj設為SERVICE_ADJ
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
is--) {
ServiceRecord s = app.services.valueAt(is);
if (s.startRequested) {
app.hasStartedServices = true;
if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
procState = ActivityManager.PROCESS_STATE_SERVICE;
}
if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
// debug and understand what is going on.
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-ui-services";
}
} else {
if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
// This service has seen some activity within
// recent memory, so we will keep its process ahead
// of the background processes.
if (adj > ProcessList.SERVICE_ADJ) {
adj = ProcessList.SERVICE_ADJ;
app.adjType = "started-services";
app.cached = false;
}
}
// If we have let the service slide into the background
// state, still have some text describing what it is doing
// even though the service no longer has an impact.
if (adj > ProcessList.SERVICE_ADJ) {
app.adjType = "cch-started-services";
}
}
}
// 如果App有Service,那麼需要檢查是否有外部的App在Bind它,如果一個高優先級的App,bind了你的Service,那麼你的優先級也會同樣有提升
for (int conni = s.connections.size()-1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
conni--) {
ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
i++) {
// XXX should compute this based on the max of
// all connected clients.
ConnectionRecord cr = clist.get(i);
if (cr.binding.client == app) {
// Binding to ourself is not interesting.
continue;
}
// 只有bind的時候不加BIND_WAIVE_PRIORITY這個flag才會影響對方的adj
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
int clientAdj = computeOomAdjLocked(client, cachedAdj,
TOP_APP, doingAll, now);
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
// doesn't propagate except under certain conditions.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
String adjType = null;
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Not doing bind OOM management, so treat
// this guy more like a started service.
if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
// debug and understand what is going on.
if (adj > clientAdj) {
adjType = "cch-bound-ui-services";
}
app.cached = false;
clientAdj = adj;
clientProcState = procState;
} else {
if (now >= (s.lastActivity
+ ActiveServices.MAX_SERVICE_INACTIVITY)) {
// This service has not seen activity within
// recent memory, so allow it to drop to the
// LRU list if there is no other reason to keep
// it around. We'll also tag it with a label just
// to help debug and undertand what is going on.
if (adj > clientAdj) {
adjType = "cch-bound-services";
}
clientAdj = adj;
}
}
}
if (adj > clientAdj) {
// If this process has recently shown UI, and
// the process that is binding to it is less
// important than being visible, then we don't
// care about the binding as much as we care
// about letting this process get into the LRU
// list to be killed and restarted if needed for
// memory.
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "cch-bound-ui-services";
} else {
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
// 如果Client Bind的時候加了BIND_ABOVE_CLIENT和BIND_IMPORTANT,那麼講client的adj值給Service,最低不小於PERSISTENT_SERVICE_ADJ
adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
// 如果Client Bind的時候加了BIND_NOT_VISIBLE,並且client的adj比PERCEPTIBLE_APP_ADJ小的時候,將PERCEPTIBLE_APP_ADJ給adj
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
// 把Client的adj給adj,因為adj是> clientAdj的,所以Service的adj還是得到了提升
adj = clientAdj;
} else {
// 這裡client的adj是要小於等於VISIBLE_APP_ADJ的,所以adj將會提升至VISIBLE_APP_ADJ
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
}
}
if (!client.cached) {
app.cached = false;
}
adjType = "service";
}
}
......
......
......
}
// ContentProvider的連接也同樣會影響到app的adj
for (int provi = app.pubProviders.size()-1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
for (int i = cpr.connections.size()-1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
|| procState > ActivityManager.PROCESS_STATE_TOP);
i--) {
ContentProviderConnection conn = cpr.connections.get(i);
ProcessRecord client = conn.client;
if (client == app) {
// Being our own client is not interesting.
continue;
}
int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
app.adjType = "cch-ui-provider";
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
app.adjType = "provider";
}
app.cached &= client.cached;
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
app.adjSourceProcState = clientProcState;
app.adjTarget = cpr.name;
}
......
......
}
// If the provider has external (non-framework) process
// dependencies, ensure that its adjustment is at least
// FOREGROUND_APP_ADJ.
if (cpr.hasExternalProcessHandles()) {
if (adj > ProcessList.FOREGROUND_APP_ADJ) {
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
app.adjType = "provider";
app.adjTarget = cpr.name;
}
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
}
......
......
app.curAdj = app.modifyRawOomAdj(adj);
app.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
return app.curRawAdj;
}
computeOomAdjLocked計算完oom_adj之後,就調用applyOomAdjLocked使之生效,applyOomAdjLocked比較簡單,調用ProcessList的setOomAdj,通過LocalSocket連接到
lmkd,通過進程間通信寫入。
Android學習筆記(七)——顯示對話框窗口
顯示對話框窗口 1、創建Dialog1項目,在activity_main.xml文件中添加一個Button: 2、在MainActivity.jav
Android SDK目錄及版本號區別
今天又有人問Tools,Build-Tools,Platform-tools有什麼區別,是干嘛的?現在對SDK目錄做一下總結闡述!SDK目錄add-ons這裡面保存著附加
自定義控件之android列表分組及字母導航
有了以上兩篇文章的重構,現在把ListView分組列表重構為自定義控件就會非常簡單,只需要把初始化操作放在自定義控件的構造函數裡面。重構後的自定義控件以上一篇的注解重構為
Android中子線程真的不能更新UI嗎?
Android的UI訪問是沒有加鎖的,這樣在多個線程訪問UI是不安全的。所以Android中規定只能在UI線程中訪問UI。但是有沒有極端的情況?使得我們在子線程中訪問UI