android APK應用安裝過程以及默認安裝路徑[轉]


一:安裝過程

APK是類似Symbian Sis或Sisx的文件格式。通過將APK文件直接傳到Android模擬器或Android手機中執行即可安裝。

Android應用安裝有如下四種方式


1.        系統應用安裝――開機時完成,沒有安裝界面


2.        網絡下載應用安裝――通過market應用完成,沒有安裝界面


3.        ADB工具安裝――沒有安裝界面。


4.        第三方應用安裝――通過SD卡里的APK文件安裝,有安裝界面,由packageinstaller.apk應用處理安裝及卸載過程的界面。


應用安裝的流程及路徑 
應用安裝涉及到如下幾個目錄:


system/app 
 系統自帶的應用程序,無法刪除
 
data/app
 用戶程序安裝的目錄,有刪除權限。


安裝時把apk文件復制到此目錄
 
data/data
 存放應用程序的數據
 
Data/dalvik-cache
 將apk中的dex文件安裝到dalvik-cache目錄下(dex文件是dalvik虛擬機的可執行文件,其大小約為原始apk文件大小的四分之一)
 


       安裝過程:復制APK安裝包到data/app目錄下,解壓並掃描安裝包,把dex文件(Dalvik字節碼)保存到dalvik-cache目錄,並data/data目錄下創建對應的應用數據目錄。


       卸載過程:刪除安裝過程中在上述三個目錄下創建的文件及目錄。




 


一、系統應用安裝: 
PackageManagerService處理各種應用的安裝,卸載,管理等工作,開機時由systemServer啟動此服務


(源文件路徑:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)


PackageManagerService服務啟動的流程:


1. 首先掃描安裝“system\framework”目錄下的jar包


1. scanDirLI(mFrameworkDir,PackageParser.PARSE_IS_SYSTEM,


                    scanMode | SCAN_NO_DEX);




2.第二步掃描安裝“system\app”目錄下的各個系統應用


scanDirLI(mSystemAppDir,PackageParser.PARSE_IS_SYSTEM, scanMode);




3.第三步掃描“data\app”目錄,即用戶安裝的第三方應用


scanDirLI(mAppInstallDir, 0, scanMode);




4.第四步掃描" data\app-private"目錄,即安裝DRM保護的APK文件(目前沒有遇到過此類的應用)。


scanDirLI(mDrmAppPrivateInstallDir,0, scanMode | SCAN_FORWARD_LOCKED);


安裝應用的過程


1.scanDirLI(Filedir, int flags, int scanMode) 遍歷安裝指定目錄下的文件


2.scanPackageLI(FilescanFile,


            File destCodeFile, FiledestResourceFile, int parseFlags,


            int scanMode)                安裝package文件


3.scanPackageLI(


        File scanFile, File destCodeFile, FiledestResourceFile,


        PackageParser.Package pkg, intparseFlags, int scanMode)


通過解析安裝包parsePackage獲取到安裝包的信息結構


4.mInstaller.install(pkgName,pkg.applicationInfo.uid,


              pkg.applicationInfo.uid);   實現文件復制的安裝過程


(源文件路徑:frameworks\base\cmds\installd\installd.install)




二、從market上下載應用: 
Google Market應用需要使用gmail賬戶登錄才可以使用,選擇某一應用后,開始下載安裝包,此過程中,在手機的信號區有進度條提示,下載完成后,會自動調用Packagemanager的接口安裝,調用接口如下:


public voidinstallPackage(final Uri packageURI, final IPackageInstallObserver observer,final int flags)


final Uri packageURI:文件下載完成后保存的路徑


final IPackageInstallObserver observer:處理返回的安裝結果


final int flags:安裝的參數,從market上下載的應用,安裝參數為-r (replace)


installPackage接口函數的安裝過程:


1.public voidinstallPackage(


            final Uri packageURI, final IPackageInstallObserverobserver, final int flags,


            final String installerPackageName)


final StringinstallerPackageName:安裝完成后此名稱保存在settings里,一般為null,不是關鍵參數


2.FiletmpPackageFile = copyTempInstallFile(packageURI, res);


把apk文件復制到臨時目錄下的臨時文件


3.private voidinstallPackageLI(Uri pPackageURI,


            int pFlags, boolean newInstall,String installerPackageName,


           File tmpPackageFile, PackageInstalledInfo res)


解析臨時文件,獲取應用包名pkgName = PackageParser.parsePackageName(


                   tmpPackageFile.getAbsolutePath(), 0);


