installPackageWithVerification的代碼如下:
**PackageManagerService.java::installPackageWithVerification函數**
~~~
public void installPackageWithVerification(UripackageURI,
IPackageInstallObserverobserver,
int flags, String installerPackageName, Uri verificationURI,
ManifestDigest manifestDigest) {
//檢查客戶端進程是否具有安裝Package的權限。在本例中,該客戶端進程是shell
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES,null);
final int uid = Binder.getCallingUid();
final int filteredFlags;
if(uid == Process.SHELL_UID || uid == 0) {
......//如果通過shell pm的方式安裝,則增加INSTALL_FROM_ADB標志
filteredFlags = flags | PackageManager.INSTALL_FROM_ADB;
}else {
filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB;
}
//創建一個Message,code為INIT_COPY,將該消息發送給之前在PKMS構造函數中
//創建的mHandler對象,將在另外一個工作線程中處理此消息
final Message msg = mHandler.obtainMessage(INIT_COPY);
//創建一個InstallParams,其基類是HandlerParams
msg.obj = new InstallParams(packageURI, observer,
filteredFlags,installerPackageName,
verificationURI,manifestDigest);
mHandler.sendMessage(msg);
}
~~~
installPackageWithVerification函數倒是蠻清閑,簡簡單單創建幾個對象,然后發送INIT_COPY消息給mHandler,就甩手退出了。根據之前在PKMS構造函數中介紹的知識可知,mHandler被綁定到另外一個工作線程(借助ThreadHandler對象的Looper)中,所以該INIT_COPY消息也將在那個工作線程中進行處理。我們馬上轉戰到那。
1. INIT_COPY處理
INIT_COPY只是安裝流程的第一步。先來看相關代碼:
**PackageManagerService.java::handleMesssage**
~~~
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);//調用doHandleMessage函數
} ......
}
voiddoHandleMessage(Message msg) {
switch(msg.what) {
caseINIT_COPY: {
//①這里記錄的是params的基類類型HandlerParams,實際類型為InstallParams
HandlerParams params = (HandlerParams) msg.obj;
//idx為當前等待處理的安裝請求的個數
intidx = mPendingInstalls.size();
if(!mBound) {
/*
很多讀者可能想不到,APK的安裝居然需要使用另外一個APK提供的服務,該服務就是
DefaultContainerService,由DefaultCotainerService.apk提供,
下面的connectToService函數將調用bindService來啟動該服務
*/
if(!connectToService()) {
return;
}else {//如果已經連上,則以idx為索引,將params保存到mPendingInstalls中
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
if(idx == 0) {
//如果安裝請求隊列之前的狀態為空,則表明要啟動安裝
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
......//后續再分析
~~~
這里假設之前已經成功啟動了DefaultContainerService(以后簡稱DCS),并且idx為零,所以這是PKMS首次處理安裝請求,也就是說,下一個將要處理的是MCS_BOUND消息。
>[info] **注意**:connectToService在調用bindService時會傳遞一個DefaultContainerConnection類型的對象,以接收服務啟動的結果。當該服務成功啟動后,此對象的onServiceConnected被調用,其內部也將發送MCS_BOUND消息給mHandler。
2. MCS_BOUND處理
現在,安裝請求的狀態從INIT_COPY變成MCS_BOUND了,此時的處理流程時怎樣的呢?依然在doHandleMessage函數中,直接從對應的case開始,代碼如下:
**PackageManagerService.java::**
~~~
......//接doHandleMesage中的switch/case
case MCS_BOUND: {
if(msg.obj != null) {
mContainerService= (IMediaContainerService) msg.obj;
}
if(mContainerService == null) {
......//如果沒法啟動該service,則不能安裝程序
mPendingInstalls.clear();
} else if(mPendingInstalls.size() > 0) {
HandlerParamsparams = mPendingInstalls.get(0);
if(params != null) {
//調用params對象的startCopy函數,該函數由基類HandlerParams定義
if(params.startCopy()) {
......
if(mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);//刪除隊列頭
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
......//如果安裝請求都處理完了,則需要和Service斷絕聯系,
//通過發送MSC_UNB消息處理斷交請求。讀者可自行研究此情況的處理流程
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
sendMessageDelayed(ubmsg, 10000);
}
}else {
//如果還有未處理的請求,則繼續發送MCS_BOUND消息。
//為什么不通過一個循環來處理所有請求呢
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
} ......
break;
~~~
MCS_BOUND的處理還算簡單,就是調用HandlerParams的startCopy函數。在深入分析前,應先認識一下HandlerParams及相關的對象。
(1) HandlerParams和InstallArgs介紹
除了HandlerParams家族外,這里提前請出另外一個家族InstallArgs及其成員,如圖4-8所示。
:-: 
圖4-8 HandlerParams及InstallArgs家族成員
由圖4-8可知:
- HandlerParams和InstallArgs均為抽象類。
- HandlerParams有三個子類,分別是InstallParams、MoveParams和MeasureParams。其中,InstallParams用于處理APK的安裝,MoveParams用于處理某個已安裝APK的搬家請求(例如從內部存儲移動到SD卡上),MeasureParams用于查詢某個已安裝的APK占據存儲空間的大小(例如在設置程序中得到的某個APK使用的緩存文件的大小)。
- 對于InstallParams來說,它還有兩個伴兒,即InstallArgs的派生類FileInstallArgs和SdInstallArgs。其中,FileInstallArgs針對的是安裝在內部存儲的APK,而SdInstallArgs針對的是那些安裝在SD卡上的APK。
本節將討論用于內部存儲安裝的FileInstallArgs。
* * * * *
**提示**:讀者可以在介紹完MountService后,結合本章知識點,自行研究SdInstallArgs的處理流程。
* * * * *
在前面MCS_BOUND的處理中,首先調用InstallParams的startCopy函數,該函數由其基類HandlerParams實現,代碼如下:
**PackageManagerService.java::HandlerParams.startCopy函數**
~~~
final boolean startCopy() {
booleanres;
try {
//MAX_RETIRES目前為4,表示嘗試4次安裝,如果還不成功,則認為安裝失敗
if(++mRetries > MAX_RETRIES) {
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
handleStartCopy();//①調用派生類的handleStartCopy函數
res= true;
}
} ......
handleReturnCode();//②調用派生類的handleReturnCode,返回處理結果
returnres;
}
~~~
在上述代碼中,基類的startCopy將調用子類實現的handleStartCopy和handleReturnCode函數。下面來看InstallParams是如何實現這兩個函數的。
(2) InstallParams分析
先來看派生類InstallParams的handleStartCopy函數,代碼如下:
**PackageManagerService::InstallParams.handleStartCopy**
~~~
public void handleStartCopy() throwsRemoteException {
int ret= PackageManager.INSTALL_SUCCEEDED;
finalboolean fwdLocked = //本書不考慮fwdLocked的情況
(flags &PackageManager.INSTALL_FORWARD_LOCK) != 0;
//根據adb install的參數,判斷安裝位置
finalboolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
finalboolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
if(onInt && onSd) {
//APK不能同時安裝在內部存儲和SD卡上
ret =PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} elseif (fwdLocked && onSd) {
//fwdLocked的應用不能安裝在SD卡上
ret =PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
finallong lowThreshold;
//獲取DeviceStorageMonitorService的binder客戶端
finalDeviceStorageMonitorService dsm =
(DeviceStorageMonitorService) ServiceManager.getService(
DeviceStorageMonitorService.SERVICE);
if(dsm == null) {
lowThreshold = 0L;
}else {
//從DSMS查詢內部空間最小余量,默認是總空間的10%
lowThreshold = dsm.getMemoryLowThreshold();
}
try {
//授權DefContainerService URI讀權限
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE,
packageURI,Intent.FLAG_GRANT_READ_URI_PERMISSION);
//①調用DCS的getMinimalPackageInfo函數,得到一個PackageLite對象
pkgLite =mContainerService.getMinimalPackageInfo(packageURI,
flags,lowThreshold);
}finally ......//撤銷URI授權
//PacakgeLite的recommendedInstallLocation成員變量保存該APK推薦的安裝路徑
int loc =pkgLite.recommendedInstallLocation;
if (loc== PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret= PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if......{
} else {
//②根據DCS返回的安裝路徑,還需要調用installLocationPolicy進行檢查
loc =installLocationPolicy(pkgLite, flags);
if(!onSd && !onInt) {
if(loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
flags |= PackageManager.INSTALL_EXTERNAL;
flags &=~PackageManager.INSTALL_INTERNAL;
} ......//處理安裝位置為內部存儲的情況
}
}
}
//③創建一個安裝參數對象,對于安裝位置為內部存儲的情況,args的真實類型為FileInstallArgs
finalInstallArgs args = createInstallArgs(this);
mArgs =args;
if (ret== PackageManager.INSTALL_SUCCEEDED) {
final int requiredUid = mRequiredVerifierPackage == null ? -1
:getPackageUid(mRequiredVerifierPackage);
if(requiredUid != -1 && isVerificationEnabled()) {
......//④待會再討論verification的處理
}else {
//⑤調用args的copyApk函數
ret= args.copyApk(mContainerService, true);
}
}
mRet =ret;//確定返回值
}
~~~
在以上代碼中,一共列出了五個關鍵點,總結如下:
- 調用DCS的getMinimalPackageInfo函數,將得到一個PackageLite對象,該對象是一個輕量級的用于描述APK的結構(相比PackageParser.Package來說)。在這段代碼邏輯中,主要想取得其recommendedInstallLocation的值。此值表示該APK推薦的安裝路徑。
- 調用installLocationPolicy檢查推薦的安裝路徑。例如系統Package不允許安裝在SD卡上。
- createInstallArgs將根據安裝位置創建不同的InstallArgs。如果是內部存儲,則返回FileInstallArgs,否則為SdInstallArgs。
- 在正式安裝前,應先對該APK進行必要的檢查。這部分代碼后續再介紹。
- 調用InstallArgs的copyApk。對本例來說,將調用FileInstallArgs的copyApk函數。
下面圍繞這五個基本關鍵點展開分析,其中installLocationPolicy和createInstallArgs比較簡單,讀者可自行研究。
3. handleStartCopy分析
(1) DefaultContainerService分析
首先分析DCS的getMinimalPackageInfo函數,其代碼如下:
**DefaultContainerService.java::getMinimalPackageInfo函數**
~~~
public PackageInfoLite getMinimalPackageInfo(finalUri fileUri, int flags,
longthreshold) {
//注意該函數的參數:fileUri指向該APK的文件路徑(此時還在/data/local/tmp下)
PackageInfoLite ret = new PackageInfoLite();
......
Stringscheme = fileUri.getScheme();
......
StringarchiveFilePath = fileUri.getPath();
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
//調用PackageParser的parsePackageLite解析該APK文件
PackageParser.PackageLite pkg =
PackageParser.parsePackageLite(archiveFilePath,0);
if (pkg== null) {//解析失敗
......//設置錯誤值
returnret;
}
ret.packageName = pkg.packageName;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
//調用recommendAppInstallLocation,取得一個合理的安裝位置
ret.recommendedInstallLocation =
recommendAppInstallLocation(pkg.installLocation,archiveFilePath,
flags, threshold);
returnret;
}
~~~
APK可在AndroidManifest.xml中聲明一個安裝位置,不過DCS除了解析該位置外,還需要做進一步檢查,這個工作由recommendAppInstallLocation函數完成,代碼如下:
**DefaultContainerService.java::recommendAppInstallLocation函數**
~~~
private int recommendAppInstallLocation(intinstallLocation,
StringarchiveFilePath, int flags,long threshold) {
int prefer;
booleancheckBoth = false;
check_inner: {
if((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
prefer = PREFER_INTERNAL;
break check_inner; //根據FOWRAD_LOCK的情況,只能安裝在內部存儲
} elseif ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
prefer = PREFER_INTERNAL;
break check_inner;
}
......//檢查各種情況
} else if(installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
prefer= PREFER_INTERNAL;//一般設定的位置為AUTO,默認是內部空間
checkBoth = true; //設置checkBoth為true
breakcheck_inner;
}
//查詢settings數據庫中的secure表,獲取用戶設置的安裝路徑
intinstallPreference =
Settings.System.getInt(getApplicationContext()
.getContentResolver(),
Settings.Secure.DEFAULT_INSTALL_LOCATION,
PackageHelper.APP_INSTALL_AUTO);
if(installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
prefer = PREFER_INTERNAL;
break check_inner;
} else if(installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
prefer= PREFER_EXTERNAL;
breakcheck_inner;
}
prefer =PREFER_INTERNAL;
}
//判斷外部存儲空間是否為模擬的,這部分內容我們以后再介紹
finalboolean emulated = Environment.isExternalStorageEmulated();
final FileapkFile = new File(archiveFilePath);
booleanfitsOnInternal = false;
if(checkBoth || prefer == PREFER_INTERNAL) {
try {//檢查內部存儲空間是否足夠大
fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
} ......
}
booleanfitsOnSd = false;
if(!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
try{ //檢查外部存儲空間是否足夠大
fitsOnSd = isUnderExternalThreshold(apkFile);
} ......
}
if (prefer== PREFER_INTERNAL) {
if(fitsOnInternal) {//返回推薦安裝路徑為內部空間
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
} elseif (!emulated && prefer == PREFER_EXTERNAL) {
if(fitsOnSd) {//返回推薦安裝路徑為外部空間
returnPackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
if(checkBoth) {
if(fitsOnInternal) {//如果內部存儲滿足條件,先返回內部空間
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}else if (!emulated && fitsOnSd) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
...... //到此,前幾個條件都不滿足,此處將根據情況返回一個明確的錯誤值
returnPackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
~~~
DCS的getMinimalPackageInfo函數為了得到一個推薦的安裝路徑做了不少工作,其中,各種安裝策略交叉影響。這里總結一下相關的知識點:
- APK在AndroidManifest.xml中設置的安裝點默認為AUTO,在具體對應時傾向內部空間。
- 用戶在Settings數據庫中設置的安裝位置。
- 檢查外部存儲或內部存儲是否有足夠空間。
(2) InstallArgs的copyApk函數分析
至此,我們已經得到了一個合適的安裝位置(先略過Verification這一步)。下一步工作就由copyApk來完成。根據函數名可知該函數將完成APK文件的復制工作,此中會有蹊蹺嗎?來看下面的代碼。
**PackageManagerService.java::InstallArgs.copyApk函數**
~~~
int copyApk(IMediaContainerService imcs, booleantemp) throws RemoteException {
if (temp){
/*
本例中temp參數為true,createCopyFile將在/data/app下創建一個臨時文件。
臨時文件名為vmdl-隨機數.tmp。為什么會用這樣的文件名呢?
因為PKMS通過Linux的inotify機制監控了/data/app,目錄,如果新復制生成的文件名后綴
為apk,將觸發PKMS掃描。為了防止發生這種情況,這里復制生成的文件才有了
如此奇怪的名字
*/
createCopyFile();
}
FilecodeFile = new File(codeFileName);
......
ParcelFileDescriptor out = null;
try {
out =ParcelFileDescriptor.open(codeFile,
ParcelFileDescriptor.MODE_READ_WRITE);
}......
int ret= PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE,
packageURI,Intent.FLAG_GRANT_READ_URI_PERMISSION);
//調用DCS的copyResource,該函數將執行復制操作,最終結果是/data/local/tmp
//下的APK文件被復制到/data/app下,文件名也被換成vmdl-隨機數.tmp
ret= imcs.copyResource(packageURI, out);
}finally {
......//關閉out,撤銷URI授權
}
returnret;
}
~~~
關于臨時文件,這里提供一個示例,如圖4-9所示。
:-: 
圖4-9 createCopyFile生成的臨時文件
由圖4-9可知:/data/app下有兩個文件,第一個是正常的APK文件,第二個是createCopyFile生成的臨時文件。
4. handleReturnCode分析
在HandlerParams的startCopy函數中,handleStartCopy執行完之后,將調用handleReturnCode開展后續工作,代碼如下:
**PackageManagerService.java::InstallParams.HandleParams**
void handleReturnCode() {
if(mArgs != null) {
//調用processPendingInstall函數,mArgs指向之前創建的FileInstallArgs對象
processPendingInstall(mArgs, mRet);
}
}
**PackageManagerService.java::**
~~~
private void processPendingInstall(finalInstallArgs args,
final intcurrentStatus) {
//向mHandler中拋一個Runnable對象
mHandler.post(new Runnable() {
publicvoid run() {
mHandler.removeCallbacks(this);
//創建一個PackageInstalledInfo對象,
PackageInstalledInfo res = new PackageInstalledInfo();
res.returnCode = currentStatus;
res.uid = -1;
res.pkg = null;
res.removedInfo = new PackageRemovedInfo();
if(res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//①調用FileInstallArgs的doPreInstall
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
//②調用installPackageLI進行安裝
installPackageLI(args, true, res);
}
//③調用FileInstallArgs的doPostInstall
args.doPostInstall(res.returnCode);
}
final boolean update = res.removedInfo.removedPackage != null;
boolean doRestore = (!update&& res.pkg != null &&
res.pkg.applicationInfo.backupAgentName!= null);
int token;//計算一個ID號
if(mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
//創建一個PostInstallData對象
PostInstallData data = new PostInstallData(args, res);
//保存到mRunningInstalls結構中,以token為key
mRunningInstalls.put(token, data);
if (res.returnCode ==PackageManager.INSTALL_SUCCEEDED && doRestore)
{
......//備份恢復的情況暫時不考慮
}
if(!doRestore) {
//④拋一個POST_INSTALL消息給mHandler進行處理
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
~~~
由上面代碼可知,handleReturnCode主要做了4件事情:
- 調用InstallArgs的doPreInstall函數,在本例中是FileInstallArgs的doPreInstall函數。
- 調用PKMS的installPackageLI函數進行APK安裝,該函數內部將調用InstallArgs的doRename對臨時文件進行改名。另外,還需要掃描此APK文件。此過程和之前介紹的“掃描系統Package”一節的內容類似。至此,該APK中的私有財產就全部被登記到PKMS內部進行保存了。
- 調用InstallArgs的doPostInstall函數,在本例中是FileInstallArgs的doPostInstall函數。
- 此時,該APK已經安裝完成(不論失敗還是成功),繼續向mHandler拋送一個POST_INSTALL消息,該消息攜帶一個token,通過它可從mRunningInstalls數組中取得一個PostInstallData對象。
* * * * *
**提示**:對于FileInstallArgs來說,其doPreInstall和doPostInstall都比較簡單,讀者可自行閱讀相關代碼。另外,讀者也可自行研究PKMS的installPackageLI函數。
* * * * *
這里介紹一下FileInstallArgs的doRename函數,它的功能是將臨時文件改名,最終的文件的名稱一般為“包名-數字.apk”。其中,數字是一個index,從1開始。讀者可參考圖4-9中/data/app目錄下第一個文件的文件名。
5. POST_INSTALL處理
現在需要處理POST_INSTALL消息,因為adb install還等著安裝結果呢。相關代碼如下:
**PackageManagerService.java::doHandleMessage函數**
~~~
......//接前面的switch/case
case POST_INSTALL: {
PostInstallData data = mRunningInstalls.get(msg.arg1);
mRunningInstalls.delete(msg.arg1);
booleandeleteOld = false;
if (data!= null) {
InstallArgs args = data.args;
PackageInstalledInfo res = data.res;
if(res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
res.removedInfo.sendBroadcast(false, true);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
//發送PACKAGE_ADDED廣播
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,extras, null, null);
if (update) {
/*
如果是APK升級,那么發送PACKAGE_REPLACE和MY_PACKAGE_REPLACED廣播。
二者不同之處在于PACKAGE_REPLACE將攜帶一個extra信息
*/
}
Runtime.getRuntime().gc();
if(deleteOld) {
synchronized (mInstallLock) {
//調用FileInstallArgs的doPostDeleteLI進行資源清理
res.removedInfo.args.doPostDeleteLI(true);
}
}
if(args.observer != null) {
try {
// 向pm通知安裝的結果
args.observer.packageInstalled(res.name, res.returnCode);
} ......
} break;
~~~
- 前言
- 第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 本章小結