在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所示。
:-: 
圖6-23 updateOomAdjLocked函數的調用點統計圖
注意,圖6-23統計的是updateOomAdjLocked(ProcessRecord)函數的調用點。從該圖可知,此函數被調用的地方較多,這也說明AMS非常關注應用進程的狀況。
>[warning] **提示**:筆者覺得,AMS中這部分代碼不是特別高效,不知各位讀者是否有同感,?
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結