4.判斷如果帶有參數INSTALL_REPLACE_EXISTING,則調用replacePackageLI(pkgName,


                        tmpPackageFile,


                        destFilePath,destPackageFile, destResourceFile,


                        pkg, forwardLocked,newInstall, installerPackageName,


                        res)


5.如果沒有,則調用installNewPackageLI(pkgName,


                        tmpPackageFile,


                        destFilePath,destPackageFile, destResourceFile,


                        pkg,forwardLocked, newInstall, installerPackageName,


                        res);


6.privatePackageParser.Package scanPackageLI(


        File scanFile, File destCodeFile, FiledestResourceFile,


        PackageParser.Package pkg, intparseFlags, int scanMode)


scanPackageLI以后的流程,與開機時的應用安裝流程相同。


三、從ADB工具安裝 
Android Debug Bridge (adb) 是SDK自帶的管理設備的工具,通過ADB命令行的方式也可以為手機或模擬器安裝應用,其入口函數源文件為pm.java


(源文件路徑:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)


ADB命令行的形式為adb install <path_to_apk> ,還可以帶安裝參數如:"-l""-r" "-i" "-t"


函數runInstall()中判斷參數


"-l"――INSTALL_FORWARD_LOCK


 "-r"——INSTALL_REPLACE_EXISTING 


"-i" ——installerPackageName


"-t"——INSTALL_ALLOW_TEST


我們常用的參數為-r,表示覆蓋安裝手機上已安裝的同名應用。從market上下載的應用,也是直接傳入這個參數安裝的。


runInstall與market調用同樣的接口完成應用安裝。


public voidinstallPackage(android.net.Uri packageURI,android.content.pm.IPackageInstallObserver observer, int flags,java.lang.String installerPackageName)


四、第三方應用安裝――通過SD卡里的APK文件安裝 
把APK安裝包保存在SD卡中,從手機里訪問SD卡中的APK安裝包,點擊就可以啟動安裝界面,系統應用Packageinstaller.apk處理這種方式下的安裝及卸載界面流程,如下圖:




PackageInstallerActivity負責解析包,判斷是否是可用的Apk文件


創建臨時安裝文件/data/data/com.android.packageinstaller/files/ApiDemos.apk


並啟動安裝確認界面startInstallConfirm,列出解析得到的該應用基本信息。如果手機上已安裝有同名應用,則需要用戶確認是否要替換安裝。


確認安裝后,啟動InstallAppProgress,調用安裝接口完成安裝。


pm.installPackage(mPackageURI,observer, installFlags);


其它: 
1. PackageManagerService.java的內部類AppDirObserver實現了監聽app目錄的功能:當把某個APK拖到app目錄下時,可以直接調用scanPackageLI完成安裝。


2.手機數據區目錄“data/system/packages.xml”文件中,包含了手機上所有已安裝應用的基本信息,如安裝路徑,申請的permission等信息。

 

二:更改默認安裝路徑

    如果你是一個apk應用開發者,沒用android系統全套代碼,你只想更改你的APK的默認安裝路徑的話,可以按下面方法來更改:

 

在AndroidManifest.xml文件Manifest標簽中添加android:installLocation屬性

android:installLocation

這個屬性設置的是默認安裝位置, 共有三個有效值,auto、internalOnly、preferExternal

對應表

auto 表示自動,由系統決定安裝位置,如果系統手機內存足夠,默認安裝在手機內存里,如果手機內在不夠,則會安裝在T卡內

internalOnly 安裝在手機內存

preferExternal 安裝在外部存儲中

Constant Value Description
auto 0 Let the system decide install location
internalOnly 1 Explicitly request to be installed on internal phone storage only
preferExternal 2 Perfer to be installed on SD card, There is no guarantee that the system will honor this request. The application might end up being installed on internal storage if external media is unavailable or too full

 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.ray"
      android:installLocation="auto"
      android:versionCode="1"
      android:versionName="1.0">

如果你是一個手機方案開發者,能改framework層的代碼,你希望下載到手機里的APK都默認優先安裝到T卡的話,可以按下面方法更改:

在PackageParser.java文件里,將private static final int PARSE_DEFAULT_INSTALL_LOCATION  這個PARSE_DEFAULT_INSTALL_LOCATION值,改為PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL,就可以了.默認下載就會下到T卡里,T卡不存在或者滿了時,才會下到手機內部. 或者如果在應用的AndroidManifest.xml里,指定了installLocation屬性為手機內部存儲的話,是會存在手機內部的.沒指這定的話,PARSE_DEFAULT_INSTALL_LOCATION這個值指定什么,就下到哪里

