Android Framework重要服务之PackageManagerService(二) APP安装流程

769 阅读12分钟

上一章详细分析了PMS的启动流程,本章将继续探究PMS的应用安装流程。

一、APK结构

在探究PMS安装流程之前,先简单了解下APK的组成:

目录 or 文件描述
assert存放的原生资源文件,通过AssetManager类访问
libnative库文件
META-INF存放签名信息,用来保证APK包的完整性和系统的安全。系统安装APK时,应用管理器会按照对应算法对包里文件做校验,如果校验结果与META-INF中内容不一致,则不会安装这个APK。
res种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件比较简单,通过R.XXX.ID即可
AndroidManifest.xml每个应用都必须定义和包含,描述应用的名字、版本权限、引用的库文件等信息。apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。
classes.dex是JAVA源码编译后生成的JAVA字节码文件。但Android使用的dalvik虚拟机与标准的JAVA虚拟机不兼容,dex文件与class文件相比,不论是文件结构还是opcode都不一样。
resources.arsc编译后的二进制资源文件。

二、应用安装方法

安卓的应用安装方式可分为以下几种: APK有下面4种安装方法:

方法描述
开机过程中安装开机时完成,没有安装界面,如系统应用、其它预置应用
adb工具安装没有安装界面,adb install/push xxxx.apk
第三方应用安装通过packageinstaller.apk进行安装,有安装界面,如打开文件管理器并点击sdk卡里APK文件
网络下载应用安装通过google market应用完成,没有安装界面

简单来说,apk的安装可以分为两步,一是拷贝目标apk到指定文件目录,二是调用scanPackageLI为apk文件在系统中注册信息。

三、应用安装流程

这里主要来看一下通过ADB工具安装APK的流程。

adb install

当执行adb install时,会调用packages/modules/adb/client/commandline.cpp中的adb_commandline函数,这个过程会把apk文件copy到data/local/tmp/目录下,然后向shell服务发送pm命令安装apk,最后调用Pm.runInstall()方法来安装apk。

Pm.runInstall

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

private int runInstall() throws RemoteException {
    return doRunInstall(makeInstallParams());
}

private int doRunInstall(final InstallParams params) throws RemoteException {
    ...

    // 创建session
    final int sessionId = doCreateSession(params.sessionParams,
            params.installerPackageName, params.userId);
    boolean abandonSession = true;
    try {
        if (isStreaming) {
            if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
                    != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
        } else {
            // 写session
            if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
                    != PackageInstaller.STATUS_SUCCESS) {
                return 1;
            }
        }

        // 提交Session
        if (doCommitSession(sessionId, false /*logSuccess*/)
                != PackageInstaller.STATUS_SUCCESS) {
            return 1;
        }
        abandonSession = false;

        if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
            return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
        }

        pw.println("Success");
        return 0;
    } finally {
        if (abandonSession) {
            try {
                doAbandonSession(sessionId, false /*logSuccess*/);
            } catch (Exception ignore) {
            }
        }
    }
}

从上面的代码来看,runInstall主要进行了三件事,即创建session、对session进行写操作,最后提交session,这三步单独拆开如下:

doCreateSession

实际调用的是PackageInstallerServicecreateSession,这个过程主要是为APK安装做好准备工作,例如权限检查、目的临时文件的创建等, 最终创建出PackageInstallerSession对象。 PackageInstallerSession可以看做是”安装APK”这个请求的封装,其中包含了处理这个请求需要的一些信息。
实际上PackageInstallerSession不仅是封装请求的对象,其自身还是个服务端。

doWriteSession

通过PackageInstallerSession/data/local/tmp的apk拷贝到终端目录内。

doCommitSession

doWriteSession结束后,如果没有出现任何错误,那么APK源文件已经copy到目的地址了,doCommitSession最终会调用到PMS.installStage来安装apk,调用流程如下:

PackageInstallerSession.commit ==> commitLocked(); ==> PMS.installStage()

PMS.installStage()会调用sendMessageINIT_COPY发送给PackageHandlerframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

// 进入安装阶段
void installStage(InstallParams params) {
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    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);
}

PackageHandler用于处理apk的安装请求等消息,后面分析。

PackageHanlder

PackageHandler用于处理apk的安装请求等消息,在PMS构造函数中有初始化。其代码位于: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,实际处理消息的函数为doHandleMessage,由于此处代码较多,我们按照处理流程拆开分析。

INIT_COPY

我们来看看INIT_COPY的处理流程:

