PackageManagerService
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub implements PackageSender { }
installStage()
installStage 方法就是正式开始 apk 的安装过程。这个过程包括两大步:
1、拷贝安装包;
2、装载代码。
void installStage(ActiveInstallSession activeInstallSession) { ... final Message msg = mHandler.obtainMessage(INIT_COPY); //把之前传入的 sessionParams 安装信息,及其它信息封装成 InstallParams final InstallParams params = new InstallParams(activeInstallSession); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } void installStage(List<ActiveInstallSession> children) throws PackageManagerException { final Message msg = mHandler.obtainMessage(INIT_COPY); final MultiPackageInstallParams params = new MultiPackageInstallParams(UserHandle.ALL, children); params.setTraceMethod("installStageMultiPackage") .setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); }
MultiPackageInstallParams:多包安装的容器,指的是一起提交的所有安装会话和参数。
这两个方法很详细就是把之前传入的 sessionParams 安装信息及其它信息封装成 InstallParams(MultiPackageInstallParams)。
mHandler 发送的消息 INIT_COPY 从名字上就知道是去初始化复制。
mHandler()
class PackageHandler extends Handler { PackageHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } } void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; if (params != null) { if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy"); params.startCopy(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } break; } ... } } }
HandlerParams.startCopy()
private abstract class HandlerParams { /** User handle for the user requesting the information or installation. */ private final UserHandle mUser; String traceMethod; int traceCookie; ... final void startCopy() { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy(); handleReturnCode(); } abstract void handleStartCopy(); abstract void handleReturnCode(); }
startCopy(),里面有两个抽象方法,咱只能去找他的实现类 InstallParams 里面的这两个方法了。
InstallParams
class InstallParams extends HandlerParams { ... /* * 调用远程方法来获取包信息和安装位置值。 * 如果需要,根据默认策略覆盖安装位置,然后根据安装位置创建安装参数。 */ public void handleStartCopy() { int ret = PackageManager.INSTALL_SUCCEEDED; // 表示文件已下载,不需要再次下载。 if (origin.staged) { // 设置安装标志位,决定是安装在手机内部存储空间还是 sdcard 中 if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } // 判断安装位置 final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; PackageInfoLite pkgLite = null; //解析给定的包并返回最少的细节。 pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, origin.resolvedPath, installFlags, packageAbiOverride); if (DEBUG_INSTANT && ephemeral) { Slog.v(TAG, "pkgLite for install: " + pkgLite); } /* * 如果我们的可用空间太少,请在放弃之前尝试释放缓存。 */ if (!origin.staged && pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { // TODO: 释放目标设备上的磁盘空间 final StorageManager storage = StorageManager.from(mContext); //返回给定路径被(Environment.getDataDirectory())认为存储空间不足的可用字节数。 final long lowThreshold = storage.getStorageLowBytes( Environment.getDataDirectory()); //返回:-1 计算安装包大小有错误 //返回其他:安装包大小。 final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( origin.resolvedPath, packageAbiOverride); if (sizeBytes >= 0) { try { //用于权限提升。 mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, origin.resolvedPath, installFlags, packageAbiOverride); } catch (InstallerException e) { Slog.w(TAG, "Failed to free cache", e); } } /* * 缓存删除了我们下载安装的文件。 * 用于存储错误 */ if (pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { pkgLite.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } //安装返回码 if (ret == PackageManager.INSTALL_SUCCEEDED) { //指定推荐的安装位置。 可以是其中之一 //RECOMMEND_INSTALL_INTERNAL 安装在内部存储上, //RECOMMEND_INSTALL_EXTERNAL 安装在外部媒体上, //RECOMMEND_FAILED_INSUFFICIENT_STORAGE 用于存储错误, //或 RECOMMEND_FAILED_INVALID_APK 解析错误。 int loc = pkgLite.recommendedInstallLocation; ... } //创建安装参数 final InstallArgs args = createInstallArgs(this); mVerificationCompleted = true; mIntegrityVerificationCompleted = true; mEnableRollbackCompleted = true; mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) { final int verificationId = mPendingVerificationToken++; // 执行安装包验证(除非我们只是简单地移动装包)。 if (!origin.existing) { ... } //INSTALL_ENABLE_ROLLBACK 的标志参数以指示应为此安装启用回滚。 if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { // TODO(ruhler) b/112431924: 在“move”的情况下不要这样做? final int enableRollbackToken = mPendingEnableRollbackToken++; Trace.asyncTraceBegin( TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); mPendingEnableRollback.append(enableRollbackToken, this); Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, enableRollbackToken); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, mSessionId); enableRollbackIntent.setType(PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //允许在启动完成前发送广播。 在早期启动中提交分阶段会话的 apk 部分时需要这样做。 回滚管理器在启动过程中足够早地注册其接收器,以免错过广播。 // 在早期启动中提交分阶段会话的 apk 部分时需要这样做。 // 回滚管理器在启动过程中足够早地注册其接收器,以免错过广播。 enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM, android.Manifest.permission.PACKAGE_ROLLBACK_AGENT, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 等待回滚启用的持续时间,以毫秒为单位 long rollbackTimeout = DeviceConfig.getLong( DeviceConfig.NAMESPACE_ROLLBACK, PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS); if (rollbackTimeout < 0) { rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS; } final Message msg = mHandler.obtainMessage( ENABLE_ROLLBACK_TIMEOUT); msg.arg1 = enableRollbackToken; msg.arg2 = mSessionId; mHandler.sendMessageDelayed(msg, rollbackTimeout); } }, null, 0, null, null); mEnableRollbackCompleted = false; } } mRet = ret; } @Override void handleReturnCode() { if (mVerificationCompleted && mIntegrityVerificationCompleted && mEnableRollbackCompleted) { //INSTALL_DRY_RUN :installPackage 的标志参数,指示只应验证包而不应安装包。 if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) { ... } if (mRet == PackageManager.INSTALL_SUCCEEDED) { //注释1 mRet = mArgs.copyApk(); } //注释2 processPendingInstall(mArgs, mRet); } } } }
注释1:mArgs 其实就是 InstallArgs ,而 InstallArgs 则是通过 createInstallArgs(this); 创建如下代码: createInstallArgs(this)
1. private InstallArgs createInstallArgs(InstallParams params) { if (params.move != null) { //处理现有已安装应用程序移动的逻辑。 return new MoveInstallArgs(params); } else { //处理新应用程序安装的逻辑,包括复制和重命名逻辑。 return new FileInstallArgs(params); } }
这里createInstallArgs 返回的是 FileInstallArgs 对象。
FileInstallArgs.copyApk()
拷贝部分
class FileInstallArgs extends InstallArgs { private File codeFile; private File resourceFile; // Example topology: // /data/app/com.example/base.apk // /data/app/com.example/split_foo.apk // /data/app/com.example/lib/arm/libfoo.so // /data/app/com.example/lib/arm64/libfoo.so // /data/app/com.example/dalvik/arm/base.apk@classes.dex /** New install */ FileInstallArgs(InstallParams params) { super(params); } /** Existing install */ FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) { super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT, false, null /* parent */, DataLoaderType.NONE); this.codeFile = (codePath != null) ? new File(codePath) : null; this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; } //执行此处方法 int copyApk() { try { //就调用个doCopyApk(),接着往下看 return doCopyApk(); } finally { } } private int doCopyApk() { //表示文件已下载 if (origin.staged) { ... if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy"); //获取安装包路径 codeFile = origin.file; resourceFile = origin.file; return PackageManager.INSTALL_SUCCEEDED; } try { final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; //创建路径 final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); codeFile = tempDir; resourceFile = tempDir; } catch (IOException e) { Slog.w(TAG, "Failed to create copy file: " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } //将包复制到目标位置(origin.file.getAbsolutePath())。 //返回状态码。注释3 int ret = PackageManagerServiceUtils.copyPackage( origin.file.getAbsolutePath(), codeFile); if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "无法复制安装包"); return ret; } final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath()); final File libraryRoot = new File(codeFile, LIB_DIR_NAME); NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(codeFile); // 将 apk 中的动态库 .so 文件也拷贝到目标路径中。 ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, abiOverride, isIncremental); } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } finally { IoUtils.closeQuietly(handle); } return ret; } }
注释3:PackageManagerServiceUtils.copyPackage() 这个看名字 就是调用 工具类 的 copyPackage 方法拷贝安装包。具体咱们往下看。
PackageManagerServiceUtils.copyPackage()
frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
/** * 将包复制到目标位置。 * @param packagePath 要复制的包的绝对路径。 * 可以是单个单一的 APK 文件,也可以是包含一个或多个 APK 的集群目录。 * @return 根据PackageManager 中的状态返回状态码 */ public static int copyPackage(String packagePath, File targetDir) { if (packagePath == null) { return PackageManager.INSTALL_FAILED_INVALID_URI; } try { final File packageFile = new File(packagePath); final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0); //下面有copyFile的源码,咱一起看 copyFile(pkg.baseCodePath, targetDir, "base.apk"); if (!ArrayUtils.isEmpty(pkg.splitNames)) { for (int i = 0; i < pkg.splitNames.length; i++) { copyFile(pkg.splitCodePaths[i], targetDir, "split_" + pkg.splitNames[i] + ".apk"); } } return PackageManager.INSTALL_SUCCEEDED; } catch (PackageParserException | IOException | ErrnoException e) { Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } } private static void copyFile(String sourcePath, File targetDir, String targetName) throws ErrnoException, IOException { if (!FileUtils.isValidExtFilename(targetName)) { throw new IllegalArgumentException("Invalid filename: " + targetName); } Slog.d(TAG, "Copying " + sourcePath + " to " + targetName); final File targetFile = new File(targetDir, targetName); final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(), O_RDWR | O_CREAT, 0644); Os.chmod(targetFile.getAbsolutePath(), 0644); FileInputStream source = null; try { source = new FileInputStream(sourcePath); //将 source.getFD() 的内容复制到targetFd。 //FileUtils:frameworks/base/core/java/android/os/FileUtils.java FileUtils.copy(source.getFD(), targetFd); } finally { IoUtils.closeQuietly(source); } }
看到这里 最终安装包在 data/app 目录下以 base.apk 的方式保存,至此安装包拷贝工作就已经完成。
例:/data/app/com.example/base.apk