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所示。
:-: ![](http://img.blog.csdn.net/20150803110954000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图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所示。
:-: ![](http://img.blog.csdn.net/20150803111034657?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图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 本章小结