ContentProvider启动流程分析(二)
0x01 扯东扯西的前言&概述
本片博客对应时序图上的step6—14:上接第一篇博客:ContentProvider启动流程分析一! 下接第三篇ContentProvider启动流程分析三!
同时此系列博客同步在简书发布:ContentProvider启动流程分析系列!详情戳这里即可访问~
0x02 ContentProvider启动流程分析
step6: ActivityManagerProxy#getContentProvider()
代理类ActivityManagerProxy位于ActivityManagerNative.java文件中,其getContentProvider()成员函数的源码如下:
class ActivityManagerProxy implements IActivityManager {
....
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
data.writeInt(userId);
data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
}
}
- getContentProvider()函数中,前面7行代码,将传进来的参数封装到一个Parcel对象中;
- 然后再通过ActivityManagerProxy内部的一个Binder代理对象mRemote,向ActivityManagerService发送一个类型为GET_CONTENT_PROVIDER_TRANSACTION的进程间通信的请求;
- 最后,再将ActivityManagerService返回的对象封装成一个ContentProviderHolder对象返回给调用者。
需要注意:以上step1—6是在应用程序AxxApp所在进程中执行的;接下来的step7—9在ActivityManagerService中执行,主要用来处理MainActivity组件发出的类型为GET_CONTENT_PROVIDER_TRANSACTION的进程间通信的请求!
step7: ActivityManagerService#getContentProvider()
ActivityManagerService类的成员函数getContentProvider()源码如下:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
....
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
....
return getContentProviderImpl(caller, name, null, stable, userId);
}
....
}
- 成员函数getContentProvider(),是用来处理类型为 GET_CONTENT_PROVIDER_TRANSACTION 的进程间通信的请求的;
- 其内部直接调用getContentProviderImpl(),来进一步获得参数name对应的ContentProviderHolder对象。
step8: ActivityManagerService#getContentImpl()
getCOntentImpl()函数的作用是,获得参数name对应的ContentProviderHolder对象,这个对象用来描述一个ContentProvider组件的代理对象;getCOntentImpl()函数源码较长,我做了部分删减后如下:
- 第10行,调用成员函数getRecordForAppLocked(),用来获取发出访问请求的应用程序所在进程的相关信息,在我们的场景中,也就是AxxApp应用程序所在进程的相关信息。这些信息,用一个ProcessRecord对象 r 来描述!
- 在ActivityManagerService中,每一个已经启动的ContentProvider组件都使用一个ContentProviderRecord对象来描述。这些ContentProviderRecord对象保存在ActivityManagerService类的成员变量mProviderMap中!
- mProviderMap实质上是一个HashMap,可通过两种方式进行查找,查找结果是一个ContentProviderRecord对象cpr:
- mProviderMap.getProviderByName()函数,通过参数name和参数userId进行查找;参数name指向了将要启动的ContentProvider组件的android:authorities属性值,也就是URI值对应的权限部分;参数userId则是调用方应用程序的Linux用户ID;
- mProviderMap.getProviderByClass()函数,通过ContentProvider组件的类名进行查找;
需要注意的是,mProvidersByName和mProvidersByClass的内部实现是哈希表,虽然都是保存的ContentProviderRecord对象,但是mProvidersByName变量是以ContentProvider组件的android:authorities属性值为关键字的,而mProvidersByClass变量是以ContentProvider组件的类名作为关键字的!
第15行,首先通过参数name和userId,mProviderMap.getProviderByName()检查是否存在对应的ContentProvider组件?接下来的逻辑很简单,分为两种情况:
- 第18行到27行代码,就是表示这个ContentProvider组件已经发布(启动)了,此时调用方(AxxApp)就可以直接通过ContentProviderRecord对象cpr来创建一个ContentProviderHolder对象;需要做两点说明:
- ContentProviderRecord对象用来记录ContentProvider组件的发布(启动)信息,通过其对象cpr的provider成员变量来记录ContentProvider组件,它们是一对一的关系;
- ContentProviderHolder是ContentProvider组件的代理对象,它持有一个ContentProvider对象;
- 第29到93行代码,就是表示这个ContentProvider组件还没有发布,需要进一步验证,第31行到35行通过mProviderMap.getProviderByClass()方式进行二次查找。如果还是没有找到?接下来就要启动这个ContentProvider组件了!
- 第37到43行,先根据name参数和userId参数创建一个ContentProviderRecord对象;
- 在启动cpr描述的ContentProvider组件之前,先判断这个COntentProvider组件的android:multiprocess属性值!如果为true,表示这个ContentProvider组件需要在访问它的应用程序进程中启动;为false表示需要创建第三方进程并在第三方进程中启动这个ContentProvider组件;也即第44到53行;
- 第57行,关注常量mLaunchingProviders,ActivityManagewrService就是把正在启动的ContentProvider组件保存在mLaunchingProviders中;
- 第59到65行,通过for循环判断目标ContentProvider组件的状态是否处于正在启动中。如果是,则等待它继续启动完成;
- 如果不是,即66到83行,ActivityManagerService会调用成员函数startProcessLocked()新建一个应用程序进程,专门用来启动目标ContnrtProvider组件
- 第85到89行,分别通过两种方式mProviderMap.putProviderByClass()和mProviderMap.putProviderByName()把启动的ContentProvider组件保存在mProviderMap变量中;
- 最后,第93到99行,等待ContentProvider组件发布完成后,直接返回其对应的ContentProviderRecord对象即可;
step9: ActivityMangerService#startProcessLocked()
在step8中,目标ContentProvider组件是通过一个新建的第三方应用程序进程来启动!而这个第三方应用程序进程,就是通过ActivityMangerService的成员函数startProcessLocked()新建的。它主要通过调用Process的静态成员函数start()创建一个新的应用程序进程,并且把这个新建的应用程序进程的入口设置为ActivityThread类的静态成员函数main()!
以上三步都是在ActivityManagerService类中执行的!接下来我们分析新创建的应用程序进程,启动ContentProvider组件的过程,所以step10和step11是在第三方应用程序进程中完成的。
step10: ActivityThread#main()
ActivityThread.main()函数,会在新创建的应用程序进程中,创建一个ActivityThread对象和一个ApplicationThread对象,然后调用ActivityManagerProxy.attchApplication()函数,将ApplicationThread对象传递给ActivityManagerService!
step11: ActivityManagerProxy#attchApplication()
ActivityManagerProxy.attchApplication()函数,先向ActivityManagerService发出一个类型为ATTACH_APPLICATION_TRANSACTION的进程间通信请求,这个请求通过Binder机制处理!然后,就是把step10创建的ApplicationThread对象传递给ActivityManagerService!
接下来step12—14又回到ActivityManagerService中执行!主要用来处理新建应用程序进程发出的类型为ATTACH_APPLICATION_TRANSACTION的进程间通信请求。
step12: ActivityManagerService#attachApplication()
ActivityManagerService.attachApplication()函数,它调用了ApplicationManagerService类的成员函数attachApplicationLocked()来处理类型为ATTACH_APPLICATION_TRANSACTION的进程间通信请求,用来执行启动目标ContentProvider组件的操作!
接下来重点看看ApplicationManagerService类的成员函数attachApplicationLocked()!
step13: ApplicationManagerService#attachApplicationLocked()
ApplicationManagerService类的成员函数attachApplicationLocked()较长,删减后如下:
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {app = null;}
try {
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
}
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
ProfilerInfo profilerInfo = profileFile == null ? null :
new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
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());
}
return true;
}
- 注意到,参数pid指向前面所创建的应用程序进程PID,也即第三方应用进程PID,ProcessRecord对象app就是用来记录新建应用的进程信息的。
- 在前面的step8中,ActivityManagerService以这个PID为关键字将一个ProcessRecord对象保存在了mPidsSelfLocked变量中,这里,首先通过参数pid取回ProcessRecord对象并保存在局部变量app中,然后调用generateApplicationProvidersLocked(app)函数需要在app所描述的第三方进程中启动的ContentProvider组件!
generateApplicationProvidersLocked()函数源码如下:
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
providers = slice != null ? slice.getList() : null;
}
int userId = app.userId;
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
// This is a singleton provider, but a user besides the
// default user is asking to initialize a process it runs
// in... well, no, it doesn't actually run in this process,
// it runs in the process of the default user. Get rid of it.
providers.remove(i);
N--;
i--;
continue;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode, mProcessStats);
}
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
}
- 先去PackageMangerService找目标ContentProvider组件,并保存到列表providers中;
- 然后,for循环检查ActivityManagerService是否已经为这些ContentProvider组件创建过对应的ContnetProviderRecord对象来记录每一个ContentProvider组件;
- 如果没有,则分别为它们创建一个ContentProviderRecord对象,并以它们的类名作为关键字保存在AMS的全局变量mProviderMap中!
从这里可以看出,一个应用程序进程在启动的时候,会将它所需要的所有ContentProvider组件全部启动起来!
最后,继续关注thread.bindApplication()函数,也即ActivityThread.bindApplication()函数!
step14: ActivityThreadProxy#bindApplication()
ActivityThreadProxy.bindApplication()函数源码如下:
public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
Bundle testArgs, IInstrumentationWatcher testWatcher,
IUiAutomationConnection uiAutomationConnection, int debugMode,
boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
info.writeToParcel(data, 0);
data.writeTypedList(providers);
if (testName == null) {
data.writeInt(0);
} else {
data.writeInt(1);
testName.writeToParcel(data, 0);
}
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
data.writeBundle(testArgs);
data.writeStrongInterface(testWatcher);
data.writeStrongInterface(uiAutomationConnection);
data.writeInt(debugMode);
data.writeInt(openGlTrace ? 1 : 0);
data.writeInt(restrictedBackupMode ? 1 : 0);
data.writeInt(persistent ? 1 : 0);
config.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
data.writeMap(services);
data.writeBundle(coreSettings);
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,IBinder.FLAG_ONEWAY);
data.recycle();
}
- 先创建一个Parcel对象data用来保存接收的参数;
- 然后,mRemote是ActivityThreadProxy内部的一个Binder代理对象,通过mRemote向新建的应用程序进程(也即,第三方进程)发送一个类型为BIND_APPLICATION_TRANSACTION的进程间通信请求。
0x03 参考文献与简单的结语
以上三步都是在ActivityManagerService中执行的,接下来的step15—24在新建的应用程序进程中执行,主要用来处理类型为BIND_APPLICATION_TRANSACTION的进程间通信请求!对应时序图上的step15—24