还记得Settings数据库吗?SystemServer中很多Service都需要向它查询配置信息。为此,Android提供了一个SettingsProvider来帮助开发者。该Provider在SettingsProvider.apk中,installSystemProviders就会加载该APK并把SettingsProvider放到SystemServer进程中来运行。
此时的SystemServer已经加载了framework-res.apk,现在又要加载另外一个APK文件,这就是多个APK运行在同一进程的典型案例。另外,通过installSystemProviders函数还能见识ContentProvider的安装过程,下面就来分析它。
* * * * *
**提示**:读者在定制自己的Android系统时,万不可去掉/system/app/SettingsProvider.apk,否则系统将无法正常启动。
* * * * *
**ActivityManagerService.java::installSystemProviders**
~~~
public static final void installSystemProviders(){
List<ProviderInfo> providers;
synchronized (mSelf) {
/*
从mProcessNames找到进程名为“system”且uid为SYSTEM_UID的ProcessRecord,
返回值就是前面在installSystemApplication中创建的那个ProcessRecord,它代表
SystemServer进程
*/
ProcessRecord app = mSelf.mProcessNames.get("system",Process.SYSTEM_UID);
//①关键调用,见下文分析
providers= mSelf.generateApplicationProvidersLocked(app);
if(providers != null) {
......//将非系统APK(即未设ApplicationInfo.FLAG_SYSTEM标志)提供的Provider
//从providers列表中去掉
}
if(providers != null) {//②为SystemServer进程安装Provider
mSystemThread.installSystemProviders(providers);
}
//监视Settings数据库中Secure表的变化,目前只关注long_press_timeout配置的变化
mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
//UsageStatsService的工作,以后再讨论
mSelf.mUsageStatsService.monitorPackages();
}
~~~
在代码中列出了两个关键调用,分别是:
- 调用generateApplicationProvidersLocked函数,该函数返回一个ProviderInfo List。
- 调用ActivityThread的installSystemProviders函数。ActivityThread可以看做是进程的Android运行环境,那么installSystemProviders表示为该进程安装ContentProvider。
* * * * *
**注意**:此处不再区分系统进程还是应用进程。由于只和ActivityThread交互,因此它运行在什么进程无关紧要。
* * * * *
下面来看第一个关键点generateApplicationProvidersLocked函数。
1. AMS的 generateApplicationProvidersLocked函数分析
**ActivityManagerService.java::generateApplicationProvidersLocked**
~~~
private final List<ProviderInfo> generateApplicationProvidersLocked(
ProcessRecordapp) {
List<ProviderInfo> providers = null;
try {
//①向PKMS查询满足要求的ProviderInfo,最重要的查询条件包括:进程名和进程uid
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} ......
if(providers != null) {
finalint N = providers.size();
for(int i=0; i<N; i++) {
//②AMS对ContentProvider的管理,见下文解释
ProviderInfo cpi = (ProviderInfo)providers.get(i);
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProvidersByClass.get(comp);
if(cpr == null) {
cpr = new ContentProviderRecord(cpi, app.info, comp);
//ContentProvider在AMS中用ContentProviderRecord来表示
mProvidersByClass.put(comp, cpr);//保存到AMS的mProvidersByClass中
}
//将信息也保存到ProcessRecord中
app.pubProviders.put(cpi.name, cpr);
//保存PackageName到ProcessRecord中
app.addPackage(cpi.applicationInfo.packageName);
//对该APK进行dex优化
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
returnproviders;
}
~~~
由以上代码可知:generateApplicationProvidersLocked先从PKMS那里查询满足条件的ProviderInfo信息,而后将它们分别保存到AMS和ProcessRecord中对应的数据结构中。
先看查询函数queryContentProviders。
(1) PMS中 queryContentProviders函数分析
**PackageManagerService.java::queryContentProviders**
~~~
public List<ProviderInfo>queryContentProviders(String processName,
int uid,int flags) {
ArrayList<ProviderInfo> finalList = null;
synchronized (mPackages) {
//还记得mProvidersByComponent的作用吗?它以ComponentName为key,保存了
//PKMS扫描APK得到的PackageParser.Provider信息。读者可参考图4-8
finalIterator<PackageParser.Provider> i =
mProvidersByComponent.values().iterator();
while(i.hasNext()) {
final PackageParser.Provider p = i.next();
//下面的if语句将从这些Provider中搜索本例设置的processName为“system”,
//uid为SYSTEM_UID,flags为FLAG_SYSTEM的Provider
if (p.info.authority != null
&& (processName == null
||(p.info.processName.equals(processName)
&&p.info.applicationInfo.uid == uid))
&& mSettings.isEnabledLPr(p.info, flags)
&& (!mSafeMode || ( p.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
finalList = newArrayList<ProviderInfo>(3);
}
//由PackageParser.Provider得到ProviderInfo,并添加到finalList中
//关于Provider类及ProviderInfo类,可参考图4-5
finalList.add(PackageParser.generateProviderInfo(p,flags));
}
}
}
if(finalList != null)
//最终结果按provider的initOrder排序,该值用于表示初始化ContentProvider的顺序
Collections.sort(finalList, mProviderInitOrderSorter);
returnfinalList;//返回最终结果
}
~~~
queryContentProviders函数很简单,就是从PKMS那里查找满足条件的Provider,然后生成AMS使用的ProviderInfo信息。为何偏偏能找到SettingsProvider呢?来看它的AndroidManifest.xml文件,如图6-7所示。
:-: ![](http://img.blog.csdn.net/20150803122756437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-7 SettingsProvider的AndroidManifest.xml文件示意
由图6-7可知,SettingsProvider设置了其uid为“android.uid.system”,同时在application中设置了process名为“system”。而在framework-res.apk中也做了相同的设置。所以,现在可以确认SettingsProvider将和framework-res.apk运行在同一个进程,即SystemServer中。
提示从运行效率角度来说,这样做也是合情合理的。因为SystemServer的很多Service都依赖Settings数据库,把它们放在同一个进程中,可以降低由于进程间通信带来的效率损失。
(2) 关于ContentProvider的介绍
前面介绍的从PKMS那里查询到的ProviderInfo还属于公有财产,现在我们要将它与AMS及ProcessRecord联系起来。
- AMS保存ProviderInfo的原因是它要管理ContentProvider。
- ProcessRecord保存ProviderInfo的原因是ContentProvider最终要落实到一个进程中。其实也是为了方便AMS管理,例如该进程一旦退出,AMS需要把其中的ContentProvider信息从系统中去除。
AMS及ProcessRecord均使用了一个新的数据结构ContentProviderRecord来管理ContentProvider信息。图6-8展示了ContentProviderRecord相应的数据结构。
:-: ![](http://img.blog.csdn.net/20150803122817345?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-8 ContentProvicerRecord及相应的“管理团队”
由图6-8可知:
- ContentProviderRecord从ContentProviderHolder派生,内部保存了ProviderInfo、该Provider所驻留的进程ProcessRecord,以及使用该ContentProvider的客户端进程ProcessRecord(即clients成员变量)。
- AMS的mProviderByClass成员变量及ProcessRecord的pubProviders成员变量均以ComponentName为Key来保存对应的ContentProviderRecord对象。
至此,Provider信息已经保存到AMS及ProcessRecord中了。那么,下一步的工作是什么呢?
2. ActivityThread 的installSystemProviders函数分析
在AMS和ProcessRecord中都保存了Provider信息,但这些仅仅都是一些信息,并不是ContentProvider,因此下面要创建一个ContentProvider实例(即SettingsProvider对象)。该工作由ActivityThread的installSystemProviders来完成,代码如下:
**ActivityThread.java::installSystemProviders**
~~~
public final void installSystemProviders(List<ProviderInfo>providers) {
if(providers != null)
//调用installContentProviders,第一个参数真实类型是Application
installContentProviders(mInitialApplication, providers);
}
~~~
installContentProviders这个函数是所有ContentProvider产生的必经之路,其代码如下:
**ActivityThread.java::installContentProviders**
~~~
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
finalArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
Iterator<ProviderInfo> i = providers.iterator();
while(i.hasNext()) {
ProviderInfo cpi = i.next();
//①调用installProvider函数,得到一个IContentProvider对象
IContentProvider cp = installProvider(context, null, cpi, false);
if (cp!= null) {
IActivityManager.ContentProviderHolder cph =
newIActivityManager.ContentProviderHolder(cpi);
cph.provider = cp;
//将返回的cp保存到results数组中
results.add(cph);
synchronized(mProviderMap){
//mProviderRefCountMap,;类型为HashMap<IBinder,ProviderRefCount>,
//主要通过ProviderRefCount对ContentProvider进行引用计数控制,一旦引用计数
//降为零,表示系统中没有地方使用该ContentProvider,要考虑从系统中注销它
mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
}
}
}
try {
//②调用AMS的publishContentProviders注册这些ContentProvider,第一个参数
//为ApplicationThread
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} ......
}
~~~
installContentProviders实际上是标准的ContentProvider安装时调用的程序。安装ContentProvider包括两方面的工作:
- 先在ActivityThread中通过installProvider得到一个ContentProvider实例。
- 向AMS发布这个ContentProvider实例。如此这般,一个APK中声明的ContentProvider才能登上历史舞台,发挥其该有的作用。
* * * * *
**提示** :上述工作其实和Binder Service类似,一个Binder Service也需要先创建,然后注册到ServiceManager中。
* * * * *
马上来看ActivityThread的installProvider函数。
(1) ActivityThread的installProvider函数分析
**ActivityThread.java::installProvider**
~~~
private IContentProvider installProvider(Contextcontext,
IContentProvider provider, ProviderInfoinfo, boolean noisy) {
//注意本例所传的参数:context为mInitialApplication,provider为null,info不为null,
// noisy为false
ContentProvider localProvider = null;
if(provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
/*
下面这个if判断的作用就是为该ContentProvider找到对应的Application。
在AndroidManifest.xml中,ContentProvider是Application的子标签,所以
ContentProvider和Application有一种对应关系。在本例中,传入的context(
其实是mInitialApplication)代表的是framework-res.apk,而Provider代表的
是SettingsProvider。而SettingsProvider.apk所对应的Application还未创建,
所以下面的判断语句最终会进入最后的else分支
*/
if(context.getPackageName().equals(ai.packageName)) {
c= context;
}else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)){
c = mInitialApplication;
} else {
try{
//ai.packageName应该是SettingsProvider.apk的Package,
//名为“com.android.providers.settings”
//下面将创建一个Context,指向该APK
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
}
}//if(context.getPackageName().equals(ai.packageName))判断结束
if (c == null) return null;
try {
/*
为什么一定要找到对应的Context呢?除了ContentProvider和Application的
对应关系外,还有一个决定性原因:即只有对应的Context才能加载对应APK的Java字节码,
从而可通过反射机制生成ContentProvider实例
*/
finaljava.lang.ClassLoader cl = c.getClassLoader();
//通过Java反射机制得到真正的ContentProvider,
//此处将得到一个SettingsProvider对象
localProvider=(ContentProvider)cl.loadClass(info.name).newInstance();
//从ContentProvider中取出其mTransport成员(见下文分析)
provider =localProvider.getIContentProvider();
if (provider == null) return null;
//初始化该ContentProvider,内部会调用其onCreate函数
localProvider.attachInfo(c, info);
}......
}//if(provider == null)判断结束
synchronized (mProviderMap) {
/*
ContentProvider必须指明一个和多个authority,在第4章曾经提到过,
在URL中host:port的组合表示一个authority。这个单词不太好理解,可简单
认为它用于指定ContentProvider的位置(类似网站的域名)
*/
String names[] =PATTERN_SEMICOLON.split(info.authority);
for (int i=0; i<names.length; i++) {
ProviderClientRecord pr = newProviderClientRecord(names[i],
provider, localProvider);
try {
//下面这句对linkToDeath的调用颇让人费解,见下文分析
provider.asBinder().linkToDeath(pr, 0);
mProviderMap.put(names[i], pr);
}......
}//for循环结束
if(localProvider != null) {
// mLocalProviders用于存储由本进程创建的ContentProvider信息
mLocalProviders.put(provider.asBinder(),
new ProviderClientRecord(null, provider, localProvider));
}
}//synchronized 结束
return provider;
}
~~~
以上代码不算复杂,但是涉及一些数据结构和一句令人费解的对inkToDeath函数的调用。先来说说那句令人费解的调用。
在本例中,provider变量并非通过函数参数传入,而是在本进程内部创建的。provider在本例中是Bn端(后面分析ContentProvider的getIContentProvider时即可知道),Bn端进程为Bn端设置死亡通知本身就比较奇怪。如果Bn端进程死亡,它设置的死亡通知也无法发送给自己。幸好源代码中有句注释:“Cache the pointer for the remote provider”。意思是如果provider参数是通过installProvider传递过来的(即该Provider代表远端进程的ContentProvider,此时它应为Bp端),那么这种处理是合适的。不管怎样,这仅仅是为了保存pointer,所以也无关宏旨。
至于代码中涉及的数据结构,我们整理为如图6-9所示。
:-: ![](http://img.blog.csdn.net/20150803122848097?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-9 ActivityThread中ContentProvider涉及的数据结构
由图6-9可知:
- ContentProvider类本身只是一个容器,而跨进程调用的支持是通过内部类Transport实现的。Transport从ContentProviderNative派生,而ContentProvider的成员变量mTransport指向该Transport对象。ContentProvider的getIContentProvider函数即返回mTransport成员变量。
- ContentProviderNative从Binder派生,并实现了IContentProvider接口。其内部类ContentProviderProxy是供客户端使用的。
- ProviderClientRecord是ActivityThread提供的用于保存ContentProvider信息的一个数据结构。它的mLocalProvider用于保存ContentProvider对象,mProvider用于保存IContentProvider对象。另外一个成员mName用于保存该ContentProvider的一个authority。注意,ContentProvider可以定义多个authority,就好像一个网站有多个域名一样。
至此,本例中的SettingProvider已经创建完毕,接下来的工作就是把它推向历史舞台——即发布该Provider。
(2) AMS的 publishContentProviders分析
publicContentProviders函数用于向AMS注册ContentProviders,其代码如下:
**ActivityManagerService.java::publishContentProviders**
~~~
publicfinal void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder>providers) {
......
synchronized(this){
//找到调用者所在的ProcessRecord对象
finalProcessRecord r = getRecordForAppLocked(caller);
......
finallong origId = Binder.clearCallingIdentity();
final intN = providers.size();
for (inti=0; i<N; i++) {
ContentProviderHolder src = providers.get(i);
......
//①注意:先从该ProcessRecord中找对应的ContentProviderRecord
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if(dst != null) {
ComponentName comp = newComponentName(dst.info.packageName,
dst.info.name);
//以ComponentName为key,保存到mProvidersByClass中
mProvidersByClass.put(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++)
mProvidersByName.put(names[j], dst);//以authority为key,保存
//mLaunchingProviders用于保存处于启动状态的Provider
int NL = mLaunchingProviders.size();
int j;
for (j=0; j<NL; j++) {
if (mLaunchingProviders.get(j) ==dst) {
mLaunchingProviders.remove(j);
j--;
NL--;
}//
}//for (j=0; j<NL; j++)结束
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}//synchronized结束
updateOomAdjLocked(r);//每发布一个Provider,需要调整对应进程的oom_adj
}//for(int j = 0; j < names.length; j++)结束
}//for(int i=0; i<N; i++)结束
Binder.restoreCallingIdentity(origId);
}// synchronized(this)结束
}
~~~
这里应解释一下publishContentProviders的工作流程:
- 先根据调用者的pid找到对应的ProcessRecord对象。
- 该ProcessRecord的pubProviders中保存了ContentProviderRecord信息。该信息由前面介绍的AMS的generateApplicationProvidersLocked函数根据Package本身的信息生成。此处将判断要发布的ContentProvider是否由该Package声明。
- 如果判断返回成功,则将该ContentProvider及其对应的authority加到mProvidersByName中。注意,AMS中还有一个mProvidersByClass变量,该变量以ContentProvider的ComponentName为key,即系统提供多种方式找到某一个ContentProvider,一种是通过 authority,另一种方式就是指明ComponentName。
- mLaunchingProviders和最后的notifyAll函数用于通知那些等待ContentProvider所在进程启动的客户端进程。例如,进程A要查询一个数据库,需要通过进程B中的某个ContentProvider 来实施。如果B还未启动,那么AMS就需要先启动B。在这段时间内,A需要等待B启动并注册对应的ContentProvider。B一旦完成注册,就需要告知A退出等待以继续后续的查询工作。
现在,一个SettingsProvider就算正式在系统中挂牌并注册了,此后,和Settings数据库相关的操作均由它来打理。
3. AMS的installSystemProviders总结
AMS的installSystemProviders函数其实就是用于启动SettingsProvider,其中比较复杂的是ContentProvider相关的数据结构,读者可参考图6-9。
- 前言
- 第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 本章小结