我是靠谱客的博主 负责裙子,最近开发中收集的这篇文章主要介绍PackageManagerService分析(Android 10)->应用安装的整体流程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Android的应用安装分为三种情况,我们从adb命令可以窥探一二。

 install [-lrtsdg] [--instant] PACKAGE
     push a single package to the device and install it
 install-multiple [-lrtsdpg] [--instant] PACKAGE...
     push multiple APKs to the device for a single package and install them
 install-multi-package [-lrtsdpg] [--instant] PACKAGE...
     push one or more packages to the device and install them atomically

install主要用于安装单个apk文件。
install-multiple 用于安装split apk。关于split apk 请参考Google原生Split APK浅析 。 这里简单说明下,split apk的特点是多个安装包最终被安装成一个程序。
install-multi-package 命令用于同时安装多个应用,可以理解为批量安装。

另外安装有分为 正常安装和移动两种情况。

针对上述几种安装分类,在PackageManagerService中实现了几个类去处理不同情况。

在这里插入图片描述

这其中有两个抽象类,分别是HandlerParams和InstallArgs, 这一层用于指导整个安装过程,实现类有MutilPackageInstallParams和InstallParams, MutilPackageInstallParams用于负责批量安装, InstallParams则负责单一安装, MutilPackageInstallParams的成员变量mChildParams指向多个InstallParams, 说明批量安装其实就是调用多个单一安装的实现的。 另外一个抽象类InstallParams用于处理安装过程中的文件相关的操作,比如apk的拷贝,清理工作, 这部分有两个实现类,分别是FileInstallArgs用于正常安装过程的apk拷贝,而另外一个实现类MoveInstallArgs则用于移动应用apk。这里没有体现split apk的安装,其实split apk的安装特殊之处主要在于解析,安装过程会把属于同一split apk的apk文件放在相同的目录下面(比如/data/apk/xxxx/base.apk, /data/apk/xxxx/f1.apk, /data/apk/xxxx/f2.apk** )。这些apk具有相同包名,加载的时候也可以一起加载。 解析过程在PackageParser中,我们可以简单看下apk 的解析。

    /**
     * Parse only lightweight details about the package at the given location.
     * Automatically detects if the package is a monolithic style (single APK
     * file) or cluster style (directory of APKs).
     * <p>
     * This performs sanity checking on cluster style packages, such as
     * requiring identical package name and version codes, a single base APK,
     * and unique split names.
     *
     * @see PackageParser#parsePackage(File, int)
     */
    @UnsupportedAppUsage
    public static PackageLite parsePackageLite(File packageFile, int flags)
            throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackageLite(packageFile, flags);
        } else {
            return parseMonolithicPackageLite(packageFile, flags);
        }
    }

如果解析路径是一个文件夹,那么就会执行parseClusterPackageLite函数,对这个目录下的所有apk进行解析,所以split apk安装的apk信息在这个过程中完成并会。

下面忽略异步线程和一些中间函数我们来看下Pms的整体安装过程。
在这里插入图片描述
我们忽略安装的前半部分, 按照顺序来说明下安装过程,首先会通过Pms的INIT_COPY消息来通知Pms进行拷贝工作, 拷贝工作会调用HandlerParams来处理,这一步可能是由MutilPackageInstallParams来实现,也可能是由InstallParams来实现,调用handleStartCopy函数, 该函数最重要的工作就是计算应用安装的位置。 位置计算无误之后就会调用InstallParams.handleReturnCode() 函数,handleReturnCode()函数会调用InstallArgs来拷贝应用(一般拷贝到/data/app/${package}下)。 拷贝没有出现问题的话,就可以继续安装流程,通过PackageManagerService.processInstallRequestsAsync()函数将处理流程搞出来。 安装前调用InstallArgs.doPreInstall 函数再做一些准备工作, 然后调用PackageManagerService.installPackagesTracedLI, 这是安装过程中最核心的部分。安装完成后调用InstallArgs.doPostInstall 再做一些清理工作。 最终安装已经完成,调用PackageManagerService.handlePackagePostInstall做一些后续工作(比如发送应用变化相关的广播)。所以这里安装过程的重中之重是PackageManagerService.installPackagesTracedLI。

在这里插入图片描述

installPackagesTracedLI 步骤如上图, preparePackageLI函数主要还是进行安装的准备工作,我稍微做了些总结,大概如下:

