ContentProvider的起源和获取
大名鼎鼎的ContentProvider相信大家都很熟悉了,但是或许你对于ContentProvider的起源和获取并不是很了解,下面我们就来看看吧!
ContentProvider的起源
先看看ContentProvider是如何安装于android系统中的吧!
1,在用户安装android app时,会用到PM(Package
Manager),这一点相信大家都很熟悉了。在安装过程中,有以下代码需要关注:
PackageManagerService. scanPackageLI (@PackageManagerService.java)
{
……
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProvidersByComponent.put(new ComponentName(p.info.packageName,
p.info.name), p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
// We only want the first authority for a provider to possibly be
// syncable, so if we already added this provider using a different
// authority clear the syncable flag. We copy the provider before
// changing it because the mProviders object contains a reference
// to a provider that we don't want to change.
// Only do this for the second authority since the resulting provider
// object can be the same for all future authorities for this provider.
p = new PackageParser.Provider(p);
p.syncable = false;
}
if (!mProviders.containsKey(names[j])) {
mProviders.put(names[j], p);
if (p.info.authority == null) {
p.info.authority = names[j];
} else {
p.info.authority = p.info.authority + ";" + names[j];
}
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
Log.d(TAG, "Registered content provider: " + names[j] +
", className = " + p.info.name +
", isSyncable = " + p.info.isSyncable);
} else {
PackageParser.Provider other = mProviders.get(names[j]);
Slog.w(TAG, "Skipping provider name " + names[j] +
" (in package " + pkg.applicationInfo.packageName +
"): name already used by "
+ ((other != null && other.getComponentName() != null)
? other.getComponentName().getPackageName() : "?"));
}
}
}
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(p.info.name);
}
}
……
}
这里PM从app的androidManifest.xml中获取ContentProvider的信息且将其存储于mProvidersByComponent中。
2,Android系统对于app的启动处理中会调用到ActivityManagerService.attachApplicationLocked
(@ActivityManagerService.java),其中有以下处理
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
……
boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
……
}
private final List generateApplicationProvidersLocked(ProcessRecord app) {
List providers = null;
try {
providers =
ActivityThread.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (providers != null) {
final int N = providers.size();
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
ContentProviderRecord cpr =
(ContentProviderRecord)mProvidersByClass.get(cpi.name);
if (cpr == null) {
cpr = new ContentProviderRecord(cpi, app.info);
mProvidersByClass.put(cpi.name, cpr);
}
app.pubProviders.put(cpi.name, cpr);
app.addPackage(cpi.applicationInfo.packageName);
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
}
然后到PackageManagerService.java,看下面这个函数
public List<ProviderInfo> queryContentProviders(String processName,
int uid, int flags) {
ArrayList<ProviderInfo> finalList = null;
synchronized (mPackages) {
Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
while (i.hasNext()) {
PackageParser.Provider p = i.next();
if (p.info.authority != null
&& (processName == null ||
(p.info.processName.equals(processName)
&& p.info.applicationInfo.uid == uid))
&& mSettings.isEnabledLP(p.info, flags)
&& (!mSafeMode || (p.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
finalList.add(PackageParser.generateProviderInfo(p,
flags));
}
}
}
if (finalList != null) {
Collections.sort(finalList, mProviderInitOrderSorter);
}
return finalList;
}
上面的处理将会找到和app相关的ContentProvider(也即是在app的androidManifest.xml中定义的ContentProvider)。
3,找到app的ContentProvider后,下面就是安装和启动了,代码比较多,下面就简单说一下调用流程吧!
ActivityThrad:handleBindApplication |
|
ActivityThrad:installContentProviders |
|
ActivityThread:installProvider |
|
ContentProvider:attachInfo |
|
ContentProvider.this.onCreate() ContentProvider在此启动了 |
ContentProvider的获取
ContentProvider的获取流程比较简单,且涉及的代码比较多,在这里就简单说调用流程吧!有兴趣的话,请看详细代码。
ContentResolver:acquireProvider(Uri uri) |
ContentResolver:acquireProvider(mContext, uri.getAuthority()); |
ActivityThread.acquireProvider(context, name) |
ActivityThread:getProvider(c, name) |
ActivityManagerService:getContentProvider |
ActivityManagerService:getContentProviderImpl |
ActivityThread:getPackageManager():resolveContentProvider |
ContentProvider的一个注意点:ContentProvider运行在定义它的app内。举例说明如下:app
A定义了一个ContentProvider,app B访问这个ContentProvider。如果在app
B访问app A的ContentProvider时,app
A没有启动,那么此时app A会被启动。处理代码位置如下:
ActivityManagerService:getContentProviderImpl
{
……
// 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);
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
Binder.restoreCallingIdentity(origId);
}
……
}