Android xapk安装(三)

2023年 9月 23日 70.2k 0

1 引言

在前文Android xapk安装(二)中,我们提到,使用adb install-multiply安装xapk包时,最终会调用PackageManagerService#installStage方法完成最终的应用安装,本文继续分析installStage方法的执行过程。

2 PackageManagerService#installStage

installStage方法的核心代码如下:

    void installStage(ActiveInstallSession activeInstallSession) {
       //...省略无关代码
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final InstallParams params = new InstallParams(activeInstallSession);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;
      //...省略无关代码
        mHandler.sendMessage(msg);
    }

可看到,在该方法中,先获取一个核心逻辑就是向PackageManagerServicePackageHandler发送一个INIT_COPY类型的Message,该Messageobj就是安装应用的安装参数InstallParams,下面看PackageHandler中对INIT_COPY Message的相关处理逻辑:

void doHandleMessage(Message msg) {
      switch (msg.what) {
          case INIT_COPY: {
                HandlerParams params = (HandlerParams) msg.obj;
                if (params != null) {
                     params.startCopy();
                }
                break;
         }
       //其他逻辑
                

从代码中可以看到,对于INIT_COPY类型的Message,处理逻辑就是调用HandlerParams#startCopy方法,下面分析该方法的逻辑

2.1 HandlerParams#startCopy

HandlerParamsParamsPackageManagerService的一个内部类,startCopy方法的逻辑如下:

        final void startCopy() {
            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
            handleStartCopy();
            handleReturnCode();
        }

        abstract void handleStartCopy();
        abstract void handleReturnCode();

startCopy方法中,实际调用的是HandleStartCopyHandleReturnCode这两个抽象方法,而方法的具体实现交给其子类,在此处,实际上调用的就是InstallParams类的对应实现,下面分别看这两个方法

2.1.1 InstallParams#handleStartCopy

handleStartCopy方法较长,我们分步骤来分析。

  • 确定安装的存储分区,一般是安装在/data/app目录
  •              //是否将程序安装到内部存储,即/data/app目录,一般是true
                final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
                //是否安装到临时存储区,一般是false
                final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
                PackageInfoLite pkgLite = null;
    
  • 根据参数生成对应的PackageInfoLite对象
  •             PackageInfoLite pkgLite = null;
    
                //获取PackageInfoLite对象
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        origin.resolvedPath, installFlags, packageAbiOverride);
    

    PackageInfoLite对象和PackageLite对象类似,也是存放了一些安装包的关键信息,比如packageName,versionCode,installLocation等信息

  • 计算/data目录是否有足够的空间安装应用
  •     //计算/data目录存储空间是否足够
        final StorageManager storage = StorageManager.from(mContext);
        final long lowThreshold = storage.getStorageLowBytes(
              Environment.getDataDirectory());
    
        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);
             }
        }
        
    
  • 确定安装位置,一般就是安装到/data/app目录
  • 
    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        int loc = pkgLite.recommendedInstallLocation;
        if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                ret = PackageManager.INSTALL_FAILED_INVALID_APK;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                ret = PackageManager.INSTALL_FAILED_INVALID_URI;
        } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
       } else {
                // Override with defaults if needed.
               loc = installLocationPolicy(pkgLite);
               if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                     ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
               } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
                     ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
               } else if (!onInt) {
                    // Override install location with flags
                if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                    // Set the flag to install on external media.
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                    if (DEBUG_INSTANT) {
                           Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                     }
                     installFlags |= PackageManager.INSTALL_INSTANT_APP;
                     installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else {
                               
                      installFlags |= PackageManager.INSTALL_INTERNAL;
                      }
                }
           }
      }
    
    
  • 生成InstallArgs对象并保存
  • final InstallArgs args = createInstallArgs(this);
    mVerificationCompleted = true;
    mEnableRollbackCompleted = true;
    mArgs = args;
    

    生成的InstallArgs对象一般是FileInstallArgs子类

  • 构造校验安装包的相关数据,并向mPendingVerification中添加待验证信息
  • 
    if (ret == PackageManager.INSTALL_SUCCEEDED) {
    // TODO: http://b/22976637
    // Apps installed for "all" users use the device owner to verify the app
    UserHandle verifierUser = getUser();
    if (verifierUser == UserHandle.ALL) {
         verifierUser = UserHandle.SYSTEM;
    }
              
    final int requiredUid = mRequiredVerifierPackage == null ? -1
          : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
               verifierUser.getIdentifier());
    
    final int optionalUid = mOptionalVerifierPackage == null ? -1
          : getPackageUid(mOptionalVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
               verifierUser.getIdentifier());
    
    final int installerUid = verificationInfo == null ? -1 : verificationInfo.installerUid;
    if (!origin.existing && (requiredUid != -1 || optionalUid != -1)
          && isVerificationEnabled(
               verifierUser.getIdentifier(), installFlags, installerUid)) {
        final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
        verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),PACKAGE_MIME_TYPE);
        verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
        // Query all live verifiers based on current user state
        final List receivers = queryIntentReceiversInternal(verification,
                                PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
                                false /*allowDynamicSplits*/);
    
        final int verificationId = mPendingVerificationToken++;
    
        verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
    
         verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,installerPackageName);
    
        verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,installFlags);
    
        verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
    
        verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,pkgLite.versionCode);
               
        verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
               pkgLite.getLongVersionCode());
    
        if (verificationInfo != null) {
            if (verificationInfo.originatingUri != null) {
                  verification.putExtra(Intent.EXTRA_ORIGINATING_URI,verificationInfo.originatingUri);
           }
           if (verificationInfo.referrer != null) {
                 verification.putExtra(Intent.EXTRA_REFERRER,
                                        verificationInfo.referrer);
           }
           if (verificationInfo.originatingUid >= 0) {
                  verification.putExtra(Intent.EXTRA_ORIGINATING_UID,verificationInfo.originatingUid);
           }
           if (verificationInfo.installerUid >= 0) {
                 verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                     verificationInfo.installerUid);
          }
        }
    
        final PackageVerificationState verificationState = new PackageVerificationState(
                                requiredUid, this);
    
         mPendingVerification.append(verificationId, verificationState); 
    

    Android系统安装一个应用程序时,它会进行安全验证以确保应用程序来源可靠。验证过程可能包括验证应用程序的数字签名和权限等。而mPendingVerification变量则用于存储等待进行验证的应用程序的信息。

    PackageManagerService收到验证请求时,它将相应的应用程序添加到mPendingVerification中。然后,PackageManagerService将根据验证器的配置来处理待验证的应用程序,以确保它们的签名和权限是合法的。一旦应用程序的验证通过,PackageManagerService将继续进行应用程序的安装或其他处理。

    mPendingVerification变量的主要作用是在应用程序验证期间保留待处理的应用程序的信息,以便能够适时进行验证并完成后续的操作。这有助于保证系统安全性和应用程序的合法性.

  • 向其他验证器或验证包发送验证广播
  •  final List sufficientVerifiers = matchVerifiers(pkgLite,
                                receivers, verificationState);
    
        DeviceIdleController.LocalService idleController = getDeviceIdleController();
        final long idleDuration = getVerificationTimeout();
    /*
    * If any sufficient verifiers were listed in the package
    * manifest, attempt to ask them.
    * 应用程序包的验证器,用于对应用程序包进行验证的数字证书机构,使用这些验证器对应用包进行验证,可能为null
    * 向这些验证器发送广播
    */
    if (sufficientVerifiers != null) {
        final int N = sufficientVerifiers.size();
        if (N == 0) {
            ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
        } else {
            for (int i = 0; i < N; i++) {
                final ComponentName verifierComponent = sufficientVerifiers.get(i);
                idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                            verifierComponent.getPackageName(), idleDuration,
                                            verifierUser.getIdentifier(), false, "package verifier");
    
                final Intent sufficientIntent = new Intent(verification);
                sufficientIntent.setComponent(verifierComponent);
                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
            }
         }
    }
    //系统可选的应用程序包验证器包名
    if (mOptionalVerifierPackage != null) {
    
        optionalIntent.setAction("com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION");
        final List optional_receivers = queryIntentReceiversInternal(optionalIntent,
                                PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(), false /*allowDynamicSplits*/);
        final ComponentName optionalVerifierComponent = matchComponentForVerifier(
                                mOptionalVerifierPackage, optional_receivers);
        optionalIntent.setComponent(optionalVerifierComponent);
        verificationState.addOptionalVerifier(optionalUid);
        if (mRequiredVerifierPackage != null) {
             mContext.sendBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
         } else {
            mContext.sendOrderedBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
                    msg.arg1 = verificationId;
                    mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                }
            }, null, 0, null, null);
    
                              
            mVerificationCompleted = false;
        }
    }
    if (ret == PackageManager.INSTALL_SUCCEEDED && mRequiredVerifierPackage != null) {
        final ComponentName requiredVerifierComponent = matchComponentForVerifier(mRequiredVerifierPackage, receivers);
                            
        verification.setComponent(requiredVerifierComponent);
        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),mRequiredVerifierPackage, idleDuration,verifierUser.getIdentifier(), false, "package verifier");
        mContext.sendOrderedBroadcastAsUser(verification, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
             new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
                        final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
                        msg.arg1 = verificationId;
                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                        }
                }, null, 0, null, null);
    
        mVerificationCompleted = false;
    }
    

    在构造完验证数据后,会向验证器发送验证数据来验证安装包,然后向系统预置的可选验证器发送验证广播,然后在验证超时时间过后向PackageHandler发送一个CHECK_PENDING_VERIFICATIONMessage,最后,还会向一些Component发送验证广播等待这些Component的验证结果,并在验证超时时间之后,向PackageHandler发送一个CHECK_PENDING_VERIFICATIONMessage。在上面的这些验证器中,一般只会进入requiredVerifierComponent的逻辑中,但是不管进入哪个逻辑,最后都会发送一个CHECK_PENDING_VERIFICATION的消息,该消息的处理我们放在下文分析

  • 发送回滚广播,方便需要时回滚操作
  •  
                    if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                        // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
                        Slog.i(TAG, "enter enable rollback");
                        final int enableRollbackToken = mPendingEnableRollbackToken++;
                        Trace.asyncTraceBegin(
                                TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
                        mPendingEnableRollback.append(enableRollbackToken, this);
    
                        final int[] installedUsers;
                        synchronized (mPackages) {
                            PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
                            if (ps != null) {
                                installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
                                        true);
                            } else {
                                installedUsers = new int[0];
                            }
                        }
    
                        Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
                        enableRollbackIntent.putExtra(
                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                                enableRollbackToken);
                        enableRollbackIntent.putExtra(
                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
                                installFlags);
                        enableRollbackIntent.putExtra(
                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
                                installedUsers);
                        enableRollbackIntent.putExtra(
                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
                                getRollbackUser().getIdentifier());
                        enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                                PACKAGE_MIME_TYPE);
                        enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
                        // Allow the broadcast to be sent before boot complete.
                        // This is needed when committing the apk part of a staged
                        // session in early boot. The rollback manager registers
                        // its receiver early enough during the boot process that
                        // it will not miss the broadcast.
                        enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                         Slog.i(TAG, "enableRollbackIntent="+enableRollbackIntent.toString());
                        mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
                                android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                        // the duration to wait for rollback to be enabled, in millis
                                        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;
                                        mHandler.sendMessageDelayed(msg, rollbackTimeout);
                                    }
                                }, null, 0, null, null);
    
                        mEnableRollbackCompleted = false;
                    }
    

    同样,回滚广播会在回滚超时时间之后向PackageHandler发送一个 ENABLE_ROLLBACK_TIMEOUT类型的广播,一般情况下不会进入到该部分逻辑。

    至此,HandleStartCopy方法就分析完成了,从代码中我们知道,该方法主要的就是确认应用安装位置,对安装包进行数字验证,然后向PackageHandler发送一个CHECK_PENDING_VERIFICATIONENABLE_ROLLBACK_TIMEOUT类型的消息,下面先看CHECK_PENDING_VERIFICATION消息的处理

    case CHECK_PENDING_VERIFICATION: {
        final int verificationId = msg.arg1;
        final PackageVerificationState state = mPendingVerification.get(verificationId);
    
        if ((state != null) && !state.timeoutExtended()) {
            final InstallParams params = state.getInstallParams();
            final InstallArgs args = params.mArgs;
            final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
    
            Slog.i(TAG, "Verification timed out for " + originUri);
            mPendingVerification.remove(verificationId);
    
            final UserHandle user = args.getUser();
            //如果允许该用户安装,就继续安装,发送相应的广播
            if (getDefaultVerificationResponse(user)
                    == PackageManager.VERIFICATION_ALLOW) {
                Slog.i(TAG, "Continuing with installation of " + originUri);
                state.setVerifierResponse(Binder.getCallingUid(),
                        PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                broadcastPackageVerified(verificationId, originUri,
             
               PackageManager.VERIFICATION_ALLOW, user);
            //不允许安装,发送拒绝安装广播
            } else {
                broadcastPackageVerified(verificationId, originUri,
                        PackageManager.VERIFICATION_REJECT, user);
                params.setReturnCode(
                        PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
            }
    
            Trace.asyncTraceEnd(
                    TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
            //验证安装包结束
            params.handleVerificationFinished();
        }
        break;
    }
    

    从代码逻辑看,会发送对应的广播,然后调用InstallParamshandleVerificationFinished,广播的处理逻辑此处略去,下面看看handleVerificationFinished方法的处理逻辑

    void handleVerificationFinished() {
    	mVerificationCompleted = true;
            handleReturnCode();
    }
    

    在该方法中,会将mVerificationCompleted变量设为true,然后调用handleReturnCode方法。

    基于类似的逻辑,ENABLE_ROLLBACK_TIMEOUT消息会调用InstallParamshandleRollbackEnabled方法,在该方法中,会将 mEnableRollbackCompleted设为true,然后调用handleReturnCode方法。下面我们看InstallParamshandleReturnCode方法

    2.1.2 InstallParams#handleReturnCode

    handleReturnCode方法的源码如下

    @Override
    void handleReturnCode() {
        if (mVerificationCompleted && mEnableRollbackCompleted) {
            //1.判断是否为模拟运行,模拟运行不会安装,一般用来测试安装的正确性,正常安装不会进入该逻辑
            if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
                String packageName = "";
                try {
                    PackageLite packageInfo = new PackageParser().parsePackageLite(origin.file, 0);
                    packageName = packageInfo.packageName;
                } catch (PackageParserException e) {
                    Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
                }
                try {
                    observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
                 } catch (RemoteException e) {
                    Slog.i(TAG, "Observer no longer exists.");
                }
                return;
             }
             if (mRet == PackageManager.INSTALL_SUCCEEDED) {
              //2. 调用InstallArgs的copyApk方法复制apk包
              mRet = mArgs.copyApk();
             }
             //3.准备安装工作,完成apk安装
            processPendingInstall(mArgs, mRet);
         
        }
    }
    

    在该代码中,主要做的是三件事:

  • 判断是否为模拟运行,模拟运行不会安装,一般用来测试安装的正确性,正常安装不会进入该逻辑
  • 调用InstallArgs的copyApk方法复制apk包
  • 准备安装工作,完成apk安装
  • 在上面三个步骤中,第一步一般不用考虑,所以主要是第2步和第3步,下面分别介绍这两个方法

    2.2 InstallArgs#copyApk

    InstallArgsPackageManagerService内部类,该类是一个抽象类,实际使用的一般是FileInstallArgs子类,其copyApk代码如下

            int copyApk() {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
                try {
                    return doCopyApk();
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            }
    

    在该方法中,实际是调用了docopyApk完成实际操作

    private int doCopyApk() {
        //是否已经staged处理,本文此处为true  
        if (origin.staged) {
            if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
            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;
        }
    
        int ret = PackageManagerServiceUtils.copyPackage(origin.file.getAbsolutePath(), codeFile);
        if (ret != PackageManager.INSTALL_SUCCEEDED) {
            Slog.e(TAG, "Failed to copy package");
            return ret;
        }
    
        final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
        NativeLibraryHelper.Handle handle = null;
        try {
            handle = NativeLibraryHelper.Handle.create(codeFile);
            ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);
        } catch (IOException e) {
            Slog.e(TAG, "Copying native libraries failed", e);
            ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
        } finally {
            IoUtils.closeQuietly(handle);
        }
    
        return ret;
    }
    

    在该方法中,会先判断源文件是否为staged,该标识位用于标识apk是否已经在内存中准备好,无需再复制。在install-multiple命令中,最终会调用installStage方法完成调用,在该方法中,构造InstallParams对象时,会将其OriginInfostaged属性标记为true, 这样就无需再复制一次apk

    origin.staged为fasle,则进一步判断是否为即时应用,即时应用一般是用来测试安装的,系统不会将其真正安装,一般为false.

    若安装的apk的origin.staged为false,也不是即时应用,系统就会调用PackageManagerServiceUtilscopyPackage方法copy apk包,并解析复制apk的so库到lib目录。

    在完成apk复制后,hanldeReturenCode下一步会调用processPendingInstall方法完成apk安装

    2.3 processPendingInstall

    processPendingInstall方法的分析,参考了博客:# Android 10.0 PackageManagerService(四)APK安装流程-[Android取经之路]。

    processPendingInstall方法完成最后的apk安装操作:

        private void processPendingInstall(final InstallArgs args, final int currentStatus) {
            if (args.mMultiPackageInstallParams != null) {
                args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
            } else {
                PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
                processInstallRequestsAsync(
                        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                        Collections.singletonList(new InstallRequest(args, res)));
            }
        }
    

    在该方法中,首先会调用createPackageInstalledInfo方创建一个PackageInstalledInfo对象:

        private PackageInstalledInfo createPackageInstalledInfo(
                int currentStatus) {
            PackageInstalledInfo res = new PackageInstalledInfo();
            res.setReturnCode(currentStatus);
            res.uid = -1;
            res.pkg = null;
            res.removedInfo = null;
            return res;
        }
    

    在该方法中,创建一个PackageInstalledInfo对象,将returnCode设置为PackageManager.INSTALL_SUCCEEDED或其他错误相关的错误码,然后将其他属性初始化。

    创建好PackageInstalledInfo对象后,下一步调用processInstallRequestsAsync方法完成操作:

        // Queue up an async operation since the package installation may take a little while.
        private void processInstallRequestsAsync(boolean success,
                List installRequests) {
            mHandler.post(() -> {
                if (success) {
                    for (InstallRequest request : installRequests) {
                        //1.清理之前安装失败的数据
                        request.args.doPreInstall(request.installResult.returnCode);
                    }
                    synchronized (mInstallLock) {
                        //2.安装核心方法
                        installPackagesTracedLI(installRequests);
                    }
                    for (InstallRequest request : installRequests) {
                        //3.若安装失败,清理掉数据
                        request.args.doPostInstall(
                                request.installResult.returnCode, request.installResult.uid);
                    }
                }
                for (InstallRequest request : installRequests) {
                    restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                            new PostInstallData(request.args, request.installResult, null));
                }
            });
        }
    

    在该方法中,会向mHandler post一个异步任务。如果returnCodePackageManager.INSTALL_SUCCEEDED,则遍历每一个InstallRequest对象,调用其request.args.doPreInstall方法,然后调用installPackagesTracedLI方法,之后遍历每一个InstallRequest对象,调用其request.args.doPostInstall方法。在最后,会遍历每一个InstallRequest对象,调用restoreAndPostInstall方法。下面我们逐一分析这些方法

    首先我们看看InstallRequest的结构:

        private static class InstallRequest {
            public final InstallArgs args;
            public final PackageInstalledInfo installResult;
    
            private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
                this.args = args;
                this.installResult = res;
            }
        }
    

    可以看到,InstallRequest就是对InstallArgsPackageInstalledInfo的一个组合封装。所以request.args.doPreInstall方法实际上就是InstallArgsdoPreInstall方法,最后实际会调用FileInstallArgsdoPreInstall方法:

    int doPreInstall(int status) {
        if (status != PackageManager.INSTALL_SUCCEEDED) {
            cleanUp();
        }
        return status;
    }
    

    在该方法中,若status不是PackageManager.INSTALL_SUCCEEDED,则调用cleanUp方法清理掉安装包。

    因为request.args.doPostInstall实际上也是调用的FileInstallArgsdoPostInstall方法,下面先看看该方法:

    int doPostInstall(int status, int uid) {
        if (status != PackageManager.INSTALL_SUCCEEDED) {
            cleanUp();
        }
        return status;
    }
    

    可以看到,在FileInstallArgs中,doPreInstalldoPostInstall的逻辑是一样的。

    在分析完FileInstallArgs中的两个方法后,下面我们继续看installPackagesTracedLI方法和restoreAndPostInstall方法。

    2.3.1 installPackagesTracedLI

    installPackagesTracedLI方法源码如下:

    @GuardedBy({"mInstallLock", "mPackages"})
    private void installPackagesTracedLI(List requests) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
            installPackagesLI(requests);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
    

    可以看到,该方法实际上是调用了installPackagesLI方法。该方法是安装apk的一个关键方法:

        @GuardedBy("mInstallLock")
        private void installPackagesLI(List requests) {
            final Map preparedScans = new ArrayMap(requests.size());
            final Map installArgs = new ArrayMap(requests.size());
            final Map installResults = new ArrayMap(requests.size());
            final Map prepareResults = new ArrayMap(requests.size());
            final Map versionInfos = new ArrayMap(requests.size());
            final Map lastStaticSharedLibSettings =
                    new ArrayMap(requests.size());
            final Map createdAppId = new ArrayMap(requests.size());
            boolean success = false;
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
                for (InstallRequest request : requests) {
                    // TODO(b/109941548): remove this once we've pulled everything from it and into
                    //                    scan, reconcile or commit.
                    final PrepareResult prepareResult;
                    try {
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                        //1. 准备安装包,对安装状态进行分析(是新安装还是替换已有的安装包),做一些初始化操作
                        prepareResult = preparePackageLI(request.args, request.installResult);
                    } catch (PrepareFailure prepareFailure) {
                        request.installResult.setError(prepareFailure.error,
                                prepareFailure.getMessage());
                        request.installResult.origPackage = prepareFailure.conflictingPackage;
                        request.installResult.origPermission = prepareFailure.conflictingPermission;
                        return;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                    request.installResult.installerPackageName = request.args.installerPackageName;
    
                    final String packageName = prepareResult.packageToScan.packageName;
                    prepareResults.put(packageName, prepareResult);
                    installResults.put(packageName, request.installResult);
                    installArgs.put(packageName, request.args);
                    try {
                        //2. 扫描安装包
                        final List scanResults = scanPackageTracedLI(
                                prepareResult.packageToScan, prepareResult.parseFlags,
                                prepareResult.scanFlags, System.currentTimeMillis(),
                                request.args.user);
                        for (ScanResult result : scanResults) {
                            if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
                                request.installResult.setError(
                                        PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
                                        "Duplicate package " + result.pkgSetting.pkg.packageName
                                                + " in multi-package install request.");
                                return;
                            }
                            createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                            versionInfos.put(result.pkgSetting.pkg.packageName,
                                    getSettingsVersionForPackage(result.pkgSetting.pkg));
                            if (result.staticSharedLibraryInfo != null) {
                                final PackageSetting sharedLibLatestVersionSetting =
                                        getSharedLibLatestVersionSetting(result);
                                if (sharedLibLatestVersionSetting != null) {
                                    lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
                                            sharedLibLatestVersionSetting);
                                }
                            }
                        }
                    } catch (PackageManagerException e) {
                        request.installResult.setError("Scanning Failed.", e);
                        return;
                    }
                }
                //3 验证扫描的包,确保安装成功
                ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                        installResults,
                        prepareResults,
                        mSharedLibraries,
                        Collections.unmodifiableMap(mPackages), versionInfos,
                        lastStaticSharedLibSettings);
                CommitRequest commitRequest = null;
                synchronized (mPackages) {
                    Map reconciledPackages;
                    try {
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                        reconciledPackages = reconcilePackagesLocked(
                                reconcileRequest, mSettings.mKeySetManagerService);
                    } catch (ReconcileFailure e) {
                        for (InstallRequest request : requests) {
                            request.installResult.setError("Reconciliation failed...", e);
                        }
                        return;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    try {
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                        commitRequest = new CommitRequest(reconciledPackages,
                                sUserManager.getUserIds());
                        //4. 提交所有扫描的包并更新系统状态,是安装过程中唯一可以修改系统状态的地方
                        commitPackagesLocked(commitRequest);
                        success = true;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                }
                //5  apk成功安装后,完成剩下的工作
                executePostCommitSteps(commitRequest);
            }
            ...
    

    从代码中可以看到,installPackagesTracedLI主要有5个步骤,也对应着5个关键方法,下面逐一分析这5个方法

    2.3.1.1 preparePackageLI

    preparePackageLI方法用于对安装包做一些检查和初始化准备工作,该方法较长,下面我们分段分析

  • 构造scanFlags
  •     @GuardedBy("mInstallLock")
        private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
                throws PrepareFailure {
            final int installFlags = args.installFlags;
            final String installerPackageName = args.installerPackageName;
            final String volumeUuid = args.volumeUuid;
            final File tmpPackageFile = new File(args.getCodePath());
            final boolean onExternal = args.volumeUuid != null;
            final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
            final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
            final boolean virtualPreload =
                    ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
    
            @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
            if (args.move != null) {
                // moving a complete application; perform an initial scan on the new install location
                scanFlags |= SCAN_INITIAL;
            }
            if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
                scanFlags |= SCAN_DONT_KILL_APP;
            }
            //即时app,类似微信小程序,无需安装
            if (instantApp) {
                scanFlags |= SCAN_AS_INSTANT_APP;
            }
            //一般为ture
            if (fullApp) {
                scanFlags |= SCAN_AS_FULL_APP;
            }
            if (virtualPreload) {
                scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
            }
    
            if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
            Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
    
            // Sanity check
            if (instantApp && onExternal) {
                Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
                throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
            }
    
  • 解析安装包信息和校验dex
  •         @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                    | PackageParser.PARSE_ENFORCE_CODE
                    | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
    
            PackageParser pp = new PackageParser();
            pp.setSeparateProcesses(mSeparateProcesses);
            pp.setDisplayMetrics(mMetrics);
            pp.setCallback(mPackageParserCallback);
    
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
            final PackageParser.Package pkg;
            try {
                //和parsePackageLite类似,也会调用parseClusterPackage解析Package
                pkg = pp.parsePackage(tmpPackageFile, parseFlags);
                DexMetadataHelper.validatePackageDexMetadata(pkg);
            } catch (PackageParserException e) {
                throw new PrepareFailure("Failed parse during installPackageLI", e);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
    

    3.若app是即时app,其targetSdkVersion需要大于0:

            // Instant apps have several additional install-time checks.
            //即时app,类似微信小程序,无需安装,其targetSdkVersion不能小于0
            if (instantApp) {
                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
                    Slog.w(TAG,
                            "Instant app package " + pkg.packageName + " does not target at least O");
                    throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                            "Instant app package must target at least O");
                }
                if (pkg.mSharedUserId != null) {
                    Slog.w(TAG, "Instant app package " + pkg.packageName
                            + " may not declare sharedUserId.");
                    throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                            "Instant app package may not declare a sharedUserId");
                }
            }
    
  • 若有静态共享库,则将包名修改为“包名_pkg.staticSharedLibVersion“的形式
  •         //静态库处理
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                // Static shared libraries have synthetic package names
                Slog.i(TAG,"isStaticSharedLibrary");
                renameStaticSharedLibraryPackage(pkg);
    
                // No static shared libs on external storage
                if (onExternal) {
                    Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
                    throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                            "Packages declaring static-shared libs cannot be updated");
                }
            }
    
  • 若有子安装包,则需要对子安装包也检修检查,主要是检查是否已经安装了子包
  •         // If we are installing a clustered package add results for the children
            if (pkg.childPackages != null) {
                synchronized (mPackages) {
                    final int childCount = pkg.childPackages.size();
                    for (int i = 0; i < childCount; i++) {
                        PackageParser.Package childPkg = pkg.childPackages.get(i);
                        PackageInstalledInfo childRes = new PackageInstalledInfo();
                        childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                        childRes.pkg = childPkg;
                        childRes.name = childPkg.packageName;
                        PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                        if (childPs != null) {
                            childRes.origUsers = childPs.queryInstalledUsers(
                                    sUserManager.getUserIds(), true);
                        }
                        if ((mPackages.containsKey(childPkg.packageName))) {
                            childRes.removedInfo = new PackageRemovedInfo(this);
                            childRes.removedInfo.removedPackage = childPkg.packageName;
                            childRes.removedInfo.installerPackageName = childPs.installerPackageName;
                        }
                        if (res.addedChildPackages == null) {
                            res.addedChildPackages = new ArrayMap();
                        }
                        
                        res.addedChildPackages.put(childPkg.packageName, childRes);
                    }
                }
            }
    
  • 检查apk的cpuabi信息,如arm64-v8a
  •         // If package doesn't declare API override, mark that we have an install
            // time CPU ABI override.
            if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
                pkg.cpuAbiOverride = args.abiOverride;
            }
    
  • 若是测试安装包,则需要PackageManager.INSTALL_ALLOW_TEST
  •         if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
                if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                    throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
                }
            }
    
  • 检查签名
  •         try {
                // either use what we've been given or parse directly from the APK
                if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                    pkg.setSigningDetails(args.signingDetails);
                } else {
                    PackageParser.collectCertificates(pkg, false /* skipVerify */);
                }
            } catch (PackageParserException e) {
                throw new PrepareFailure("Failed collect during installPackageLI", e);
            }
    
            if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
                    < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
                Slog.w(TAG, "Instant app package " + pkg.packageName
                        + " is not signed with at least APK Signature Scheme v2");
                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Instant app package must be signed with APK Signature Scheme v2 or greater");
            }
    
  • 若安装包已经存在,则检查是否替换已有的安装包
  •         synchronized (mPackages) {
    // Check if installing already existing package
    if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
    Slog.i(TAG,"package is existing");
    String oldName = mSettings.getRenamedPackageLPr(pkgName);
    if (pkg.mOriginalPackages != null
    && pkg.mOriginalPackages.contains(oldName)
    && mPackages.containsKey(oldName)) {
    // This package is derived from an original package,
    // and this device has been updating from that original
    // name. We must continue using the original name, so
    // rename the new package here.
    pkg.setPackageName(oldName);
    pkgName = pkg.packageName;
    replace = true;
    if (DEBUG_INSTALL) {
    Slog.d(TAG, "Replacing existing renamed package: oldName="
    + oldName + " pkgName=" + pkgName);
    }
    //系统应用中已经存在该包,需要将系统中包替换掉,常见的如使用自己下载的google play替换系统安装的google play
    } else if (mPackages.containsKey(pkgName)) {
    // This package, under its official name, already exists
    // on the device; we should replace it.
    replace = true;
    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
    acquireUxPerfLock(BoostFramework.UXE_EVENT_PKG_INSTALL, pkgName, 1);
    BoostFramework mPerf = new BoostFramework();
    if (mPerf != null) {
    mPerf.perfHint(BoostFramework.VENDOR_HINT_APP_UPDATE, pkgName, -1, 0);
    }
    }

    // Child packages are installed through the parent package
    //子安装包必须由父包更新,不能单独更新
    if (pkg.parentPackage != null) {
    throw new PrepareFailure(
    PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
    "Package " + pkg.packageName + " is child of package "
    + pkg.parentPackage.parentPackage + ". Child packages "
    + "can be updated only through the parent package.");
    }
    //如果是替换已经存在的包,则需要对旧包和新包做一些校验,看看是否允许替换
    if (replace) {
    // Prevent apps opting out from runtime permissions
    PackageParser.Package oldPackage = mPackages.get(pkgName);
    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
    && newTargetSdk

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论