PackageManagerService流程

本文详细介绍了Android系统中PMS(PackageManagerService)如何在启动时及用户安装时处理应用程序的过程,包括解析APK文件、分配权限、写入安装信息等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PMS安装应用程序流程

一、启动时安装

1、查看PMS的功能与启动过程,首先PMS是在systemserver中启动的。之后分为两大部分启动

  • 1)恢复之前的引用安装信息:在main中new,开始调用readLP()恢复上一次引用程序安装信息(读取/data/system/packages.xml文件)—-> ScanDirLP()扫描指定目录—->readPackageLP()、addPackageLP()来读取解析xml文件中的信息。。。。。
  • 2)应用程序安装过程:调用scanDirLI扫描指定目录下(system/framework、system/app等)的文件时候有.apk的应用,—–>scanPackageLI()解析.apk—> PackageParser.parsePackage()实现真正的解析工作(读取AndroidManfest.xml文件等)—–>解析正确—->调用另一个重载的scanPackageLI()来安装应用。
  • 3)安装好应用之后,updatePermissionsLPw()—–> grantPermissionsLPw()——–>requestedPermissions,分配LINUX的用户组ID,即资源访问权限,最后writeLP()将应用信息写入到本地—->writePackage()将应用安装信息写到/data/system/packages.xml中,这正好一第一步中的readLP()与readPackageLP()形成闭环。

注意:

  • (a) 重载的scanPackageLI()来安装应用后,已经安装的应用的四大组件都会记录在PackageManagerService类的成员变量mActivitys,mReceivers,mServices,mProvidersByComponent中。应用使用Packages对象保存在mPackages所属的HashMap中
  • (b) AMS是负责管理应用程序进程的,在ActivityManagerService.java中会通过 startProcessLocked()函数中的 pm.getPackageGids(app.info.packageName)获取需要创建应用程序的LINUX用户ID和LInux用户组ID,此LINUX用户ID和LInux用户组ID正是PMS安装应用程序时创建的。

二、用户安装

adb install xxx.apk

PM : pm.java---->run()---->runInstall()
                |
            .....binder.....
                |
PMS :      installPackageAsUser()
                |
                  消息机制
                final Message msg = mHandler.obtainMessage(INIT_COPY);
                msg.obj = new InstallParams(origin, observer, installFlags,
                    installerPackageName, verificationParams, user, packageAbiOverride);
                mHandler.sendMessage(msg)
                |
            doHandleMessage(Message msg) 
                |
            case INIT_COPY
                |
            connectToService()流程
            然后再发送一个消息到 MCS_BOUND
                |
            case  MCS_BOUND
                |
            params.startCopy()
                |
            handleReturnCode()
                |
            processPendingInstall(mArgs, mRet)
                |
            installPackageLI(args, res)
                |
            pkg = pp.parsePackage(tmpPackageFile, parseFlags) //用parsePackage解析APK
                |
            installNewPackageLI()
                |
            scanPackageLI() //重载
                |
            接下你就和启动时安装应用流程一样
                  .....

MCS_BOUND 消息发送流程
connectToService()的最后会在AMS中的publishServiceLocked()函数中通过ContextImpl传过去的connection的IBinder接口,调用connected()函数

注意:

重载的scanPackageLI()函数
- 1、private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, …
- 2、private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, …
和启动是被调用的scanPackageLI()不一样,启动是安装要调用两次scanPackageLI()重载函数,而用户安装值调用2

发现问题:

Message消息循环
问题:sendMessage与handleMessage是怎么实现的???
Android应用程序在每一个线程启动的时,都会在内部创建一个消息队列,然后进入到无限循环中,不断检查消息队列是否有新消息需要处理。如果有则会从消息队列中取出来,处理。否则线程就会进入睡眠状态

connectToService()流程

doHandleMessage             ----PMS
    | 
connectToService()      
    |
mContext.bindServiceAsUser()        ----ContextImpl.java
    |
ActivityManagerNative.getDefault().bindService()    ----ContextImpl.java
    |
{Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>()
IBinder b = ServiceManager.getService("activity")
IActivityManager am = asInterface(b)}
    |
IActivityManager.bindService()      ----ActivityManagerNative
    |
   ...binder...
    |
ActivityManagerService.bindService()    ----AMS
    |
mServices.bindServiceLocked()       ----ActiveServices.java
    |
retrieveServiceLocked()
bringUpServiceLocked()
    |
startProcessLocked()
    |
