Android PMS——PMS服务启动流程(二)

        PackageManagerService 既然是系统服务,那么肯定是通过 SystemServer 启动的,所以我们首先看一下 SystemServer 服务中启动 PackageManagerService 相关代码。

一、PMS启动

1、SystemServer

源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer {private PackageManagerService mPackageManagerService;private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("StartPackageManagerService");try {Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);} finally {Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");}// 现在包管理器已经启动,请注册索引加载报告程序以捕获系统服务器加载的任何索引文件。// 这些索引文件将被后台dexoptservice优化SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);mFirstBoot = mPackageManagerService.isFirstBoot();mPackageManager = mSystemContext.getPackageManager();t.traceEnd();}
}

        这里通过 PackageManagerService.main 来启动 PackageManagerService 服务。同时这里在调用 OtaDexoptService.main 时也传入了 mPackageManagerService。

// 管理A/B OTA采用。这是一个引导服务,因为我们需要它在引导后重命名A/B工件,在其他任何东西可能接触/需要它们之前。
if (!mOnlyCore) {boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false);if (!disableOtaDexopt) {t.traceBegin("StartOtaDexOptService");try {Watchdog.getInstance().pauseWatchingCurrentThread("moveab");OtaDexoptService.main(mSystemContext, mPackageManagerService);} catch (Throwable e) {reportWtf("starting OtaDexOptService", e);} finally {Watchdog.getInstance().resumeWatchingCurrentThread("moveab");t.traceEnd();}}
}

2、PackageManagerService

源码位置:/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {// 自检初始设置PackageManagerServiceCompilerMapping.checkProperties();……PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);t.traceEnd(); // "创建包管理器"……m.installWhitelistedSystemPackages();ServiceManager.addService("package", m);final PackageManagerNative pmn = m.new PackageManagerNative();ServiceManager.addService("package_native", pmn);return m;
}

        在这里 new 了一个新的 PackageManagerService,接下来看一下 PackageManagerService 的构造函数。

