写点什么

Android 系统 - 包管理机制 (一)PMS 服务启动,腾讯大牛教你自己写 Android 第三方库

  • 2021 年 11 月 05 日
  • 本文字数:9276 字

    阅读完需:约 30 分钟

  1. BOOT_PROGRESS_PMS_READY(准备阶段)

1、开始阶段

BOOT_PROGRESS_PMS_START


public PackageManagerService(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {//打印开始日志 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());


if (mSdkVersion <= 0) {Slog.w(TAG, "**** ro.build.version.sdk not set!");}


mContext = context;


mPermissionReviewRequired = context.getResources().getBoolean(R.bool.config_permissionReviewRequired);


mFactoryTest = factoryTest;mOnlyCore = onlyCore;//用于存储屏幕的相关信息 mMetrics = new DisplayMetrics();//创建 Settings 对象 (1)mSettings = new Settings(mPackages);// 添加 system, phone, log, nfc, bluetooth, shell 这六种 shareUserId 到 mSettings;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);


......


mInstaller = installer;//创建 Dex 优化工具类 mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,"dexopt");mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());


mOnPermissionChangeListeners = new OnPermissionChangeListeners(FgThread.get().getLooper());


getDefaultDisplayMetrics(context, mMetrics);//得到全局系统配置信息 SystemConfig systemConfig = SystemConfig.getInstance();//获取全局的 groupIdmGlobalGids = systemConfig.getGlobalGids();//获取系统权限 mSystemPermissions = systemConfig.getSystemPermissions();mAvailableFeatures = systemConfig.getAvailableFeatures();


mProtectedPackages = new ProtectedPackages(mContext);


//安装 APK 时需要的锁,保护所有对 installd 的访问。synchronized (mInstallLock) {//更新 APK 时需要的锁,保护内存中已经解析的包信息等内容 synchronized (mPackages) {//创建后台线程 ServiceThreadmHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /allowIo/);mHandlerThread.start();//创建 PackageHandler 绑定到 ServiceThread 的消息队列 mHandler = new PackageHandler(mHandlerThread.getLooper());mProcessLoggingHandler = new ProcessLoggingHandler();//将 PackageHandler 添加到 Watchdog 的检测集中 Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);


mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);


//在 Data 分区创建一些目录 File dataDir = Environment.getDataDirectory();mAppInstallDir = new File(dataDir, "app");mAppLib32InstallDir = new File(dataDir, "app-lib");mEphemeralInstallDir = new File(dataDir, "app-ephemeral");mAsecInternalPath = new File(dataDir, "app-asec").getPath();mDrmAppPrivateInstallDir = new File(dataDir, "app-private");mRegionalizationAppInstallDir = new File(dataDir, "app-regional");


//创建多用户管理服务 sUserManager = new UserManagerService(context, this, mPackages);


mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();


//解析 packages.xml 等文件的信息,保存到 Settings 的对应字段中。packages.xml 中记录系统中所有安装的应用信息,包括基本信息、签名和权限。如果 packages.xml 有安装的应用信息,readLPw 方法会返回 true,mFirstBoot 的值为 false,说明 PMS 不是首次被启动。mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));


在开始阶段,创建了很多 PMS 中的关键对象并赋值给 PMS 中的成员变量

mSettings

用于保存所有包的动态设置。


Settings(Object lock) {this(Environment.getDataDirectory(), lock);}


Settings(File dataDir, Object lock) {mLock = lock;


mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);


mSystemDir = new File(dataDir, "system");mSystemDir.mkdirs(); //创建/data/systemFileUtils.setPermissions(mSystemDir.toString(),FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH|FileUtils.S_IXOTH,-1, -1);mSettingsFilename = new File(mSystemDir, "packages.xml");mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");mPackageListFilename = new File(mSystemDir, "packages.list");FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);


mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");}


此处 mSystemDir 是指目录/data/system,在该目录有以下 5 个文件:


mInstaller

Installer 继承自 SystemService,和 PMS、AMS 一样是系统的服务(引导服务),PMS 很多的操作都是由 Installer 来完成的,比如 APK 的安装和卸载。在 Installer 内部,通过 socket 与 installd 通信,(貌似 8.0 以上改成了 IInstalld 和 installd 进行 Binder 通信),由位于 nativie 层的 installd 来完成具体的操作。

systemConfig

用于得到全局系统配置信息。比如系统的权限就可以通过 SystemConfig 来获取。

mPackageDexOptimizer

Dex 优化的工具类。

mHandler(PackageHandler 类型)

PackageHandler 继承自 Handler,PMS 通过 PackageHandler 驱动 APK 的复制和安装工作。 PackageHandler 处理的消息队列如果过于繁忙,有可能导致系统卡住, 因此将它添加到 Watchdog 的监测集中。 Watchdog 主要有两个用途,一个是定时检测系统关键服务(AMS 和 WMS 等)是否可能发生死锁,还有一个是定时检测线程的消息队列是否长时间处于工作状态(可能阻塞等待了很长时间)。如果出现上述问题,Watchdog 会将日志保存起来,必要时还会杀掉自己所在的进程,也就是 SystemServer 进程。

sUserManager(UserManagerService 类型)

多用户管理服务。

2、扫描系统阶段

//打印扫描系统阶段日志 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);


// Set flag to monitor and not change apk file paths when// scanning install directories.final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;


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!");}


final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();final String[] dexCodeInstructionSets =getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));


