[原]Android 5.0 進程A和APK B依賴關系問題的研究
(本文來自于和博客上一個朋友的聊天,但可惜我回復后一直沒收到這位朋友的回答。故在此把這個問題和大家介紹下,希望能拋磚引玉)
這位朋友的問題是這樣的:
應用程序A運行時跑在進程A中,它可以在運行時通過ClassLoader加載另外一個應用程序B。
當然,應用程序B也是可以運行的,它運行在進程B中。
在Android 5.0以前,進程B和進程A是沒有關系。但是5.0以后,如果進程B被stop的話,進程A一樣會被干掉。
這就是Android 5.0帶來的進程A/B依賴關系。
這個問題有幾個關鍵技術點:
1 進程A如何加載應用程序B。這是通過ClassLoader來完成的,主要代碼如下所示:
(來自這位朋友的提示:)
private static Class<?> loadPluginClass(Context launcherContext, String packageName, String className, int type) { try { Context context = launcherContext.createPackageContext(packageName, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE); final String apkPath = context.getApplicationInfo().sourceDir; PathClassLoader l = new PathClassLoader(apkPath, context.getClassLoader()); return l.loadClass(className); } ...... }
在load的時候:
1 在Android 5.0以前,進 程A和應用程序B的關系:沒有顯示的關系。就是普通的加載
2 在Android 5.0及以后,進程A和應用程序B的關系:顯示的綁定。代碼在LoadedApk.java中
-->每一個被加載的Apk都對應一個LoaderApk對象。代碼在LoadedApk.java中
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode, boolean registerPackage) {
final int myUid = Process.myUid();
aInfo = adjustNativeLibraryPaths(aInfo);
......
mRegisterPackage = registerPackage; // 在這里被“綁定”了
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
}
Android 5.0之后為什么會這樣呢?進程A和APK B這種依賴關系有什么用呢?
原來,Android 5.0之后:
1 當進程A加載一個package的時候,framework將調用ActivityManagerService的addPackageDependency
這個函數將把進程A和APK B(也就是Package B)綁定到一起去
這個函數在哪里調用的呢?也在LoadedApk.java中:
public ClassLoader getClassLoader() { synchronized (this) { if (mClassLoader != null) { return mClassLoader; } if (mIncludeCode && !mPackageName.equals("android")) { ...... if (mRegisterPackage) { try { ActivityManagerNative.getDefault().addPackageDependency(mPackageName); } catch (RemoteException e) { } }
2 進程B(也就是Package B本身運行時所在的進程)被殺時,有依賴關系的進程A也會被干掉。這里有幾個注意點:
2.1 如果進程B是自己crash或者被shell kill掉,那么依賴關系不會影響進程A
2.2 如果進程B是被調用killBackgroundProcess或者forceStopPackage的話,由于ActivityManagerService真正調用的是killPackageProcessesLocked
那么依賴關系會導致A被干掉。 從設計角度來看,這本身也是對的,因為APK B運行在自己的進程B,同時也被加載到進程A去運行。
kill package B的時候就應該stop進程B和A。
當然,由于5.0之前google沒有考慮這么細,所以沒有處理這個問題。
當然,這種依賴關系的引入還有一個原因是Android 5.0在應用程序安裝方面的一些新的特性:
1 以前的apk文件 side load到/daa/app等監控目錄下不會導致PacakgeManagerService去安裝它們。而是需要等到下次重啟掃描后,系統才會掃描并安裝它們
2 adb install安裝的APK,在/data/app目錄下會創建一個Package-name(比如com.google.xxx)的文件夾,而apk文件被放到這個package-name目錄下,改名叫base.apk
這么搞的目的是因為:Android終于支持一個進程可以加載多個APK了(當然以前也可以,但現在安裝的時候,base-apk是主要邏輯, 以后升級了,或者添加新的功能,就不需要重新安裝新的base,而是安裝一個額外的新apk,這個新apk會被加載到base的那個進程里。)這個功能在 SDK文檔中已經有展示,但是內容不是很詳細
總之,base apk和新apk需要package名, 簽名都一致才可以。
原文 http://blog.csdn.net/innost/article/details/43899041