二、构造函数

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {PackageManager.disableApplicationInfoCache();PackageManager.disablePackageInfoCache();……// 第一阶段:BOOT_PROGRESS_PMS_STARTEventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis());……// 1.创建DisplayMetricsmMetrics = new DisplayMetrics();// 2.创建InstallermInstaller = injector.getInstaller();……// 3.创建mPermissionManagermPermissionManager = injector.getPermissionManagerServiceInternal();// 4.创建mSettingsmSettings = injector.getSettings();……mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);……// 5.创建PackageDexOptimizer和DexManagermPackageDexOptimizer = new PackageDexOptimizer(mInstaller, mInstallLock, mContext, "*dexopt*");mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, mInstaller, mInstallLock);……// 6.创建SystemConfigSystemConfig systemConfig = SystemConfig.getInstance();……// CHECKSTYLE:OFF IndentationChecksynchronized (mInstallLock) {// writersynchronized (mLock) {mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);mHandlerThread.start();// 7.创建PackageManager.handlermHandler = new PackageHandler(mHandlerThread.getLooper());mProcessLoggingHandler = new ProcessLoggingHandler();Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);……// 第二阶段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_STARTEventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);// 1.获取环境变量final String bootClassPath = System.getenv("BOOTCLASSPATH");final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");……// 2.从pre-M升级时,将系统应用程序权限从安装提升到运行时mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;// 当从pre-N升级时,我们需要像第一次引导一样处理包提取,因为没有可用的分析数据。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;……// 3.扫描apkmApexManager.scanApexPackagesTraced(packageParser, executorService);……// 解析覆盖配置文件以设置系统覆盖的默认启用状态、可变性和优先级。mOverlayConfig = OverlayConfig.initializeSystemInstance(consumer -> mPmInternal.forEachPackage(pkg -> consumer.accept(pkg, pkg.isSystem())));……// 4.删除任何没有关联包的共享useridmSettings.pruneSharedUsersLPw();……if (!mOnlyCore) {// 第三阶段:BOOT_PROGRESS_PMS_DATA_SCAN_STARTEventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());// 扫描 /system/app 目录下的APK文件scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, packageParser, executorService);}packageParser.close();if (!mOnlyCore) {// 删除通过OTA删除的更新系统应用程序的禁用包设置。// 如果更新不再存在,完全删除应用程序。否则,撤销其系统权限。for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {final String packageName = possiblyDeletedUpdatedSystemApps.get(i);……// 从禁用系统列表中删除mSettings.removeDisabledSystemPackageLPw(packageName);……}……}……// 读取并更新保存所有包的最后使用时间。mPackageUsage.read(mSettings.mPackages);mCompilerStats.read();// 第四阶段:BOOT_PROGRESS_PMS_SCAN_ENDEventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());// 1.SDK发生了变化,重新授予应用权限。final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated);ver.sdkVersion = mSdkVersion;// 第一次启动或从pre-M版本更新,初始化所有已定义用户的默认首选应用程序。if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {mSettings.applyDefaultPreferredAppsLPw(user.id);primeDomainVerificationsLPw(user.id);}}……// 2.OTA第一次引导,清除代码缓存目录。if (mIsUpgrade && !mOnlyCore) {// 构建改变,清除代码缓存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)) {clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);}}ver.fingerprint = Build.FINGERPRINT;}……// 3.更新了权限和其他默认值后,才能清除mPromoteSystemApps = false;// 所有更改都是在包扫描期间完成的。ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;// can downgrade to readert.traceBegin("write settings");mSettings.writeLPr();t.traceEnd();// 第五阶段:BOOT_PROGRESS_PMS_READYEventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());……// 包解析器供应商,解析apex文件。final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null /* cacheDir */,mPackageParserCallback);// 1.创建PackageInstallerServicemInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);……}}……// 2.GC回收t.traceBegin("GC");Runtime.getRuntime().gc();t.traceEnd();……
}

        PackageManagerService 构造函数代码比较多,但总结起来主要包含下面五个阶段。

1、BOOT_PROGRESS_PMS_START

(1)构造 DisplayMetrics,保存分辨率等相关信息;
(2)创建 Installer 对象,与 installd 交互;
(3)创建 mPermissionManager对象,进行权限管理;
(4)构造Settings类,保存安装包信息,清除路径不存在的孤立应用,主要涉及 /data/system/ 目录的 packages.xml、packages-backup.xml、packages.list、packages-stopped.xml、packages-stopped-backup.xml 等文件。

  • packages.xml:记录了系统中所有安装的应用信息,包括基本信息、签名和权限。
  • pakcages-back.xml:packages.xml文件的备份。
  •  pakcages-stoped.xml:记录系统中被强制停止的运行的应用信息,系统在强制停止某个应用的时候,会将应用的信息记录在该文件中。
  • pakcages-stoped-backup.xml:pakcages-stoped.xml文件的备份。
  • packages.list:保存普通应用的数据目录和uid等信息。

(5)构造PackageDexOptimizer及DexManager类,处理dex优化;
(6)创建SystemConfig实例,获取系统配置信息,配置共享lib库;
(7)创建PackageManager的handler线程,循环处理外部安装相关消息。

2、BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

(1)从 init.rc 中获取环境变量 BOOTCLASSPATH 和 SYSTEMSERVERCLASSPATH;
(2)对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
(3)扫描 system/vendor/product/odm/oem 等目录的 priv-app、app、overlay 包;
(4)清除安装时临时文件以及其他不必要的信息。

3、BOOT_PROGRESS_PMS_DATA_SCAN_START

处理 data 目录的应用信息,及时更新,祛除不必要的数据。

4、BOOT_PROGRESS_PMS_SCAN_END

(1)sdk版本变更,更新权限;
(2)OTA升级后首次启动,清除不必要的缓存数据;
(3)权限等默认项更新完后,清理相关数据;
(4)更新 package.xml。