安裝在T卡里的應用,有幾個缺點:
1:因為android裝載T卡是在系統啟動完成后,才開始裝載的.所以如果應用裝在T卡里的話,那么它是收不到開機啟動完成的BOOT_COMPLETED這個廣播的
2:如果T卡損壞或者T卡撥出來了,那么裝在T卡里的應用是啟動不了的.

 

 

系統應用安裝的詳細過程,老羅有篇文章寫得很透徹,這里引用下:

 

Android系統在啟動的過程中,會啟動一個應用程序管理服務PackageManagerService,這個服務負責掃描系統中特定的目錄,找到里面的應用程序文件,即以Apk為后綴的文件,然后對這些文件進解析,得到應用程序的相關信息,完成應用程序的安裝過程,本文將詳細分析這個過程。

        應用程序管理服務PackageManagerService安裝應用程序的過程,其實就是解析析應用程序配置文件AndroidManifest.xml的過程,並從里面得到得到應用程序的相關信息,例如得到應用程序的組件Activity、Service、Broadcast Receiver和Content Provider等信息,有了這些信息后,通過ActivityManagerService這個服務,我們就可以在系統中正常地使用這些應用程序了。

        應用程序管理服務PackageManagerService是系統啟動的時候由SystemServer組件啟動的,啟后它就會執行應用程序安裝的過程,因此,本文將從SystemServer啟動PackageManagerService服務的過程開始分析系統中的應用程序安裝的過程。

        應用程序管理服務PackageManagerService從啟動到安裝應用程序的過程如下圖所示:

        下面我們具體分析每一個步驟。

        Step 1. SystemServer.main

        這個函數定義在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

 

[java]  view plain copy
 
 
  1. public class SystemServer  
  2. {  
  3.     ......  
  4.   
  5.     native public static void init1(String[] args);  
  6.   
  7.     ......  
  8.   
  9.     public static void main(String[] args) {  
  10.         ......  
  11.   
  12.         init1(args);  
  13.   
  14.         ......  
  15.     }  
  16.   
  17.     ......  
  18. }  

        SystemServer組件是由Zygote進程負責啟動的,啟動的時候就會調用它的main函數,這個函數主要調用了JNI方法init1來做一些系統初始化的工作。

 

        Step 2. SystemServer.init1

        這個函數是一個JNI方法,實現在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:

 

[cpp]  view plain copy
 
 
  1. namespace android {  
  2.   
  3. extern "C" int system_init();  
  4.   
  5. static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)  
  6. {  
  7.     system_init();  
  8. }  
  9.   
  10. /* 
  11.  * JNI registration. 
  12.  */  
  13. static JNINativeMethod gMethods[] = {  
  14.     /* name, signature, funcPtr */  
  15.     { "init1""([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },  
  16. };  
  17.   
  18. int register_android_server_SystemServer(JNIEnv* env)  
  19. {  
  20.     return jniRegisterNativeMethods(env, "com/android/server/SystemServer",  
  21.             gMethods, NELEM(gMethods));  
  22. }  
  23.   
  24. }; // namespace android  

        這個函數很簡單,只是調用了system_init函數來進一步執行操作。

 

        Step 3. libsystem_server.system_init

        函數system_init實現在libsystem_server庫中,源代碼位於frameworks/base/cmds/system_server/library/system_init.cpp文件中:

 

