接下去这个代码判断当前要获取的Content Provider是否允许在客户进程中加载,即查看一个这个Content Provider否配置了multiprocess属性为true,如果允许在客户进程中加载,就直接返回了这个Content Provider的信息了:
-
if (r != null && cpr.canRunHere(r)) {
-
// If this is a multiprocess provider, then just return its
-
// info and allow the caller to instantiate it. Only do
-
// this if the provider is the same user as the caller's
-
// process, or can run as root (so can be in any process).
-
return cpr;
-
}
在我们这个情景中,要获取的ArticlesProvider设置了要在独立的进程中运行,因此,继续往下执行:
-
// This is single process, and our app is now connecting to it.
-
// See if we are already in the process of launching this
-
// provider.
-
final int N = mLaunchingProviders.size();
-
int i;
-
for (i=0; i<N; i++) {
-
if (mLaunchingProviders.get(i) == cpr) {
-
break;
-
}
-
}
系统中所有正在加载的Content Provider都保存在mLaunchingProviders成员变量中。在加载相应的Content Provider之前,首先要判断一下它是可否正在被其它应用程序加载,如果是的话,就不用重复加载了。在我们这个情景中,没有其它应用程序也正在加载ArticlesProvider这个Content Provider,继续往前执行:
-
// If the provider is not already being launched, then get it
-
// started.
-
if (i >= N) {
-
final long origId = Binder.clearCallingIdentity();
-
ProcessRecord proc = startProcessLocked(cpi.processName,
-
cpr.appInfo, false, 0, "content provider",
-
new ComponentName(cpi.applicationInfo.packageName,
-
cpi.name), false);
-
......
-
mLaunchingProviders.add(cpr);
-
......
-
}
这里的条件i >= N为true,就表明没有其它应用程序正在加载这个Content Provider,因此,就要调用startProcessLocked函数来启动一个新的进程来加载这个Content Provider对应的类了,然后把这个正在加载的信息增加到mLaunchingProviders中去。我们先接着分析这个函数,然后再来看在新进程中加载Content Provider的过程,继续往下执行:
-
// Make sure the provider is published (the same provider class
-
// may be published under multiple names).
-
if (firstClass) {
-
mProvidersByClass.put(cpi.name, cpr);
-
}
-
cpr.launchingApp = proc;
-
mProvidersByName.put(name, cpr);
这段代码把这个Content Provider的信息分别保存到mProvidersByName和mProviderByCalss两个Map中去,以方便后续查询。
因为我们需要获取的Content Provider是在新的进程中加载的,而getContentProviderImpl这个函数是在系统进程中执行的,它必须要等到要获取的Content Provider是在新的进程中加载完成后才能返回,这样就涉及到进程同步的问题了。这里使用的同步方法是不断地去检查变量cpr的provider域是否被设置了。当要获取的Content Provider在新的进程加载完成之后,它会通过Binder进程间通信机制调用到系统进程中,把这个cpr变量的provider域设置为已经加载好的Content Provider接口,这时候,函数getContentProviderImpl就可以返回了。下面的代码就是用来等待要获取的Content Provider是在新的进程中加载完成的:
-
// Wait for the provider to be published...
-
synchronized (cpr) {
-
while (cpr.provider == null) {
-
......
-
try {
-
cpr.wait();
-
} catch (InterruptedException ex) {
-
}
-
}
-
}
下面我们再分析在新进程中加载ArticlesProvider这个Content Provider的过程。
Step 8. ActivityManagerService.startProcessLocked
Step 9. Process.start
Step 10. ActivityThread.main
Step 11. ActivityThread.attach
Step 12. ActivityManagerService.attachApplication
这五步是标准的Android应用程序启动步骤,具体可以参考 Android应用程序启动过程源代码分析 一文中的Step 23到Step 27,或者 Android系统在新进程中启动自定义服务过程(startService)的原理分析 一文中的Step 4到Step 9,这里就不再详细描述了。
这五步是标准的Android应用程序启动步骤,具体可以参考 Android应用程序启动过程源代码分析 一文中的Step 23到Step 27,或者 Android系统在新进程中启动自定义服务过程(startService)的原理分析 一文中的Step 4到Step 9,这里就不再详细描述了。
本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966987,如需转载请自行联系原作者