应用安装(三)- 系统实现apk安装整体流程

系统源码参考:android 11。

系统侧实现apk安装,主要通过PakcageManagerService来完成,安装过程主要分为复制apk和安装apk两个阶段,本篇文章现在针对整体安装流程进行梳理,中间牵扯到的重要模块之后单独梳理。

一、复制apk流程解析

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
       }
    }

    final Message msg = mHandler.obtainMessage(INIT_COPY);
   //初始化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));
  //发送INIT_COPY消息
   mHandler.sendMessage(msg);
}

这个方法主要干了两件事:

  • 初始化InstallParams
  • 发送INIT_COPY消息

初始化InstallParams,在构造方法中:

InstallParams(ActiveInstallSession activeInstallSession) {
    super(activeInstallSession.getUser());
   final PackageInstaller.SessionParams sessionParams =
            activeInstallSession.getSessionParams();
   if (DEBUG_INSTANT) {
        if ((sessionParams.installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
       }
    }
    verificationInfo = new VerificationInfo(
            sessionParams.originatingUri,
           sessionParams.referrerUri,
           sessionParams.originatingUid,
           activeInstallSession.getInstallerUid());
   origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
   move = null;
   installReason = fixUpInstallReason(
            activeInstallSession.getInstallSource().installerPackageName,
           activeInstallSession.getInstallerUid(),
           sessionParams.installReason);
   observer = activeInstallSession.getObserver();
   installFlags = sessionParams.installFlags;
   installSource = activeInstallSession.getInstallSource();
   volumeUuid = sessionParams.volumeUuid;
   packageAbiOverride = sessionParams.abiOverride;
   grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
   whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
   autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
   signingDetails = activeInstallSession.getSigningDetails();
   requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
   forceQueryableOverride = sessionParams.forceQueryableOverride;
   mDataLoaderType = (sessionParams.dataLoaderParams != null)
            ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
   mSessionId = activeInstallSession.getSessionId();
}

这里很明显,之前PackageInstaller将apk写入session,这里通过session获取到安装包信息,并赋值给InstallParams,同时这里额外初始化了一个VerificationInfo验证信息类。

再来看发送INIT_COPY消息:

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是抽象基类,具体实现是前面传入的InstallParams,由它来执行startCopy

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

startCopy分了两步,一个个来看。

/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
* policy if needed and then create install arguments based
* on the install location.
*/
public void handleStartCopy() {
    int ret = PackageManager.INSTALL_SUCCEEDED;
   // If we're already staged, we've firmly committed to an install location
   if (origin.staged) {
        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;
    //通过PackageParser.parsePackageLite解析一个精简版的包信息
   pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
           origin.resolvedPath, installFlags, packageAbiOverride);
   if (DEBUG_INSTANT && ephemeral) {
        Slog.v(TAG, "pkgLite for install: " + pkgLite);
   }
    /*
    * If we have too little free space, try to free cache
    * before giving up.
    */
    //检查剩余的磁盘空间
        //如果是通过ActiveInstallSession 初始化的InstallParams,origin.staged为true
   if (!origin.staged && pkgLite.recommendedInstallLocation
            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        // TODO: focus freeing disk space on the target device
       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);
           }
        }
        /*
        * The cache free must have deleted the file we downloaded to install.
        *
        * TODO: fix the "freeCache" call to not delete the file we care about.
        */
       if (pkgLite.recommendedInstallLocation
                == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
            pkgLite.recommendedInstallLocation
                    = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
       }
    }
    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 {
                    // Make sure the flag for installing on external
                   // media is unset
                   installFlags |= PackageManager.INSTALL_INTERNAL;
               }
            }
        }
    }

    //创建InstallArgs
    final InstallArgs args = createInstallArgs(this);
   mVerificationCompleted = true;
   mIntegrityVerificationCompleted = true;
   mEnableRollbackCompleted = true;
   mArgs = args;
   if (ret == PackageManager.INSTALL_SUCCEEDED) {
        final int verificationId = mPendingVerificationToken++;
       // Perform package verification (unless we are simply moving the package).
       if (!origin.existing) {
            PackageVerificationState verificationState =
                    new PackageVerificationState(this);
           mPendingVerification.append(verificationId, verificationState);
            //发起安装包完整性校验
           sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
           ret = sendPackageVerificationRequest(
                    verificationId, pkgLite, verificationState);
           // If both verifications are skipped, we should remove the state.
           if (verificationState.areAllVerificationsComplete()) {
                mPendingVerification.remove(verificationId);
           }
        }
  ...
    mRet = ret;

}

整个方法都是基于PackageManagerServiceUtils.getMinimalPackageInfo发起的,根据对包解析的情况,来决定如下事情的处理:

  • 是否有足够的磁盘空间,不够则清理;
  • 确定推荐安装位置
  • 初始化InstallArgs来做后续的copy apk任务;
  • 发起包的完整性校验;

然后接着走handleReturnCode方法

