Step 7. ActivityManagerService.getContentProviderImpl
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
-
public final class ActivityManagerService extends ActivityManagerNative
-
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
-
......
-
-
private final ContentProviderHolder getContentProviderImpl(
-
IApplicationThread caller, String name) {
-
ContentProviderRecord cpr;
-
ProviderInfo cpi = null;
-
-
synchronized(this) {
-
ProcessRecord r = null;
-
if (caller != null) {
-
r = getRecordForAppLocked(caller);
-
......
-
}
-
-
// First check if this content provider has been published...
-
cpr = mProvidersByName.get(name);
-
if (cpr != null) {
-
......
-
} else {
-
try {
-
cpi = AppGlobals.getPackageManager().
-
resolveContentProvider(name,
-
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
-
} catch (RemoteException ex) {
-
}
-
......
-
}
-
-
cpr = mProvidersByClass.get(cpi.name);
-
final boolean firstClass = cpr == null;
-
if (firstClass) {
-
try {
-
ApplicationInfo ai =
-
AppGlobals.getPackageManager().
-
getApplicationInfo(
-
cpi.applicationInfo.packageName,
-
STOCK_PM_FLAGS);
-
......
-
cpr = new ContentProviderRecord(cpi, ai);
-
} catch (RemoteException ex) {
-
// pm is in same process, this will never happen.
-
}
-
}
-
-
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;
-
}
-
-
......
-
-
// 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;
-
}
-
}
-
-
// 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);
-
......
-
}
-
-
// 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);
-
-
......
-
}
-
-
// Wait for the provider to be published...
-
synchronized (cpr) {
-
while (cpr.provider == null) {
-
......
-
try {
-
cpr.wait();
-
} catch (InterruptedException ex) {
-
}
-
}
-
}
-
-
return cpr;
-
}
-
-
......
-
}
这个函数比较长,我们一步一步地分析。
函数首先是获取调用者的进程记录块信息:
函数首先是获取调用者的进程记录块信息:
-
ProcessRecord r = null;
-
if (caller != null) {
-
r = getRecordForAppLocked(caller);
-
......
-
}
在我们这个情景中,要获取的就是应用程序Article的进程记录块信息了,后面会用到。
在ActivityManagerService中,有两个成员变量是用来保存系统中的Content Provider信息的,一个是mProvidersByName,一个是mProvidersByClass,前者是以Content Provider的authoriry值为键值来保存的,后者是以Content Provider的类名为键值来保存的。一个Content Provider可以有多个authority,而只有一个类来和它对应,因此,这里要用两个Map来保存,这里为了方便根据不同条件来快速查找而设计的。下面的代码就是用来检查要获取的Content Provider是否已经加存在的了:
-
// First check if this content provider has been published...
-
cpr = mProvidersByName.get(name);
-
if (cpr != null) {
-
......
-
} else {
-
try {
-
cpi = AppGlobals.getPackageManager().
-
resolveContentProvider(name,
-
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
-
} catch (RemoteException ex) {
-
}
-
......
-
}
-
-
cpr = mProvidersByClass.get(cpi.name);
-
final boolean firstClass = cpr == null;
-
if (firstClass) {
-
try {
-
ApplicationInfo ai =
-
AppGlobals.getPackageManager().
-
getApplicationInfo(
-
cpi.applicationInfo.packageName,
-
STOCK_PM_FLAGS);
-
......
-
cpr = new ContentProviderRecord(cpi, ai);
-
} catch (RemoteException ex) {
-
// pm is in same process, this will never happen.
-
}
-
}
在我们这个情景中,由于是第一次调用ArticlesProvider接口,因此,在mProvidersByName和mProvidersByClass两个Map中都不存在ArticlesProvider的相关信息,因此,这里会通过AppGlobals.getPackageManager函数来获得PackageManagerService服务接口,然后分别通过它的resolveContentProvider和getApplicationInfo函数来分别获取ArticlesProvider应用程序的相关信息,分别保存在cpi和cpr这两个本地变量中。这些信息都是在安装应用程序的过程中保存下来的,具体可以参考Android应用程序安装过程源代码分析一文。
本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966983,如需转载请自行联系原作者