編輯:關於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,通過進程間通信寫入。
顯示對話框窗口 1、創建Dialog1項目,在activity_main.xml文件中添加一個Button: 2、在MainActivity.jav
今天又有人問Tools,Build-Tools,Platform-tools有什麼區別,是干嘛的?現在對SDK目錄做一下總結闡述!SDK目錄add-ons這裡面保存著附加
有了以上兩篇文章的重構,現在把ListView分組列表重構為自定義控件就會非常簡單,只需要把初始化操作放在自定義控件的構造函數裡面。重構後的自定義控件以上一篇的注解重構為
Android的UI訪問是沒有加鎖的,這樣在多個線程訪問UI是不安全的。所以Android中規定只能在UI線程中訪問UI。但是有沒有極端的情況?使得我們在子線程中訪問UI