5、BOOT_PROGRESS_PMS_READY

(1)创建 PackageInstallerService 对象;
(2)GC 回收内存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iPhone手电筒不能工作的几种修复办法,总有一种适合你

这篇文章解释了为什么你的iPhone的手电筒不工作以及如何修复它。 手电筒不工作的原因 iPhone手电筒功能可能不起作用的原因有几个。通常&#xff0c;软件错误或小故障会导致该功能出现故障&#xff0c;但可能是你处于错误的电源模式或只需要充电。其他时候&#xff0c;确切的…

STM32F407移植OpenHarmony笔记4

上一篇写到make menuconfig报错&#xff0c;继续开整。 make menuconfig需要/device/soc/*下面有对应的Kconfig文件。 直接去gitee下载stm32的配置文件拿来参考用。 先提取Kconfig文件&#xff0c;后面再添加其它文件。https://gitee.com/openharmony/device_soc_st/tree/Open…

arcgis 如何将线路转为路面

在出外业的时候&#xff0c;用手机软件测出来的路&#xff08;线要素&#xff09;&#xff0c;需要转换成路面。具体操作如下&#xff1a; 1.打开线图层 2.菜单-地理处理-缓冲区 在缓冲区中&#xff0c;输入要转换的线要素&#xff0c;在线性单位下方填写要转换的面的宽度&am…

[E模拟] lc2670. 找出不同元素数目差数组(哈希表+状态压缩)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;2670. 找出不同元素数目差数组 2. 题目解析 哈希计数统计就行了&#xff0c;题解里有看到用 long 64 位进行状态压缩的&#xff0c;可以参考下。这类题就不纠结写法了。 思路&#xff1a; 两个哈希表&#x…

回响科技二面面试题解答

面试题 1、你们的数仓中DWD层为什么要划分数据域&#xff1f;划分数据域之后会对ADS层造成什么影响&#xff1f;是可以提效还是可扩展性强&#xff1f;你们是如何考虑的呢&#xff1f; 2、AZkaban和dolphinScheduler的区别是什么&#xff1f;如果选型会从哪几个方面来考虑呢&a…

《Numpy 简易速速上手小册》第10章:Numpy案例研究和实践技巧(2024 最新版)

文章目录 10.1 实际案例分析10.1.1 基础知识10.1.2 完整案例&#xff1a;天气数据分析10.1.3 拓展案例 1&#xff1a;股票价格分析10.1.4 拓展案例 2&#xff1a;信号处理 10.2 Numpy 最佳实践10.2.1 基础知识10.2.2 完整案例&#xff1a;高效数组操作10.2.3 拓展案例 1&#x…

vue-cli初始化项目很慢?

第一种情况 大部分是由于npm的镜像源不是淘宝的 cmd输入npm config get registry查看是不是淘宝的&#xff0c;是的话看第二种情况试试不是的话输入npm config set registry https://registry.npm.taobao.org 第二种情况 vue-cli配置文件不是使用淘宝镜像源的 找到文件.vue…

已实现:vue、h5项目如何使用echarts实现雷达图、六边形图表

说实话&#xff0c;要说图表里&#xff0c;最强的应该属于echarts了&#xff0c;不管是接入难度上&#xff0c;还是样式多样性上&#xff0c;还有社区庞大程度上&#xff0c;都是首屈一指的&#xff0c;反观有的人习惯用chart.js了&#xff0c;这个无可厚非&#xff0c;但是如果…

从C向C++5——友元和string

一.对象特性&#xff08;续&#xff09; 1.空指针访问成员函数 C中空指针也是可以调用成员函数的&#xff0c;但是也要注意有没有用到this指针。 如果用到this指针&#xff0c;需要加以判断保证代码的健壮性。 如果调用的成员函数不访问成员属性&#xff0c;那么空指针可以调…

C语言中大小写字母的转化

