這裏主要介紹 PackageManagerService(簡稱PMS)的啓動 和 一個應用的安裝過程。這裏只是大體總結,供參考,很多地方一樣須要進一步深刻了解學習的。
該篇相關代碼也是基於AndroidQ的。html
PMS也是核心服務之一,管理包相關內容,解析AndroidManifest.xml、管理應用等,最多見的是應用的安裝和卸載。
和AMS相似,PMS提供服務也是經過binder完成,也有相應的服務端和客戶端。java
PMS的幾個相關類:
IPackageManager.aidl:接口,定義了服務端和客戶端之間通訊的函數方法。
PackageManagerService:服務端。繼承IPackageManager.Stub,繼承Binder。
PackageManager:抽象類,對外的接口(可調用,SDK)。能夠經過Context#getPackageManager獲取,能夠看下下面源碼中關於PackageManager的註釋部分。
ApplicationPackageManager:客戶端。PackageManager實現類,經過內部的mPM變量參與Binder通訊。android
//PackageManager.java /** * Class for retrieving various kinds of information related to the application * packages that are currently installed on the device. * * You can find this class through {@link Context#getPackageManager}. */ public abstract class PackageManager { ...... } //ApplicationPackageManager.java protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; }
以前已經總結過 AMS的啓動過程 以及 應用的第一次啓動過程 ,比較詳細,關於PMS的啓動就容易理解了。
PMS啓動過程 和 AMS啓動過程 相似,都是在SystemServer啓動以後完成的,若想詳細瞭解能夠先參考AMS的啓動過程瞭解下,關於PMS的啓動這裏就大體說明下。shell
PMS的啓動也是在SystemServer啓動以後,也屬於引導服務,在startBootstrapServices()中啓動。session
//SystemServer.java private void startBootstrapServices() { ...... //Installer服務,真正安裝的服務,與installd交互 Installer installer = mSystemServiceManager.startService(Installer.class); ...... //標記1 mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); ...... //標記2 mPackageManager = mSystemContext.getPackageManager(); } private void startOtherServices() { ...... //完成dex優化 mPackageManagerService.updatePackagesIfNeeded(); ...... //清理磁盤,釋放空間 mPackageManagerService.performFstrimIfNeeded(); ...... //PMS準備就緒 mPackageManagerService.systemReady(); ...... }
能夠看註釋大體瞭解下。
這裏主要看下標記1和標記2處,PackageManagerService.main()
和mSystemContext.getPackageManager()
。app
先看下mSystemContext.getPackageManager(),一路看下去,就看到以下代碼。即Context#getPackageManager
是建立了ApplicationPackageManager,mPM獲得賦值 IPackageManager對象,能夠經過mPm參與PMS通訊。less
//ContextImpl.java @Override 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; }
這是真正建立PMS服務,並啓動。dom
//PackageManagerService.java public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); //初始化PMS PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); m.enableSystemUserPackages(); //註冊服務 package ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); //註冊服務 package_native ServiceManager.addService("package_native", pmn); return m; }
這裏很簡單,主要檢查PMS環境,然建立並註冊了兩個服務package和package_native。
接下來主要看 建立PMS對象過程作了些什麼。異步
PMS的構造方法很長,下面摺疊起來了,要了解能夠打開。async
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); if (mSdkVersion <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); } mContext = context; mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = new DisplayMetrics(); mInstaller = installer; // Create sub-components that provide services / data. Order here is important. synchronized (mInstallLock) { synchronized (mPackages) { // Expose private service for system components to use. LocalServices.addService( PackageManagerInternal.class, new PackageManagerInternalImpl()); sUserManager = new UserManagerService(context, this, new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages); mComponentResolver = new ComponentResolver(sUserManager, LocalServices.getService(PackageManagerInternal.class), mPackages); mPermissionManager = PermissionManagerService.create(context, mPackages /*externalLock*/); mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy(); mSettings = new Settings(Environment.getDataDirectory(), mPermissionManager.getPermissionSettings(), mPackages); } } mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.se", SE_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; mSeparateProcesses = null; Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); } else { mDefParseFlags = 0; mSeparateProcesses = separateProcesses.split(","); Slog.w(TAG, "Running with debug.separate_processes: " + separateProcesses); } } else { mDefParseFlags = 0; mSeparateProcesses = null; } mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context, "*dexopt*"); mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock); mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock); mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper()); mViewCompiler = new ViewCompiler(mInstallLock, mInstaller); mOnPermissionChangeListeners = new OnPermissionChangeListeners( FgThread.get().getLooper()); getDefaultDisplayMetrics(context, mMetrics); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config"); SystemConfig systemConfig = SystemConfig.getInstance(); mAvailableFeatures = systemConfig.getAvailableFeatures(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); mProtectedPackages = new ProtectedPackages(mContext); mApexManager = new ApexManager(context); synchronized (mInstallLock) { // writer synchronized (mPackages) { mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); mProcessLoggingHandler = new ProcessLoggingHandler(); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); mInstantAppRegistry = new InstantAppRegistry(this); ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig = systemConfig.getSharedLibraries(); final int builtInLibCount = libConfig.size(); for (int i = 0; i < builtInLibCount; i++) { String name = libConfig.keyAt(i); SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i); addBuiltInSharedLibraryLocked(entry.filename, name); } // Now that we have added all the libraries, iterate again to add dependency // information IFF their dependencies are added. long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED; for (int i = 0; i < builtInLibCount; i++) { String name = libConfig.keyAt(i); SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i); final int dependencyCount = entry.dependencies.length; for (int j = 0; j < dependencyCount; j++) { final SharedLibraryInfo dependency = getSharedLibraryInfoLPr(entry.dependencies[j], undefinedVersion); if (dependency != null) { getSharedLibraryInfoLPr(name, undefinedVersion).addDependency(dependency); } } } SELinuxMMAC.readInstallPolicy(); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks"); FallbackCategoryProvider.loadFallbacks(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings"); mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Clean up orphaned packages for which the code path doesn't exist // and they are an update to a system app - caused by bug/32321269 final int packageSettingCount = mSettings.mPackages.size(); for (int i = packageSettingCount - 1; i >= 0; i--) { PackageSetting ps = mSettings.mPackages.valueAt(i); if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists()) && mSettings.getDisabledSystemPkgLPr(ps.name) != null) { mSettings.mPackages.removeAt(i); mSettings.enableSystemPackageLPw(ps.name); } } if (!mOnlyCore && mFirstBoot) { requestCopyPreoptedFiles(); } String customResolverActivityName = Resources.getSystem().getString( R.string.config_customResolverActivity); if (!TextUtils.isEmpty(customResolverActivityName)) { mCustomResolverComponentName = ComponentName.unflattenFromString( customResolverActivityName); } long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); final String bootClassPath = System.getenv("BOOTCLASSPATH"); final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH"); if (bootClassPath == null) { Slog.w(TAG, "No BOOTCLASSPATH found!"); } if (systemServerClassPath == null) { Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!"); } File frameworkDir = new File(Environment.getRootDirectory(), "framework"); final VersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint); if (mIsUpgrade) { logCriticalInfo(Log.INFO, "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT); } // when upgrading from pre-M, promote system app permissions from install to runtime mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1; // When upgrading from pre-N, we need to handle package extraction like first boot, // as there is no profiling data available. mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N; mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1; mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q; int preUpgradeSdkVersion = ver.sdkVersion; // save off the names of pre-existing system packages prior to scanning; we don't // want to automatically grant runtime permissions for new system apps if (mPromoteSystemApps) { Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator(); while (pkgSettingIter.hasNext()) { PackageSetting ps = pkgSettingIter.next(); if (isSystemApp(ps)) { mExistingSystemPackages.add(ps.name); } } } mCacheDir = preparePackageParserCache(); // Set flag to monitor and not change apk file paths when // scanning install directories. int scanFlags = SCAN_BOOTING | SCAN_INITIAL; if (mIsUpgrade || mFirstBoot) { scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } // Collect vendor/product/product_services overlay packages. (Do this before scanning // any apps.) // For security and version matching reason, only consider overlay packages if they // reside in the right directory. scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR, 0); scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT, 0); scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES, 0); scanDirTracedLI(new File(ODM_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_ODM, 0); scanDirTracedLI(new File(OEM_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_OEM, 0); mParallelPackageParserCallback.findStaticOverlayPackages(); // Find base frameworks (resource packages without code). scanDirTracedLI(frameworkDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_NO_DEX | SCAN_AS_SYSTEM | SCAN_AS_PRIVILEGED, 0); if (!mPackages.containsKey("android")) { throw new IllegalStateException( "Failed to load frameworks package; check log for warnings"); } // Collect privileged system packages. final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); scanDirTracedLI(privilegedAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRIVILEGED, 0); // Collect ordinary system packages. final File systemAppDir = new File(Environment.getRootDirectory(), "app"); scanDirTracedLI(systemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM, 0); // Collect privileged vendor packages. File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); try { privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(privilegedVendorAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR | SCAN_AS_PRIVILEGED, 0); // Collect ordinary vendor packages. File vendorAppDir = new File(Environment.getVendorDirectory(), "app"); try { vendorAppDir = vendorAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(vendorAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR, 0); // Collect privileged odm packages. /odm is another vendor partition // other than /vendor. File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app"); try { privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(privilegedOdmAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR | SCAN_AS_PRIVILEGED, 0); // Collect ordinary odm packages. /odm is another vendor partition // other than /vendor. File odmAppDir = new File(Environment.getOdmDirectory(), "app"); try { odmAppDir = odmAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(odmAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR, 0); // Collect all OEM packages. final File oemAppDir = new File(Environment.getOemDirectory(), "app"); scanDirTracedLI(oemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_OEM, 0); // Collected privileged /product packages. File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); try { privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(privilegedProductAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT | SCAN_AS_PRIVILEGED, 0); // Collect ordinary /product packages. File productAppDir = new File(Environment.getProductDirectory(), "app"); try { productAppDir = productAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(productAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT, 0); // Collected privileged /product_services packages. File privilegedProductServicesAppDir = new File(Environment.getProductServicesDirectory(), "priv-app"); try { privilegedProductServicesAppDir = privilegedProductServicesAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(privilegedProductServicesAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES | SCAN_AS_PRIVILEGED, 0); // Collect ordinary /product_services packages. File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app"); try { productServicesAppDir = productServicesAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } scanDirTracedLI(productServicesAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES, 0); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); // Stub packages must either be replaced with full versions in the /data // partition or be disabled. final List<String> stubSystemApps = new ArrayList<>(); if (!mOnlyCore) { // do this first before mucking with mPackages for the "expecting better" case final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator(); while (pkgIterator.hasNext()) { final PackageParser.Package pkg = pkgIterator.next(); if (pkg.isStub) { stubSystemApps.add(pkg.packageName); } } final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); /* * If this is not a system app, it can't be a * disable system app. */ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } /* * If the package is scanned, it's not erased. */ final PackageParser.Package scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. */ if (mSettings.isDisabledSystemPackageLPr(ps.name)) { logCriticalInfo(Log.WARN, "Expecting better updated system app for " + ps.name + "; removing system app. Last known" + " codePath=" + ps.codePathString + ", versionCode=" + ps.versionCode + "; scanned versionCode=" + scannedPkg.getLongVersionCode()); removePackageLI(scannedPkg, true); mExpectingBetter.put(ps.name, ps.codePath); } continue; } if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); logCriticalInfo(Log.WARN, "System package " + ps.name + " no longer exists; it's data will be wiped"); // Actual deletion of code and data will be handled by later // reconciliation step } else { // we still have a disabled system package, but, it still might have // been removed. check the code path still exists and check there's // still a package. the latter can happen if an OTA keeps the same // code path, but, changes the package name. final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); } else { // We're expecting that the system app should remain disabled, but add // it to expecting better to recover in case the data version cannot // be scanned. mExpectingBetter.put(disabledPs.name, disabledPs.codePath); } } } } //delete tmp files deleteTempPackageFiles(); final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get(); // Remove any shared userIDs that have no associated packages mSettings.pruneSharedUsersLPw(); final long systemScanTime = SystemClock.uptimeMillis() - startTime; final int systemPackagesCount = mPackages.size(); Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime + " ms, packageCount: " + systemPackagesCount + " , timePerPackage: " + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount) + " , cached: " + cachedSystemApps); if (mIsUpgrade && systemPackagesCount > 0) { MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time", ((int) systemScanTime) / systemPackagesCount); } if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) { final String packageName = possiblyDeletedUpdatedSystemApps.get(i); final PackageParser.Package pkg = mPackages.get(packageName); final String msg; // remove from the disabled system list; do this first so any future // scans of this package are performed without this state mSettings.removeDisabledSystemPackageLPw(packageName); if (pkg == null) { // should have found an update, but, we didn't; remove everything msg = "Updated system package " + packageName + " no longer exists; removing its data"; // Actual deletion of code and data will be handled by later // reconciliation step } else { // found an update; revoke system privileges msg = "Updated system package " + packageName + " no longer exists; rescanning package on data"; // NOTE: We don't do anything special if a stub is removed from the // system image. But, if we were [like removing the uncompressed // version from the /data partition], this is where it'd be done. // remove the package from the system and re-scan it without any // special privileges removePackageLI(pkg, true); try { final File codePath = new File(pkg.applicationInfo.getCodePath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " + e.getMessage()); } } // one final check. if we still have a package setting [ie. it was // previously scanned and known to the system], but, we don't have // a package [ie. there was an error scanning it from the /data // partition], completely remove the package data. final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null && mPackages.get(packageName) == null) { removePackageDataLIF(ps, null, null, 0, false); } logCriticalInfo(Log.WARN, msg); } /* * Make sure all system apps that we expected to appear on * the userdata partition actually showed up. If they never * appeared, crawl back and revive the system version. */ for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i); if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i); logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system"); final @ParseFlags int reparseFlags; final @ScanFlags int rescanFlags; if (FileUtils.contains(privilegedAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRIVILEGED; } else if (FileUtils.contains(systemAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM; } else if (FileUtils.contains(privilegedVendorAppDir, scanFile) || FileUtils.contains(privilegedOdmAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR | SCAN_AS_PRIVILEGED; } else if (FileUtils.contains(vendorAppDir, scanFile) || FileUtils.contains(odmAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_VENDOR; } else if (FileUtils.contains(oemAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_OEM; } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT | SCAN_AS_PRIVILEGED; } else if (FileUtils.contains(productAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT; } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES | SCAN_AS_PRIVILEGED; } else if (FileUtils.contains(productServicesAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES; } else { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; } mSettings.enableSystemPackageLPw(packageName); try { scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse original system package: " + e.getMessage()); } } } // Uncompress and install any stubbed system applications. // This must be done last to ensure all stubs are replaced or disabled. installSystemStubPackages(stubSystemApps, scanFlags); final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get() - cachedSystemApps; final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime; final int dataPackagesCount = mPackages.size() - systemPackagesCount; Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime + " ms, packageCount: " + dataPackagesCount + " , timePerPackage: " + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount) + " , cached: " + cachedNonSystemApps); if (mIsUpgrade && dataPackagesCount > 0) { MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time", ((int) dataScanTime) / dataPackagesCount); } } mExpectingBetter.clear(); // Resolve the storage manager. mStorageManagerPackage = getStorageManagerPackageName(); // Resolve protected action filters. Only the setup wizard is allowed to // have a high priority filter for these actions. mSetupWizardPackage = getSetupWizardPackageName(); mComponentResolver.fixProtectedFilterPriorities(); mSystemTextClassifierPackage = getSystemTextClassifierPackageName(); mWellbeingPackage = getWellbeingPackageName(); mDocumenterPackage = getDocumenterPackageName(); mConfiguratorPackage = getDeviceConfiguratorPackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); // Now that we know all of the shared libraries, update all clients to have // the correct library paths. updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages)); for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { // NOTE: We ignore potential failures here during a system scan (like // the rest of the commands above) because there's precious little we // can do about it. A settings error is reported, though. final List<String> changedAbiCodePath = adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/); if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { final String codePathString = changedAbiCodePath.get(i); try { mInstaller.rmdex(codePathString, getDexCodeInstructionSet(getPreferredInstructionSet())); } catch (InstallerException ignored) { } } } // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same // SELinux domain. setting.fixSeInfoLocked(); } // Now that we know all the packages we are keeping, // read and update their last usage times. mPackageUsage.read(mPackages); mCompilerStats.read(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); // If the platform SDK has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some // cases get permissions that the user didn't initially explicitly // allow... it would be nice to have some better way to handle // this situation. final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion); if (sdkUpdated) { Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to " + mSdkVersion + "; regranting permissions for internal storage"); } mPermissionManager.updateAllPermissions( StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(), mPermissionCallback); ver.sdkVersion = mSdkVersion; // If this is the first boot or an update from pre-M, and it is a normal // boot, then we need to initialize the default preferred apps across // all defined users. if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) { for (UserInfo user : sUserManager.getUsers(true)) { mSettings.applyDefaultPreferredAppsLPw(user.id); primeDomainVerificationsLPw(user.id); } } // Prepare storage for system user really early during boot, // since core system apps like SettingsProvider and SystemUI // can't wait for user to start final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated()) { storageFlags = StorageManager.FLAG_STORAGE_DE; } else { storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, true /* onlyCoreApps */); mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(() -> { TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync", Trace.TRACE_TAG_PACKAGE_MANAGER); traceLog.traceBegin("AppDataFixup"); try { mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); } catch (InstallerException e) { Slog.w(TAG, "Trouble fixing GIDs", e); } traceLog.traceEnd(); traceLog.traceBegin("AppDataPrepare"); if (deferPackages == null || deferPackages.isEmpty()) { return; } int count = 0; for (String pkgName : deferPackages) { PackageParser.Package pkg = null; synchronized (mPackages) { PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) { pkg = ps.pkg; } } if (pkg != null) { synchronized (mInstallLock) { prepareAppDataAndMigrateLIF(pkg, UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */); } count++; } } traceLog.traceEnd(); Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages"); }, "prepareAppData"); // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. // Note that we do *not* clear the application profiles. These remain valid // across OTAs and are used to drive profile verification (post OTA) and // profile compilation (without waiting to collect a fresh set of profiles). if (mIsUpgrade && !onlyCore) { Slog.i(TAG, "Build fingerprint changed; clearing code caches"); for (int i = 0; i < mSettings.mPackages.size(); i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) { // No apps are running this early, so no need to freeze clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } } ver.fingerprint = Build.FINGERPRINT; } // Grandfather existing (installed before Q) non-system apps to hide // their icons in launcher. if (!onlyCore && mIsPreQUpgrade) { Slog.i(TAG, "Whitelisting all existing apps to hide their icons"); int size = mSettings.mPackages.size(); for (int i = 0; i < size; i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { continue; } ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME, UserHandle.USER_SYSTEM); } } // clear only after permissions and other defaults have been updated mExistingSystemPackages.clear(); mPromoteSystemApps = false; // All the changes are done during package scanning. ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION; // can downgrade to reader Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "write settings"); mSettings.writeLPr(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); if (!mOnlyCore) { mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(); mRequiredInstallerPackage = getRequiredInstallerLPr(); mRequiredUninstallerPackage = getRequiredUninstallerLPr(); mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); if (mIntentFilterVerifierComponent != null) { mIntentFilterVerifier = new IntentVerifierProxy(mContext, mIntentFilterVerifierComponent); } else { mIntentFilterVerifier = null; } mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES, SharedLibraryInfo.VERSION_UNDEFINED); mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( PackageManager.SYSTEM_SHARED_LIBRARY_SHARED, SharedLibraryInfo.VERSION_UNDEFINED); } else { mRequiredVerifierPackage = null; mRequiredInstallerPackage = null; mRequiredUninstallerPackage = null; mIntentFilterVerifierComponent = null; mIntentFilterVerifier = null; mServicesSystemSharedLibraryPackageName = null; mSharedSystemSharedLibraryPackageName = null; } // PermissionController hosts default permission granting and role management, so it's a // critical part of the core system. mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(); // Initialize InstantAppRegistry's Instant App list for all users. final int[] userIds = UserManagerService.getInstance().getUserIds(); for (PackageParser.Package pkg : mPackages.values()) { if (pkg.isSystem()) { continue; } for (int userId : userIds) { final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) { continue; } mInstantAppRegistry.addInstantAppLPw(userId, ps.appId); } } mInstallerService = new PackageInstallerService(context, this, mApexManager); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { if (DEBUG_INSTANT) { Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent); } mInstantAppResolverConnection = new InstantAppResolverConnection( mContext, instantAppResolverComponent.first, instantAppResolverComponent.second); mInstantAppResolverSettingsComponent = getInstantAppResolverSettingsLPr(instantAppResolverComponent.first); } else { mInstantAppResolverConnection = null; mInstantAppResolverSettingsComponent = null; } updateInstantAppInstallerLocked(null); // Read and update the usage of dex files. // Do this at the end of PM init so that all the packages have their // data directory reconciled. // At this point we know the code paths of the packages, so we can validate // the disk file and build the internal cache. // The usage file is expected to be small so loading and verifying it // should take a fairly small time compare to the other activities (e.g. package // scanning). final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>(); for (int userId : userIds) { userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList()); } mDexManager.load(userPackages); if (mIsUpgrade) { MetricsLogger.histogram(null, "ota_package_manager_init_time", (int) (SystemClock.uptimeMillis() - startTime)); } } // synchronized (mPackages) } // synchronized (mInstallLock) mModuleInfoProvider = new ModuleInfoProvider(mContext, this); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and // tidy. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "GC"); Runtime.getRuntime().gc(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // The initial scanning above does many calls into installd while // holding the mPackages lock, but we're mostly interested in yelling // once we have a booted system. mInstaller.setWarnIfHeld(mPackages); PackageParser.readConfigUseRoundIcon(mContext.getResources()); mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }
從構造方法中的EventLogTags的標記,大體分爲5個階段,根據這個大體瞭解下。
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
掃描系統目錄中的app等,經過scanDirTracedLI()方法。
這個階段主要掃描的路徑是:/vendor/overlay;/product/overlay;/product_services/overlay;/odm/overlay;/oem/overlay;/system/framework;/system/priv-app;/system/app;/vendor/priv-app;/vendor/app;/odm/priv-app;/odm/app;/oem/app;/product/priv-app;/product/app;/product_services/priv-app;/product_services/app;
歸納起來,就是vendor/product/product_services/odm/oem下的overlay目錄;/system/framework/;system/vendor/odm/oem/product/product_services下的priv-app和app目錄(沒有/oem/priv-app)。
BOOT_PROGRESS_PMS_DATA_SCAN_START
掃描非系統目錄app等。
這個階段主要掃描目錄:/data/app;
BOOT_PROGRESS_PMS_SCAN_END
掃描完成,將結果寫入文件中。
經過mSettings.writeLPr();
方法。寫入到文件:/data/system/packages.xml和/data/system/packages.list。
安裝、卸載等都會更新這個目錄。
BOOT_PROGRESS_PMS_READY
PMS準備完成,建立PackageInstallerService服務。mInstallerService = new PackageInstallerService(context, this, mApexManager);
。
題外話:
apex是 AndroidQ開始提出的mainline計劃後 而有的一種新格式,google將framework也分紅一個個小模塊,最終但願經過play store對system的核心內容的進行更新,不須要odm、oem干預。而這一個個模塊與apk應用不一樣,所以有了apex這種格式。其實google在Android O開始就再弄的Treble計劃,一步步將system與vendor分開了獨立,最終整個系統能夠直接使用一套公共的system.img即GSI(Generic System Image)。在Android R開始,kernel部分也開始使用這套,弄一套通用內核鏡像GKI(Generic Kernel Image)。 Android各個版本之間變更是很是大的,可能用戶感覺不到。爲了實現這些,引入了不少新的概念和技術。
/data/system/packages.xml,在 Android調試很是有用的命令集 總結中也提到過,這裏就是該文件內容是什麼,怎麼來的。
因此預置應用越多,掃描時間會越長,影響開機時間。
應用的安裝,最多見的是點擊apk後的有界面的安裝 和 開發中經過adb命令的靜默安裝。
下面關於這兩種安裝方式,簡單說明下。
這個過程經過系統預置的PackageInstaller.apk或相似應用完成。
點擊apk,進行一些驗證後跳轉到了PackageInstallerActivity,即彈出的」是否安裝此應用「的確認安裝界面。點擊確認安裝後,進入了InstallInstalling。
點擊apk進行安裝,PackageInstaller.apk是從InstallStart->PackageInstallerActivity->InstallInstalling。
注:這裏以aosp中的PackageInstaller.apk說明(com.android.packageinstaller),在外單中 通常預置的是GMS包中的GooglePackageInstaller。
下面是大體的代碼過程的關鍵代碼:
//InstallStart.java protected void onCreate(@Nullable Bundle savedInstanceState) { Intent nextActivity = new Intent(intent); ..... if (isSessionInstall) { nextActivity.setClass(this, PackageInstallerActivity.class); } ...... if (nextActivity != null) { startActivity(nextActivity); } } //PackageInstallerActivity.java protected void onCreate(Bundle icicle) { ....... bindUi(); } private void bindUi() { ...... mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install), (ignored, ignored2) -> { if (mOk.isEnabled()) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); } else { startInstall(); } } }, null); ...... } private void startInstall() { Intent newIntent = new Intent(); newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); newIntent.setClass(this, InstallInstalling.class); ...... startActivity(newIntent); finish(); }
能夠清晰看到,點擊確認安裝後,經過startInstall()方法進入了InstallInstalling。
接着看InstallInstalling的處理:
//InstallInstalling.java protected void onCreate(@Nullable Bundle savedInstanceState) { ...... mPackageURI = getIntent().getData(); if ("package".equals(mPackageURI.getScheme())) { ....... } else { ...... if (savedInstanceState != null) { ...... } else { ...... try { mInstallId = InstallEventReceiver .addObserver(this, EventResultPersister.GENERATE_NEW_ID, this::launchFinishBasedOnResult); } catch (EventResultPersister.OutOfIdsException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } try { mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE); mSessionCallback = new InstallSessionCallback(); } } @Override protected void onResume() { super.onResume(); // This is the first onResume in a single life of the activity if (mInstallingTask == null) { PackageInstaller installer = getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId); if (sessionInfo != null && !sessionInfo.isActive()) { mInstallingTask = new InstallingAsyncTask(); mInstallingTask.execute(); } else { // we will receive a broadcast when the install is finished mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } } }
onCreate()中建立了一個安裝會話並返回得到一個sessionId。onResume()中進行進一步安裝。
先看onCreate()中建立安裝會話,返回的sessionId很重要。
InstallEventReceiver是一個BroadcastReceiver,接收安裝事件並回調給EventResultPersister。mSessionId是安裝的會話id。
添加log能夠看到,mPackageURI.getScheme()
的值是"file"。最後關鍵執行到的是getPackageManager().getPackageInstaller().createSession(params)
這句。
getPackageManager()獲取PM對象,而後調用實現類ApplicationPackageManager中getPackageInstaller()獲得的是PackageInstaller對象。最終調用的是PackageInstaller中的createSession()建立安裝會話並返回sessionId。這裏不列出代碼,直接看createSession()方法。
//PackageInstaller.java //frameworks/base/core/java/android/content/pm/PackageInstaller.java private final IPackageInstaller mInstaller; public int createSession(@NonNull SessionParams params) throws IOException { try { final String installerPackage; ...... return mInstaller.createSession(params, installerPackage, mUserId); } ...... }
注意,這裏調用的是mInstaller.createSession()。mInstaller是IPackageInstaller,一看就知道這也是經過binder調用的一個服務,這個服務是PackageInstallerService,即最終調用的是PackageInstallerService的createSession()方法建立了一個安裝會話 並 返回了sessionId。
這裏不細述建立安裝會話的過程了。
接着看onResume()。這裏主要是看mInstallingTask.execute()
。
/** * Send the package to the package installer and then register a event result observer that * will call {@link #launchFinishBasedOnResult(int, int, String)} */ private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> { volatile boolean isDone; @Override protected PackageInstaller.Session doInBackground(Void... params) { PackageInstaller.Session session; try { session = getPackageManager().getPackageInstaller().openSession(mSessionId); } catch (IOException e) { return null; } session.setStagingProgress(0); try { File file = new File(mPackageURI.getPath()); try (InputStream in = new FileInputStream(file)) { long sizeBytes = file.length(); try (OutputStream out = session .openWrite("PackageInstaller", 0, sizeBytes)) { byte[] buffer = new byte[1024 * 1024]; while (true) { int numRead = in.read(buffer); if (numRead == -1) { session.fsync(out); break; } if (isCancelled()) { session.close(); break; } out.write(buffer, 0, numRead); if (sizeBytes > 0) { float fraction = ((float) numRead / (float) sizeBytes); session.addProgress(fraction); } } } } return session; } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Could not write package", e); session.close(); return null; } finally { synchronized (this) { isDone = true; notifyAll(); } } } @Override protected void onPostExecute(PackageInstaller.Session session) { if (session != null) { Intent broadcastIntent = new Intent(BROADCAST_ACTION); broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntent.setPackage(getPackageName()); broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId); PendingIntent pendingIntent = PendingIntent.getBroadcast( InstallInstalling.this, mInstallId, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } else { getPackageManager().getPackageInstaller().abandonSession(mSessionId); if (!isCancelled()) { launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null); } } } }
InstallingAsyncTask是個異步任務。
doInBackground中,apk的信息(經過URI獲取)經過IO流寫入到PackageInstaller.Session中。在onPostExecute中,經過session.commit()發送安裝。
Session就是經過sessionId獲取打開的。
接下來主要看發送安裝。
//frameworks/base/core/java/android/content/pm/PackageInstaller.java public static class Session implements Closeable { protected final IPackageInstallerSession mSession; public void commit(@NonNull IntentSender statusReceiver) { try { mSession.commit(statusReceiver, false); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } //PackageInstallerSession.java public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { ...... if (!markAsCommitted(statusReceiver, forTransfer)) { return; } if (isMultiPackage()) { final SparseIntArray remainingSessions = mChildSessionIds.clone(); final IntentSender childIntentSender = new ChildStatusIntentReceiver(remainingSessions, statusReceiver) .getIntentSender(); RuntimeException commitException = null; boolean commitFailed = false; for (int i = mChildSessionIds.size() - 1; i >= 0; --i) { final int childSessionId = mChildSessionIds.keyAt(i); try { // commit all children, regardless if any of them fail; we'll throw/return // as appropriate once all children have been processed if (!mSessionProvider.getSession(childSessionId) .markAsCommitted(childIntentSender, forTransfer)) { commitFailed = true; } } catch (RuntimeException e) { commitException = e; } } if (commitException != null) { throw commitException; } if (commitFailed) { return; } } mHandler.obtainMessage(MSG_COMMIT).sendToTarget(); } }
最終調用到PackageInstallerSession中的commit()。主要看mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
,即經過Handler發送了MSG_COMMIT的消息,進程間通訊。
接着看消息處理代碼:
//PackageInstallerSession.java private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_COMMIT: handleCommit(); break; ...... } return true; } }; private void handleCommit() { ...... // For a multiPackage session, read the child sessions // outside of the lock, because reading the child // sessions with the lock held could lead to deadlock // (b/123391593). List<PackageInstallerSession> childSessions = getChildSessions(); try { synchronized (mLock) { commitNonStagedLocked(childSessions); } } catch (PackageManagerException e) { ...... } } @GuardedBy("mLock") private void commitNonStagedLocked(List<PackageInstallerSession> childSessions) throws PackageManagerException { final PackageManagerService.ActiveInstallSession committingSession = makeSessionActiveLocked(); if (committingSession == null) { return; } if (isMultiPackage()) { List<PackageManagerService.ActiveInstallSession> activeChildSessions = new ArrayList<>(childSessions.size()); boolean success = true; PackageManagerException failure = null; for (int i = 0; i < childSessions.size(); ++i) { final PackageInstallerSession session = childSessions.get(i); try { final PackageManagerService.ActiveInstallSession activeSession = session.makeSessionActiveLocked(); if (activeSession != null) { activeChildSessions.add(activeSession); } } catch (PackageManagerException e) { failure = e; success = false; } } if (!success) { try { mRemoteObserver.onPackageInstalled( null, failure.error, failure.getLocalizedMessage(), null); } catch (RemoteException ignored) { } return; } mPm.installStage(activeChildSessions); } else { mPm.installStage(committingSession); } }
很清晰,最終經過mPm.installStage() 進入PMS進行處理。
直接看PMS的installStage()。
//PackageManagerService.java void installStage(ActiveInstallSession activeInstallSession) { if (DEBUG_INSTANT) { if ((activeInstallSession.getSessionParams().installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName()); } } final Message msg = mHandler.obtainMessage(INIT_COPY); final InstallParams params = new InstallParams(activeInstallSession); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } class PackageHandler extends Handler { void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; if (params != null) { if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy"); params.startCopy(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } break; } ...... } } }
經過Handler發送了INIT_COPY消息,開始拷貝apk到執行地方進行進一步安裝。
看startCopy():
//PackageManagerService.java private abstract class HandlerParams { final void startCopy() { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy(); handleReturnCode(); } abstract void handleStartCopy(); abstract void handleReturnCode(); } class InstallParams extends HandlerParams { @Override public void handleStartCopy() { int ret = PackageManager.INSTALL_SUCCEEDED; // If we're already staged, we've firmly committed to an install location ...... /* * If we have too little free space, try to free cache * before giving up. */ ...... if (ret == PackageManager.INSTALL_SUCCEEDED) { int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { ret = PackageManager.INSTALL_FAILED_INVALID_APK; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { ret = PackageManager.INSTALL_FAILED_INVALID_URI; } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; } else { // Override with defaults if needed. ...... } } final InstallArgs args = createInstallArgs(this); mVerificationCompleted = true; mEnableRollbackCompleted = true; Args = args; ...... mRet = ret; } @Override void handleReturnCode() { if (mVerificationCompleted && mEnableRollbackCompleted) { ...... if (mRet == PackageManager.INSTALL_SUCCEEDED) { mRet = mArgs.copyApk(); } processPendingInstall(mArgs, mRet); } } }
startCopy()只有兩個方法,handleStartCopy()和handleReturnCode()。
handleStartCopy()中進行安裝前的各類驗證,檢查文件、空間、發送給全部sufficientVerifiers進行驗證。 驗證成功,即mRet == PackageManager.INSTALL_SUCCEEDED
,在handleReturnCode()中進行apk拷貝工做。
接着看下handleReturnCode()中的拷貝apk操做:mArgs.copyApk()
。
mArgs這裏是FileInstallArgs。
//PackageManagerService.java private InstallArgs createInstallArgs(InstallParams params) { if (params.move != null) { return new MoveInstallArgs(params); } else { return new FileInstallArgs(params); } } //PackageManagerService.java class FileInstallArgs extends InstallArgs { int copyApk() { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk"); try { return doCopyApk(); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private int doCopyApk() { ...... final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); codeFile = tempDir; resourceFile = tempDir; ...... int ret = PackageManagerServiceUtils.copyPackage( origin.file.getAbsolutePath(), codeFile); ...... return ret; } } //PackageManagerServiceUtils.java public static int copyPackage(String packagePath, File targetDir) { if (packagePath == null) { return PackageManager.INSTALL_FAILED_INVALID_URI; } try { final File packageFile = new File(packagePath); final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0); copyFile(pkg.baseCodePath, targetDir, "base.apk"); if (!ArrayUtils.isEmpty(pkg.splitNames)) { for (int i = 0; i < pkg.splitNames.length; i++) { copyFile(pkg.splitCodePaths[i], targetDir, "split_" + pkg.splitNames[i] + ".apk"); } } return PackageManager.INSTALL_SUCCEEDED; } catch (PackageParserException | IOException | ErrnoException e) { Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } }
拷貝到的目標文件是:/data/app/vmdl[sessionId].tmp/base.apk。如果多個,/data/app/vmdl[sessionId].tmp/split_[pkgname].apk。
例如:如個人一次安裝 /data/app/vmdl1101585668.tmp/base.apk,此次安裝的sessionId是1101585668。
注:用userdebug軟件,安裝抓取的log也能看出大體安裝過程的信息,能夠輔助。如搜索TAG爲 PackageManager(PMS類的TAG)。
下面是路徑相關代碼:
//PackageInstallerService.java public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException { synchronized (mSessions) { ...... final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid); ...... } } private File buildTmpSessionDir(int sessionId, String volumeUuid) { final File sessionStagingDir = getTmpSessionDir(volumeUuid); return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp"); } private File getTmpSessionDir(String volumeUuid) { return Environment.getDataAppDirectory(volumeUuid); }
copyFile完成拷貝後,回頭看handleReturnCode(),mArgs.copyApk();
後執行processPendingInstall(mArgs, mRet);
開始真正的安裝。
//PackageManagerService.java private void processPendingInstall(final InstallArgs args, final int currentStatus) { if (args.mMultiPackageInstallParams != null) { args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus); } else { //安裝參數 PackageInstalledInfo res = createPackageInstalledInfo(currentStatus); processInstallRequestsAsync( res.returnCode == PackageManager.INSTALL_SUCCEEDED, Collections.singletonList(new InstallRequest(args, res))); } } // Queue up an async operation since the package installation may take a little while. private void processInstallRequestsAsync(boolean success, List<InstallRequest> installRequests) { mHandler.post(() -> { if (success) { for (InstallRequest request : installRequests) { //若是以前安裝失敗,清理無用信息 request.args.doPreInstall(request.installResult.returnCode); } synchronized (mInstallLock) { //進行安裝 installPackagesTracedLI(installRequests); } for (InstallRequest request : installRequests) { //安裝失敗,清理無用信息 request.args.doPostInstall( request.installResult.returnCode, request.installResult.uid); } } for (InstallRequest request : installRequests) { restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult, new PostInstallData(request.args, request.installResult, null)); } }); } private PackageInstalledInfo createPackageInstalledInfo( int currentStatus) { PackageInstalledInfo res = new PackageInstalledInfo(); res.setReturnCode(currentStatus); res.uid = -1; res.pkg = null; res.removedInfo = null; return res; }
看上述註釋大體瞭解下,咱們接着看installPackagesTracedLI()。
//PMS @GuardedBy({"mInstallLock", "mPackages"}) private void installPackagesTracedLI(List<InstallRequest> requests) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); installPackagesLI(requests); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void installPackagesLI(List<InstallRequest> requests) { ...... try { for (InstallRequest request : requests) { // TODO(b/109941548): remove this once we've pulled everything from it and into // scan, reconcile or commit. final PrepareResult prepareResult; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage"); //分析安裝狀態、分析包並檢查驗證 //檢查包並分析完整性;檢查SDK版本、靜態庫等;檢查簽名;設置權限; prepareResult = preparePackageLI(request.args, request.installResult); } ...... try { //掃描apk final List<ScanResult> scanResults = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user); } ...... } executePostCommitSteps(commitRequest); } finally { ...... } }
installPackagesLI()方法很複雜,這裏也不細述了。
installPackagesLI()對安裝包自己以及安裝環境等進行一些相關的檢查驗證。檢查包的完整性、SDK版本、簽名、共享庫、設置權限等等,檢查安裝環境是否知足等。能夠大體看下方法中這幾個方法:
prepareResult = preparePackageLI(request.args, request.installResult); final List<ScanResult> scanResults = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user); ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
最後執行executePostCommitSteps()
進一步進行安裝,最終經過binder進入installd進程完成安裝。這個過程也很複雜,本人也需進一步閱讀。executePostCommitSteps()後續簡單參考過程:
PackageManagerService.java installPackagesLI()->executePostCommitSteps()->prepareAppDataAfterInstallLIF()->prepareAppDataLIF()->prepareAppDataLeafLIF()->mInstaller.createAppData()。 Installer.java: createAppData()->mInstalld.createAppData()。
關於過程當中一些路徑操做多說一點:
在preparePackageLI()中有個rename的過程,將前面拷貝的文件目錄重命名了下,因此安裝後能在手機中看到的是重命名後的目錄。
重命名規則:/data/app/[packagename]-[suffix]。
例如個人安裝:PackageManager: Renaming /data/app/vmdl1101585668.tmp to /data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==
相關代碼:
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) ...... if (!args.doRename(res.returnCode, pkg)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } ...... } class FileInstallArgs extends InstallArgs { boolean doRename(int status, PackageParser.Package pkg) { ..... final File targetDir = codeFile.getParentFile(); final File beforeCodeFile = codeFile; final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); ..... Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); ..... } } private File getNextCodePath(File targetDir, String packageName) { File result; SecureRandom random = new SecureRandom(); byte[] bytes = new byte[16]; do { random.nextBytes(bytes); String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); result = new File(targetDir, packageName + "-" + suffix); } while (result.exists()); return result; }
點擊安裝,經過相似PackageInstaller.apk處理。
確認安裝後,拷貝apk到/data/app/vmdl[sessionId].tmp/base.apk下。
進一步安裝中,重命名路徑爲 /data/app/[packagename]-[suffix]。
如個人安裝:拷貝到/data/app/vmdl1101585668.tmp/base.apk。重命名後是:/data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==。
查看/data/app/[packagename]-RDISkz-0p77Yh-pAwNtfFA==目錄,有base.apk lib/ oat/,安裝後的apk、庫、odex、vdex都在這個目錄下。
系統預置的還在預置目錄下,如/system/priv-app。
/data/data/[packagename]存放應用數據,通常有cache code_cache lib。
這也是一個簡單參考,不完整。
使用adb命令進行安裝,下面大體能夠參考:
//system/core/adb/client/commandline.cpp int adb_commandline(int argc, const char** argv) { ...... else if (!strcmp(argv[0], "install")) { if (argc < 2) error_exit("install requires an argument"); return install_app(argc, argv); } ...... } //system/core/adb/client/adb_install.cpp int install_app(int argc, const char** argv) { ...... switch (installMode) { case INSTALL_PUSH: return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(), use_fastdeploy, use_localagent); case INSTALL_STREAM: return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(), use_fastdeploy, use_localagent); case INSTALL_DEFAULT: default: return 1; } } static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy, bool use_localagent) { ...... result = pm_command(argc, argv); ...... } static int pm_command(int argc, const char** argv) { std::string cmd = "pm"; while (argc-- > 0) { cmd += " " + escape_arg(*argv++); } return send_shell_command(cmd); }
在AndroidO時,還有源碼frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java。AndroidO最終Pm.java執行mInstaller.createSession()
進入PMS。
AndroidQ中,frameworks/base/cmds/pm/src/com/android/commands/pm只有一個Andoird.mk了,pm是system/bin下的一個可執行文件了system/bin/pm
。 不過應該是和O相似的(AndoridP中也沒有Pm.java的源碼了),最終也是進入的PMS中方法,迴歸到相似點擊安裝的過程。 咱們能夠在上面點擊安裝過程當中的PMS方法中添加調用棧或log等,瞭解adb安裝的過程是 進入的哪,進一步跟蹤瞭解。