[cpp]  view plain copy
 
 
  1. extern "C" status_t system_init()  
  2. {  
  3.     LOGI("Entered system_init()");  
  4.   
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.   
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp<GrimReaper> grim = new GrimReaper();  
  11.     sm->asBinder()->linkToDeath(grim, grim.get(), 0);  
  12.   
  13.     char propBuf[PROPERTY_VALUE_MAX];  
  14.     property_get("system_init.startsurfaceflinger", propBuf, "1");  
  15.     if (strcmp(propBuf, "1") == 0) {  
  16.         // Start the SurfaceFlinger  
  17.         SurfaceFlinger::instantiate();  
  18.     }  
  19.   
  20.     // Start the sensor service  
  21.     SensorService::instantiate();  
  22.   
  23.     // On the simulator, audioflinger et al don't get started the  
  24.     // same way as on the device, and we need to start them here  
  25.     if (!proc->supportsProcesses()) {  
  26.   
  27.         // Start the AudioFlinger  
  28.         AudioFlinger::instantiate();  
  29.   
  30.         // Start the media playback service  
  31.         MediaPlayerService::instantiate();  
  32.   
  33.         // Start the camera service  
  34.         CameraService::instantiate();  
  35.   
  36.         // Start the audio policy service  
  37.         AudioPolicyService::instantiate();  
  38.     }  
  39.   
  40.     // And now start the Android runtime.  We have to do this bit  
  41.     // of nastiness because the Android runtime initialization requires  
  42.     // some of the core system services to already be started.  
  43.     // All other servers should just start the Android runtime at  
  44.     // the beginning of their processes's main(), before calling  
  45.     // the init function.  
  46.     LOGI("System server: starting Android runtime.\n");  
  47.   
  48.     AndroidRuntime* runtime = AndroidRuntime::getRuntime();  
  49.   
  50.     LOGI("System server: starting Android services.\n");  
  51.     runtime->callStatic("com/android/server/SystemServer""init2");  
  52.   
  53.     // If running in our own process, just go into the thread  
  54.     // pool.  Otherwise, call the initialization finished  
  55.     // func to let this process continue its initilization.  
  56.     if (proc->supportsProcesses()) {  
  57.         LOGI("System server: entering thread pool.\n");  
  58.         ProcessState::self()->startThreadPool();  
  59.         IPCThreadState::self()->joinThreadPool();  
  60.         LOGI("System server: exiting thread pool.\n");  
  61.     }  
  62.   
  63.     return NO_ERROR;  
  64. }  

        這個函數首先會初始化SurfaceFlinger、SensorService、AudioFlinger、MediaPlayerService、CameraService和AudioPolicyService這幾個服務,然后就通過系統全局唯一的AndroidRuntime實例變量runtime的callStatic來調用SystemServer的init2函數了。關於這個AndroidRuntime實例變量runtime的相關資料,可能參考前面一篇文章Android應用程序進程啟動過程的源代碼分析一文。

 

        Step 4. AndroidRuntime.callStatic

        這個函數定義在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

 

[cpp]  view plain copy
 
 
  1. /* 
  2. * Call a static Java Programming Language function that takes no arguments and returns void. 
  3. */  
  4. status_t AndroidRuntime::callStatic(const char* className, const char* methodName)  
  5. {  
  6.     JNIEnv* env;  
  7.     jclass clazz;  
  8.     jmethodID methodId;  
  9.   
  10.     env = getJNIEnv();  
  11.     if (env == NULL)  
  12.         return UNKNOWN_ERROR;  
  13.   
  14.     clazz = findClass(env, className);  
  15.     if (clazz == NULL) {  
  16.         LOGE("ERROR: could not find class '%s'\n", className);  
  17.         return UNKNOWN_ERROR;  
  18.     }  
  19.     methodId = env->GetStaticMethodID(clazz, methodName, "()V");  
  20.     if (methodId == NULL) {  
  21.         LOGE("ERROR: could not find method %s.%s\n", className, methodName);  
  22.         return UNKNOWN_ERROR;  
  23.     }  
  24.   
  25.     env->CallStaticVoidMethod(clazz, methodId);  
  26.   
  27.     return NO_ERROR;  
  28. }  

        這個函數調用由參數className指定的java類的靜態成員函數,這個靜態成員函數是由參數methodName指定的。上面傳進來的參數className的值為"com/android/server/SystemServer",而參數methodName的值為"init2",因此,接下來就會調用SystemServer類的init2函數了。

 

        Step 5. SystemServer.init2

        這個函數定義在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

[java]  view plain copy
 
 
  1. public class SystemServer  
  2. {  
  3.     ......  
  4.   
  5.     public static final void init2() {  
  6.         Slog.i(TAG, "Entered the Android system server!");  
  7.         Thread thr = new ServerThread();  
  8.         thr.setName("android.server.ServerThread");  
  9.         thr.start();  
  10.     }  
  11. }  

        這個函數創建了一個ServerThread線程,PackageManagerService服務就是這個線程中啟動的了。這里調用了ServerThread實例thr的start函數之后,下面就會執行這個實例的run函數了。

 

        Step 6. ServerThread.run

        這個函數定義在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

