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()函数源码较长,我做了部分删减后如下:

AMS#getContentProviderImpl()

  • 第10行,调用成员函数getRecordForAppLocked(),用来获取发出访问请求的应用程序所在进程的相关信息,在我们的场景中,也就是AxxApp应用程序所在进程的相关信息。这些信息,用一个ProcessRecord对象 r 来描述!
  • 在ActivityManagerService中,每一个已经启动的ContentProvider组件都使用一个ContentProviderRecord对象来描述。这些ContentProviderRecord对象保存在ActivityManagerService类的成员变量mProviderMap中!
  • mProviderMap实质上是一个HashMap,可通过两种方式进行查找,查找结果是一个ContentProviderRecord对象cpr:
    1. mProviderMap.getProviderByName()函数,通过参数name和参数userId进行查找;参数name指向了将要启动的ContentProvider组件的android:authorities属性值,也就是URI值对应的权限部分;参数userId则是调用方应用程序的Linux用户ID;
    2. mProviderMap.getProviderByClass()函数,通过ContentProvider组件的类名进行查找;

需要注意的是,mProvidersByName和mProvidersByClass的内部实现是哈希表,虽然都是保存的ContentProviderRecord对象,但是mProvidersByName变量是以ContentProvider组件的android:authorities属性值为关键字的,而mProvidersByClass变量是以ContentProvider组件的类名作为关键字的!

第15行,首先通过参数name和userId,mProviderMap.getProviderByName()检查是否存在对应的ContentProvider组件?接下来的逻辑很简单,分为两种情况:

  1. 第18行到27行代码,就是表示这个ContentProvider组件已经发布(启动)了,此时调用方(AxxApp)就可以直接通过ContentProviderRecord对象cpr来创建一个ContentProviderHolder对象;需要做两点说明:
    • ContentProviderRecord对象用来记录ContentProvider组件的发布(启动)信息,通过其对象cpr的provider成员变量来记录ContentProvider组件,它们是一对一的关系;
    • ContentProviderHolder是ContentProvider组件的代理对象,它持有一个ContentProvider对象;
  2. 第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 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 generateApplicationProvidersLocked(ProcessRecord app) {
List providers = null;
try {
ParceledListSlice 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 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

posted @ 2016-10-12 22:26  布鲁克林一棵树  阅读(577)  评论(0)    收藏  举报