<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                在AMS中,和進程管理有關的函數只要有兩個,分別是updateLruProcessLocked和updateOomAdjLocked。這兩個函數的調用點有多處,本節以attachApplication為切入點,嘗試對它們進行分析。 >[info]** 注意**:AMS一共定義了3個updateOomAdjLocked函數,此處將其歸為一類。 先回顧一下attachApplication函數被調用的情況:AMS新創建一個應用進程,該進程啟動后最重要的就是調用AMS的attachApplication。 * * * * * **提示**:不熟悉的讀者可閱讀6.3.3節的第5小節。 * * * * * 其相關代碼如下: **ActivityManagerService.java::attachApplicationLocked** ~~~ //attachApplication主要工作由attachApplicationLocked完成,故直接分析它 private final booleanattachApplicationLocked(IApplicationThread thread, int pid) { ProcessRecord app; //根據之前的介紹的內容,AMS在創建應用進程前已經將對應的ProcessRecord保存到 //mPidsSelfLocked中了 ...... //其他一些處理 //初始化ProcessRecord中的一些成員變量 app.thread= thread; app.curAdj= app.setAdj = -100; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.setSchedGroup= Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; app.hasShownUi = false; ...... //調用應用進程的bindApplication,以初始化其內部的Android運行環境 thread.bindApplication(......); //①調用updateLruProcessLocked函數 updateLruProcessLocked(app, false, true); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); ......//啟動Activity等操作 //②didSomething為false,則調用updateOomAdjLocked函數 if(!didSomething) { updateOomAdjLocked(); } ~~~ 在以上這段代碼中有兩個重要函數調用,分別是updateLruProcessLocked和updateOomAdjLocked。 1. updateLruProcessLocked函數分析 根據前文所述,我們知道了系統中所有應用進程(同時包括SystemServer)的ProcessRecord信息都保存在mPidsSelfLocked成員中。除此之外,AMS還有一個成員變量mLruProcesses也用于保存ProcessRecord。mLruProcesses的類型雖然是ArrayList,但其內部成員卻是按照ProcessRecord的lruWeight大小排序的。在運行過程中,AMS會根據lruWeight的變化調整mLruProcesses成員的位置。 就本例而言,剛連接(attach)上的這個應用進程的ProcessRecord需要通過updateLruProcessLocked函數加入mLruProcesses數組中。來看它的代碼,如下所示: **ActivityManagerService.java::updateLruProcessLocked** ~~~ final void updateLruProcessLocked(ProcessRecordapp, boolean oomAdj, boolean updateActivityTime) { mLruSeq++;//每一次調整LRU列表,系統都會分配一個唯一的編號 updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0); } ~~~ **ActivityManagerService.java::updateLruProcessInternalLocked** ~~~ private final voidupdateLruProcessInternalLocked(ProcessRecord app, boolean oomAdj, boolean updateActivityTime, int bestPos) { //獲取app在mLruProcesses中的索引位置,對于本例而言,返回值lrui為-1 int lrui =mLruProcesses.indexOf(app); //如果之前有記錄,則先從數組中刪掉,因為此處需要重新調整位置 if (lrui>= 0) mLruProcesses.remove(lrui); //獲取mLruProcesses中數組索引的最大值,從0開始 int i =mLruProcesses.size()-1; intskipTop = 0; app.lruSeq= mLruSeq; //將系統全局的lru調整編號賦給ProcessRecord的lruSeq //更新lastActivityTime值,其實就是獲取一個時間 if(updateActivityTime) { app.lastActivityTime =SystemClock.uptimeMillis(); } if(app.activities.size() > 0) { //如果該app含Activity,則lruWeight為當前時間 app.lruWeight = app.lastActivityTime; } else if(app.pubProviders.size() > 0) { /* 如果有發布的ContentProvider,則lruWeight要減去一個OFFSET。 對此的理解需結合CONTENT_APP_IDLE_OFFSET的定義。讀者暫時把它 看做一個常數 */ app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET; //設置skipTop。這個變量實際上沒有用,放在此處讓人很頭疼 skipTop = ProcessList.MIN_HIDDEN_APPS; } else { app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET; skipTop = ProcessList.MIN_HIDDEN_APPS; } //從數組最后一個元素開始循環 while (i>= 0) { ProcessRecord p = mLruProcesses.get(i); //下面這個if語句沒有任何意義,因為skipTop除了做自減操作外,不影響其他任何內容 if(skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { skipTop--; } //將app調整到合適的位置 if(p.lruWeight <= app.lruWeight || i < bestPos) { mLruProcesses.add(i+1, app); break; } i--; } //如果沒有找到合適的位置,則把app加到隊列頭 if (i <0) mLruProcesses.add(0, app); //如果該將app 綁定到其他service,則要對應調整Service所在進程的LRU if (app.connections.size() > 0) { for(ConnectionRecord cr : app.connections) { if(cr.binding != null && cr.binding.service != null && cr.binding.service.app!= null &&cr.binding.service.app.lruSeq != mLruSeq) { updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,updateActivityTime,i+1); } } } //conProviders也是一種Provider,相關信息下一章再介紹 if(app.conProviders.size() > 0) { for(ContentProviderRecord cpr : app.conProviders.keySet()) { ......//對ContentProvider所在進程做類似的調整 } } //在本例中,oomAdj為false,故updateOomAdjLocked不會被調用 if (oomAdj) updateOomAdjLocked(); //以后分析 } ~~~ 從以上代碼可知,updateLruProcessLocked的主要工作是根據app的lruWeight值調整它在數組中的位置。lruWeight值越大,其在數組中的位置就越靠后。如果該app和某些Service(僅考慮通過bindService建立關系的那些Service)或ContentProvider有交互關系,那么這些Service或ContentProvider所在的進程也需要調節lruWeight值。 下面介紹第二個重要函數updateOomAdjLocked。 * * * * * **提示**:以上代碼中, skipTop變量完全沒有實際作用,卻給為閱讀代碼帶來了很大干擾。 * * * * * 2. updateOomAdjLocked函數分析 (1) updateOomAdjLocked分析之一 分段來看updateOomAdjLocked函數。 **ActivityManagerService.java::updateOomAdjLocked()** ~~~ final void updateOomAdjLocked() { //在一般情況下,resumedAppLocked返回 mResumedActivity,即當前正處于前臺的Activity finalActivityRecord TOP_ACT = resumedAppLocked(); //得到前臺Activity所屬進程的ProcessRecord信息 finalProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; mAdjSeq++;//oom_adj在進行調節時也會有唯一的序號 mNewNumServiceProcs= 0; /* 下面這幾句代碼的作用如下: 1 根據hidden adj劃分級別,一共有9個級別(即numSlots值) 2 根據mLruProcesses的成員個數計算平均落在各個級別的進程數(即factor值)。但是這里 的魔數(magic number)4卻令人頭疼不已。如有清楚該內容的讀者,不妨讓分享一下 研究結果 */ intnumSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1; int factor= (mLruProcesses.size()-4)/numSlots; if (factor< 1) factor = 1; int step =0; intnumHidden = 0; int i =mLruProcesses.size(); intcurHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ; //從mLruProcesses數組末端開始循環 while (i> 0) { i--; ProcessRecordapp = mLruProcesses.get(i); //①調用另外一個updateOomAdjLocked函數 updateOomAdjLocked(app,curHiddenAdj, TOP_APP, true); // updateOomAdjLocked函數會更新app的curAdj if(curHiddenAdj < ProcessList.HIDDEN_APP_MAX_ADJ &&app.curAdj == curHiddenAdj) { /* 這段代碼的目的其實很簡單。即當某個adj級別的ProcessRecord處理個數超過均值后, 就跳到下一級別進行處理。注意,這段代碼的結果會影響updateOomAdjLocked的第二個參數 */ step++; if(step >= factor) { step = 0; curHiddenAdj++; } }// if(curHiddenAdj < ProcessList.HIDDEN_APP_MAX_ADJ...)判斷結束 //app.killedBackground初值為false if(!app.killedBackground) { if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { numHidden++; //mProcessLimit初始值為ProcessList.MAX(值為15), //可通過setProcessLimit函數對其進行修改 if (numHidden > mProcessLimit) { app.killedBackground =true; //如果后臺進程個數超過限制,則會殺死對應的后臺進程 Process.killProcessQuiet(app.pid); } } }//if(!app.killedBackground)判斷結束 }//while循環結束 ~~~ updateOomAdjLocked第一階段的工作看起來很簡單,但是其中也包含一些較難理解的內容。 - 處理hidden adj,劃分9個級別。 - 根據mLruProcesses中進程個數計算每個級別平均會存在多少進程。在這個計算過程中出現了一個魔數4令人極度費解。 - 然后利用一個循環從mLruProcesses末端開始對每個進程執行另一個updateOomAdjLocked函數。關于這個函數的內容,我們放到下一節再討論。 - 判斷處于Hidden狀態的進程數是否超過限制,如果超過限制,則會殺死一些進程。 接著來看updateOomAdjLocked下一階段的工作。 (2) updateOomAdjLocked分析之二 **ActivityManagerService.java::updateOomAdjLocked** ~~~ mNumServiceProcs = mNewNumServiceProcs; //numHidden表示處于hidden狀態的進程個數 //當Hidden進程個數小于7時候(15/2的整型值),執行if分支 if(numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) { ...... /* 我們不討論這段缺乏文檔及使用魔數的代碼,但這里有個知識點要注意: 該知識點和Android 4.0新增接口ComponentCallbacks2有關,主要是通知應用進程進行 內存清理,ComponentCallbacks2接口定了一個函數onTrimMemory(int level), 而四大組件除BroadcastReceiver外,均實現了該接口。系統定義了4個level以通知進程 做對應處理: TRIM_MEMORY_UI_HIDDEN,提示進程當前不處于前臺,故可釋放一些UI資源 TRIM_MEMORY_BACKGROUND,表明該進程已加入LRU列表,此時進程可以對一些簡單的資源 進行清理 TRIM_MEMORY_MODERATE,提示進程可以釋放一些資源,這樣其他進程的日子會好過些。 即所謂的“我為人人,人人為我” TRIM_MEMORY_COMPLETE,該進程需盡可能釋放一些資源,否則當內存不足時,它可能被殺死 */ } else {//假設hidden進程數超過7, finalint N = mLruProcesses.size(); for(i=0; i<N; i++) { ProcessRecord app = mLruProcesses.get(i); if ((app.curAdj >ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) && app.pendingUiClean) { if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN && app.thread!= null) { try {//調用應用進程ApplicationThread的scheduleTrimMemory函數 app.thread.scheduleTrimMemory( ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); }...... }// if (app.trimMemoryLevel...)判斷結束 app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; app.pendingUiClean = false; }else { app.trimMemoryLevel = 0; } }//for循環結束 }//else結束 //Android4.0中設置有一個開發人員選項,其中有一項用于控制是否銷毀后臺的Activity。 //讀者可自行研究destroyActivitiesLocked函數 if (mAlwaysFinishActivities) mMainStack.destroyActivitiesLocked(null, false,"always-finish"); } ~~~ 通過上述代碼,可獲得兩個信息: - Android 4.0增加了新的接口類ComponentCallbacks2,其中只定義了一個函數onTrimMemory。從以上描述中可知,它主要通知應用進程進行一定的內存釋放。 - Android 4.0 Settings新增了一個開放人員選項,通過它可控制AMS對后臺Activity的操作。 這里和讀者探討一下ComponentCallbacks2接口的意義。此接口的目的是通知應用程序根據情況做一些內存釋放,但筆者覺得,這種設計方案的優劣尚有待考證,主要是出于以下下幾種考慮: - 第一,不是所有應用程序都會實現該函數。原因有很多,主要原因是,該接口只是SDK 14才有的,之前的版本沒有這個接口。另外,應用程序都會盡可能搶占資源(在不超過允許范圍內)以保證運行速度,不應該考慮其他程序的事情。 - 第二個重要原因是無法區分在不同的level下到底要釋放什么樣的內存。代碼中的注釋也是含糊其辭。到底什么樣的資源可以在TRIM_MEMORY_BACKGROUND級別下釋放,什么樣的資源不可以在TRIM_MEMORY_BACKGROUND級別下釋放? 既然系統加了這些接口,讀者不妨參考源碼中的使用案例來開發自己的程序。 * * * * * **建議**:真誠希望Google能給出一個明確的文檔,說明這幾個函數該怎么使用。 * * * * * 接下來分析在以上代碼中出現的針對每個ProcessRecord都調用的updateOomAdjLocked函數。 3. 第二個updateOomAdjLocked分析 **ActivityManagerService.java::updateOomAdjLocked** ~~~ private final boolean updateOomAdjLocked( ProcessRecordapp, int hiddenAdj, ProcessRecord TOP_APP, boolean doingAll) { //設置該app的hiddenAdj app.hiddenAdj = hiddenAdj; if(app.thread == null) return false; finalboolean wasKeeping = app.keeping; booleansuccess = true; //下面這個函數的調用極其關鍵。從名字上看,它會計算該進程的oom_adj及調度策略 computeOomAdjLocked(app, hiddenAdj, TOP_APP, false, doingAll); if(app.curRawAdj != app.setRawAdj) { if (wasKeeping && !app.keeping) { .....//統計電量 app.lastCpuTime = app.curCpuTime; } app.setRawAdj = app.curRawAdj; } //如果新舊oom_adj不同,則重新設置該進程的oom_adj if(app.curAdj != app.setAdj) { if(Process.setOomAdj(app.pid, app.curAdj)) //設置該進程的oom_adj app.setAdj = app.curAdj; ..... } //如果新舊調度策略不同,則需重新設置該進程的調度策略 if(app.setSchedGroup != app.curSchedGroup) { app.setSchedGroup = app.curSchedGroup; //waitingToKill是一個字符串,用于描述殺掉該進程的原因 if (app.waitingToKill != null && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) { Process.killProcessQuiet(app.pid);// success = false; } else{ if (true) {//強制執行if分支 long oldId = Binder.clearCallingIdentity(); try {//設置進程調度策略 Process.setProcessGroup(app.pid, app.curSchedGroup); }...... } ...... } } returnsuccess; } ~~~ 上面的代碼還算簡單,主要完成兩項工作: - 調用computeOomAdjLocked計算獲得某個進程的oom_adj和調度策略。 - 調整進程的調度策略和oom_adj。 * * * * * **建議**:思考一個問題:為何AMS只設置進程的調度策略,而不設置進程的調度優先級? * * * * * 看來AMS調度算法的核心就在computeOomAdjLocked中。 4. computeOomAdjLocked分析 這段代碼較長,其核心思想是綜合考慮各種情況以計算進程的oom_adj和調度策略。建議讀者閱讀代碼時聚焦到AMS關注的幾個因素上。computeOomAdjLocked的代碼如下: **ActivityManagerService.java::computeOomAdjLocked** ~~~ private final intcomputeOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) { ...... app.adjTypeCode= ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; app.empty= false; app.hidden= false; //該應用進程包含Activity的個數 final intactivitiesSize = app.activities.size(); //如果maxAdj小于FOREGROUND_APP_ADJ,基本上沒什么工作可以做了。這類進程優先級相當高 if(app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) { ......//讀者可自行閱讀這塊代碼 return(app.curAdj=app.maxAdj); } finalboolean hadForegroundActivities = app.foregroundActivities; app.foregroundActivities = false; app.keeping = false; app.systemNoUi = false; int adj; intschedGroup; //如果app為前臺Activity所在的那個應用進程 if (app ==TOP_APP) { adj =ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType= "top-activity"; app.foregroundActivities = true; } else if (app.instrumentationClass != null){ ......//略過instrumentationClass不為null的情況 } else if (app.curReceiver != null || (mPendingBroadcast != null && mPendingBroadcast.curApp == app)){ //此情況對應正在執行onReceive函數的廣播接收者所在進程,它的優先級也很高 adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "broadcast"; } else if(app.executingServices.size() > 0) { //正在執行Service生命周期函數的進程 adj= ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "exec-service"; } elseif (activitiesSize > 0) { adj = hiddenAdj; schedGroup =Process.THREAD_GROUP_BG_NONINTERACTIVE; app.hidden = true; app.adjType = "bg-activities"; } else {//不含任何組件的進程,即所謂的Empty進程 adj= hiddenAdj; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.hidden= true; app.empty = true; app.adjType = "bg-empty"; } //下面幾段代碼將根據情況重新調整前面計算處理的adj和schedGroup,我們以后面的 //mHomeProcess判斷為例 if(!app.foregroundActivities && activitiesSize > 0) { //對無前臺Activity所在進程的處理 } if (adj> ProcessList.PERCEPTIBLE_APP_ADJ) { ....... } //如果前面計算出來的adj大于HOME_APP_ADJ,并且該進程又是Home進程,則需要重新調整 if (adj> ProcessList.HOME_APP_ADJ && app == mHomeProcess) { //重新調整adj和schedGroupde的值 adj = ProcessList.HOME_APP_ADJ; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.hidden = false; app.adjType = "home";//描述調節adj的原因 } if (adj> ProcessList.PREVIOUS_APP_ADJ && app == mPreviousProcess && app.activities.size() > 0) { ...... } app.adjSeq = mAdjSeq; app.curRawAdj = adj; ...... //下面這幾段代碼處理那些進程中含有Service,ContentProvider組件情況下的adj調節 if(app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { } if(s.connections.size() > 0 && (adj >ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { } if(app.pubProviders.size() != 0 && (adj >ProcessList.FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { ...... } //終于計算完畢 app.curRawAdj = adj; if (adj> app.maxAdj) { adj= app.maxAdj; if(app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) schedGroup = Process.THREAD_GROUP_DEFAULT; } if (adj< ProcessList.HIDDEN_APP_MIN_ADJ) app.keeping = true; ...... app.curAdj = adj; app.curSchedGroup = schedGroup; ...... returnapp.curRawAdj; } ~~~ computeOomAdjLocked的工作比較瑣碎,實際上也談不上什么算法,僅僅是簡單地根據各種情況來設置幾個值。隨著系統的改進和完善,這部分代碼變動的可能性比較大。 5. updateOomAdjLocked調用點統計 updateOomAdjLocked調用點很多,這里給出其中一個updateOomAdjLocked函數的調用點統計,如圖6-23所示。 :-: ![](http://img.blog.csdn.net/20150803123523362?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖6-23 updateOomAdjLocked函數的調用點統計圖 注意,圖6-23統計的是updateOomAdjLocked(ProcessRecord)函數的調用點。從該圖可知,此函數被調用的地方較多,這也說明AMS非常關注應用進程的狀況。 >[warning] **提示**:筆者覺得,AMS中這部分代碼不是特別高效,不知各位讀者是否有同感,?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看