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