標籤:android style blog class c code
在windowphone,ios和android中到目前為止,還是android的市場份額最大。個人認為除了google開源外,廣大開發人員早就了android的霸主地位。各位兄弟姐妹開發出各種各樣的apk,才組成android的廣闊天下。本篇主要分析一下android系統是針對處理這些apk的,主要涉及到pm這塊的代碼。分析這種底層服務,最好從android的開啟啟動流程中開始分析。因為這樣才能更清楚的瞭解服務的啟動流程。
1.在SystemServer.java 中啟動PM
android 開機啟動後載入的第一個java的程式就是SystemServer,在包含android系統的最主要的一些底層服務。在4.4kk之前都是建一個Thread線程來啟動。4.4KK的啟動機制就變了,具體後續的文章會講解。
Installer installer = null; Slog.i(TAG, "Waiting for installd to be ready."); installer = new Installer(); installer.ping(); pm = PackageManagerService.main(context, installer, factoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore); boolean firstBoot = false; try { firstBoot = pm.isFirstBoot(); } catch (RemoteException e) { }
public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }在systemServer中初始化了Installer,並將它傳入PackageManagerService.main()中。在main函數中將pm添加到ServiceManager中,供開發人員調用。
2.PackageManagerService啟動安裝分析
啟動PackageManagerService後,主要完成以下幾個步驟
2.1.初始化PackageSetting,設定sharedUserID
mSettings = new Settings(context); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);2.2.擷取螢幕參數:
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Display d = wm.getDefaultDisplay(); d.getMetrics(mMetrics);
2.3.使用HandlerThread開啟packagemanager背景工作執行緒和初始化app目錄
mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); mAppInstallDir = new File(dataDir, "app"); mAppLibInstallDir = new File(dataDir, "app-lib"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
2.4.載入Framework的主要jar和BOOTCLASSPATH
mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); mDalvikCacheDir = new File(dataDir, "dalvik-cache"); boolean didDexOpt = false; /** * Out of paranoia, ensure that everything in the boot class * path has been dexed. */ String bootClassPath = System.getProperty("java.boot.class.path");2.5.安裝system/app,vendor/app和data/app目錄下apk
// Collect all system packages. mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching(); scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all vendor packages. mVendorAppDir = new File("/vendor/app"); mVendorInstallObserver = new AppDirObserver( mVendorAppDir.getPath(), OBSERVER_EVENTS, true); mVendorInstallObserver.startWatching(); scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);...... mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false); mAppInstallObserver.startWatching(); scanDirLI(mAppInstallDir, 0, scanMode, 0);
其中具體如果安裝代碼在scanDirLI()函數,最終調用scanPackageLI()進行安裝。在安裝過程中會搜集ApplicationInfo和ActivityInfo資訊,比較簽名,匹配本地so的目錄。
具體細節參看PackageManagerService.java 中的
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
函數。
3.在Activity使用PackageManger的分析
我們在應用經常通過
PackageManager pm = this.getPackageManager() 來擷取pm。這部分主要從它的來源來深入分析。
由於我們在Activity中使用this來擷取pm,很容易想到到context類裡去尋找實現。
/** Return PackageManager instance to find global package information. */ public abstract PackageManager getPackageManager();
但是context是虛函數,因此要找到它的實現,由於context的實現採用 設計模式裡面的 "橋接模式‘ 因此很容易想到從contextImpl.java 中尋找實現。
果然找到。
public PackageManager getPackageManager() { if (mPackageManager != null) { return mPackageManager; } IPackageManager pm = ActivityThread.getPackageManager(); if (pm != null) { // Doesn‘t matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; }
從代碼上看擷取IPackageManager,還是需要從ActivityThread中擷取。我在Activity裡面擷取嗎出現在ActivityThread 也不意外。
那我們就看看他是怎麼實現的
public static IPackageManager getPackageManager() { if (sPackageManager != null) { //Slog.v("PackageManager", "returning cur default = " + sPackageManager); return sPackageManager; } IBinder b = ServiceManager.getService("package"); //Slog.v("PackageManager", "default service binder = " + b); sPackageManager = IPackageManager.Stub.asInterface(b); //Slog.v("PackageManager", "default service = " + sPackageManager); return sPackageManager; }原來是通過ServiceManager.getService("package").從上你們的代碼知道,這句其實就是擷取PackageManagerService 並賦給IBinder ,成為一個binder對象。
通過asInterface()函數,通過binder對象擷取介面類IPackageManager的執行個體。並返回回去。
if (pm != null) { // Doesn‘t matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); }
在接著同ApplicationPackageManager 建立PackageManager 對象。到此我們在Activity中就可以使用pm這個對象作業系統中的各種包。
4.Android 系統中PackageManager的關鍵類和UML的類圖。
在pm中主要涉及的類和路徑如下:
frameworks\base\services\java\com\android\server\pm\PackageManagerService.java 和 其他檔案
frameworks\base\core\java\android\content\pm\IPackageManager.aidl
frameworks\base\core\java\android\app\ActivityThread.java ,context.java ,contextimpl.java
frameworks\base\core\java\android\content\pm\PackageManager.java