该系列文章总纲链接:专题总纲目录 Android Framework 总纲
本章关键点总结 & 说明:
说明:本章节主要解读ContentProvider组件的基本知识。关注思维导图中左上侧部分即可。
有了前面activity组件分析、service组件分析、广播组件分析、ContentProvider组件的基本流程分析、基于此,接下来我们来分析上一章节提到的第2个流程。ContentProvider组件的基本流程,ContentProvider主要涉及2个:
- ContentProvider的注册,开即启动后解析和处理ContentProvider组件。
- getContentResolver,然后执行对应ContentProvider.query方法。
本章,我们详细分析第二个流程。结合代码,主要针对这两句关键的语句来进行分析,代码如下:
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(CONTENT_URI, null, null, null, null);
接下来开始我们的详细分析。
1 getContentResolver流程完整解读
Context.getContentResolver方法是从Context中的getContentResolver开始调用的,接口代码实现如下:
//Context
public abstract ContentResolver getContentResolver();
其真正的实现是在ContextImpl中,代码实现如下:
//ContextImpl
private final ApplicationContentResolver mContentResolver;
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
这里直接返回了一个ApplicationContentResolver类型的成员变量mContentResolver。这里我们关注ApplicationContentResolver类,该类的解读如下:
//ContextImpl
private static final class ApplicationContentResolver extends ContentResolver {
// 成员变量,保存主线程ActivityThread的引用和用户标识UserHandle
private final ActivityThread mMainThread;
private final UserHandle mUser;
// 构造函数,接收Context、ActivityThread和UserHandle对象,并保存到成员变量
public ApplicationContentResolver(
Context context, ActivityThread mainThread, UserHandle user) {
super(context); // 调用父类的构造函数
mMainThread = Preconditions.checkNotNull(mainThread); // 确保主线程对象不为空
mUser = Preconditions.checkNotNull(user); // 确保用户对象不为空
}
// 重写acquireProvider方法,用于获取一个稳定的ContentProvider连接
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context, // 主线程对象
ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
resolveUserIdFromAuthority(auth), true); // 获取provider,true表示稳定的连接
}
// 重写acquireExistingProvider方法,用于获取一个已经存在的ContentProvider连接
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
return mMainThread.acquireExistingProvider(context, // 主线程对象
ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
resolveUserIdFromAuthority(auth), true); // 获取provider,true表示稳定的连接
}
// 重写releaseProvider方法,用于释放一个ContentProvider连接
@Override
public boolean releaseProvider(IContentProvider provider) {
return mMainThread.releaseProvider(provider, true); // 释放provider,true表示稳定的连接
}
// 重写acquireUnstableProvider方法,用于获取一个不稳定的ContentProvider连接
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c, // 上下文对象
ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
resolveUserIdFromAuthority(auth), false); // 获取provider,false表示不稳定的连接
}
// 重写releaseUnstableProvider方法,用于释放一个不稳定的ContentProvider连接
@Override
public boolean releaseUnstableProvider(IContentProvider icp) {
return mMainThread.releaseProvider(icp, false); // 释放provider,false表示不稳定的连接
}
// 重写unstableProviderDied方法,当一个不稳定的ContentProvider死亡时调用
@Override
public void unstableProviderDied(IContentProvider icp) {
mMainThread.handleUnstableProviderDied(icp.asBinder(), true); // 处理provider死亡,true表示稳定的连接
}
// 重写appNotRespondingViaProvider方法,当ContentProvider无响应时调用
@Override
public void appNotRespondingViaProvider(IContentProvider icp) {
mMainThread.appNotRespondingViaProvider(icp.asBinder()); // 处理provider无响应
}
// 解析authority中包含的用户ID
/** @hide */
protected int resolveUserIdFromAuthority(String auth) {
return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); // 根据authority和用户标识解析用户ID
}
}
这个内部类ApplicationContentResolver主要负责管理ContentProvider的生命周期,包括获取和释放稳定的或不稳定的ContentProvider连接。它通过ActivityThread来实际获取ContentProvider的代理对象,并处理ContentProvider的异常情况,如无响应或崩溃。这个类是Android系统中ContentResolver机制的一部分,用于确保ContentProvider的稳定性和正确性。
本质上这里就是获取了该类型的一个成员变量,接下来在query的流程中我们会使用该类中的一些方法,比如acquireProvider、releaseProvider等。
2 ContentResolver的query查询流程解读
ContentResolver.query 方法在ApplicationContentResolver中没有实现,因此我们看它的父类ContentResolver中的代码实现,具体如下:
//ContentResolver
//关键流程:step1
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
//关键流程:step2
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
// 获取一个不稳定的ContentProvider连接
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null; // 如果获取失败,返回null
}
IContentProvider stableProvider = null; // 用于存储稳定的ContentProvider连接
Cursor qCursor = null; // 用于存储查询结果的Cursor对象
try {
long startTime = SystemClock.uptimeMillis(); // 记录查询开始时间
// 如果提供了CancellationSignal,则创建远程取消信号,并设置关联
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled(); // 检查是否已经取消
remoteCancellationSignal = unstableProvider.createCancellationSignal(); // 创建远程取消信号
cancellationSignal.setRemote(remoteCancellationSignal); // 设置远程取消信号
}
try {
// 通过不稳定的ContentProvider执行查询
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 如果ContentProvider死亡,则标记为不稳定,并尝试获取一个新的稳定的ContentProvider
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri); // 获取稳定的ContentProvider
if (stableProvider == null) {
return null; // 如果获取失败,返回null
}
// 使用新的稳定的ContentProvider执行查询
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null; // 如果查询结果为空,返回null
}
// 获取查询结果的行数,并计算查询持续时间
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder); // 记录查询日志
// 将查询结果的Cursor包装成CursorWrapperInner对象
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null; // 重置stableProvider
qCursor = null; // 重置qCursor
return wrapper; // 返回包装后的Cursor对象
} catch (RemoteException e) {
return null; // 如果发生远程异常,返回null
} finally {
// 最后,关闭查询结果的Cursor,并释放ContentProvider连接
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null); // 清除远程取消信号
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider); // 释放不稳定的ContentProvider
}
if (stableProvider != null) {
releaseProvider(stableProvider); // 释放稳定的ContentProvider
}
}
}
query
方法是一个用于从ContentProvider
查询数据并返回Cursor
对象的过程,它首先尝试通过不稳定的ContentProvider
进行查询,如果遇到DeadObjectException
异常,则会获取一个稳定的ContentProvider
重新查询。查询成功后,方法会记录查询日志,并将结果Cursor
包装在CursorWrapperInner
对象中返回。如果在查询过程中发生远程异常或者查询结果为空,则会返回null
。此外,方法还会处理CancellationSignal
以支持查询的取消操作,并在最后释放所有相关资源。
这里我们要知道,ContentProvider的核心代码就是从
acquireProvider中获取provider,然后执行query操作。那么为什么非要搞出一个unstable的provider呢?先尝试从不稳定(unstable)的ContentProvider
获取数据,如果失败再从稳定(stable)的ContentProvider
获取,是基于性能和资源管理的考虑。详细解读如下:
- 性能优化:不稳定的
ContentProvider
连接(acquireUnstableProvider
)通常比稳定的连接(acquireProvider
)更快地建立,因为它们不需要进行额外的状态检查和同步操作。这意味着,如果ContentProvider
是健康的,使用不稳定连接可以减少查询的延迟,提高性能。 - 资源管理:稳定的
ContentProvider
连接需要更多的资源来维护,因为它们需要确保在ContentProvider
的整个生命周期内保持稳定。如果每次查询都直接使用稳定的连接,可能会导致不必要的资源占用,特别是在高频率查询的场景下。 - 容错机制:
DeadObjectException
异常表明ContentProvider
可能已经崩溃或不稳定。在这种情况下,系统会尝试获取一个新的稳定的ContentProvider
连接,这可以看作是一种容错机制。通过这种方式,系统可以确保即使在ContentProvider
不稳定的情况下,也能够尽可能地提供服务。
这种设计允许系统在大多数情况下快速响应查询请求,同时在遇到异常时能够提供一种可靠的后备方案,确保系统的鲁棒性和数据的一致性。
接下来我们分析acquireProvider获取provider的具体流程。
2.1 acquireProvider流程详细解读
从之前的分析中可知,这里的acquireProvider实际上就是ContentProvider的
子类ApplicationContentResolver中的方法,对应的代码实现如下:
//ContextImpl
//ApplicationContentResolver
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
这里可以看出是调用ActivityThread中的acquireProvider方法,对应代码实现如下:
//ActivityThread
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
// 尝试获取一个已经存在的ContentProvider实例
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
// 如果已经存在,直接返回这个provider
return provider;
}
// 如果不存在,尝试从ActivityManager获取ContentProviderHolder
IActivityManager.ContentProviderHolder holder = null;
try {
// 通过ActivityManager的getContentProvider方法获取ContentProviderHolder
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
//...
}
if (holder == null) {
return null;
}
// 如果成功获取到holder,调用installProvider方法来安装provider
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
// 返回安装后的provider实例
return holder.provider;
}
这里针对3个关键点进行分析:acquireExistingProvider、AMS的getContentProvider方法调用(因为ActivityManagerNative.getDefault().getContentProvider本质上就是调用AMS的getContentProvider方法)、installProvider方法,分别进行解读。
2.1.1 acquireExistingProvider方法解读
acquireExistingProvider代码实现如下:
//ActivityThread
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
// 创建一个ProviderKey对象,用于标识ContentProvider的authority和用户ID
final ProviderKey key = new ProviderKey(auth, userId);
// 从mProviderMap中获取对应的ProviderClientRecord对象
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
// 如果没有找到对应的ProviderClientRecord,返回null
return null;
}
// 获取IContentProvider实例
IContentProvider provider = pr.mProvider;
// 获取IBinder实例,用于与ContentProvider进行通信
IBinder jBinder = provider.asBinder();
// 检查Binder是否存活,即ContentProvider的进程是否还活着
if (!jBinder.isBinderAlive()) {
// 处理不稳定的ContentProvider死亡情况
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// 如果ProviderRefCount不为null,说明这个provider是引用计数的,需要增加引用计数
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 增加引用计数
incProviderRefLocked(prc, stable);
}
// 返回IContentProvider实例
return provider;
}
}
acquireExistingProvider
方法用于尝试获取一个已经存在的ContentProvider
实例,它通过检查mProviderMap
映射表来查找与给定authority和用户ID对应的ProviderClientRecord
。如果找到,并且对应的IBinder
是活跃的,那么方法会增加该ContentProvider
的引用计数(如果需要),并返回IContentProvider
实例;如果Binder
不活跃或没有找到对应的ProviderClientRecord
,则返回null
。这个方法确保了对现有ContentProvider
实例的安全访问,并处理了ContentProvider
进程可能已经死亡的情况。
2.1.2 AMS.getContentProvider方法解读
AMS.getContentProvider代码实现如下:
//AMS
//关键流程:step1
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
//...
}
return getContentProviderImpl(caller, name, null, stable, userId);
}
//关键流程:step2
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
// 初始化ContentProviderRecord、ContentProviderConnection和ProviderInfo对象
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
// 记录方法开始执行的时间
long startTime = SystemClock.elapsedRealtime();
// 获取调用者的ProcessRecord
ProcessRecord r = null;
//...
// 检查是否需要跨用户访问ContentProvider
boolean checkCrossUser = true;
// 根据名称和用户ID获取ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, userId);
// 如果没有找到,并且用户ID不是主用户,则尝试获取主用户的ContentProvider
if (cpr == null && userId != UserHandle.USER_OWNER) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
if (cpr != null) {
cpi = cpr.info;
// 如果是单例ContentProvider,并且调用合法,则使用主用户的ContentProvider
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;
}
}
}
// 检查ContentProvider是否正在运行
boolean providerRunning = cpr != null;
if (providerRunning) {
cpi = cpr.info;
//...
// 如果调用者可以在这个应用中运行ContentProvider,则直接返回一个新的ContentProviderHolder
if (r != null && cpr.canRunHere(r)) {
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
// 增加ContentProvider的引用计数
final long origId = Binder.clearCallingIdentity();
conn = incProviderCountLocked(r, cpr, token, stable);
//...
Binder.restoreCallingIdentity(origId);
}
// 如果ContentProvider尚未运行,则尝试解析ContentProvider的信息
boolean singleton;
if (!providerRunning) {
try {
cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
//...
// 如果是单例ContentProvider,并且调用合法,则使用主用户的ContentProvider
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);
//...
// 获取ContentProvider的ComponentName
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 {
ApplicationInfo ai =
AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
//...
ai = getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
//...
} finally {
Binder.restoreCallingIdentity(ident);
}
}
// 如果调用者可以在这个应用中运行ContentProvider,则直接返回一个新的ContentProviderHolder
if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}
// 检查是否已经在启动ContentProvider的列表中
final int N = mLaunchingProviders.size();
int i;
for (i=0; i<N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// 如果不在启动列表中,则启动ContentProvider
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
try {
AppGlobals.getPackageManager().setPackageStoppedState(cpr.appInfo.packageName, false, userId);
} catch (Exception e) {
//...
}
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
proc.pubProviders.put(cpi.name, cpr);
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);
//...
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
// 如果是首次创建ContentProviderRecord,则添加到映射中
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
// 将ContentProvider添加到映射中
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
// 等待ContentProvider被创建
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;
}
}
}
}
// 返回ContentProviderHolder对象
return cpr != null ? cpr.newHolder(conn) : null;
}
getContentProviderImpl方法用于获取一个ContentProviderHolder对象,该对象封装了对ContentProvider的引用以及与之相关的信息。如果ContentProvider已经存在并且可以被调用者访问,则直接返回一个新的ContentProviderHolder。如果ContentProvider尚未运行,则解析其信息并启动它。如果ContentProvider是单例并且调用合法,则使用主用户的ContentProvider。
该方法还处理了跨用户访问和进程启动的逻辑。解读如下:
如果ProcessRecord
不为空,说明进程已经启动,则在该进程中安装ContentProvider。
- 如果
ProcessRecord
不存在或其thread
为空,说明需要启动一个新的进程。startProcessLocked
方法用于启动新进程,它需要进程名、应用信息、标志、进程组ID、进程名称、组件名等参数。
最后,若ContentProvider成功创建,则返回包含ContentProvider引用的ContentProviderHolder;否则,返回null。
2.1.3 installProvider方法解读
installProvider方法代码实现如下:
//ActivityThread
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
// 如果传入的holder或holder中的provider为空,则创建一个新的ContentProvider实例
if (holder == null || holder.provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
// 尝试获取Context对象,用于创建ContentProvider
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) {
//...
}
}
// 创建ContentProvider实例
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
//...
}
} else {
// 如果holder非空,则直接使用holder中的provider
provider = holder.provider;
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
// 如果localProvider非空,表示这是一个本地ContentProvider
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
provider = pr.mProvider;
} else {
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 {
// 对于非本地ContentProvider,处理引用计数和生命周期管理
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//...
}
}
} 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;
}
installProvider方法负责根据提供的ContentProviderHolder和ProviderInfo安装一个ContentProvider。如果holder或holder.provider为空,实际上会创建一个新的ContentProvider实例,但本流程中不涉及。方法内部会处理本地和非本地ContentProvider的安装,更新引用计数,并管理ContentProvider的生命周期。最终,方法返回安装好的ContentProvider的ContentProviderHolder。
至此,acquireProvider的3个关键流程就解读完了。这里接下来就是调用对应ContentProvider的query操作了。接下来主要针对acquireProvider中AMS.getContentProvider的启动流程进行分析,因为这里也会涉及ContentProvider的初始化相关操作。
2.2 AMS.getContentProvider启动流程分析
从之前2.1.2 中AMS.getContentProvider的启动流程进行分析。如果ProcessRecord
不存在或其thread
为空,说明需要启动一个新的进程。startProcessLocked
方法用于启动新进程,启动相关的代码可参考文章:
Android Framework AMS(04)startActivity分析-1(am启动到ActivityThread启动)
Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起)
这里我们主要从AMS的attachApplicationLocked方法入手进行分析。代码实现如下:
//AMS
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
// 根据传入的pid获取对应的ProcessRecord对象
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid); // 从mPidsSelfLocked中获取ProcessRecord
}
} else {
app = null; // 如果pid无效,则设置app为null
}
// 检查应用程序是否处于正常模式
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
//关键代码1:如果在正常模式下,生成应用程序的ContentProvider信息
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
//...
//关键代码2:绑定应用程序到指定的线程
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
// 更新最近使用的进程列表
updateLruProcessLocked(app, false, null);
//...
} catch (Exception e) {
//...
}
//...
return true;
}
这里我们主要关注generateApplicationProvidersLocked方法和ActivityThread的bindApplication方法,前者是通过PMS获取provider,后者是绑定App后的处理。
2.2.1 generateApplicationProvidersLocked方法解读
generateApplicationProvidersLocked方法,它的代码实现如下:
//AMS
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
// 尝试查询PackageManager以获取该应用程序进程名下的所有ContentProvider信息
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
//...
}
int userId = app.userId;
if (providers != null) {
int N = providers.size();
// 确保pubProviders的容量足够
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
ProviderInfo cpi = (ProviderInfo)providers.get(i);
// 检查ContentProvider是否是单例,并且不是主用户的ContentProvider
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
if (singleton && UserHandle.getUserId(app.uid) != 0) {
// 如果是单例并且不是主用户的ContentProvider,则移除
providers.remove(i);
N--;
i--;
continue;
}
// 创建ComponentName对象,用于标识ContentProvider
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
// 尝试从mProviderMap中获取现有的ContentProviderRecord
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
// 如果不存在,则创建新的ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
// 将ContentProviderRecord添加到应用程序的pubProviders映射中
app.pubProviders.put(cpi.name, cpr);
// 如果ContentProvider不是多进程的,或者不是系统应用,则添加包名到应用程序的包列表中
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
mProcessStats);
}
// 确保包的Dex优化完成
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
// 返回ContentProvider列表
return providers;
}
generateApplicationProvidersLocked方法负责生成和返回一个应用程序提供的ContentProvider列表。它查询PackageManager以获取ContentProvider信息,创建ContentProviderRecord,并进行必要的初始化和配置。这个方法确保了应用程序的ContentProvider可以被正确地管理和访问。
关于queryContentProviders功能解读:开机启动后PMS存储了解析各个APP中AndroidManifest.xml定义的ContentProviders信息。通过queryContentProviders可以查询到这些信息。了解更多,可参考上一章节文章:
标签:...,ContentProvider,15,getContentResolver,ContentResolver,provider,cpr,null,hold From: https://blog.csdn.net/vviccc/article/details/143694653