- 概述
- 初始化content provider。這一階段主要是參照AndroidManifest.xml,初始化content provider。注意這裏只有當包含content provider的進程運行的時候,纔會對該進程內所有的content provider進行初始化。其它provider是按需初始化的(後續文章會介紹該問題)。
- 調用content provider,進行數據庫操作。這個調用通常發生在用戶定義的Activity子類的相關接口內。調用時,首先會獲取對應的content provider對象(有可能是代理對象)。然後,再調用(直接調用或者通過IBinder接口)。
- 應用進程的管理模型
Android框架內,應用程序Java代碼的入口爲ActivityThread.main。用來管理不同的應用的服務名稱爲activity。它的模型大致爲:
左邊爲多個應用進程,每個進程中有個主線程ActivityThread.main,Looper.loop()是主線程的消息循環。所有的應用進程都是通過IBinder機制和ActivityManagerService進程進行交互的。應用進程爲了能調用activity服務進程的ActivityManagerService中的方法,必須通過ActivityManagerProxy類。activity服務進程則通過ApplicationThreadProxy類與服務進程的ApplicationThread通信。ApplicationThread的作用主要是將activity服務進程的調用轉換爲ActivityThread主線程中的消息,從而保證ActivityManagerService的調用是異步的。
右邊的activity服務進程是所有應用的服務進程,用於管理應用進程。啓動新的應用進程時,會向zygote服務進程發送socket消息。zygote接收到消息後,則會啓動新的delvik虛擬機,然後運行ActivityThread.main,啓動新的應用。
- PackageManagerService
PackageManagerService也是一個服務,是用來管理手機內所有的apk包的。調用它的方式和調用ActivityManagerService是一樣的,通過IBinder。它的初始化入口爲PackageManagerService.main:
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
ServiceManager.addService("package", m);
return m;
}
main方法主要是創建一個PackageManagerService,然後註冊到ServiceManager中,名稱爲"package”。PackageManagerService的構造函數中,會去查找系統目錄和應用目錄下的apk文件,以獲取應用的包相關的信息;比如:包名稱,包含的Acvity、Provider等。
// ……
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
// ……
scanDirLI(mAppInstallDir, 0, scanMode);
// ……
scanDirLI函數中,對於每個package,使用函數scanPackageLI解析其中的信息(此處應該是讀取AndroidManifest.xml)。scanPackageLI檢查相關信息後,又會調用另一個scanPackageLI。這個函數內部會掃描到手機內所有的Provider信息:
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProvidersByComponent.put(new ComponentName(p.info.packageName,
p.info.name), p);
mProvidersByComponent保存了所有的provider信息,這部分數據源自於manifest。每個數據包含了PackageParser.Provider、包名稱和Provider的類名。
到這裏,我們可以看到,PackageManagerService真的是用來管理手機的應用包的。通過它可以知道所有的系統可用資源。當然這些資源只是一些靜態信息。通過這些信息,可以創建應用進程、初始化相關的Android組件。
- 應用進程的初始化
public static final void main(String[] args) {
// ......
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
// ......
}
attach函數中,回去調用ActivityManagerService.attachApplication方法。
mgr.attachApplication(mAppThread);
此時,會進入ActivityManagerService的進程空間,進入方法attachApplicationLocked,它會去獲取和當前客戶端應用程序關聯的Provider信息。
List providers = generateApplicationProvidersLocked(app);
根據上面的信息,很容易知道此處是通過PackageManagerService獲取Provider信息的。參數app表明,只是取運行在該app內的Provider。根據Android的文檔,content provider必須在對應的AndroidManifest.xml中定義。默認情況下,是運行在安裝包名稱命名的進程裏面。你也可以在android:process屬性中制定所屬的進程名稱。另一個重要的屬性android:multiprocess則可以指定provider的初始化方式,是分散在調用端進程中,從而避免進程間通信;還是隻初始化在某個進程內,各個調用端只保留provider的代理。
隨後,通過下面的方法調用,返回到應用程序的進程空間,參數中包含了上面獲得的providers。此處的thread實際上就是應用端的ApplicationThread對象。
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
ApplicationThread.bindApplication會發送BIND_APPLICATION消息給主線程。主線程會調用ActivityThread.handleBindApplication方法。這個函數裏面主要分兩步:一是根據需要創建Application、ApplicationContext和ApplicationContentResolver對象。因爲,有可能多個apk運行在一個進程中,那麼它們內部的組件(Component)執行的上下文(context)是不一樣的。這幾個對象實際上就是provider執行的上下文。二是根據傳遞過來的provider信息,創建provider實例,並保存在ActivityThread.mProviderMap中。具體的實例化provider過程如下(下面的代碼位於ActivityThread.handleBindApplication中):
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
}
獲取ActivityManagerService傳遞過來的provider信息,並在本進程中初始化。具體的,installContentProviders方法中,會對每個provider調用installProvider方法:
IContentProvider cp = installProvider(context, null, cpi, false);
installProvider方法中,主要是實例化Provider,並保存到mProviderMap中:
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
// ......
// Cache the pointer for the remote provider.
String names[] = PATTERN_SEMICOLON.split(info.authority);
for (int i=0; i<names.length; i++) {
ProviderRecord pr = new ProviderRecord(names[i], provider,
localProvider);
try {
provider.asBinder().linkToDeath(pr, 0);
mProviderMap.put(names[i], pr);
} catch (RemoteException e) {
return null;
}
}
上面的installContentProviders方法執行完成之後,會調用ActivityManagerService.publishContentProviders方法,將provider註冊到ActivityManagerService中,方便其它應用進程獲取。這裏面有兩個參數,一個是ApplicationThread對象,另一個是provider實例信息。 try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
ActivityManagerService.publishContentProviders的實現也很簡單,主要是將provider信息保存到ActivityManagerService.mProvidersByName中。具體參見源碼。
- 總結
下一篇文章會介紹調用provider的流程。