class PackageHandler extends Handler {
    void doHandleMessage(Message msg) {
        ...
        
        switch (msg.what) {
            case INIT_COPY: {
                // 这里取出的其实就是InstallParams
                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;
           }
           ...
           
     }
}

INIT_COPY主要是将安装请求队列中的任务取出,并复制开始安装流程。其中startCopy() 完成的工作:

  1. 超出最大重试次数,发送 MCS_GIVE_UP 消息放弃
  2. 实际调用 handleStartCopy() 开始处理拷贝
  3. 远程调用抛出异常,发出 MCS_RECONNECT 消息重连
  4. 最后调用 handleReturnCode() 处理返回值

这里需要注意的是,startCopy()函数在安卓11以前是在MCS_BOUND这个case下被调用的,但在Android 11下被放到了INIT_COPY这个case下执行,同时,INIT_COPY的逻辑也发生了一些变化。

startCopy

InstallParams继承HandlerParams,实际调用的是HandlerParams.startCopy: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private abstract class HandlerParams {
    ...

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

PMS将先后调用handleStartCopyhandleReturnCode来完成主要的工作。

handleStartCopy

handleStartCopy函数在HandleParams抽象类定义,在其子类InstallParams来实现,我们看看与实际安装相关的handleStartCopy函数:

public void handleStartCopy() {
    if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
        mRet = INSTALL_SUCCEEDED;
        return;
    }
    PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
            
    boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
    if (isStaged) {
        mRet = verifyReplacingVersionCode(
                pkgLite, requiredInstalledVersionCode, installFlags);
        if (mRet != INSTALL_SUCCEEDED) {
            return;
        }
    }

    mRet = overrideInstallLocation(pkgLite);
}

overrideInstallLocation

在Android 11以前,`handleStartCopy`一个函数就处理了apk的安装信息检查,但在Android 11内,这些逻辑被放到了`overrideInstallLocation`中实现,下面分析一下`overrideInstallLocation`的相关代码:
private int overrideInstallLocation(PackageInfoLite pkgLite) {
    ...
    
    // 检查文件和cid是否已生成,如生成则设置installFlags
    if (origin.staged) {
        // If we're already onInt && onSdstaged, we've firmly committed to an install location
        if (origin.file != null) {
            installFlags |= PackageManager.INSTALL_INTERNAL;
        } else {
            throw new IllegalStateException("Invalid stage location");
        }
    } else if (pkgLite.recommendedInstallLocation
            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
            
        // 检查空间大小,如果空间不够则释放无用空间。
        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,
                        mPackageLite, origin.resolvedPath, installFlags,
                        packageAbiOverride);
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to free cache", e);
            }
        }
        ...
        
        if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
            ...
        } else {
            // 覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置installFlags。
            loc = installLocationPolicy(pkgLite);

            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

            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 {
                    // Make sure the flag for installing on external
                    // media is unset
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                }
            }
        }
        return ret;    
  }

handleReturnCode

在handleReturnCode中,调用handleReturnCode方法处理安装

@Override
void handleReturnCode() {
    processPendingInstall();
}

processPendingInstall

主要的安装流程都在这个方法里面: PMS.processPendingInstall

private void processPendingInstall() {
    // createInstallArgs用于创建一个安装参数对象
    InstallArgs args = createInstallArgs(this);
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        // 调用 copyApk() 进行APK的拷贝动作,通过文件流的操作,把APK拷贝到/data/app等目录
        mRet = args.copyApk();
    }
    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
        F2fsUtils.releaseCompressedBlocks(
                mContext.getContentResolver(), new File(args.getCodePath()));
    }
    if (mParentInstallParams != null) {
        // 当安装信息不为空时,尝试继续安装流程
        mParentInstallParams.tryProcessInstallRequest(args, mRet);
    } else {
        // 设置安装参数
        PackageInstalledInfo res = createPackageInstalledInfo(mRet);
        // 创建一个新线程,处理安装参数,进行安装
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
    ...
    
        if (success) {
            for (InstallRequest request : apkInstallRequests) {
                // 如果之前安装失败,清除无用信息
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                // installPackagesTracedLI 是安装过程的核心方法,然后调用 installPackagesLI 进行安装
                installPackagesTracedLI(apkInstallRequests);
            }
            for (InstallRequest request : apkInstallRequests) {
                // 如果之前安装失败,清除无用信息
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : apkInstallRequests) {
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });

    ...
}

在Android11中,加入了一个续装流程,既当安装信息不为空时,系统会尝试继续安装该应用,而不是创建一个新线程进行安装,这提高了应用安装的效率。

installPackageTracedLI