在C语言中&#xff0c;大小写字母的转化是一个非常基础且常用的功能。C语言中的字符是以ASCII码的形式存储的&#xff0c;而ASCII码中&#xff0c;小写字母和大写字母之间相差32。因此&#xff0c;可以通过简单的数学运算来实现大小写字母的转换。 一、数学运算转化 大写字母…

微信小程序如何实现实时显示输入内容

如下所示&#xff0c;在许多场景中需要实时显示用户输入&#xff0c;具体实现见下文。 .wxml <input type"text" placeholder"请输入{{item.value}}(必填)" style"width:80%;" bindinput"get_required_value" data-info"{{it…

科技云报道:新趋势下,国产数据库或“春山可望”

科技云报道原创。 从540亿元到1286亿元——这是中国通信标准化协会大数据技术标准推进委员会针对中国数据库行业给出的一份预测报告。 报告指出&#xff0c;未来五年&#xff0c;中国数据库行业将从百亿级市场跨越成为千亿级市场。 最近两年&#xff0c;中国的数据库行业似乎…

【PyRestTest】PyRestTest入门引导

pyresttest环境安装完毕之后&#xff0c;进行如下操作&#xff0c;快速入门pyresttest。 第一步&#xff1a;创建一个简单的REST服务 1、进行如下命令clonepyresttest项目: git clone https://github.com/svanoort/pyresttest.git2、安装运行Rest服务的依赖包 (Django and D…

Ubuntu 22.04 中文乱码解决方案

sudo apkg-reconfigure locales 按空格键选中

团队管理-如何提高员工积极性

一、审题 关键词&#xff1a;提高、工作积极性 有哪些指标&#xff1a; 1、迭代工作交付量&#xff0c;单位时间内完成的工作内容 2、问题解决&#xff0c;处理问题的态度是否积极&#xff0c;效率是否提高 3、工作主动性&#xff0c;是否主动的承担一些工作职责&#xff…

PHP面试--echo、print、print_r、var_dump区别

echo、print、print_r、var_dump 区别 echo 输出单个或多个字符&#xff0c;多个使用逗号分隔无返回值 echo "String 1", "String 2";print 只可以输出单个字符返回1&#xff0c;因此可用于表达式 print "Hello"; if ($expr && pri…

Jenkins自动化打包

Jenkins自动化打包 下载安装 我们直接从官网https://www.jenkins.io/download/ 下载所需的Jenkins文件 如上图所示, 选择Windows版本,下面就是一路安装即可,需要注意的是,选择作为系统服务选项, 不要自己设置账号密码登录. Web配置 安装完根据提示在浏览器打开 http://lo…

达梦数据库存储过程

根据网上语法自学写的存储过程&#xff0c;使用的是DBeaver工具&#xff0c;但是调试过程太痛苦&#xff0c;也不清楚为什么有时候改了报错或者没生效。 注意点&#xff1a; 1.如果怀疑没生效或者不对&#xff0c;可以建个临时表每次往里面插不同数据确认代码是否最新。 2.不…

iZotope RX 10.4.2 mac激活版 音频修复和增强工具

iZotope RX 10 for Mac是一款专业的音频修复软件&#xff0c;旨在提供强大、精确的工具&#xff0c;让用户能够清晰、纯净地处理音频。以下是其主要功能和特点&#xff1a; 软件下载&#xff1a;iZotope RX 10.4.2 mac激活版下载 强大的降噪功能&#xff1a;iZotope RX 10采用了…

动态住宅IP可以用来注册亚马逊电商吗?

注册亚马逊店铺可以用动态IP&#xff0c;只要是独立且干净的网线就没问题&#xff0c;亚马逊规则要求一个IP地址只能出现一个亚马逊店铺&#xff0c;若使用不当会导致关联账户。所以现在非常多人使用指纹浏览器搭配代理IP 固定ip可以给我们的账户带来更多的安全&#xff0c;要知…