谈谈AMS管理ContentProvider
重要数据结
ContentProviderRecord
-
provider:在ActivityThread的installProvider()过程,会创建ContentProvider对象
-
proc:记录provider所在的进程
-
launchingApp:记录等待provider所在进程启动
-
connections:记录该ContentProvider的所有连接信息
ContentProviderConnection
功能:连接contentProvider与请求该provider所对应的进程
- provider:目标provider所对应的ContentProviderRecord结构体;
- client:请求该provider的客户端进程
- waiting:该连接的client进程正在等待该provider发布
ProcessRecord
- pubProviders: ArrayMap<String, ContentProviderRecord>记录发布的provider
- conProviders: ArrayList 记录当前进程跟其他进程provider所建立的连接
AMS
- mProviderMap记录系统所有的provider信息;
- mLaunchingProviders记录当前正在启动的provider;
ActivityThread
- mProviderMap: 记录App端的所有provider信息;
- mProviderRefCountMap:记录App端的所有provider引用信息;
查询切入
首先通过查询ContentProvider来切入
ContentResolver cr = getContentResolver(); //获取ContentResolver
Cursor cursor = cr.query(uri, null, null, null, null); //执行查询操作
其中getContentResolver()
是ContextImpl中的方法
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
其中ContextImpl的构造方法中给变量mContentResolver赋值
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
从结构上看:
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
private final UserHandle mUser;
public ApplicationContentResolver(
Context context, ActivityThread mainThread, UserHandle user) {
super(context);
mMainThread = Preconditions.checkNotNull(mainThread);
mUser = Preconditions.checkNotNull(user);
}
...
}
在构造中得到了ActivityThread对象,这个对象是管理四大组件的核心对象
2
我们继续顺着查询来找
public final Cursor query( Uri uri, String[] projection,
String selection, String[] selectionArgs,
String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs,
String sortOrder, CancellationSignal cancellationSignal) {
//获取unstable provider
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
...
try {
//执行查询操作
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 远程进程死亡,处理unstable provider死亡过程
unstableProviderDied(unstableProvider);
//unstable类型死亡后,再创建stable类型的provider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
//再次执行查询操作
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
//强制执行查询操作,可能会失败并跑出RuntimeException
qCursor.getCount();
//创建对象CursorWrapperInner
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
这段代码可以看出来,首先获取的是unstable的ContentProvider;然后执行对应query方法。
当有DeadObjectException时候代表ContentProvider在的进程已经挂掉了在重新获取stable的ContentProvider:
- 先调用unstableProviderDied(),清理刚创建的unstable的ContentProvider;
- 调用acquireProvider(),尝试获取stable的ContentProvider; 此时当ContentProvider进程死亡,则会杀掉该ContentProvider的客户端进程。
然后执行query操作;
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
return acquireUnstableProvider(mContext, uri.getAuthority());
}
return null;
}
ContextImpl.java
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
public final IContentProvider acquireProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
if (auth != null) {
return acquireProvider(mContext, auth);
}
return null;
}
我们看到无论时那一种方法,都是调用ActivityThread.acquireProvider方法
怎么看出来的?
private static final class ApplicationContentResolver extends ContentResolver {
知道这个关系,然后在这个类中找对应acquireUnstableProvider方法
于是有:
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
首先会找看看有没有已经存在的IContentProvider如果有就用有的。没有就会调用AMS.getContentProvider()方法得到一个ContentProviderHolder对象,如果出错返回null。
我们详细看
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
//从AT.mProviderMap查询是否存在相对应的provider
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
//当provider所在进程已经死亡则返回
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
从
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
这个集合是包括本地对象和引用对象在内的所有ContentProvider对象。但是如果Provider进程挂掉了,就返回空。比高且要处理进程死亡的一些清理工作。
如果第一次调用肯定是空,空的话干什么,空的话
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
空就要通过AMS了
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
return getContentProviderImpl(caller, name, null, stable, userId);
}
其中getContentProviderImpl太长了
我们分部分进行吧。
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord r = null;
if (caller != null) {
r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
}
}
...
}
得到getRecordForAppLocked记录,这里看调用者的进程是不是存在,如果不存在抛出异常。
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
if (cpr == null && userId != UserHandle.USER_OWNER) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_OWNER;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
content provider是否已经发布,如果发布继续执行,没有发布则看是不是存在用户0。
boolean providerRunning = cpr != null;
if (providerRunning) {
cpi = cpr.info;
String msg;
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
!= null) {
throw new SecurityException(msg);
}
if (r != null && cpr.canRunHere(r)) {
//当允许运行在调用者进程且已发布,则直接返回
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
final long origId = Binder.clearCallingIdentity();
//增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
//更新进程LRU队列
updateLruProcessLocked(cpr.proc, false, null);
}
}
if (cpr.proc != null) {
if (false) {
if (cpr.name.flattenToShortString().equals(
"com.android.providers.calendar/.CalendarProvider2")) {
Process.killProcess(cpr.proc.pid);
}
}
//更新进程adj
boolean success = updateOomAdjLocked(cpr.proc);
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
//如果没有更新成功说明进程不存在,不存则则减少引用计数
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc);
if (!lastRef) {
return null;
}
providerRunning = false;
conn = null;
}
}
Binder.restoreCallingIdentity(origId);
}
这里主要介绍的时Provider进程存在的情况,当进程存在的时候,做的事情如下:
- 首先进行权限检查
- 看content provider是否已经发布,当允许运行在调用者进程且已发布,则直接返回
- 增加引用计数
- 更新进程优先级,如果更新失败,说明此时进程被杀,则减少引用计数并且设置未发布状态
当目标provider不存在呢?
if (!providerRunning) {
//根据authority,获取ProviderInfo对象,存储这ContentProvider的信息
cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
...
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}
//
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
...
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
throw new IllegalArgumentException(...);
}
//当拥有该provider的用户并没有运行,则直接返回
if (!isUserRunningLocked(userId, false)) {
return null;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {//此时并没有通过名称找到ContentProviderRecord对象
final long ident = Binder.clearCallingIdentity();
try {
//得到包含Provider的应用信息
ApplicationInfo ai = AppGlobals.getPackageManager().
getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
//通过应用信息与Provider信息创建对象ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
//如果调用者进程不为空,并且cpr,能运行在调用者进程中,则返回一个空对象
if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}
final int N = mLaunchingProviders.size();
int i;
//从mLaunchingProviders中查询是否存在该cpr
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
//当provider并没有处于mLaunchingProviders队列,则启动它
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
//查询进程记录ProcessRecord,得到provider所在进程记录
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
//如果进程记录存在,把ContentProvider保存到pubProvidrts中
if (proc != null && proc.thread != null) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
//启动provider进程启动并发布provider
proc.thread.scheduleInstallProvider(cpi);
}
} else {
// 启动进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null) {
return null;
}
}
cpr.launchingApp = proc;
//将cpr添加到mLaunchingProviders
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
//增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
...
我们之前讨论的是进程存在的情况,provider所在进程存在的时候如果允许在调用者进程中发布provider则直接返回,然后更新进程优先级。
然后我们就进入到了provider目标进程不存在的情况
-首先获取ProviderInfo
- 然后进行权限检查
-
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) {
当系统没有准备好,并且ProviderInfo得到的进程名不是system,也就是说provider进程并不是system进程的时候返回异常 - 当拥有该provider的用户并没有运行,则直接返回
- 根据ComponentName,从AMS.mProviderMap中查找对应的ContentProviderRecord。AMS中mProviderMap存储所有ContentProviderRecord的本地对象和引用对象。
- 如果没找到,说明是首次调用,首次调用则通过PMS拿到对应应用的ApplicationInfo,然后根据ProviderInfo和ApplicationInfo创建ContentProviderRecord
- 此时目标进程存在&新创建的ContentProviderRecord允许运行在调用者进程中则返回通过ContentProviderRecord创建的ContentProviderHolder
- provider并没有处于mLaunchingProviders队列,则启动它
- 当ProcessRecord不为空,则加入到pubProviders,并开始安装provider;
- 当ProcessRecord为空,则启动进程
- 增加引用计数
小结
上面说的那些大概什么意思?这里总结一下
主要分成两个大的部分:
第一部分:如果请求的ContentProvider已经发布,但是通过cpr.canRunHere()调用判断ContentProvider能不能运行在请求者进程中,如果可以发布在请求者进程中将不会将已经发布的ContentProvider返回,返回的ContentProviderHolder对象中ContentProvider对象是null,这里注意canRunHere判断条件之一就是provider设置了""multiprovess"属性,并且两个进程uid相同。
说白了就是两个进程一样,然后这种情况下ContentProvider已经发布了,那么返回的ContentProvider就是null
第二种情况就是ContentProvider没有发布,首先检查ContentProvider能不能在调用者进程中创建,如果包含ContentProvider进程没有创建,则启动进程,如果进程启动了,则给Provider进程中安装ContentProvider,然后将ContentProvider加入到mProviderMap中
最后还有一部分:
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
return null;
}
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
一直等到provider发布完才退出
3
我们多次提到,provider能不能运行在调用者进程中,那么通过方法判断是不是在调用者进程中
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& uid == app.info.uid;
}
- 我们在清单文件中配置的multiprocess=true或者调用者进程与ContentProvider在同一个进程一个中
- ContentProvider进程跟调用者所在进程是同一个uid
我们需要重新简化过程再来一次这个复杂的方法:
r = getRecordForAppLocked(caller);
得到调用者进程记录
ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
通过名字和uid查找对应ContentProviderRecord
boolean providerRunning = cpr != null;
用变量providerRunning区分ContentProviderRecord是不是可以从AMS的缓存中得到
下面时得到的情况
if (providerRunning) {
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
检查权限
if (r != null && cpr.canRunHere(r)) {
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
如果调用者进程存在&&provider可以运行在调用者进程中,判断条件上面已经给出,那么就返回一个没有provider的ContentProviderHolder
conn = incProviderCountLocked(r, cpr, token, stable);
增加引用计数&&新建链接信息
updateLruProcessLocked(cpr.proc, false, null);
boolean success = updateOomAdjLocked(cpr.proc);
更新provider所在进程信息
if (!success) {
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc);
if (!lastRef) {
return null;
}
providerRunning = false;
conn = null;
}
如果进程已经挂掉了,那就做清理工作
if (!providerRunning) {
没有得到provider的情况下
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
先通过PM得到ProviderInfo
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
然后设置应用信息
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
检查权限
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
然后进行判断,当provider不是运行在system进程,且系统未准备好,则抛出IllegalArgumentException
f (!isUserRunningLocked(userId, false)) {
当拥有该provider的用户并没有运行,则直接返回
然后根据应用的包名和清单文件中列举那个名字
/**
* Public name of this item. From the "android:name" attribute.
*/
public String name;
/**
* Name of the package that this item is in.
*/
public String packageName;
cpr = mProviderMap.getProviderByClass(comp, userId);
通过这些名称获取ContentProviderRecord
final boolean firstClass = cpr == null;
用这个看有没有获取到
if (firstClass) {
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
当没有获取到的时候根据信息新创建一个
到了这里说明已经有ContentProviderRecord了无论如何
if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}
然后再次检查看是不是在同一个进程中,如果在那就返回一个空的provider
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
在mLaunchingProviders中寻找cpr是不是存在,
if (i >= N) {
如果不存在
ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
如果不存在&&provider所在进程存在,则添加并且安装到对应进程和对应进程所在集合中去。
else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
否则启动进程
mLaunchingProviders.add(cpr);
最后将对应cpr添加mLaunchingProviders中
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
同时添加到AMS中不同的集合中
if (conn != null) {
conn.waiting = true;
}
设置等待
synchronized (cpr) {
while (cpr.provider == null) {
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
等待到provider发布完成
4
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
//成功获取已经存在的ContentProvider对象,则直接返回
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
//无法获取auth所对应的provider则直接返回
return null;
}
//安装provider将会增加引用计数
holder = installProvider(c, holder, holder.info,
true , holder.noReleaseNeeded, stable);
return holder.provider;
}
我们已经将AMS中getContentProvider方法分析了下面我们就继续看看如何安装provider
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
try {
//得到ContentProvider对象是一个Binder对象
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if (!mInstrumentation.onException(null, e)) {
}
return null;
}
} else {
provider = holder.provider;
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
//根据名称查看应用是否已经创建了Provider
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
provider = pr.mProvider;
} else {
//当Provider不存在列表中时候,创建并加入到列表
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
这个方法干什么,主要是和AMS中那个得到Holder的方法对应,如果传递的参数
ContentProviderHolder==null,说明要创建在当前进程中,然后代码就创建一个ContentProvider,如果不等于null说明安装的时其他进程中的ContentProvider的引用,那么做一些引用计数的相关处理。
实际上最终会调用到ContentProvider中的query方法。
怎么理解,就是ContentProvider可以放入到一个进程中,这个进程可以时当前应用所在进程也可以不是。不管怎么样AMS中都有记录,能知道这个进程,当发送消息的时候找到对应Binder,然后进行通信就行。
我们下面就用文字说明一下Provider的进程
1.(Provider进程尚未启动):system_server进程调用startProcessLocked()创建provider进程且attach到system_server后, 通过binder call到provider进程执行AT.bindApplication()方法
2.场景2provider进程已经启动但是没有发布。首先通过AMS获取provider如果发现进程已经存在attach到system_server中但所对应的provider还没有发布, 通过binder call到provider进程执行AT.scheduleInstallProvider方法