installPackageTracedLI方法创建了一个新的线程,并在线程中执行了installPackagesLI方法进行应用的安装。

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

installPackagesLI

以原子操作方式安装一个或多个包。此操作分为五个阶段:

  1. Prepare 准备:分析任何当前安装状态,分析包并对其进行初始验证。
  2. Scan 扫描:考虑到prepare中收集的上下文,询问已分析的包。
  3. Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功。
  4. Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
  5. 完成APK的安装

installPackagesLI方法代码较多,大致架构如下:

private void installPackagesLI(List<InstallRequest> requests) {
    ...
    //1.Prepare 准备:分析任何当前安装状态,分析包并对其进行初始验证。
    prepareResult = preparePackageLI(request.args, request.installResult);
    ...
    //2.Scan  扫描:考虑到prepare中收集的上下文,询问已分析的包。
    final List<ScanResult> scanResults = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user);
    ...
    //3.Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功。
    ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
            installResults,
            prepareResults,
            mSharedLibraries,
            Collections.unmodifiableMap(mPackages), versionInfos,
            lastStaticSharedLibSettings);
    ...
    //4.Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
    commitPackagesLocked(commitRequest);
    ...
    //5.完成APK的安装
    executePostCommitSteps(commitRequest);
}

安装过程细分为以下15步

1. 首先检查安装包的完整性并解析安装包。

[PackageManagerService.java] preparePackageLI()
// 完整性校验
if (instantApp && onExternal) {
    Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
    throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
}
 
// 检索包设置,并解析应用
@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 {
    //解析安装包
    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);
}

2. 检查SDK版本和沙箱版本,同时检查是否有静态共享库,如有则需要放在内部存储中。

[PackageManagerService.java] preparePackageLI()
 
//检查SDK版本和沙箱版本
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");
    }
}
 
//检查是否有静态共享库
if (pkg.applicationInfo.isStaticSharedLibrary()) {
    // Static shared libraries have synthetic package names
    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");
    }
}

3. 检查是否有子安装包,如有则子安装包也需要检测。

[PackageManagerService.java] preparePackageLI()

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

4. 校验安装包签名

[PackageManagerService.java] preparePackageLI()
 
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
    if (libraryInfo != null) {
        signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
    }
}
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                + pkg.packageName + " upgrade keys do not match the "
                + "previously installed version");
    }
}

5. 设置相关的权限,包括生成权限、移植权限等

6. 如果这是一个系统应用,则检查是否在外部存储上或是是否被其他应用替换等

[PackageManagerService.java] preparePackageLI()
 
if (systemApp) {
    if (onExternal) {
        // Abort update; system app can't be replaced with app on sdcard
        throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                "Cannot install updates to system apps on sdcard");
    } else if (instantApp) {
        // Abort update; system app can't be replaced with an instant app
        throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                "Cannot update a system app with an instant app");
    }
}

7. 生成安装包Abi(Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)

[PackageManagerService.java] preparePackageLI()
 
try {
    String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
            args.abiOverride : pkg.cpuAbiOverride);
    final boolean extractNativeLibs = !pkg.isLibrary();
    derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
    Slog.e(TAG, "Error deriving application ABI", pme);
    throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
            "Error deriving application ABI");
}

8. 如有必要,优化dex文件

[PackageManagerService.java] executePostCommitSteps()
 
final boolean performDexopt =
        (!instantApp || Global.getInt(mContext.getContentResolver(),
        Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
        && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
 
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");
    // 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.
    DexoptOptions dexoptOptions = new DexoptOptions(packageName,
            REASON_INSTALL,
            DexoptOptions.DEXOPT_BOOT_COMPLETE
                    | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
    mPackageDexOptimizer.performDexOpt(pkg,
            null /* instructionSets */,
            getOrCreateCompilerPackageStats(pkg),
            mDexManager.getPackageUseInfoOrDefault(packageName),
            dexoptOptions);
    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}

9. 冻结APK,并决定是替换安装,还是新安装,组装参数

[PackageManagerService.java] preparePackageLI()
final PackageFreezer freezer =
                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
 
if (replace) {
    //替换安装
 
} else {// new package install
    //安装新的APK
    //1)已安装具有相同名称的包,但已将其重命名为旧名称
    //2)不要允许在同一名称的现有包上安装。
    renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
}

10. 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。

进入 [PackageManagerService.java] scanPackageTracedLI

调用顺序: scanPackageTracedLI() => scanPackageLI() => parsePackage()

11. 更新共享库

[PackageManagerService.java] commitPackageSettings()
 
synchronized (mPackages) {
    if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
        for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
            commitSharedLibraryInfoLocked(info);
        }
        final Map<String, PackageParser.Package> combinedPackages =
                reconciledPkg.getCombinedPackages();
        try {
            // Shared libraries for the package need to be updated.
            updateSharedLibrariesLocked(pkg, null, combinedPackages);
        } catch (PackageManagerException e) {
            Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
        }
        // Update all applications that use this library. Skip when booting
        // since this will be done after all packages are scaned.
        if ((scanFlags & SCAN_BOOTING) == 0) {
            clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
        }
    }
}