preparePackageLI
    1 准备scanflags: move 表示已经初始化过,添加SCAN_INITIAL标志, 不需要杀掉添加 SCAN_DONT_KILL_APP, instantApp 为SCAN_AS_INSTANT_APP, fullApp 为 SCAN_AS_FULL_APP, virtualPreload 虚拟预加载SCAN_AS_VIRTUAL_PRELOAD
    2 instant app 不能安装在外置存储
    3 pp.parsePackage(tmpPackageFile, parseFlags) 解析, DexMetadataHelper.validatePackageDexMetadata(pkg) 验证dm文件
    4 instantApp 验证, targetSdkVersion不能小于o, 不能是isharedUid
    5 静态库修改包名,包名添加上version信息,方便安装多版本库
    6 子包的处理
    7 cpuAbiOverride 处理, 如果安装选项设置了使用安装选项覆盖
    8 TEST_ONLY app 应用判断是否可以安装, 没有-t选项不允许安装
    9 判断是否是replace安装
       9.1 包含original-package使用旧包名验证是否安装过
       9.2 非original-package使用包名看下是否安装过
       9.3 子包禁止安装
       9.4 替换安装情况下, targetSdk 范围检查
       9.5 禁止PERSISTENT 非 stage安装(因为可能会导致persistent被杀)
       9.6 禁止子包安装
    10 替换安装情况对签名进行检查
    11 权限处理
          11.1 除了系统应用之外不允许定义PROTECTION_FLAG_INSTANT级别的权限
          11.2 对于要更新的权限执行以下操作
               11.2.1 如果是应用升级则并且有升级key限制则验证
               11.2.2 没有升级key限制则验证证书匹配才可以升级权限
               11.2.3 非PLATFORM_PACKAGE_NAME禁止签名不同升级权限
               11.2.4 PROTECTION_DANGEROUS 权限禁止修改(降低) 保护级别
    12 系统应用禁止是instantApp,禁止安装在外置存储
    13 abi的处理
          13.1 move 应用安装位置,直接设置primaryCpuAbi 和 secondaryCpuAbi
          13.2 非move应用 derivePackageAbi
    14 修改包名
    15 fsverify
    16 startIntentFilterVerifications
    17 创建 freezer 禁止启动
    19 替换安装情况
         19.1 静态库禁止同版本升级
         19.2 再次验证签名
         19.3 验证系统应用升级的restrict-update
         19.4 检查shareduid是否变化
         19.5 禁止fullapp -> instant app 安装
         19.6 设置更新后被移除的子包
         19.7 系统包根据旧包设置targetParseFlags targetScanFlags, 设置setApplicationInfoFlags位FLAG_UPDATED_SYSTEM_APP
    20 非替换安装情况(新安装)
         20.1 没有指定INSTALL_REPLACE_EXISTING 禁止非替换安装
    21 创建 PrepareResult返回

scanPackageTrackLI函数主要用于生成PackageSetting数据结构

private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user) throws PackageManagerException
1 对于包含child的包
    先check扫描一遍
    再非check扫描一遍
2 不包含child的包直接非check扫描一遍

扫描函数scanPackageNewLI


private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user) throws PackageManagerException
    1 private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
            PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
            PackageParser.Package pkg)
         1 如果覆盖安装系统应用设置系统相关的扫描属性
         2 如果instant安装设置 SCAN_AS_INSTANT_APP, 如果 VirtulalPreload设置 SCAN_AS_VIRTUAL_PRELOAD
         3 如果签名是系统签名,并且shareduid 是privleged的,并且要安装的应用签名和平台签名一致,设置 SCAN_AS_PRIVILEGED(这相当于一种权限提升呀)
    2 applyPolicy 这一步根据scanFlags设置pkg.applicationInfo下的标志和 四大组件的标志
        1 系统应用设置
            1.1 directBootAware 设置所有组件的directBootAware标志
            1.2 如果是stub安装设置 pkg.isStub = true
        2 非系统应用删除一些特权flags,设置降低权限组优先级,pkg.permissionGroups.get(i).info.priority
        3 非SCAN_AS_PRIVILEGED app
            1 pkg.protectedBroadcasts = null
            2 不支持多用户的receivers services 和 providers 禁止导出
        4 设置其他标志
        5 不是SystemApp 不允许orginial-package
    3 assertPackageIsValid
        1 PARSE_ENFORCE_CODE 标志,检查hascode属性的apk是否包含代码
        2 必须设置codepath或者resourcePath
        3 不允许用户安装和手册启动或者ota检查apex包重复
        4 禁止重新安装平台包(android.jar)
        5 非安装过程禁止同名包
        6 静态库检查
    4 创建ScanRequest
    5 scanPackageOnlyLI


private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
            boolean isUnderFactoryTest, long currentTime)
扫描软件包设置Package 和PackageSettings
   1 第一次启动或者ota需要重新确定abi
   2 sharedUser不能修改
   3 创建PackageSettings(根据旧的或者重新创建)
   4 original-package 设置为旧报名,打日志
   5 修改状态 instant_app 或者full_app (full 不能到instant。 instant 能到full?)
   6 覆盖安装系统应用设置 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
   7 seInfo 设置 seInfoUser设置
   8 设置进程名称
   9 初始化系统user
   10 非安装流程SCAN_NEW_INSTALL = 0
       1 需要driverAbi
       2 不需要driverAbi 设置primaryCpuAbi, secondaryCpuAbi
   11 非安装流程, 设置primaryCpuAbi secondaryCpuAbi 和applicationInfo
   12 设置PackageSettings 的 firstInstallTime lastUpdateTime
   13 pkgSetting.pkg = pkg, pkgSetting.pkgFlags = pkg.applicationInfo.flags,  pkgSetting.versionCode = pkg.getLongVersionCode(), pkgSetting.volumeUuid = volumeUuid
   14 return new ScanResult                        