[java]  view plain copy
 
 
  1. class ServerThread extends Thread {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public void run() {  
  6.         ......  
  7.   
  8.         IPackageManager pm = null;  
  9.   
  10.         ......  
  11.   
  12.         // Critical services...  
  13.         try {  
  14.             ......  
  15.   
  16.             Slog.i(TAG, "Package Manager");  
  17.             pm = PackageManagerService.main(context,  
  18.                         factoryTest != SystemServer.FACTORY_TEST_OFF);  
  19.   
  20.             ......  
  21.         } catch (RuntimeException e) {  
  22.             Slog.e("System""Failure starting core service", e);  
  23.         }  
  24.   
  25.         ......  
  26.     }  
  27.   
  28.     ......  
  29. }  

        這個函數除了啟動PackageManagerService服務之外,還啟動了其它很多的服務,例如在前面學習Activity和Service的幾篇文章中經常看到的ActivityManagerService服務,有興趣的讀者可以自己研究一下。

 

        Step 7. PackageManagerService.main

        這個函數定義在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

 

[cpp]  view plain copy
 
 
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public static final IPackageManager main(Context context, boolean factoryTest) {  
  5.         PackageManagerService m = new PackageManagerService(context, factoryTest);  
  6.         ServiceManager.addService("package", m);  
  7.         return m;  
  8.     }  
  9.   
  10.     ......  
  11. }  

        這個函數創建了一個PackageManagerService服務實例,然后把這個服務添加到ServiceManager中去,ServiceManager是Android系統Binder進程間通信機制的守護進程,負責管理系統中的Binder對象,具體可以參考淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路一文。
        在創建這個PackageManagerService服務實例時,會在PackageManagerService類的構造函數中開始執行安裝應用程序的過程:

 

 

[java]  view plain copy
 
 
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     public PackageManagerService(Context context, boolean factoryTest) {  
  5.         ......  
  6.   
  7.         synchronized (mInstallLock) {  
  8.             synchronized (mPackages) {  
  9.                 ......  
  10.   
  11.                 File dataDir = Environment.getDataDirectory();  
  12.                 mAppDataDir = new File(dataDir, "data");  
  13.                 mSecureAppDataDir = new File(dataDir, "secure/data");  
  14.                 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
  15.   
  16.                 ......  
  17.   
  18.                 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");  
  19.                 mDalvikCacheDir = new File(dataDir, "dalvik-cache");  
  20.   
  21.                 ......  
  22.   
  23.                 // Find base frameworks (resource packages without code).  
  24.                 mFrameworkInstallObserver = new AppDirObserver(  
  25.                 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);  
  26.                 mFrameworkInstallObserver.startWatching();  
  27.                 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM  
  28.                     | PackageParser.PARSE_IS_SYSTEM_DIR,  
  29.                     scanMode | SCAN_NO_DEX, 0);  
  30.   
  31.                 // Collect all system packages.  
  32.                 mSystemAppDir = new File(Environment.getRootDirectory(), "app");  
  33.                 mSystemInstallObserver = new AppDirObserver(  
  34.                     mSystemAppDir.getPath(), OBSERVER_EVENTS, true);  
  35.                 mSystemInstallObserver.startWatching();  
  36.                 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM  
  37.                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  38.   
  39.                 // Collect all vendor packages.  
  40.                 mVendorAppDir = new File("/vendor/app");  
  41.                 mVendorInstallObserver = new AppDirObserver(  
  42.                     mVendorAppDir.getPath(), OBSERVER_EVENTS, true);  
  43.                 mVendorInstallObserver.startWatching();  
  44.                 scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM  
  45.                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  46.   
  47.   
  48.                 mAppInstallObserver = new AppDirObserver(  
  49.                     mAppInstallDir.getPath(), OBSERVER_EVENTS, false);  
  50.                 mAppInstallObserver.startWatching();  
  51.                 scanDirLI(mAppInstallDir, 0, scanMode, 0);  
  52.   
  53.                 mDrmAppInstallObserver = new AppDirObserver(  
  54.                     mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);  
  55.                 mDrmAppInstallObserver.startWatching();  
  56.                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,  
  57.                     scanMode, 0);  
  58.   
  59.                 ......  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64.     ......  
  65. }  

        這里會調用scanDirLI函數來掃描移動設備上的下面這五個目錄中的Apk文件:

 

        /system/framework

        /system/app

        /vendor/app

        /data/app

        /data/app-private

       Step 8. PackageManagerService.scanDirLI
       這個函數定義在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

 

