通过这篇文章,我们来梳理一下 ContentProvider 启动的整体流程以及其中我们应该注意的细节
ContentProvider 启动的整体流程
ContentProvider 运行所在进程与 APP 进程相同
当 ContentProvider 运行所在进程与 APP 进程相同时,ContentProvider 会伴随 APP 进程初始化一起启动
APP 进程在初始化时,会创建所有运行在本进程中的 ContentProvider 实例,并回调所有 ContentProvider 实例的 onCreate()
函数,完成启动
当所有 ContentProvider 启动完成后,会将这些 ContentProvider 的信息发送给 AMS 进行记录,这样其他进程就可以通过 AMS 来访问这些 ContentProvider 了
总体流程如下图:
ContentProvider 运行所在进程与 APP 进程不同
当 ContentProvider 运行所在进程与 APP 进程不同时,ContentProvider 不会在 APP 进程初始化时被启动
当 APP 进程通过 getContentResolver()
函数访问 ContentProvider 时,会访问 AMS 尝试获取目标 ContentProvider 的 Binder 通信接口
如果 AMS 中保存有该 ContentProvider 的 Binder 通信接口就直接返回给 APP 进程
如果 AMS 中没有保存有该 ContentProvider 的 Binder 通信接口,说明该 ContentProvider 还未启动,新建进程启动目标 ContentProvider,最终回调目标 ContentProvider 实例的 onCreate()
函数,完成启动
当目标 ContentProvider 启动完成后,再将目标 ContentProvider 的信息发送给 AMS 进行记录
总体流程如下图:
源码
ContentProvider 启动流程可以分为两个阶段:
- ContentProvider 进程初始化
- 访问 ContentProvider
ContentProvider 进程初始化
当 ContentProvider 进程创建完成后,就会进行初始化,调用到 ActivityThread 的 main()
函数
ActivityThread.main()
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args)
{
......
thread.attach(false, startSeq);
......
}
private void attach(boolean system, long startSeq)
{
......
// AIDL 调用 AMS 的 attachApplication 函数
final IActivityManager mgr = ActivityManager.getService();
mgr.attachApplication(mAppThread, startSeq);
......
}
ActivityManagerService.attachApplication()
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq)
{
......
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
......
}
private final boolean attachApplicationLocked(
IApplicationThread thread, // thread = App 进程的 ApplicationThread
int pid, int callingUid, long startSeq
){
......
// 此时进程已经启动,mProcessesReady = true
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
// 获取 APP 应用的 AndroidManifest 文件中注册的 ContentProvider 信息
List<ProviderInfo> providers = normalMode ?
generateApplicationProvidersLocked(app) : null;
......
final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
// AIDL 调用 APP 进程 ApplicationThread 的 bindApplication 函数
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
......
}
ActivityManagerService.generateApplicationProvidersLocked()
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app)
{
......
// AIDL 调用 PackageManagerService 的 queryContentProviders 函数,
// 获取 APP 应用中所有经过 AndroidManifest 注册的 ContentProvider 信息
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
| MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
......
}
PackageManagerService.queryContentProviders()
当 APP 应用进行安装时,PackageManagerService 会通过 ComponentResolver 解析 APK 包中的 AndroidManifest 文件,获取到所有四大组件的信息并保存
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(
String processName, // 当前进程名
int uid, // 当前线程 uid
int flags, String metaDataKey
){
......
// 最终的结果集
ArrayList<ProviderInfo> finalList = null;
// 调用 ComponentResolver 的 queryProviders 函数,
// 获取 APP 应用中所有经过 AndroidManifest 注册的 ContentProvider 信息
final List<ProviderInfo> matchList =
mComponentResolver.queryProviders(processName, metaDataKey, uid, flags, userId);
final int listSize = (matchList == null ? 0 : matchList.size());
synchronized (mLock)
{
// 遍历 matchList,进行筛选
for (int i = 0; i < listSize; i++)
{
// 获取 ContentProvider 信息
final ProviderInfo providerInfo = matchList.get(i);
// 这部分是筛选条件代码,其中大部分与流程无关,有兴趣可以自行了解
// 如果该 ContentProvider 信息不满足条件,会调用 continue 语句跳过当前循环,
// 不会添加到最终的结果集
......
// 将该 ContentProvider 信息添加到最终的结果集
finalList.add(providerInfo);
}
}
if (finalList != null)
{
finalList.sort(sProviderInitOrderSorter);
// 返回最终的结果集
return new ParceledListSlice<>(finalList);
}
return ParceledListSlice.emptyList();
}
ComponentResolver.queryProviders()
// frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
List<ProviderInfo> queryProviders(String processName, String metaDataKey,
int uid, int flags, int userId
){
......
// 最终的结果集
List<ProviderInfo> providerList = null;
......
synchronized (mLock)
{
// 经过解析得到的所有可用的 ContentProvider 信息都保存在 mProviders.mProviders 中,
// 遍历 mProviders.mProviders
for (int i = mProviders.mProviders.size() - 1; i >= 0; --i)
{
// ContentProvider 信息
final ParsedProvider p = mProviders.mProviders.valueAt(i);
// 这部分是筛选条件代码,其中大部分与流程无关,有兴趣可以自行了解
// 如果当前 ContentProvider 信息不满足条件,会调用 continue 语句跳过当前循环,
// 不会添加到最终的结果集
......
// 判断该 ContentProvider 是否指定了运行所在的进程
// (如果没指定 ContentProvider 默认运行在 APP 进程中)
// 如果指定的进程名与 APP 进程名不同,则不把该 ContentProvider 加入最终的结果集
if (processName != null && (!p.getProcessName().equals(processName)
|| !UserHandle.isSameApp(pkg.getUid(), uid)))
{
continue;
}
......
final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
pkg, p, flags, state, appInfo, userId, ps);
if (info == null)
{
continue;
}
if (providerList == null)
{
providerList = new ArrayList<>(i + 1);
}
// 将该 ContentProvider 信息添加到最终的结果集
providerList.add(info);
}
}
// 返回最终的结果集
return providerList;
}
ApplicationThread.bindApplication()
// frameworks/base/core/java/android/app/ActivityThread$ApplicationThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
......
){
......
// 发送消息 (H.BIND_APPLICATION) 给 ActivityThread 中的内部类 H (Handler)
sendMessage(H.BIND_APPLICATION, data);
}
H.handleMessage()
// frameworks/base/core/java/android/app/ActivityThread$H.java
public void handleMessage(Message msg)
{
switch (msg.what)
{
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
......
}
ActivityThread.handleBindApplication()
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data)
{
......
// 创建 ContextImpl
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
appContext.getOpPackageName());
// 创建 mInstrumentation
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
......
// 创建 Application
app = data.info.makeApplication(data.restrictedBackupMode, null);
......
// 启动当前进程的 ContentProvider
installContentProviders(app, data.providers);
......
// 回调 Application 的 onCreate 函数
mInstrumentation.callApplicationOnCreate(app);
......
}
ActivityThread.installContentProviders()
// frameworks/base/core/java/android/app/ActivityThread.java
private void installContentProviders(Context context, List<ProviderInfo> providers)
{
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
// 遍历当前进程的 ProviderInfo (存储 ContentProvider 的信息) 列表
for (ProviderInfo cpi : providers)
{
......
// 调用 installProvider 函数,启动 ContentProvider
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null)
{
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try
{
// AIDL 调用 AMS 的 publishContentProviders 函数,将这些 ContentProvider 进行发布,
// 这样其他进程就可以通过 AMS 来访问这些 ContentProvider 了
ActivityManager.getService().publishContentProviders(getApplicationThread(), results);
}
catch (RemoteException ex)
{
throw ex.rethrowFromSystemServer();
}
}
ActivityThread.installProvider()
// frameworks/base/core/java/android/app/ActivityThread.java
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, // 此时 holder = null
ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable
){
ContentProvider localProvider = null;
IContentProvider provider;
// if 命中
if (holder == null || holder.provider == null)
{
......
// 通过反射创建 ContentProvider
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
......
// 为此 ContentProvider 创建上下文
localProvider.attachInfo(c, info);
......
}
else
{
......
}
......
}
ContentProvider.attachInfo()
// frameworks/base/core/java/android/content/ContentProvider.java
public void attachInfo(Context context, ProviderInfo info)
{
attachInfo(context, info, false);
}
private void attachInfo(Context context, ProviderInfo info, boolean testing)
{
......
if (mContext == null)
{
mContext = context;
......
mMyUid = Process.myUid();
// 记录 ContentProvider 的设置 (例如访问权限、authority 等)
if (info != null)
{
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
......
// 回调 ContentProvider 的 onCreate 函数
ContentProvider.this.onCreate();
}
}
访问 ContentProvider
ContextImpl.getContentResolver()
// frameworks/base/core/java/android/app/ContextImpl.java
public ContentResolver getContentResolver()
{
return mContentResolver;
}
private final ApplicationContentResolver mContentResolver;
private ContextImpl(ContextImpl container, ActivityThread mainThread,
......
){
......
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
getContentResolver()
函数会返回一个 ApplicationContentResolver 对象,该对象在 ContextImpl 被创建时一同被创建
ApplicationContentResolver 继承自 ContentResolver,但是却没有重写 ContentResolver 对应的 CRUD 函数
以 insert 调用流程为例,getContentResolver().insert()
最终会调用到 ContentResolver.insert()
函数
ContentResolver.insert()
// frameworks/base/cre/java/android/content/ContentResolver.java
public final @Nullable Uri insert(Uri url, ContentValues values)
{
return insert(url, values, null);
}
public final @Nullable Uri insert(Uri url, ContentValues values, Bundle extras)
{
......
// 获取 ContentProvider 的 Binder 通信接口
IContentProvider provider = acquireProvider(url);
......
// AIDL 调用 ContentProvider 的 insert 函数
Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras);
......
return createdRow;
......
}
public final IContentProvider acquireProvider(Uri uri)
{
......
return acquireProvider(mContext, auth);
......
}
protected abstract IContentProvider acquireProvider(Context c, String name);
ApplicationContentResolver 实现了 acquireProvider()
函数
ApplicationContentResolver.acquireProvider()
// frameworks/base/core/java/android/app/ContextImpl$ApplicationContentResolver.java
protected IContentProvider acquireProvider(Context context, String auth)
{
// 调用 ActivityThread 的 acquireProvider 函数
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
ActivityThread.acquireProvider()
// frameworks/base/core/java/android/app/ActivityThread.java
public final IContentProvider acquireProvider(Context c, String auth,
int userId, boolean stable
){
// 查看该 ContentProvider 的 Binder 通信接口是否有缓存,
// 如果有缓存说明该 ContentProvider 不是第一次访问,直接返回缓存中的 Binder 通信接口
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null)
{
return provider;
}
ContentProviderHolder holder = null;
......
// 如果没有缓存,AIDL 调用 AMS 的 getContentProvider 函数,
// 获取该 ContentProvider 的信息
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
......
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
ActivityManagerService.getContentProvider()
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name,
int userId, boolean stable
){
......
return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
null, stable, userId);
}
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage,
String callingTag, boolean stable, int userId
){
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;
synchronized(this)
{
......
// 首先检查该 ContentProvider 是否已经在 AMS 上发布
// (发布过的 ContentProvider 信息会缓存在 mProviderMap 中)
cpr = mProviderMap.getProviderByName(name, userId);
......
ProcessRecord dyingProc = null;
// 如果该 ContentProvider 已经发布 且 运行所在进程已经被创建
if (cpr != null && cpr.proc != null)
{
// 该 ContentProvider 运行所在进程没有被杀就说明该 ContentProvider 仍在运行中
providerRunning = !cpr.proc.killed;
......
}
// 如果该 ContentProvider 仍在运行中
if (providerRunning)
{
......
// 检查是否允许该 ContentProvider 在多个进程中运行,
// 如果允许,直接返回一个空的 ContentProviderHolder
if (r != null && cpr.canRunHere(r))
{
......
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
......
}
// 如果该 ContentProvider 没有在运行,说明该 ContentProvider 还未启动
if (!providerRunning)
{
......
// AIDL 调用 PackageManagerService 的 resolveContentProvider 函数,
// 通过 authorities 标识查找该 ContentProvider 的信息
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
......
// 获取该 ContentProvider 的全类名
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
// 再次检查该 ContentProvider 是否已经在 AMS 上发布
cpr = mProviderMap.getProviderByClass(comp, userId);
// 如果没有发布,说明该 ContentProvider 是第一次启动
boolean firstClass = cpr == null;
if (firstClass)
{
......
// AIDL 调用 PackageManagerService 的 getApplicationInfo 函数,
// 获取 APP 应用的相关设置信息
ApplicationInfo ai = AppGlobals.getPackageManager().
getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);
......
// 通过 APP 应用的相关设置信息构建 ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
......
// 检查是否允许该 ContentProvider 在多个进程中运行,
// 如果允许,直接返回一个空的 ContentProviderHolder
if (r != null && cpr.canRunHere(r))
{
return cpr.newHolder(null);
}
......
// 所有正在被启动的 ContentProvider 都缓存在 mLaunchingProviders 中,
// 在启动该 ContentProvider 前,
// 检查该 ContentProvider 是否正在被其它的 APP 应用启动
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++)
{
if (mLaunchingProviders.get(i) == cpr)
{
break;
}
}
// 如果该 ContentProvider 没有正在被其它的 APP 应用启动
if (i >= N)
{
......
// 获取该 ContentProvider 运行所在进程的信息,判断该进程是否已经启动
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
// 如果进程信息不为空,则代表该进程已启动
if (proc != null && proc.thread != null && !proc.killed)
{
......
// AIDL 调用该进程中 ApplicationThread 的 scheduleInstallProvider 函数,
// 最终调用 ActivityThread 的 installContentProviders 函数
proc.thread.scheduleInstallProvider(cpi);
......
}
else // 如果该 ContentProvider 运行所在进程没有启动
{
......
// 访问 Zygote 进程请求启动一个新进程用于运行该 ContentProvider
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0,
new HostingRecord("content provider",
new ComponentName(cpi.applicationInfo.packageName,cpi.name)),
ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
......
}
cpr.launchingApp = proc;
// 将该 ContentProvider 的信息放入 mLaunchingProviders 缓存
mLaunchingProviders.add(cpr);
}
// 如果该 ContentProvider 是第一次启动
if (firstClass)
{
// 将该 ContentProvider 的信息放入 mProviderMap 缓存
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
......
}
}
// 如果该 ContentProvider 需要新起进程来运行,AMS 线程会进入睡眠等待,
// 直至 ContentProvider 发布完成,其中的代码细节与流程无关,有兴趣可以自行了解
......
return cpr.newHolder(conn);
}
这个函数的代码非常长,因此逻辑略显复杂,具体逻辑如下图所示
ActivityManagerService.getContentProvider()
函数执行完成返回后,会返回执行 ActivityThread.installProvider()
函数
根据返回的 ContentProviderHolder 是否为空来判断是否要在 APP 进程创建该 ContentProvider 的实例 (multiprocess 属性)
ActivityThread.installProvider()
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable
){
ContentProvider localProvider = null;
IContentProvider provider;
// 如果该 ContentProvider 设置了 multiprocess 属性,执行 else
if (holder == null || holder.provider == null)
{
......
}
else
{
provider = holder.provider;
}
......
}
之后 APP 进程就可以通过该 ContentProvider 的 Binder 通信接口 (ContentProviderProxy),AIDL 调用该 ContentProvider 的 CRUD 函数
总结
本篇文章分析了 ContentProvider 的启动流程,将其中对于我们开发者而言比较有意义的部分代码进行了分析
由于 ContentProvider 可以单独运行在自己的进程,需要多情况讨论,因此整体流程相对而言会有一些复杂
了解 ContentProvider 启动流程,对于我们理解 ContentProvider 的运行和进行启动优化有着很大的帮助
但源码还是非常庞大的,没办法面面俱到,希望读者还是能参照本篇文章尝试自己去阅读源码,加深理解