void handleReturnCode() {
    //校验通过
    if (mVerificationCompleted
            && mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
        if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
            String packageName = "";
           ParseResult result = ApkLiteParseUtils.parsePackageLite(
                    new ParseTypeImpl(
                            (changeId, packageName1, targetSdkVersion) -> {
                                ApplicationInfo appInfo = new ApplicationInfo();
                               appInfo.packageName = packageName1;
                               appInfo.targetSdkVersion = targetSdkVersion;
                               return mPackageParserCallback.isChangeEnabled(changeId,
                                       appInfo);
                           }).reset(),
                   origin.file, 0);
           if (result.isError()) {
                Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
                       result.getException());
           } else {
                packageName = result.getResult().packageName;
           }
            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) {
            mRet = mArgs.copyApk();
       }
        processPendingInstall(mArgs, mRet);
   }
}

校验完成,由InstallArgs发起apk copy操作。之前在初始化的时候会根据是否已经安装了当前应用来初始化不同的实现类:

private InstallArgs createInstallArgs(InstallParams params) {
    if (params.move != null) {
               //处理已安装的应用程序   
        return new MoveInstallArgs(params);
   } else {
               //处理新安装的应用程序
        return new FileInstallArgs(params);
   }
}

而后续发起的copyApk流程最终结果是将apk和lib copy到确认的安装目录下

void handleReturnCode() {
   ...
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
            mRet = mArgs.copyApk();
       }
        processPendingInstall(mArgs, mRet);
   }
}
/data/app/com.miui.packageinstaller-Qp2hRWM-6O9lWcKH-GT-dw== # ls -al
-rw-r--r--  1 system system  6385298 2021-04-28 07:44 base.apk. //apk
drwxr-xr-x  3 system system     4096 2021-04-28 07:44 lib     //native lib

整个流程粗略看起来比较简单,但是其中有几个细节值得深挖一下:确定推荐安装位置、包完整性校验。这个后续有时间再单独分析。

二、安装apk流程解析

g

handleReturnCode最终执行processPendingInstall发起安装:

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)));
   }
}

多包和单包安装,最终都会走到processInstallRequestsAsync方法

private void processInstallRequestsAsync(boolean success,
       List installRequests) {
   mHandler.post(() -> {
       if (success) {
           for (InstallRequest request : installRequests) {
                //安装前处理
               request.args.doPreInstall(request.installResult.returnCode);
           }
           synchronized (mInstallLock) {
                 //发起安装
               installPackagesTracedLI(installRequests);
           }
           for (InstallRequest request : installRequests) {
                //安装后处理
               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));
       }
   });
}

这里分了三步:对安装前、中、后分别做了处理。这里args对应的是FileInstallArgs。

2.1 安装前后处理工作

FileInstallArgs

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

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

安装前后,都会判断是否安装成功,如果不成功,走相同清理流程。clearup就是对安装相关目录文件进行清理。

2.2 发起安装流程

installPackagesTracedLI直接调用installPackagesLI来处理安装:

/**
* Installs one or more packages atomically. This operation is broken up into four phases:
* 
    *
  • Prepare *
    Analyzes any current install state, parses the package and does initial * validation on it.
  • *
  • Scan *
    Interrogates the parsed packages given the context collected in prepare.
  • *
  • Reconcile *
    Validates scanned packages in the context of each other and the current system * state to ensure that the install will be successful. *
  • Commit *
    Commits all scanned packages and updates system state. This is the only place * that system state may be modified in the install flow and all predictable errors * must be determined before this phase.
  • *
* * Failure at any phase will result in a full failure to install all packages. */ @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; // 1.prepare prepareResult = preparePackageLI(request.args, request.installResult); ... // 2.scan final ScanResult result = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user, request.args.abiOverride); ... ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs, installResults, prepareResults, mSharedLibraries, Collections.unmodifiableMap(mPackages), versionInfos, lastStaticSharedLibSettings); CommitRequest commitRequest = null; synchronized (mLock) { Map reconciledPackages; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages”); // 3.reconcile reconciledPackages = reconcilePackagesLocked( reconcileRequest, mSettings.mKeySetManagerService); ... commitRequest = new CommitRequest(reconciledPackages, mUserManager.getUserIds()); // 4.commit commitPackagesLocked(commitRequest); success = true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } //5.执行应用程序安装 executePostCommitSteps(commitRequest); ... }

主要工作分四个阶段:

  • prepare: 解析apk。
  • scan: 扫描apk,更新共享库和settings信息。
  • reconcile:验证扫描包状态以确保安装成功。
  • commit:提交所有扫描的包并更新系统状态。

这里后面会分别来进行分析。

最后:executePostCommitSteps 执行安装后的扫尾工作

/**
* 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 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 boolean onIncremental = mIncrementalManager != null
               && isIncrementalPath(pkg.getCodePath());
       …
        //createAppData
        prepareAppDataAfterInstallLIF(pkg);
      …
        //dex2oat编译
           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 violation
       BackgroundDexOptService.notifyPackageChanged(packageName);
       notifyPackageChangeObserversOnUpdate(reconciledPkg);
   }
    NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
}

这里主要是通过installd干两件事:createAppData、dex2oat 编译

你可能感兴趣的:(应用安装(三)- 系统实现apk安装整体流程)