Apk安装流程----基于Android Q

基于Android Q,以普通三方应用通过PackageInstaller进行安装的安装流程为例来进行分析。

1.Apk文件结构

2.PackageInstaller中的Activity介绍以及流程 

(1).相关Activity介绍

InstallStart:入口,以及通过不同的协议(content,package等)启动InstallStaging或是PackageInstallerActivity。

content uri: InstallStaging

package uri: PackageInstallerActivity

InstallStaging: 从content协议的uri加载包并将其转换为文件,然后从文件进行安装;先跳转到DeleteStagedFileOnResult再跳转到PackageInstallerActivity;在这个过程中会进行一次apk拷贝。InstallStaging主要起了转换的作用,将content协议的Uri转换为File协议,最后还是跳转到PackageInstallerActivity。

mStagedFile用于存储临时数据:

DeleteStagedFileOnResult:跳转到PackageInstallerActivity,并在安装成功后,点击“完成”按钮的时候,删除staged文件mStagedFile:

/data/user_de/0/com.android.packageinstaller/no_backup/packageXXX24325.apk

PackageInstallerActivity:处理pkgUri并校验安装权限(包括检查安装来源等),初始化安装,与用户交互同意安装后跳转到InstallInstalling。

processPackageUri: 处理pkgUri:

SCHEME_PACKAGE,通过mPm.getPacjageInfo获取pkgInfo;

SCHEME_FILE, 通过parsePackage获取pkgInfo。

startInstall:跳转到InstallInstalling进行安装

InstallInstalling:通过PackageInstall.Session与PKMS进行会话,调用Session.commit触发installStage,发送INIT_COPY信号,进行PKMS驱动apk安装过程。

在InstallInstalling中会把apk通过IO流的形式写入到PackageInstaller.Session中:

安装过程中查看/data/app/vmdl1193070706.tmp:

(2).简要跳转流程  

关键点及关键方法说明:

(1)createSession,最终创建一个PackageInstallerSession实例。这些工作最终均是在PackageInstallerService中进行处理。

(2)openSession,即把createSession创建的PackageInstallerSession实例赋值给PackageInstaller.Session,然后开始对这个session的一系列操作。

(3)Session与PackageInstallerSession之间的关系

PackageInstallerSession可以看做是”安装APK”这个请求的封装,其中包含了处理这个请求需要的一些信息。实际上PackageInstallerSession不仅是分装请求的对象,其自身还是个服务端。

3.框架中的调用流程

 一些类的关系图:

关键点及关键方法说明:

(1)doWriteInternal: 进行拷贝,把APK的信息通过IO流的形式写入到Session中(保存在/data/app/vmdl2037227404.tmp/PackageInstaller file中):

(2)在commit的时候,在PackageInstallerSession中,会进行一系列的验证apk,如sealAndValidateLocked/validateApkInstallLocked等,在validateApkInstallLocked过程中,会把Session中PackageInstaller file拷贝到base.apk中:

(3)在commitNonStagedLocked的时候,会调用makeSessionActiveLocked()来生成实例:PackageManagerService.ActiveInstallSession committingSession,在这个实例中,包含了一个File mStagedDir; 在new ActiveInstallSession的时候,会把stageDir赋值给mStagedDir。(stageDir.getPath() = /data/app/vmdl1472338542.tmp)

(4)在makeSessionActiveLocked()的时候,会调用extractNativeLibraries来拷贝so库

最终调用NativeLibraryHelper.copyNativeBinariesWithOverride(不再具体分析)

(5)在installStage(committingSession)的时候,会new InstallParams(activeInstallSession),在InstallParams构造方法中:

origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());

(6)在doCopy中,由于origin.staged为true,所以不再需要重新拷贝一次,

(7)拷贝完成后,调用processPendingInstall进行安装

分为三步:

doPreInstall:如果安装失败则清理文件;

installPackagesTracedLI:安装;

doPostInstall:如果安装失败则清理文件。

4.installPackagesTracedLI ,调用installPackagesLI,installPackagesLI主要分为四步:

准备阶段:在这个阶段,主要是parsePackage(解析(AndroidManifest文件),拷贝lib目录,oRename把临时文件名改为以包名命名的文件,冷冻应用(如果应用进程存在则kill掉应用进程),最后创建一个PrepareResult实例返回。

扫描阶段:在这个阶段,主要是scanPackageTracedLI扫描应用,创建uid,生成PackageSetting,最后创建一个ScanResult实例返回。

验证阶段:调用verifySignatures()进行校验签名,最后生成ReconciledPackage并返回。

提交阶段:将扫描的包添加到系统中(将pkgSetting,放到Settings.mPackages中)。此方法完成后,包将可用于查询、解析等,更新package-restrictions.xml,packages.xml等文件。

关键点及关键方法说明:

(1)derivePackageAbi,调用NativeLibraryHelper.copyNativeBinariesForSupportedAbi拷贝lib到/data/app/vmdl2037227404.tmp/lib目录;

(2)doRename,把/data/app/vmdl2037227404.tmp变更为:

/data/app/com.jingdong.app.mall-PSHCChPZmCvSZxKAiBuXoA==,也就是我们最后在data/app目录下看到的应用安装后的名字;

(3)freezePackageForInstall,冷冻应用,即kill掉应用进程,并把kill掉的应用进程包名添加到ArraySet<String> mFrozenPackages中,这样当有其它进程在此应用冷冻期间调用应用的话,会报错:

Package " + packageName + " is currently frozen! //(在checkPackageStartable中check)

应用安装完成后会解冻,即在mFrozenPackages中移除包名。

(4)scanPackageNewLI,在安装应用的时候会调用,在开机扫描的时候也会调用到。主要是获取SharedUserSetting(如果没有则new一个,在new的过程中会生成一个uid),构建ScanRequest并且调用scanPackageOnlyLI()获取ScanResult。

(5)scanPackageOnlyLI,主要是更新packageSetting和nativelibrary的解析,扫描文件为:

scanFile = /data/app/com.jingdong.app.mall-PSHCChPZmCvSZxKAiBuXoA==

更新或创建新的PackageSetting,创建的情况有两种,首次安装应用或者是恢复出厂开机;解析apk中的native so库,并获取对应so库的路径,这里有个SCAN_NEW_INSTALL,这个是给安装用的,开机scan是不会有此问题;设置安装的时间戳,主要是第一次安装和当前安装;创建ScanResult并返回。

(6)reconcilePackagesLocked,在安装应用的时候会调用,在开机扫描的时候也会调用到;生成ReconciledPackage并返回。

(7)commitReconciledScanResultLocked,安装应用和扫描应用同时都会调用的方法,处理PackageSetting,将PackageSetting写入package-restrictions.xml,

/data/system/users/0/package-restrictions.xml,里面主要存储的是disabled和enabled四大组件。

(8)commitPackagesLocked,将扫描的包添加到系统中。此方法完成后,包将可用于查询、解析等;调用mSettings.insertPackageSettingLPw(),这里并非是更新packages.xml的地方,只是将pkgSetting,放到Settings.mPackages中;将AndroidPackage放到mPackages中。

(9)updateSettingsLI,调用updateSettingsInternalLI,主要是调用updatePermissions更新权限,以及调用mSettings.writeLPr();把信息写入到/data/system/packages.xml,所有安装的应用都会在这里面记录。

(10)executePostCommitSteps,通过调用prepareAppDataAfterInstallLIF,进入调用到Installer.createAppData创建数据目录,最终调用到Installd.createAppData;并调用mPackageDexOptimizer.performDexOpt进行dex优化。

(11)通过PackageDexOptimizer.performDexOpt创建了oat的路径,最后还是调用到Installer.dexopt,最终调用Installd.dexopt进行dex优化。

5.验证签名

验证时机:commit的时候,在PackageInstallerSession中,会进行一系列的验证apk,如sealAndValidateLocked->validateApkInstallLocked等,在validateApkInstallLocked过程中,会调用PackageParser.parseApkLite,parseApkLite的时候,会进行签名验证:

在parseApkLiteInner方法中:

 

 如果签名不对的话,安装流程再这里就终止了:

接下来就会start InstallFailed界面。

6.Dex优化

优化时机:

执行executePostCommitSteps的时候,会调用mPackageDexOptimizer.performDexOpt进行dex优化。PackageDexOptimizer.performDexOpt创建了oat的路径,最后还是调用到Installer.dexopt,最终调用Installd.dexopt进行dex优化。(11)点已经记录,不再重复。

7.总结

APK核心安装步骤

(1)从AndroidManifest中解析出应用信息、各组件信息、权限信息,代码索引为PackageParser.parsePackage

(2)为应用程序分配UID,并让PKMS记录各个组件信息,代码索引为PKMS. scanPackageNewLI、Setting.addUserIdLPw

(3)更新应用程序权限信息,授权应用程序资源访问权,代码索引为mPermissionManager.updatePermissions

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值