执行完scanPackageTrackLI之后Pms的两大核心数据结构都已经准备好了,一个是代表扫描结果的final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();中的PackageParser.Package,另外一个是mSettings.mPackages的PackageSetting 数据结构,这两个结构PackageParser.Package代表扫描结果,为静态数据,扫描完成后就不会发生变化。PackageSetting用于存储安装应用的动态数据,如权限授予情况等。PackageParser.Package由于是静态数据,扫描apk就可以获取。PackageSetting生成之后会被记录到文件中,以后每次系统启动都会重新加载。

生成PackageSetting和PackageParser.Package数据结构后,还需要对多个安装apk结果进行调和,这就是reconcilePackagesLocked函数, 一般在 install-multi-package的时候会同时安装多个apk。

经过上述几个步骤,两个核心数据结构虽然已经生成,但是并没有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以该包里面的组件等还不能查询到,也不能启动。 所以需要commitPackagesLocked来进行提交, 提交之后该应用就算完整发布了。

commitPackagesLocked(commitRequest)
    1 replace
        1 设置了一遍ps的firstInstalltime 和lastUpdateTime
        2 系统应用
           1 删除旧的package
           2 删除覆盖安装的system 应用的应用,需要删除的东西放在removedInfo中
           3 处理child package
        3 非系统应用
           1 删除package
           2 手机要删除的数据
        4 commitReconciledScanResultLocked 正式提交



commitReconciledScanResultLocked
    1 sharedUser发生变化,移除旧的sharedUser
    2 更新应用 使用旧的packageSettings更新 packageSettings,pkg.mExtras = pkgSetting
    3 新安装 设置pkgSetting为 result.pkgSetting
    4 添加package 到sharedUser
    5 写入配置文件
    6 更新sharedlibrary
    7 更新签名信息
    8 transfer permission
    9 code path 有变化,mInstaller.rmdex
    10 SCAN_CHECK_ONLY  mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting)
    11 commitPackageSettings

private void commitPackageSettings
   1 如果因安装的包包含mCustomResolverComponentName, 更新
   2 如果是android 应用,并且非check, 设置 mPlatformPackage pkg.mVersionCode = mSdkVersion; pkg.mVersionCodeMajor = 0;  mAndroidApplication = pkg.applicationInfo; mResolverReplaced没有替换,设置系统的resolveActivity
   3 更新sharedLibrary
   4 lib更新,杀掉 依赖的包
   5 mSettings.insertPackageSettingLPw(pkgSetting, pkg);
            // Add the new setting to mPackages
            mPackages.put(pkg.applicationInfo.packageName, pkg); 更新核心数据
   6 mComponentResolver.addAllComponents(pkg, chatty) 添加所有组件
   7 mPermissionManager.addAllPermissionGroups(pkg, chatty) 添加所有权限组
   8 mPermissionManager.addAllPermissions(pkg, chatty); 添加所有权限
   9 instrumentation
   10 pkg.protectedBroadcasts
   11 mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
                                allPackageNames, mPermissionCallback)) 撤销需要撤销的权限



 private void updateSettingsInternalLI(PackageParser.Package pkg,
            String installerPackageName, int[] allUsers, int[] installedForUsers,
            PackageInstalledInfo res, UserHandle user, int installReason)
   1 系统应用
       1 设置多用户
   2 删除多余的用户
   3 写配置文件

executePostCommitSteps 函数主要是dexoat部分工作,这部分不会修改核心数据结构,所以在mPackage锁外面执行。

executePostCommitSteps(commitRequest)
private void executePostCommitSteps(CommitRequest commitRequest)
  1 prepareAppDataAfterInstallLIF
  2 准备/data/data下的文件夹
  3 mArtManagerService.prepareAppProfiles
  4 mViewCompiler.compileLayouts(pkg)
  5 mPackageDexOptimizer.performDexOpt

handlePackagePostInstall 就是最后完成安装的一些通知工作了。

private void restoreAndPostInstall(
            int userId, PackageInstalledInfo res, @Nullable PostInstallData data)
    1 如果该应用可以备份恢复,并且BackupManager活跃状态通知尝试恢复数据
    2 没有restore情况下升级安装可能是降级安装, 尝试使用rollbackMnaager恢复数据, rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
                            seInfo, token);
    3 没有doRestore的情况下 POST_INSTALL, 否则等安装备份或者rollback调用



private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload,
            String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver)
    1 安装成功
       1 remove 发送广播
       2 权限假如白名单
       3 根据安装参数授予运行时全新啊
       4 对每一个安装的用户
           1 发送newuser广播
           2 ACTION_PACKAGE_REPLACED

最后

以上就是负责裙子为你收集整理的PackageManagerService分析(Android 10)->应用安装的整体流程的全部内容,希望文章能够帮你解决PackageManagerService分析(Android 10)->应用安装的整体流程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部