[java]  view plain copy
 
 
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {  
  5.         String[] files = dir.list();  
  6.         ......  
  7.   
  8.         int i;  
  9.         for (i=0; i<files.length; i++) {  
  10.             File file = new File(dir, files[i]);  
  11.             if (!isPackageFilename(files[i])) {  
  12.                 // Ignore entries which are not apk's  
  13.                 continue;  
  14.             }  
  15.             PackageParser.Package pkg = scanPackageLI(file,  
  16.                 flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);  
  17.             // Don't mess around with apps in system partition.  
  18.             if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&  
  19.                 mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {  
  20.                     // Delete the apk  
  21.                     Slog.w(TAG, "Cleaning up failed install of " + file);  
  22.                     file.delete();  
  23.             }  
  24.         }  
  25.     }  
  26.   
  27.   
  28.     ......  
  29. }  

         對於目錄中的每一個文件,如果是以后Apk作為后綴名,那么就調用scanPackageLI函數來對它進行解析和安裝。

 

         Step 9. PackageManagerService.scanPackageLI

         這個函數定義在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

 

[java]  view plain copy
 
 
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     private PackageParser.Package scanPackageLI(File scanFile,  
  5.             int parseFlags, int scanMode, long currentTime) {  
  6.         ......  
  7.   
  8.         String scanPath = scanFile.getPath();  
  9.         parseFlags |= mDefParseFlags;  
  10.         PackageParser pp = new PackageParser(scanPath);  
  11.           
  12.         ......  
  13.   
  14.         final PackageParser.Package pkg = pp.parsePackage(scanFile,  
  15.             scanPath, mMetrics, parseFlags);  
  16.   
  17.         ......  
  18.   
  19.         return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime);  
  20.     }  
  21.   
  22.     ......  
  23. }  

        這個函數首先會為這個Apk文件創建一個PackageParser實例,接着調用這個實例的parsePackage函數來對這個Apk文件進行解析。這個函數最后還會調用另外一個版本的scanPackageLI函數把來解析后得到的應用程序信息保存在PackageManagerService中。

 

        Step 10. PackageParser.parsePackage
        這個函數定義在frameworks/base/core/java/android/content/pm/PackageParser.java文件中:

 

[java]  view plain copy
 
 
  1. public class PackageParser {  
  2.     ......  
  3.   
  4.     public Package parsePackage(File sourceFile, String destCodePath,  
  5.             DisplayMetrics metrics, int flags) {  
  6.         ......  
  7.   
  8.         mArchiveSourcePath = sourceFile.getPath();  
  9.   
  10.         ......  
  11.   
  12.         XmlResourceParser parser = null;  
  13.         AssetManager assmgr = null;  
  14.         boolean assetError = true;  
  15.         try {  
  16.             assmgr = new AssetManager();  
  17.             int cookie = assmgr.addAssetPath(mArchiveSourcePath);  
  18.             if(cookie != 0) {  
  19.                 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");  
  20.                 assetError = false;  
  21.             } else {  
  22.                 ......  
  23.             }  
  24.         } catch (Exception e) {  
  25.             ......  
  26.         }  
  27.   
  28.         ......  
  29.   
  30.         String[] errorText = new String[1];  
  31.         Package pkg = null;  
  32.         Exception errorException = null;  
  33.         try {  
  34.             // XXXX todo: need to figure out correct configuration.  
  35.             Resources res = new Resources(assmgr, metrics, null);  
  36.             pkg = parsePackage(res, parser, flags, errorText);  
  37.         } catch (Exception e) {  
  38.             ......  
  39.         }  
  40.   
  41.         ......  
  42.   
  43.         parser.close();  
  44.         assmgr.close();  
  45.   
  46.         // Set code and resource paths  
  47.         pkg.mPath = destCodePath;  
  48.         pkg.mScanPath = mArchiveSourcePath;  
  49.         //pkg.applicationInfo.sourceDir = destCodePath;  
  50.         //pkg.applicationInfo.publicSourceDir = destRes;  
  51.         pkg.mSignatures = null;  
  52.   
  53.         return pkg;  
  54.     }  
  55.   
  56.     ......  
  57. }  

        每一個Apk文件都是一個歸檔文件,它里面包含了Android應用程序的配置文件AndroidManifest.xml,這里主要就是要對這個配置文件就行解析了,從Apk歸檔文件中得到這個配置文件后,就調用另一外版本的parsePackage函數對這個應用程序進行解析了:

 

 

