PackageManagerService(1)扫描前的准备

PKMS源码解析
本文深入剖析了PKMS(PackageManagerService)的源码,详细解读了其在Android系统中的初始化流程,包括变量初始化、权限管理、配置文件加载、共享进程及库信息保存等关键步骤。

PKMS( PackageManagerService简称 )是一个系统服务,它的主要功能是解析APK并保存数据。由于在工作遇到过一些麻烦,最终的原因是由于对PKMS理解不够导致的,因此我决心把PKMS的源码重新并整理一次,以加深理解。

由于PKMS的代码量非常大,为了缓存阅读文章的疲劳,我将分三步讲解,如下

  1. 扫描APK前的准备工作。
  2. 扫描目录并解析APK
  3. 保存解析数据到文件。

扫描前准备工作

初始化

本文只分析第一阶段的工作,扫描前的准备工作。由于代码量非常大,因此分段来分析

	// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
    
    public PackageManagerService(Context context, Installer installer,
                                 boolean factoryTest, boolean onlyCore) {
   
   
		// ...

        mContext = context;
		// factory test mode下为true,正常模式启动下,为false
        mFactoryTest = factoryTest;
        // 设备正在加密或者已经加密状态下,这个值为true,正常模式启动下,值为false
        mOnlyCore = onlyCore;
        mMetrics = new DisplayMetrics();
        mInstaller = installer;
		
        // 1. 初始化
        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);

                // ComponentResolver 用于在匹配四大组件时,解析数据
                mComponentResolver = new ComponentResolver(sUserManager,
                        LocalServices.getService(PackageManagerInternal.class),
                        mPackages);

                // 用于管理权限服务端
                mPermissionManager = PermissionManagerService.create(context,
                        mPackages /*externalLock*/);
                // DefaultPermissionGrantPolicy类型
                mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();

                mSettings = new Settings(Environment.getDataDirectory(),
                        mPermissionManager.getPermissionSettings(), mPackages);
            }
        }
        
        // ...
	}        

这里初始化了很多变量,这些变量到底有什么用,一时间还真难总结出来。然而,随着我们分析的逐步深入,自然就会明白这些变量的作用了。

这里我们主要关心 mPermissionManager 变量的初始化,它调用的是PermissionManagerService#create() 方法

	// frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
    
    public static PermissionManagerServiceInternal create(Context context,
            @NonNull Object externalLock) {
   
   
        final PermissionManagerServiceInternal permMgrInt =
                LocalServices.getService(PermissionManagerServiceInternal.class);
        if (permMgrInt != null) {
   
   
            return permMgrInt;
        }
        new PermissionManagerService(context, externalLock);
        // 返回值是在PermissionManagerService构造函数中保存的
        return LocalServices.getService(PermissionManagerServiceInternal.class);
    }

首次调用这个方法,会先创建 PermissionManagerService 对象,然后返回的 PermissionManagerService 内部接口的一个对象。

创建 PermissionManagerService

那么来看下 PermissionManagerService 创建时候做了什么

    PermissionManagerService(Context context,
            @NonNull Object externalLock) {
   
   
         // 1. 初始化变量
        mContext = context;
        mLock = externalLock;
        mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
        mUserManagerInt = LocalServices.getService(UserManagerInternal.class);

        // PermissionSettings用于存储权限
        mPermissionSettings = new PermissionSettings(mLock);

        // 创建后台线程和Handler
        mHandlerThread = new ServiceThread(TAG,
                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
        Watchdog.getInstance().addThread(mHandler);

        // 一个默认的授权策略类
        mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
                context, mHandlerThread.getLooper(), this);
		
		// 2. 从SystemConfig中获取信息
        // SystemConfig是一个单例,在创建的时候会解析系统的配置文件
        SystemConfig systemConfig = SystemConfig.getInstance();
        // 保存SystemConfig解析的<assign-permission>标签的内容
        mSystemPermissions = systemConfig.getSystemPermissions()
<think>首先,用户的问题是关于AndroidPackageManagerService(PKMS)导致Watchdog超时的原因和解决方法。用户提供了几个引用,这些引用描述了Watchdog在SystemServer中的初始化和启动过程,以及PKMS和其他服务如何将自己添加到Watchdog的监视器中。 关键点: - Watchdog用于监视系统服务的响应性,防止服务死锁或长时间阻塞导致系统无响应。 - PKMS在启动过程中可能涉及耗时操作,如dexopt优化、磁盘维护等,这些操作可能导致Watchdog超时。 现在,我需要根据用户的问题和提供的引用,构建一个结构清晰的回答。回答应包括: 1. **原因分析**:解释PKMS导致Watchdog超时的可能原因。 2. **解决方法**:提供解决这些问题的建议。 3. **生成相关问题**:在回答末尾添加相关问题,以帮助用户深入理解。 ### 原因分析 从引用中: - 引用[1]和[2]显示,Watchdog在SystemServer启动时初始化和启动,PKMS在启动过程中执行一些耗时操作,如`updatePackagesIfNeeded()`(可能涉及dexopt优化)和`performFstrimIfNeeded()`(磁盘维护)。 - 引用[3]指出,PKMS将自己添加到Watchdog的HandlerChecker中,这意味着PKMS的主线程被Watchdog监视。 - 引用[4]描述了PKMS的main方法,其中涉及构造PKMS和启用服务。 PKMS导致Watchdog超时的常见原因: - **耗时操作**:PKMS在启动或系统准备就绪时执行的操作,如dexopt优化、包扫描、磁盘I/O等,这些操作可能阻塞主线程,导致Watchdog超时。 - **死锁**:PKMS与其他服务(如AMS、WMS)交互时可能发生死锁。 - **资源竞争**:在系统启动时,多个服务同时运行,PKMS可能因资源不足而延迟。 - **特定场景**:如OTA更新后首次启动,PKMS需要处理大量包更新。 ### 解决方法 - **优化PKMS启动**:减少不必要的操作,或异步执行耗时任务。 - **调整Watchdog超时时间**:临时增加超时时间,但不推荐作为长期解决方案。 - **日志分析**:检查logcat日志,识别超时时的具体操作。 - **代码审查**:检查PKMS代码,确保在关键路径上不阻塞主线程。 - **避免死锁**:确保锁的顺序一致,减少同步块。 ### 回答结构 1. **引言**:简要介绍问题。 2. **原因分析**:详细列出可能导致超时的原因。 3. **解决方法**:提供具体步骤和建议。 4. **结论**:总结关键点。 5. **相关问题**:生成相关问题。 ### 生成相关问题 基于用户问题,生成相关的问题: 1. 如何诊断Watchdog超时的具体原因? 2. 在PKMS中如何优化dexopt优化过程? 3. Watchdog超时对系统稳定性的影响是什么? 4. 如何修改Android源码以防止PKMS导致Watchdog超时? ### 确保格式 - 行内数学表达式:使用`$...$`,但在这个上下文中可能不需要数学,因为主题是Android系统。 - 独立公式:如果需要,使用`$$...$$`。 - LaTeX语法正确:在回答中,如果有数学,但这里可能没有。 - 使用中文回答:整个回答用中文。 - 引用标识:在引用段落末尾添加`[^n]`,如引用[1]。 用户提供的引用: - [^1]: Watchdog初始化和启动。 - [^2]: PKMS在SystemServer中的操作。 - [^3]: 服务添加到Watchdog。 - [^4]: PKMS的main方法。 在回答中,我需要自然地引用这些内容。 ### 最终回答大纲 1. **引言**:解释Watchdog的作用和PKMS导致超时的问题。 2. **原因分析**: - 耗时操作如dexopt优化。 - 死锁或资源竞争。 - 引用相关代码点。 3. **解决方法**: - 优化启动过程。 - 异步处理。 - 日志调试。 4. **结论**:强调预防措施。 5. **相关问题**:列出3-4个相关问题。</think>### PackageManagerService 导致 Watchdog 超时的原因及解决方法 在 Android 系统中,Watchdog 是一种监视机制,用于检测系统服务(如 PackageManagerService, PKMS)是否因死锁或长时间阻塞而无法响应。如果 PKMS 在关键路径上执行耗时操作,可能导致 Watchdog 超时(默认超时时间为 60 秒),触发系统重启或 ANR(Application Not Responding)。以下基于 Android 源码和工作流程分析原因及解决方案,引用内容来自您提供的资料。 #### 一、原因分析 PKMS 负责应用包管理(如安装、卸载、权限控制),在系统启动或运行时可能因以下操作导致 Watchdog 超时: 1. **耗时操作阻塞主线程**: - PKMS 在启动过程中执行 `updatePackagesIfNeeded()` 方法,涉及 dexopt 优化(将 APK 编译为 ODEX 文件)。此操作在 CPU 或 I/O 资源紧张时可能耗时过长,阻塞 SystemServer 主线程。引用[2]显示,此操作在 `startOtherServices` 中执行,且 Watchdog 会暂停监视当线程(`pauseWatchingCurrentThread`),但若优化时间过长,仍可能超时。 - 磁盘维护操作如 `performFstrimIfNeeded()`(引用[2]),在低端设备或磁盘碎片较多时可能延迟响应。 2. **死锁或资源竞争**: - PKMS 与其他服务(如 ActivityManagerService, AMS 或 WindowManagerService, WMS)共享锁资源。引用[3]指出,PKMS 在构造器中将自己添加到 Watchdog 的监视列表(`Watchdog.getInstance().addThread`)。如果 PKMS 与 AMS/WMS 发生交叉锁请求(例如 PKMS 等待 AMS 释放资源,而 AMS 又在等待 PKMS),会导致死锁。 - 多线程环境下,PKMS 的 Handler 线程(如 `mHandler`)处理消息队列时,若任务堆积(如批量安装应用),可能超时。 3. **系统启动高峰期的资源争用**: - 在 SystemServer 启动阶段,多个服务并行初始化。引用[1]和[4]显示,PKMS 在 `main()` 方法中注册服务时(`ServiceManager.addService("package", m)`),如果系统负载高(如低内存或 CPU 过载),PKMS 的初始化可能延迟,触发 Watchdog 超时。 4. **特定场景触发**: - OTA 更新后首次启动:PKMS 需重新扫描所有应用包,消耗大量时间。 - 大规模型应用安装:后台批量安装时,PKMS 的包解析和优化操作累积。 #### 二、解决方法 针对上述原因,可通过优化代码、调整配置或增强监控解决: 1. **异步执行耗时任务**: - 将 dexopt 优化或磁盘维护移至后台线程。例如,在 PKMS 的 `updatePackagesIfNeeded()` 方法中,使用 `AsyncTask` 或线程池拆分任务。确保主线程仅触发操作,不阻塞等待结果。引用[2]中 Watchdog 的 `pauseWatchingCurrentThread` 和 `resumeWatchingCurrentThread` 可用于临时豁免监视,但仍需减少主线程占用。 2. **优化锁机制**: - 避免在 PKMS 关键方法(如 `systemReady()`)中持有锁过久。使用细粒度锁或 `synchronized` 块替代方法级锁。 - 检查死锁:通过 `adb shell dumpsys watchdog` 获取超时时的线程堆栈,分析锁依赖关系。常见工具如 `systrace` 可可视化锁竞争。 3. **调整 Watchdog 超时阈值**: - 在设备兼容性允许下,临时增加超时时间(例如修改 `frameworks/base/services/core/java/com/android/server/Watchdog.java` 中的 `DEFAULT_TIMEOUT` 值)。但此方法非根治方案,仅用于调试: ```java public static final long DEFAULT_TIMEOUT = 60_000; // 改为 120_000(单位:毫秒) ``` 4. **日志分析与监控**: - 使用 `adb logcat -s Watchdog` 捕获超时事件,重点检查 `Watchdog: Blocked in handler` 日志,定位 PKMS 中阻塞的方法。 - 在 PKMS 代码中添加 Trace 点(如 `Trace.beginSection("PKMS_scan")`),结合 Perfetto 工具分析耗时。 5. **预防性优化**: - **减少启动任务**:在 PKMS 的 `main()` 方法(引用[4])中,延迟非关键操作(如非系统应用的 dexopt)到系统空闲时执行。 - **资源预留**:在低端设备上,通过 `ro.sys.fw.dexopt.background` 系统属性限制后台优化任务并发数。 - **升级硬件适配**:针对磁盘 I/O 瓶颈的设备,启用 F2FS 文件系统或增加缓存机制。 #### 三、总结 PKMS 导致 Watchdog 超时主要源于主线程阻塞或死锁,尤其在系统启动和包管理高峰期。根本解决需结合代码优化(如异步化)和资源管理。开发中可通过模拟高负载场景(如 Monkey 测试)提暴露问题。引用[3]强调,服务添加监视器是常规操作,但超时表明执行路径需重构[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值