内容提供程序
观察内容提供商
ContentService是Android四大组件之一的ContentProvider密切相关的一个系统服务,且和AccountManagerService也有着紧密的联系。ContentService以功能来划分,就两大模块:
第一个功能,对于很多开发者来说可能熟悉。而对于第二个,可能就会陌生一点,这个是Android提供的同步功能,很多APP开发者,也很难用到这个Android的同步功能。ContentService的同步功能和AccountManagerService往往紧密联系在一起。本文将不再阐述ContentService的同步功能,有兴趣的读者可以自行阅读Android的参考文档了解该功能的使用方法https://developer.android.google.cn/reference/android/content/SyncRequest.html。那么本文将阐述的内容是:
ContentProvider是Android的四大组件之一,是提供APP间安全共享数据的方式之一,APP可以通过ContentProvider从其它APP中获取到想要的数据,例如读取手机的联系人。也可以通过ContentProvider把APP的数据共享出去给其它APP使用。
以查询ContentProvider的数据的流程为线索,一步一步分析这个过程,从而了解ContentProvider的过程和原理。
引用官方的一段话:如果您想要访问内容提供程序中的数据,可以将应用的 Context 中的 ContentResolver 对象用作客户端来与提供程序通信。 ContentResolver 对象会与提供程序对象(即实现 ContentProvider 的类实例)通信。 提供程序对象从客户端接收数据请求,执行请求的操作并返回结果。
APP发起查询,很简单,如下:
ContentResolver cr = getContentResolver();
cr.query(Uri uri, ....);
首先通过getContentResolver()获取到ContentResolver对象,ContentResolver对象好比内容分解器,能够分解出来需要调用哪个内容提供程序即ContentProvider。ContentResolver分解的依据便是参数Uri。Uri是如何把ContentResolver和ContentProvider联系起来的呢?Uri可以看作是一个地址描述,随意举一个Uri可描述的地址例子:
content://user_dictionary
可以和平时上网的网址做一个类比,如访问百度:
https://www.baidu.com
Uri和网址结构有很大相似性,https表示的是网络技术中的传输协议,那么content也可以当做ContentProvider中的一种协议,那么content就代表当前需要通过ContentProvider进行数据通信。www.baidu.com是百度的域名,表示需要访问网站的位置,user_dictionary也就可以比作ContentProvider的域名,user_dictionary表示是那个ContentProvider。换句话说,ContentResolver接收到content://user_dictionary这个Uri时,就知道当前需要发起ContentProvider数据交互,通过user_dictionary可以寻找用user_dictionary表示的ContentProvider。
查看ContentResolver的定义,如下:
public abstract class ContentResolver {
......
}
可见ContentResolver是一个抽象类,所以说getContentResolver()所获取到实例本质是ContentResolver的子类,查看getContentResolver()的具体实现:
private final ApplicationContentResolver mContentResolver;
public ContentResolver getContentResolver() {
return mContentResolver;
}
上面的代码定义在文件frameworks/base/core/java/android/app/ContextImpl.java中
从上面的代码可知,getContentResolver()获取到的实际是ApplicationContentResolver的实例mContentResolver。cr.query(Uri uri, ….)的实现如下:
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,......) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
......
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
......
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
......
}
这个方法定义在文件frameworks/base/core/java/android/content/ContentResolver.java中。
这里用文字描述一下上面代码的过程,先声明两个相同类型的局部变量unstableProvider、stableProvider,都是IContentProvider的实例,IContentProvider是AIDL的接口,所以IContentProvider所调用的方法是远程调用。通过acquireUnstableProvider()方法给unstableProvider变量赋值,unstableProvider调用query()方法,如果发生DeadObjectException异常,调用acquireProvider()方法给stableProvider赋值,然后调用stableProvider的query()方法。
这里有点奇怪,为什么要声明两个一样的IContentProvider变量,且调用相同的方法query()。从变量的命名上,也能找到一点线索,unstableProvider和stableProvider,前者是不稳定的provider,后者是稳定的provider。什么样表示稳定的,什么样表示不稳定的?从上面的代码来看,不稳定的provider,调用query()方法会抛出DeadObjectException。下面先看看unstableProvider的赋值过程:
public final IContentProvider acquireExistingProvider(......) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
......
return provider;
}
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
可见unstableProvider是从变量mProviderMap的实例中遍历出来,也就是说,在调用者的进程内部,对provider会缓存到mProviderMap这个变量中。而IContentProvider是一个跨进程的远程调用。换句话说,调用者的进程内部所缓存的unstableProvider实例所对应的远程进程不能保证还正常运行着,如果所对应的远程进程没有运行,那么就会抛出DeadObjectException异常,并调用unstableProviderDied()方法把本地的缓存清除。然后通过acquireProvider()重新生产一个新的stableProvider,且Android系统会启动和stableProvider对应的远程进程,这个过程下文会阐述。可见Android这个举措是为了性能考虑,目的让APP的运行仅可能的快。
回到上文中实例化变量unstableProvider和stableProvider的代码,unstableProvider或stableProvider实例化后,直接调用query()方法,然后直接就可以返回Cursor给调用者了,说明在这里的query()这一步,已经拿到调用者需要的数据。所以理解unstableProvider和stableProvider的实质至关重要。那么unstableProvider和stableProvider所对应的远程进程的服务是哪一个呢?是不是就直接对应ContentProvider呢?
由于unstableProvider是一个调用者进程中缓存的实例,所以需要对stableProvider下手,了解stableProvider的实例化过程即可,如下:
public final IContentProvider acquireProvider(......) {
......
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
......
return holder.provider;
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
stableProvider被封装到ContentProviderHolder的变量中provider中。通过调用ActivityManagerNative.getContentProvider()获取ContentProviderHolder,ActivityManagerNative的所对应的远程服务是system_process中的ActivityManagerService,接着看getContentProvider()这个方法:
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
......
return getContentProviderImpl(caller, name, null, stable, userId);
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。
这里直接调用了getContentProviderImpl()方法:
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
synchronized(this) {
......
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
......
}
if (!providerRunning) {
......
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
try {
// Content provider is now in use, its package can't be stopped.
......
if (proc != null && proc.thread != null && !proc.killed) {
......
} else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
......
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
......
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
......
cpr.wait();
......
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。
由于这个方法的代码篇幅非常大,这里省略了很多代码,省略的代码主要就是一些缓存、权限等等相关的代码。这里假设provider的进程没有启动,从最原始,最干净的时候分析ContentProvider的这个过程。聚焦上面的代码,首先分两种情况,providerRunning和!providerRunning,providerRunning是基于!providerRunning为前提的,因此provider第一次启动是运行!providerRunning这个代码路径。假若provider没有运行过,Android首先通过startProcessLocked()把provider所在的应用启动起来,这个过程这里暂时先放下,继续往下看,在最后面,有一个while循环,循环条件是cpr.provider == null?这里会一直等待cpr的provider变量被赋值,回到上文中的acquireProvider()方法的代码,acquireProvider()首先要获取的是ContentProviderHolder的实例,上面的代码如果cpr != null,就返回一个ContentProviderHolder对象(cpr.newHolder(conn))。所以这里的cpr.provider就是上文中acquireProvider()需要获取的IContentProvider的实例对象。
因此,只要继续分析清楚cpr.provider的赋值过程,就知道开始的时候ContentResolver.query()所调用的真正的远程服务。回到上面的代码,startProcessLocked()启动应用时,运行到如下代码(APP的启动过程本文不再赘述):
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
生成ActivityThread实例,也就是常说的主线程(UI线程了),然后调用attach()方法:
private void attach(boolean system) {
......
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
......
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
又回到ActivityManagerService了,接着往下看:
public final void attachApplication(IApplicationThread thread) {
......
attachApplicationLocked(thread, callingPid);
......
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。
这里没有需要看的代码,继续往下跟踪:
private final boolean attachApplicationLocked(IApplicationThread thread,.....) {
List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,......);
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。
IApplicationThread实例thread是远程APP的远程调用端,所以thread.bindApplication()实际又从system_process进程回到了APP所在的进程,注意第三个参数providers,providers是封装了应用的所有的ContentProvider,详情读者可以阅读generateApplicationProvidersLocked(app)方法,本文不再阐述。继续往下看:
public final void bindApplication(String processName, ApplicationInfo appInfo,
List providers, ComponentName instrumentationName,......) {
......
data.providers = providers;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
发送了一个H.BIND_APPLICATION的消息,注意data.providers = providers。该消息的处理是在:
private void handleBindApplication(AppBindData data) {
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
......
}
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
调用了installContentProviders()方法,注意参数data.providers,如下:
private void installContentProviders(
Context context, List providers) {
final ArrayList results =
new ArrayList();
for (ProviderInfo cpi : providers) {
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
把应用的所有的ContentProvider信息封装到ContentProviderHolder中,这里要回到上文中acquireProvider()方法,获取IContentProvider的实例正好是ContentProviderHolder的中的变量provider,因此,这里需要了解上面代码ContentProviderHolder的实例cph的实例化过程,看installProvider()方法:
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,.....) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
......
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
......
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
......
} else {
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
......
}
retHolder = pr.mHolder;
} else {
......
return retHolder;
}
这个方法定义在文件frameworks/base/core/java/android/app/ActivityThread.java中。
上面的代码通过ClassLoader映射ContentProvider的对象实例,然后调用getIContentProvider()方法,获取到IContentProvider的实例provider,然后赋值给ContentProviderHolder的实例holder的变量provider,所以provider正是acquireProvider()中获取的的IContentProvider的实例,而继续看getIContentProvider()方法查看provider的本质是:
......
private Transport mTransport = new Transport();
public IContentProvider getIContentProvider() {
return mTransport;
}
class Transport extends ContentProviderNative {
public Cursor query(.....){
......
}
......
}
......
这个代码定义在文件frameworks/base/core/java/android/content/ContentProvider.java中。
上面的代码可见,provider实质是Transport的实例mTransport,Transport是ContentProviderNative的子类,而ContentProviderNative是IContentProvider的子类。
下面继续看看provider和ActivityManagerService的关系,回到上文中的installContentProviders()方法,调用了publishContentProviders()方法,如下:
public final void publishContentProviders(IApplicationThread caller,
List providers) {
......
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
......
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
}
}
}
这个代码定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。
把应用的ContentProvider信息缓存到mProviderMap中,这里重点关注语句dst.provider = src.provider,回到上文中getContentProviderImpl()方法中的代码,后面的while循环,等待cpr.provider的赋值,dst.provider = src.provider正好就是这个赋值过程,cpr.provider赋值后,getContentProviderImpl()返回ContentProviderHolder的实例cpr.newHolder(conn),而这个实例持有变量provider指向Transport的实例mTransport,也就是应用的ContentProvider。
这个过程非常绕乱人的头绪,下面把这个过程简单转换成一张简单的关系图,理清这个过程和关系,如下:
有时APP开发的时候,APP运行时,需要实时监听一些ContentProvider数据的变化。如用户添加了一个联系人,APP需要接收到联系人添加的通知。由于ContentProvider的提供者,和需求者不是同一个APP,所以,这个通知的纽带,就需要ContentService来完成。从注册一个观察者开始,分析这个通知的来龙去脉,注册代码如下:
ContentResolver cr = getContentResolver();
cr.registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
@NonNull ContentObserver observer);
当ContentProvider的数据发生变化时,便会回调到ContentObserver的onChange()方法,观察者ContentObserver observer被注册到哪里去呢?继续进入分析:
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer, @UserIdInt int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle);
} catch (RemoteException e) {
}
}
这个方法定义在文件frameworks/base/core/java/android/content/ContentResolver.java中。
上面的代码getContentService()获取到的对象是:
public static IContentService getContentService() {
if (sContentService != null) {
return sContentService;
}
IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
if (false) Log.v("ContentService", "default service binder = " + b);
sContentService = IContentService.Stub.asInterface(b);
if (false) Log.v("ContentService", "default service = " + sContentService);
return sContentService;
}
这个方法定义在文件frameworks/base/core/java/android/content/ContentResolver.java中。
阅读《Android系统之System Server大纲 》可知,启动的CONTENT_SERVICE_NAME的系统服务如下:
private static final String CONTENT_SERVICE_CLASS =
"com.android.server.content.ContentService$Lifecycle";
traceBeginAndSlog("StartContentService");
mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
这个方法定义在文件frameworks/base/services/java/com/android/server/SystemServer.java中。
所以getContentService()获取到的是ContentService,继续往下分析registerContentObserver():
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer, int userHandle) {
......
synchronized (mRootNode) {
mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
uid, pid, userHandle);
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
" with notifyForDescendants " + notifyForDescendants);
}
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。
上面的代码把观察者observer通过addObserverLocked放置在mRootNode对象中
private void addObserverLocked(Uri uri, int index, IContentObserver observer,
boolean notifyForDescendants, Object observersLock,
int uid, int pid, int userHandle) {
// If this is the leaf node add the observer
if (index == countUriSegments(uri)) {
mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
uid, pid, userHandle));
return;
}
// Look to see if the proper child already exists
String segment = getUriSegment(uri, index);
int N = mChildren.size();
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
observersLock, uid, pid, userHandle);
return;
}
}
// No child found, create one
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
observersLock, uid, pid, userHandle);
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。
首先把观察者observer再次封装到mObservers中,mObservers是ArrayList的实例,后面依次遍历整个需要监听的Uri,用segment生产一个ObserverNode实例,保存在ArrayList的实例mChildren中。
观察者都被封装好以后,就等待数据的变化了。在上文ContentProvider的原理中,可知,ContentProvider的需求者拿到ContentProvider提供者的远程调用后,两个APP直接进行交互了,任何数据变化并没有经过ContentService,因此,ContentService是如何监测ContentProvider数据发生变化并通知到观察者呢?这里的机制便是ContentProvider提供者的数据发生变化时,ContentProvider提供者必须主动通过notifyChange()方法通知ContentService数据发生了变化。下面以联系人的数据库变化为例,阐述这个过程。
添加一个联系人,调用ContactsProvider的insert()方法,如下:
public Uri insert(Uri uri, ContentValues values) {
incrementStats(mInsertStats, mInsertInBatchStats);
ContactsTransaction transaction = startTransaction(false);
try {
Uri result = insertInTransaction(uri, values);
if (result != null) {
transaction.markDirty();
}
transaction.markSuccessful(false);
return result;
} finally {
endTransaction(false);
}
}
这个方法定义在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/AbstractContactsProvider.java中。
上面的代码中,一次插入的业务抽象成一个ContactsTransaction,然后调用insertInTransaction()方法把数据插入数据库成功后,调用transaction.markDirty()标记当前的数据状态有变化,然后调用endTransaction()结束当前的业务。如下:
private void endTransaction(boolean callerIsBatch) {
ContactsTransaction transaction = mTransactionHolder.get();
if (transaction != null && (!transaction.isBatch() || callerIsBatch)) {
boolean notify = false;
try {
if (transaction.isDirty()) {
notify = true;
}
transaction.finish(callerIsBatch);
if (notify) {
notifyChange();
}
} finally {
// No matter what, make sure we clear out the thread-local transaction reference.
mTransactionHolder.set(null);
}
}
}
这个方法定义在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/AbstractContactsProvider.java中。
上面的代码,通过mTransactionHolder.get()获取刚刚进行的业务transaction,如果的这个业务被标记为markDirty(),transaction.isDirty()返回true,所以notify被置成true,所以会调用notifyChange()。往下看这个方法:
protected void notifyChange(boolean syncToNetwork, boolean syncToMetadataNetwork) {
getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
syncToNetwork);
getContext().getContentResolver().notifyChange(MetadataSync.METADATA_AUTHORITY_URI,
null, syncToMetadataNetwork);
}
这个方法定义在文件packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java中。
上面的代码,获取到ContentResolver()对象,和query()类似,然后调用notifyChange()通知ContentResolver数据发生了变化,如下:
public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(),
syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
userHandle);
} catch (RemoteException e) {
}
}
这个方法定义在文件frameworks/base/core/java/android/content/ContentResolver.java中。
上面的代码调用getContentService()方法,从上文可知,getContentService()获取到的是ContentService的远程调用,因此getContentService().notifyChange()实质会运行到ContentService的notifyChange()方法,如下:
public void notifyChange(Uri uri, ......) {
......
try {
ArrayList calls = new ArrayList();
synchronized (mRootNode) {
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
flags, userHandle, calls);
}
final int numCalls = calls.size();
for (int i=0; itry {
oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
} catch (RemoteException ex) {
......
}
}
......
}
} finally {
restoreCallingIdentity(identityToken);
}
}
这个方法定义在文件frameworks/base/services/core/java/com/android/server/content/ContentService.java中。
上面的代码中的mRootNode变量,在注册观察者的章节中,mRootNode封装了所有的观察者。调用collectObserversLocked()根据观察者监听的Uri类型把观察者封装到ArrayList的实例calls中,然后调用oc.mObserver.onChange()方法通知APP数据发生变化。
本文详细阐述了ContentProvider的原理,从ContentProvider的query过程入手,全面详细分析了从query()的发起APP到ActivityManagerService,再到ContentProvider提供程序的整个流程和交互过程。以及分析了ContentService在ContentProvider的数据变化监测通知的架构中,扮演了观察者模式中的抽象主题,具体主题部分。