12. 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。

[PackageManagerService.java] commitPackageSettings()
synchronized (mPackages) {
    // Add the new setting to mSettings
    mSettings.insertPackageSettingLPw(pkgSetting, pkg);
    // Add the new setting to mPackages
    mPackages.put(pkg.applicationInfo.packageName, pkg);
}

13. 安装APK,并为新的代码路径准备应用程序配置文件,并再次检查是否需要dex优化

如果是直接安装新包,会为新的代码路径准备应用程序配置文件。
如果是替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同时要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。

[PackageManagerService.java] executePostCommitSteps()
private void executePostCommitSteps(CommitRequest commitRequest) {
    for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
        ...
        //1)进行安装
        prepareAppDataAfterInstallLIF(pkg);
        //2)如果需要替换安装,则需要清楚原有的APP数据
        if (reconciledPkg.prepareResult.clearCodeCache) {
            clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                    | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
        }
 
 
        //3)为新的代码路径准备应用程序配置文件。这需要在调用dexopt之前完成,以便任何安装时配置文件都可以用于优化。
        mArtManagerService.prepareAppProfiles(
                pkg,
                resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
                /* updateReferenceProfileContent= */ true);
 
 
        final boolean performDexopt =
                (!instantApp || Global.getInt(mContext.getContentResolver(),
                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
 
        if (performDexopt) {
            ...
            //4)执行dex优化
            mPackageDexOptimizer.performDexOpt(pkg,
                    null /* instructionSets */,
                    getOrCreateCompilerPackageStats(pkg),
                    mDexManager.getPackageUseInfoOrDefault(packageName),
                    dexoptOptions);
        }
 
        BackgroundDexOptService.notifyPackageChanged(packageName);
    }
}

14. APK的安装

[PackageManagerService.java] prepareAppDataAfterInstallLIF()
通过一系列的调用,最终会调用到[Installer.java] createAppData()进行安装,交给installed进程进行APK的安装

调用顺序如下:
prepareAppDataAfterInstallLIF() => prepareAppDataLIF() => prepareAppDataLeafLIF() => Installer.java#createAppData()

private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
    ...
    for (UserInfo user : um.getUsers()) {
        ...
        if (ps.getInstalled(user.id)) {
            // TODO: when user data is locked, mark that we're still dirty
            prepareAppDataLIF(pkg, user.id, flags);
        }
    }
}
 
private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
    if (pkg == null) {
        Slog.wtf(TAG, "Package was null!", new Throwable());
        return;
    }
    prepareAppDataLeafLIF(pkg, userId, flags);
    final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    for (int i = 0; i < childCount; i++) {
        prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
    }
}
 
private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
    ...
    try {
        // 调用Installd守护进程的入口
        ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                appId, seInfo, app.targetSdkVersion);
    } catch (InstallerException e) {
        if (app.isSystemApp()) {
            destroyAppDataLeafLIF(pkg, userId, flags);
            try {
                ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                        appId, seInfo, app.targetSdkVersion);
            } catch (InstallerException e2) {
                ...
            }
        }
    }
}

[Installer.java]
public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
        String seInfo, int targetSdkVersion) throws InstallerException {
    if (!checkBeforeRemote()) return -1;
    try {
        //mInstalld 为IInstalld的对象,即通过Binder调用到 进程installd,最终调用installd的createAppData()
        //installd的安装过程后面有机会再进行讲解
        return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
                targetSdkVersion);
    } catch (Exception e) {
        throw InstallerException.from(e);
    }
}

15. 安装完成后,更新设置,更新安装锁等

四、总结

以上就是对于PMS的安装流程的解析,大体上可以分为4步:

  • 将APK的信息通过IO流的形式写入到PackageInstaller.Session中。
  • 调用PackageInstaller.Session的commit方法,将APK的信息交由PKMS处理。
  • 拷贝APK
  • 最后进行安装
    最终是交给installed守护进行完成真正的APK安装,在这里给出APK安装流程的时序图。

APK安装流程.png