这里主要介绍 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安装的过程是 进入的哪,进一步跟踪了解。