[原]Android 5.0 進程A和APK B依賴關系問題的研究

碼頭工人 9年前發布 | 14K 次閱讀 Android開發 移動開發 Android 5.0

(本文來自于和博客上一個朋友的聊天,但可惜我回復后一直沒收到這位朋友的回答。故在此把這個問題和大家介紹下,希望能拋磚引玉)

這位朋友的問題是這樣的:

應用程序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

</div> </div>

 本文由用戶 碼頭工人 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!