[java]  view plain copy
 
 
  1. public class PackageParser {  
  2.     ......  
  3.   
  4.     private Package parsePackage(  
  5.             Resources res, XmlResourceParser parser, int flags, String[] outError)  
  6.             throws XmlPullParserException, IOException {  
  7.         ......  
  8.   
  9.         String pkgName = parsePackageName(parser, attrs, flags, outError);  
  10.           
  11.         ......  
  12.   
  13.         final Package pkg = new Package(pkgName);  
  14.   
  15.         ......  
  16.   
  17.         int type;  
  18.   
  19.         ......  
  20.           
  21.         TypedArray sa = res.obtainAttributes(attrs,  
  22.             com.android.internal.R.styleable.AndroidManifest);  
  23.   
  24.         ......  
  25.   
  26.         while ((type=parser.next()) != parser.END_DOCUMENT  
  27.             && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {  
  28.                 if (type == parser.END_TAG || type == parser.TEXT) {  
  29.                     continue;  
  30.                 }  
  31.   
  32.                 String tagName = parser.getName();  
  33.                 if (tagName.equals("application")) {  
  34.                     ......  
  35.   
  36.                     if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {  
  37.                         return null;  
  38.                     }  
  39.                 } else if (tagName.equals("permission-group")) {  
  40.                     ......  
  41.                 } else if (tagName.equals("permission")) {  
  42.                     ......  
  43.                 } else if (tagName.equals("permission-tree")) {  
  44.                     ......  
  45.                 } else if (tagName.equals("uses-permission")) {  
  46.                     ......  
  47.                 } else if (tagName.equals("uses-configuration")) {  
  48.                     ......  
  49.                 } else if (tagName.equals("uses-feature")) {  
  50.                     ......  
  51.                 } else if (tagName.equals("uses-sdk")) {  
  52.                     ......  
  53.                 } else if (tagName.equals("supports-screens")) {  
  54.                     ......  
  55.                 } else if (tagName.equals("protected-broadcast")) {  
  56.                     ......  
  57.                 } else if (tagName.equals("instrumentation")) {  
  58.                     ......  
  59.                 } else if (tagName.equals("original-package")) {  
  60.                     ......  
  61.                 } else if (tagName.equals("adopt-permissions")) {  
  62.                     ......  
  63.                 } else if (tagName.equals("uses-gl-texture")) {  
  64.                     ......  
  65.                 } else if (tagName.equals("compatible-screens")) {  
  66.                     ......  
  67.                 } else if (tagName.equals("eat-comment")) {  
  68.                     ......  
  69.                 } else if (RIGID_PARSER) {  
  70.                     ......  
  71.                 } else {  
  72.                     ......  
  73.                 }  
  74.         }  
  75.   
  76.         ......  
  77.   
  78.         return pkg;  
  79.     }  
  80.   
  81.     ......  
  82. }  

        這里就是對AndroidManifest.xml文件中的各個標簽進行解析了,各個標簽的含義可以參考官方文檔http://developer.android.com/guide/topics/manifest/manifest-intro.html,這里我們只簡單看一下application標簽的解析,這是通過調用parseApplication函數來進行的。

 

        Step 11. PackageParser.parseApplication
        這個函數定義在frameworks/base/core/java/android/content/pm/PackageParser.java文件中:

[java]  view plain copy
 
 
  1. public class PackageParser {  
  2.     ......  
  3.   
  4.     private boolean parseApplication(Package owner, Resources res,  
  5.             XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)  
  6.             throws XmlPullParserException, IOException {  
  7.         final ApplicationInfo ai = owner.applicationInfo;  
  8.         final String pkgName = owner.applicationInfo.packageName;  
  9.   
  10.         TypedArray sa = res.obtainAttributes(attrs,  
  11.             com.android.internal.R.styleable.AndroidManifestApplication);  
  12.   
  13.         ......  
  14.   
  15.         int type;  
  16.         while ((type=parser.next()) != parser.END_DOCUMENT  
  17.             && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {  
  18.                 if (type == parser.END_TAG || type == parser.TEXT) {  
  19.                     continue;  
  20.                 }  
  21.           
  22.                 String tagName = parser.getName();  
  23.                 if (tagName.equals("activity")) {  
  24.                     Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);  
  25.                     ......  
  26.   
  27.                     owner.activities.add(a);  
  28.   
  29.                 } else if (tagName.equals("receiver")) {  
  30.                     Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);  
  31.                     ......  
  32.   
  33.                     owner.receivers.add(a);  
  34.                 } else if (tagName.equals("service")) {  
  35.                     Service s = parseService(owner, res, parser, attrs, flags, outError);  
  36.                     ......  
  37.   
  38.                     owner.services.add(s);  
  39.                 } else if (tagName.equals("provider")) {  
  40.                     Provider p = parseProvider(owner, res, parser, attrs, flags, outError);  
  41.                     ......  
  42.   
  43.                     owner.providers.add(p);  
  44.                 } else if (tagName.equals("activity-alias")) {  
  45.                     Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);  
  46.                     ......  
  47.   
  48.                     owner.activities.add(a);  
  49.                 } else if (parser.getName().equals("meta-data")) {  
  50.                     ......  
  51.                 } else if (tagName.equals("uses-library")) {  
  52.                     ......  
  53.                 } else if (tagName.equals("uses-package")) {  
  54.                     ......  
  55.                 } else {  
  56.                     ......  
  57.                 }  
  58.         }  
  59.   
  60.         return true;  
  61.     }  
  62.   
  63.     ......  
  64. }  

        這里就是對AndroidManifest.xml文件中的application標簽進行解析了,我們常用到的標簽就有activity、service、receiver和provider,各個標簽的含義可以參考官方文檔http://developer.android.com/guide/topics/manifest/manifest-intro.html

 

        這里解析完成后,一層層返回到Step 9中,調用另一個版本的scanPackageLI函數把來解析后得到的應用程序信息保存下來。

        Step 12. PackageManagerService.scanPackageLI

        這個函數定義在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