启动com.android.defcontainer/.DefaultContainerService   比较核心的拷贝/重命名/删除都会在这个service中进行
<think>我们被要求分析PackageManagerService.java中应用安装和卸载的流程。根据提供的引用,特别是引用[3]和引用[4],我们可以大致了解PMS在应用安装和卸载过程中的核心作用。 安装流程: 1. 解析AndroidManifest.xml:获取应用的基本信息,如包名、版本、组件(activity、service等)声明、权限等。 2. 验证和准备安装:检查安装条件(如签名、权限、存储空间等),确定安装位置(内部存储或SD卡)。 3. 复制APK文件到目标目录:通常是将APK复制到/data/app目录下。 4. 创建应用数据目录:在/data/data/下创建以包名命名的目录,用于存放应用的数据。 5. 更新系统状态:将新安装的应用信息添加到PMS的内部数据结构中,更新权限信息,发送广播通知系统应用状态变化。 卸载流程: 1. 删除APK文件:从/data/app目录中移除APK文件。 2. 删除应用数据目录:包括/data/data/包名下的数据目录和可能存在的SD卡上的数据。 3. 更新系统状态:从PMS的内部数据结构中移除该应用的信息,更新权限信息,发送广播通知系统。 根据引用[4],卸载过程还需要注意多用户环境、共享库依赖以及系统应用的特殊处理。 现在,我们结合引用[3]中提到的源码位置,进一步分析安装和卸载流程。 安装流程详细步骤(参考源码): - 入口:PackageManagerService的installPackage方法(可能通过PackageInstallerService触发)。 - 步骤: 1. 解析包(parsePackage):使用PackageParser解析APK文件,生成Package对象。 2. 验证安装包(verifySignatures等):检查签名,确保安全。 3. 执行安装(installPackageLI):这是安装的核心方法,其中LI表示需要持有安装锁(mInstallLock)进行。 - 将APK文件复制到目标目录(如/data/app/包名-1/base.apk)。 - 创建应用数据目录(通过InstallerConnection调用installd创建目录并设置权限)。 - 将解析得到的Package信息添加到PMS的mPackages等数据结构中。 - 更新权限(updatePermissionsLI)和设置(如默认的权限授予)。 - 发送广播(ACTION_PACKAGE_ADDED)通知系统新包已安装。 卸载流程详细步骤: - 入口:PackageManagerService的deletePackage方法。 - 步骤: 1. 删除包(deletePackageLI):需要持有安装锁(mInstallLock)。 - 删除APK文件(从/data/app目录)。 - 通过InstallerConnection调用installd删除应用的数据目录(/data/data/包名)。 - 从PMS的mPackages等数据结构中移除该包的信息。 - 更新权限(updatePermissionsLI)。 - 发送广播(ACTION_PACKAGE_REMOVED)通知系统包已被移除。 注意:卸载系统应用时,如果系统应用有更新,则卸载更新会回退到初始版本;如果是预装应用,则可能无法卸载(只能禁用)。 根据引用[3]和引用[4],我们还可以了解到PMS通过Binder与installd(一个本地守护进程)交互来执行文件操作(如复制、删除、设置权限等)。installd负责处理应用目录的创建和删除,因为它需要以root权限运行。 在分析源码时,可以重点关注以下方法: - installPackageLI:安装的核心逻辑。 - deletePackageLI:卸载的核心逻辑。 - scanPackageTracedLI:扫描安装包,解析包信息。 - deleteDir:删除目录(通过installd)。 另外,引用[3]提到,在安装过程中,PMS会检查白名单(如果实现了白名单功能)。这通常是在安装前进行的权限检查。 由于源码较长,这里不贴出完整代码,但我们可以描述关键步骤。 安装流程(详细): 1. 通过Binder调用到PMS的installPackage方法(可能来自PackageInstaller应用)。 2. 进行权限检查(调用者必须具有INSTALL_PACKAGES权限)。 3. 创建InstallParams(处理安装参数),并将其加入处理队列。 4. 在Handler处理中,调用processInstallRequestAsync开始异步处理。 5. 在安装过程中,会调用installPackageTracedLI方法,该方法内部调用installPackageLI。 6. 在installPackageLI中: - 创建安装目录(如果需要)。 - 将APK文件复制到/data/app目录(通常使用AtomicFile确保原子性)。 - 解析APK(PackageParser.parsePackage)。 - 验证签名。 - 如果之前有安装,则进行升级操作(替换APK,保留数据)。 - 为新安装的应用分配UID(如果未指定)。 - 调用scanPackageNewLI扫描新安装的包,将其添加到PMS的mPackages中。 - 更新Settings(将新包的信息写入packages.xml和packages.list)。 - 为新应用创建数据目录(通过mInstaller.createAppData创建)。 - 发送广播。 卸载流程(详细): 1. 通过Binder调用PMS的deletePackage方法。 2. 进行权限检查(调用者必须具有DELETE_PACKAGES权限)。 3. 创建DeletePackageArgs,并调用deletePackageVersioned方法。 4. 最终调用deletePackageLI方法: - 检查包是否存在,以及是否允许卸载(如系统应用不可卸载,但可以卸载更新)。 - 删除APK文件(移除/data/app下的目录)。 - 删除数据目录(通过mInstaller.destroyAppData递归删除数据目录)。 - 从PMS的mPackages等结构中移除包信息。 - 更新Settings(从packages.xml和packages.list中移除)。 - 发送广播。 以上是应用安装和卸载的主要流程。由于Android版本不同,具体实现可能有所差异,但核心步骤基本一致。 相关问题: 1. 在应用安装过程中,PMS是如何处理共享库依赖的? 2. 在卸载系统应用更新时,PMS是如何回退到初始版本的? 3. PMS在安装过程中如何确保多个用户之间的应用安装隔离?</think>### PackageManagerService 应用安装与卸载流程分析 #### **一、应用安装流程** 1. **入口与权限校验** 安装请求通过 `PackageManagerService.installPackage()` 入口触发[^3]。首先校验调用者权限(`INSTALL_PACKAGES`),并验证 APK 签名和包名合法性。 2. **APK 文件处理** - 复制 APK 到目标目录:`/data/app/<包名>-<随机后缀>` - 调用 `Installer` 服务(通过 `installd` 守护进程)创建应用数据目录:`/data/data/<包名>`[^4]。 3. **解析与注册** - 使用 `PackageParser` 解析 APK 的 `AndroidManifest.xml`,生成 `Package` 对象[^3]。 - 更新 PMS 内部数据结构: ```java mPackages.put(packageName, pkg); // 添加到包列表 mSettings.writeLPr(); // 写入packages.xml ``` - 注册四大组件(Activity/Service 等)到 `ActivityTaskManagerService`[^3]。 4. **资源优化与权限分配** - 调用 `performDexOpt()` 执行 Dex 优化(生成 ODEX 文件)。 - 分配应用 UID 并授予声明权限,更新 `packages.list` 文件[^4]。 5. **广播通知** 发送 `ACTION_PACKAGE_ADDED` 广播,通知系统应用安装完成[^4]。 --- #### **二、应用卸载流程** 1. **入口与校验** 卸载请求通过 `PackageManagerService.deletePackage()` 触发,校验 `DELETE_PACKAGES` 权限[^4]。 2. **资源清理** - 删除 APK 文件:`/data/app/<包名>-<随机后缀>` - 通过 `Installer.destroyAppData()` 删除数据目录: ```java mInstaller.destroyAppData(packageName, userId, flags); // 清理/data/data/<包名> ``` - 若为 SD 卡安装,同步删除外部存储数据[^4]。 3. **状态更新** - 从 PMS 内部结构移除包信息: ```java mPackages.remove(packageName); mSettings.removePackageLPw(packageName); // 更新packages.xml ``` - 撤销应用权限并回收 UID[^3]。 4. **多用户与依赖处理** - **多用户环境**:遍历所有用户删除应用数据(`/data/user/<userId>/<包名>`)。 - **共享库依赖**:检查是否有其他应用依赖当前包的共享库,若有则强制停止依赖应用[^4]。 5. **系统应用特殊处理** - 卸载系统应用更新时,回退到初始版本(`/system/app` 下的原始 APK)。 - 发送 `ACTION_PACKAGE_REMOVED` 广播[^4]。 --- #### **三、关键源码位置** 1. **安装核心逻辑** - 入口:`PackageManagerService.installPackage()` - APK 复制:`FileUtils.copyFile()` - 包解析:`PackageParser.parsePackage()`[^3] - 数据目录创建:`Installer.createAppData()` 2. **卸载核心逻辑** - 入口:`PackageManagerService.deletePackageVersioned()` - 资源删除:`Installer.destroyAppData()` - 状态更新:`Settings.removePackageLPw()`[^4] 3. **跨进程通信** PMS 通过 Binder 与 `installd` 交互,文件操作由 `InstallerConnection` 实现[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值