/**


  • Ensure all external libraries have had dexopt run on them.*/if (mSharedLibraries.size() > 0) {// NOTE: For now, we're compiling these system "shared libraries"// (and framework jars) into all available architectures. It's possible// to compile them only when we come across an app that uses them (there's// already logic for that in scanPackageLI) but that adds some complexity.for (String dexCodeInstructionSet : dexCodeInstructionSets) {for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {final String lib = libEntry.path;if (lib == null) {continue;}


try {// Shared libraries do not have profiles so we perform a full// AOT compilation (if needed).int dexoptNeeded = DexFile.getDexOptNeeded(lib, dexCodeInstructionSet,getCompilerFilterForReason(REASON_SHARED_APK),false /* newProfile */);if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,dexoptNeeded, DEXOPT_PUBLIC /dexFlags/,getCompilerFilterForReason(REASON_SHARED_APK),StorageManager.UUID_PRIVATE_INTERNAL,SKIP_SHARED_LIBRARY_CHECK);}} catch (FileNotFoundException e) {Slog.w(TAG, "Library not found: " + lib);} catch (IOException | InstallerException e) {Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "


  • e.getMessage());}}}}


//在/system 中创建 framework 目录 File frameworkDir = new File(Environment.getRootDirectory(), "framework");


final VersionInfo ver = mSettings.getInternalVersion();mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);


// when upgrading from pre-M, promote system app permissions from install to runtimemPromoteSystemApps =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;


// save off the names of pre-existing system packages prior to scanning; we don't// want to automatically grant runtime permissions for new system appsif (mPromoteSystemApps) {Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();while (pkgSettingIter.hasNext()) {PackageSetting ps = pkgSettingIter.next();if (isSystemApp(ps)) {mExistingSystemPackages.add(ps.name);}}}


// Collect vendor 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.String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);//扫描/vendor/overlay 目录下的文件 if (!overlayThemeDir.isEmpty()) {scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);}scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);


// Find base frameworks (resource packages without code).//收集包名:/system/frameworkscanDirTracedLI(frameworkDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED,scanFlags | SCAN_NO_DEX, 0);


// Collected privileged system packages.//收集私有的系统包名:/system/priv-appfinal File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");scanDirTracedLI(privilegedAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);


// Collect ordinary system packages.//收集一般的系统包名:/system/appfinal File systemAppDir = new File(Environment.getRootDirectory(), "app");scanDirTracedLI(systemAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);


// Collect all vendor packages.//收集所有的供应商包名:/vendor/appFile vendorAppDir = new File("/vendor/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| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);


// Collect all OEM packages.//收集所有 OEM 包名:/oem/appfinal File oemAppDir = new File(Environment.getOemDirectory(), "app");scanDirTracedLI(oemAppDir, mDefParseFlags| PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);


// Collect all Regionalization packages form Carrier's res packages.if (RegionalizationEnvironment.isSupported()) {Log.d(TAG, "Load Regionalization vendor apks");final List<File> RegionalizationDirs =RegionalizationEnvironment.getAllPackageDirectories();for (File f : RegionalizationDirs) {File RegionalizationSystemDir = new File(f, "system");// Collect packages in <Package>/system/priv-appscanDirLI(new File(RegionalizationSystemDir, "priv-app"),PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);// Collect packages in <Package>/system/appscanDirLI(new File(RegionalizationSystemDir, "app"),PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,scanFlags, 0);// Collect overlay in <Package>/system/vendorscanDirLI(new File(RegionalizationSystemDir, "vendor/overlay"),PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,scanFlags | SCAN_TRUSTED_OVERLAY, 0);}}


// Prune any system packages that no longer exist.// 这个列表代表有可能有升级包的系统 Appfinal List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();if (!mOnlyCore) {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)) { //1logCriticalInfo(Log.WARN, "Expecting better updated system app for "


  • ps.name + "; removing system app. Last known codePath="

  • ps.codePathString + ", installStatus=" + ps.installStatus

  • ", versionCode=" + ps.versionCode + "; scanned versionCode="

  • scannedPkg.mVersionCode);//将这个系统 App 的 PackageSetting 从 PMS 的 mPackages 中移除 removePackageLI(scannedPkg, true);//将升级包的路径添加到 mExpectingBetter 列表中 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 {final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


//这个系统 App 升级包信息在 mDisabledSysPackages 中,但是没有发现这个升级包存在 if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {//2possiblyDeletedUpdatedSystemApps.add(ps.name);}}}}


//look for any incomplete package installations//清理所有安装不完整的包 ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();for (int i = 0; i < deletePkgsList.size(); i++) {// Actual deletion of code and data will be handled by later// reconciliation stepfinal String packageName = deletePkgsList.get(i).name;logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);synchronized (mPackages) {mSettings.removePackageLPw(packageName);}}


//delete tmp files//删除临时文件 deleteTempPackageFiles();


// Remove any shared userIDs that have no associated packagesmSettings.pruneSharedUsersLPw();


系统扫描阶段的主要工作有以下 3 点:


  1. 创建/system 的子目录,比如/system/framework、/system/priv-app 和/system/app 等等

  2. 扫描系统文件,比如/vendor/overlay、/system/framework、/system/app 等等目录下的文件。

  3. 对扫描到的系统文件做后续处理。


主要来说第 3 点,一次 OTA 升级对于一个系统 App 会有三种情况:


  • 这个系统 APP 无更新。

  • 这个系统 APP 有更新。

  • 新的 OTA 版本中,这个系统 APP 已经被删除。


当系统 App 升级,PMS 会将该系统 App 的升级包设置数据(PackageSetting)存储到 Settings 的 mDisabledSysPackages 列表中(具体见 PMS 的 replaceSystemPackageLIF 方法),mDisabledSysPackages 的类型为ArrayMap<String, PackageSetting>。mDisabledSysPackages 中的信息会被 PMS 保存到 packages.xml 中的<updated-package>标签下(具体见 Settings 的 writeDisabledSysPackageLPr 方法)。


注释 1 处说明这个系统 App 有升级包,那么就将该系统 App 的 PackageSetting 从 mDisabledSysPackages 列表中移除,并将系统 App 的升级包的路径添加到 mExpectingBetter 列表中,mExpectingBetter 的类型为ArrayMap<String, File>等待后续处理。


注释 2 处如果这个系统 App 的升级包信息存储在 mDisabledSysPackages 列表中,但是没有发现这个升级包存在,则将它加入到 possiblyDeletedUpdatedSystemApps 列表中,意为“系统 App 的升级包可能被删除”,之所以是“可能”,是因为系统还没有扫描 Data 分区,只能暂放到 possiblyDeletedUpdatedSystemApps 列表中,等到扫描完 Data 分区后再做处理。

3、扫描 Data 分区阶段

//如果设备没有加密,那么就开始扫描 Data 分区 if (!mOnlyCore) {//打印扫描 Data 分区阶段日志 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());//扫描/data/app 目录下的文件 scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);//扫描/data/app-private 目录下的文件 scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags| PackageParser.PARSE_FORWARD_LOCK,scanFlags | SCAN_REQUIRE_KNOWN, 0);//扫描/data/app-ephemeral 目录下的文件 scanDirLI(mEphemeralInstallDir, mDefParseFlags| PackageParser.PARSE_IS_EPHEMERAL,scanFlags | SCAN_REQUIRE_KNOWN, 0);


/**


  • Remove disable package settings for any updated system

  • apps that were removed via an OTA. If they're not a

  • previously-updated app, remove them completely.

  • Otherwise, just revoke their system-level permissions.

  • 处理 possiblyDeletedUpdatedSystemApps 列表


*/for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {PackageParser.Package deletedPkg = mPackages.get(deletedAppName);mSettings.removeDisabledSystemPackageLPw(deletedAppName);


String msg;if (deletedPkg == null) {//1 如果这个系统 App 的包信息不在 PMS 的变量 mPackages 中,说明是残留的 App 信息,后续会删除它的数据 msg = "Updated system package " + deletedAppName


  • " no longer exists; it's data will be wiped";// Actual deletion of code and data will be handled by later// reconciliation step} else {//2 如果这个系统 App 在 mPackages 中,说明是存在于 Data 分区,不属于系统 App,那么移除其系统权限。msg = "Updated system app + " + deletedAppName

  • " no longer present; removing system privileges for "

  • deletedAppName;


deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;


PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;}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.*///遍历 mExpectingBetter 列表 for (int i = 0; i < mExpectingBetter.size(); i++) {final String packageName = mExpectingBetter.keyAt(i);if (!mPackages.containsKey(packageName)) {//得到系统 App 的升级包路径 final File scanFile = mExpectingBetter.valueAt(i);


logCriticalInfo(Log.WARN, "Expected better " + packageName


  • " but never showed up; reverting to system");


//3 根据系统 App 所在的目录设置扫描的解析参数 int reparseFlags = mDefParseFlags;if (FileUtils.contains(privilegedAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR| PackageParser.PARSE_IS_PRIVILEGED;} else if (FileUtils.contains(systemAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;} else if (FileUtils.contains(vendorAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;} else if (FileUtils.contains(oemAppDir, scanFile)) {reparseFlags = PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR;

评论

发布
暂无评论
Android系统-包管理机制(一)PMS服务启动,腾讯大牛教你自己写Android第三方库