[java]  view plain copy
 
 
  1. class PackageManagerService extends IPackageManager.Stub {  
  2.     ......  
  3.   
  4.     // Keys are String (package name), values are Package.  This also serves  
  5.     // as the lock for the global state.  Methods that must be called with  
  6.     // this lock held have the prefix "LP".  
  7.     final HashMap<String, PackageParser.Package> mPackages =  
  8.         new HashMap<String, PackageParser.Package>();  
  9.   
  10.     ......  
  11.   
  12.     // All available activities, for your resolving pleasure.  
  13.     final ActivityIntentResolver mActivities =  
  14.     new ActivityIntentResolver();  
  15.   
  16.     // All available receivers, for your resolving pleasure.  
  17.     final ActivityIntentResolver mReceivers =  
  18.         new ActivityIntentResolver();  
  19.   
  20.     // All available services, for your resolving pleasure.  
  21.     final ServiceIntentResolver mServices = new ServiceIntentResolver();  
  22.   
  23.     // Keys are String (provider class name), values are Provider.  
  24.     final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =  
  25.         new HashMap<ComponentName, PackageParser.Provider>();  
  26.   
  27.     ......  
  28.   
  29.     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,  
  30.             int parseFlags, int scanMode, long currentTime) {  
  31.         ......  
  32.   
  33.         synchronized (mPackages) {  
  34.             ......  
  35.   
  36.             // Add the new setting to mPackages  
  37.             mPackages.put(pkg.applicationInfo.packageName, pkg);  
  38.   
  39.             ......  
  40.   
  41.             int N = pkg.providers.size();  
  42.             int i;  
  43.             for (i=0; i<N; i++) {  
  44.                 PackageParser.Provider p = pkg.providers.get(i);  
  45.                 p.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  46.                     p.info.processName, pkg.applicationInfo.uid);  
  47.                 mProvidersByComponent.put(new ComponentName(p.info.packageName,  
  48.                     p.info.name), p);  
  49.   
  50.                 ......  
  51.             }  
  52.   
  53.             N = pkg.services.size();  
  54.             for (i=0; i<N; i++) {  
  55.                 PackageParser.Service s = pkg.services.get(i);  
  56.                 s.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  57.                     s.info.processName, pkg.applicationInfo.uid);  
  58.                 mServices.addService(s);  
  59.   
  60.                 ......  
  61.             }  
  62.   
  63.             N = pkg.receivers.size();  
  64.             r = null;  
  65.             for (i=0; i<N; i++) {  
  66.                 PackageParser.Activity a = pkg.receivers.get(i);  
  67.                 a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  68.                     a.info.processName, pkg.applicationInfo.uid);  
  69.                 mReceivers.addActivity(a, "receiver");  
  70.                   
  71.                 ......  
  72.             }  
  73.   
  74.             N = pkg.activities.size();  
  75.             for (i=0; i<N; i++) {  
  76.                 PackageParser.Activity a = pkg.activities.get(i);  
  77.                 a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  78.                     a.info.processName, pkg.applicationInfo.uid);  
  79.                 mActivities.addActivity(a, "activity");  
  80.                   
  81.                 ......  
  82.             }  
  83.   
  84.             ......  
  85.         }  
  86.   
  87.         ......  
  88.   
  89.         return pkg;  
  90.     }  
  91.   
  92.     ......  
  93. }  

        這個函數主要就是把前面解析應用程序得到的package、provider、service、receiver和activity等信息保存在PackageManagerService服務中了。

 

from:http://blog.csdn.net/xuhui_7810/article/details/11654577


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM