当前位置: 首页 > news >正文

Android 安装应用-提交阶段之后剩下的操作

  它的实现代码在executePostCommitSteps(commitRequest)中,看一下它的代码:

    /*** On successful install, executes remaining steps after commit completes and the package lock* is released. These are typically more expensive or require calls to installd, which often* locks on {@link #mLock}.*/private void executePostCommitSteps(CommitRequest commitRequest) {final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;final String packageName = pkg.getPackageName();final String codePath = pkg.getPath();final boolean onIncremental = mIncrementalManager != null&& isIncrementalPath(codePath);if (onIncremental) {IncrementalStorage storage = mIncrementalManager.openStorage(codePath);if (storage == null) {throw new IllegalArgumentException("Install: null storage for incremental package " + packageName);}incrementalStorages.add(storage);}prepareAppDataAfterInstallLIF(pkg);if (reconciledPkg.prepareResult.clearCodeCache) {clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);}if (reconciledPkg.prepareResult.replace) {mDexManager.notifyPackageUpdated(pkg.getPackageName(),pkg.getBaseApkPath(), pkg.getSplitCodePaths());}// Prepare the application profiles for the new code paths.// This needs to be done before invoking dexopt so that any install-time profile// can be used for optimizations.mArtManagerService.prepareAppProfiles(pkg,resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),/* updateReferenceProfileContent= */ true);// Compute the compilation reason from the installation scenario.final int compilationReason = mDexManager.getCompilationReasonForInstallScenario(reconciledPkg.installArgs.mInstallScenario);// Construct the DexoptOptions early to see if we should skip running dexopt.//// Do not run PackageDexOptimizer through the local performDexOpt// method because `pkg` may not be in `mPackages` yet.//// Also, don't fail application installs if the dexopt step fails.final boolean isBackupOrRestore =reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE|| reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP;final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE| (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);DexoptOptions dexoptOptions =new DexoptOptions(packageName, compilationReason, dexoptFlags);// Check whether we need to dexopt the app.//// NOTE: it is IMPORTANT to call dexopt://   - after doRename which will sync the package data from AndroidPackage and//     its corresponding ApplicationInfo.//   - after installNewPackageLIF or replacePackageLIF which will update result with the//     uid of the application (pkg.applicationInfo.uid).//     This update happens in place!//// We only need to dexopt if the package meets ALL of the following conditions://   1) it is not an instant app or if it is then dexopt is enabled via gservices.//   2) it is not debuggable.//   3) it is not on Incremental File System.//// Note that we do not dexopt instant apps by default. dexopt can take some time to// complete, so we skip this step during installation. Instead, we'll take extra time// the first time the instant app starts. It's preferred to do it this way to provide// continuous progress to the useur instead of mysteriously blocking somewhere in the// middle of running an instant app. The default behaviour can be overridden// via gservices.//// Furthermore, dexopt may be skipped, depending on the install scenario and current// state of the device.//// TODO(b/174695087): instantApp and onIncremental should be removed and their install//       path moved to SCENARIO_FAST.final boolean performDexopt =(!instantApp || Global.getInt(mContext.getContentResolver(),Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)&& !pkg.isDebuggable()&& (!onIncremental)&& dexoptOptions.isCompilationEnabled();if (performDexopt) {// Compile the layout resources.if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");mViewCompiler.compileLayouts(pkg);Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");ScanResult result = reconciledPkg.scanResult;// This mirrors logic from commitReconciledScanResultLocked, where the library files// needed for dexopt are assigned.// TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous//  setting needs to be passed to have a comparison, hide it behind an immutable//  interface. There's no good reason to have 3 different ways to access the real//  PackageSetting object, only one of which is actually correct.PackageSetting realPkgSetting = result.existingSettingCopied? result.request.pkgSetting : result.pkgSetting;if (realPkgSetting == null) {realPkgSetting = reconciledPkg.pkgSetting;}// Unfortunately, the updated system app flag is only tracked on this PackageSettingboolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState().isUpdatedSystemApp();realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,null /* instructionSets */,getOrCreateCompilerPackageStats(pkg),mDexManager.getPackageUseInfoOrDefault(packageName),dexoptOptions);Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}// Notify BackgroundDexOptService that the package has been changed.// If this is an update of a package which used to fail to compile,// BackgroundDexOptService will remove it from its denylist.// TODO: Layering violationBackgroundDexOptService.notifyPackageChanged(packageName);notifyPackageChangeObserversOnUpdate(reconciledPkg);}waitForNativeBinariesExtraction(incrementalStorages);}

  首先对ReconciledPackage对象循环,得到AndroidPackage对象pkg,包名、文件路径。
  接着调用prepareAppDataAfterInstallLIF(pkg),它主要用来创建应用需要使用的文件或文件夹。应用需要使用的文件或文件夹和参数uuid(存储位置相关)、userId和包名相关。如果uuid为null,userId为0,则文件夹为"/data/data/“(版本遗留) + 包名 或 “/data/user/0/” + 包名,及其目录下面的"cache"和"code_cache"目录;”/data/user_de/0/" + 包名,及其目录下面的"cache"和"code_cache"目录,如果"dalvik.vm.usejitprofiles"属性值为true的情况下(和JIT编译有关),还会创建 “/data/misc/profiles/cur/0” + 包名 目录 和 “/data/misc/profiles/ref/” + 包名 目录。
  如果reconciledPkg.prepareResult.clearCodeCache为true,代表需要清除代码缓存,所以调用带有Installer.FLAG_CLEAR_CODE_CACHE_ONLY标识的clearAppDataLIF()方法。带这个标识的方法,就是清除这个应用数据文件夹下面的"code_cache"目录及其中文件。
  reconciledPkg.prepareResult.replace为true,代表是替换升级。mDexManager.notifyPackageUpdated()通知mDexManager应用包发生了更新,它会更新其中应用的安装位置,去除使用该应用的其他APP。
  mArtManagerService.prepareAppProfiles()是和使用profile优化应用有关,它的参数updateReferenceProfileContent为true,代表它需要将dex元数据文件(“.dm"结尾文件)更新到它自己引用的profile内容中,这块需要使用Profman程序。主APK文件相关的profile文件名为"primary.prof”。
  接着往下就是和执行Dex优化相关的,就是将相关的Dex指令转化成对应的机器指令。
  在属性变量PRECOMPILE_LAYOUTS值为true,调用mViewCompiler.compileLayouts(pkg)。它是用来将布局资源文件转化成dex文件。生成的dex文件为 包的数据目录 + “/code_cache/compiled_view.dex”。包的数据目录和uuid、userId、ce标识相关,如果uuid为null,userId为0,ce标识存在,则生成的文件位置为"/data/user/0/" + packageName + “/code_cache/compiled_view.dex”。它是对应用的一种优化。
  可以看到执行dexopt需要满足几个条件:不是instantApp,除非设置了Global.INSTANT_APP_DEXOPT_ENABLED对应的值不为0;包不是debuggable;不是在增量文件系统上。
  接着,BackgroundDexOptService.notifyPackageChanged(packageName) 是从BackgroundDexOptService中将应用包从之前编译失败的名单中去除。
  notifyPackageChangeObserversOnUpdate(reconciledPkg) 是通知注册在PackageManagerService对象成员mPackageChangeObservers集合中的每一个元素,调用它的onPackageChanged(event)方法。
  最后waitForNativeBinariesExtraction(incrementalStorages) 是处理增量更新的。

总结

  该阶段主要就是创建应用需要使用的目录,在更新应用安装情况下,会将代码缓存目录"code_cache"目录及其中文件清除。如果有dex元数据文件(.dm文件)会将它更新到应用的profile中去,如果满足dex优化条件,会执行Dexopt。

相关文章:

  • 引入Scrum激发研发体系活力
  • 【ArcGIS Pro实操第三期】多模式道路网构建(Multi-model road network construction)原理及实操案例
  • Mac屏蔽系统更新,取出红点标记如果解锁hosts文件
  • css3-----2D转换、动画
  • 【C语言指南】数据类型详解(上)——内置类型
  • 质量技术支持对用户忠诚度的影响
  • Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)
  • CSP-J模拟赛一补题报告
  • 经典文献阅读之--WiROS(用于机器人的WiFi感知工具箱)
  • AutoSar 通信服务架构,CAN通信诊断详解
  • WPS使用越来越卡顿
  • 【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69
  • Vue 3中进行组件开发
  • vue3中< keep-alive >页面实现缓存及遇到的问题
  • OpenAI o1与GPT-4o究竟强在哪里
  • 2019年如何成为全栈工程师?
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • C# 免费离线人脸识别 2.0 Demo
  • CSS魔法堂:Absolute Positioning就这个样
  • es6
  • extract-text-webpack-plugin用法
  • input的行数自动增减
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • java8 Stream Pipelines 浅析
  • JavaScript函数式编程(一)
  • Shell编程
  • SpiderData 2019年2月16日 DApp数据排行榜
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • vuex 学习笔记 01
  • Webpack入门之遇到的那些坑,系列示例Demo
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 浮动相关
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 盘点那些不知名却常用的 Git 操作
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 区块链技术特点之去中心化特性
  • 让你的分享飞起来——极光推出社会化分享组件
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 异常机制详解
  • ​HTTP与HTTPS:网络通信的安全卫士
  • ​什么是bug?bug的源头在哪里?
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #define
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (1)SpringCloud 整合Python
  • (2)STM32单片机上位机
  • (4)Elastix图像配准:3D图像
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (八十八)VFL语言初步 - 实现布局
  • (第27天)Oracle 数据泵转换分区表
  • (翻译)terry crowley: 写给程序员
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (含笔试题)深度解析数据在内存中的存储
  • (六)DockerCompose安装与配置