深入理解Android Framework(五)- Framework重要服务之PackageManagerService(二) PMS应用安装

1,418 阅读11分钟

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

1、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编译后的二进制资源文件。

2、应用安装方法

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

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

简单来说,apk的安装可以分为两步:

一是拷贝目标apk到指定文件目录

二是调用scanPackageLI为apk文件在系统中注册信息。

3、应用安装流程

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

3.1、adb install

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

3.2、 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 {
    final PrintWriter pw = getOutPrintWriter();

    final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
    final boolean isApex =
            (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;

    ArrayList<String> args = getRemainingArgs();

    final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
    final boolean hasSplits = args.size() > 1;

    if (fromStdIn && params.sessionParams.sizeBytes == -1) {
        pw.println("Error: must either specify a package size or an APK file");
        return 1;
    }

    if (isApex && hasSplits) {
        pw.println("Error: can't specify SPLIT(s) for APEX");
        return 1;
    }

    if (!isStreaming) {
        if (fromStdIn && hasSplits) {
            pw.println("Error: can't specify SPLIT(s) along with STDIN");
            return 1;
        }

        if (args.isEmpty()) {
            args.add(STDIN_PATH);
        } else {
            setParamsSize(params, args);
        }
    }
    //创建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;
            }
        }
        if (doCommitSession(sessionId, false /*logSuccess*/)
                != PackageInstaller.STATUS_SUCCESS) {
            return 1;
        }
        abandonSession = false;

        if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
            pw.println("Success");
            return 0;
        }
        return doWaitForStagedSessionRead(sessionId, params.timeoutMs, pw);
    } finally {
        if (abandonSession) {
            try {
                doAbandonSession(sessionId, false /*logSuccess*/);
            } catch (Exception ignore) {
            }
        }
    }
}

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

3.2.1、 doCreateSession

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

3.2.2、doWriteSession

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

3.2.3、doCommitSession

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

PackageInstallerSession.commit ==> commitLocked(); ==> PMS.installStage()
PMS.installStage()会调用sendMessage将INIT_COPY发送给PackageHandler
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);
    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);
}

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

3.3、PackageHanlder

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

3.3.1、INIT_COPY

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

class PackageHandler extends Handler {
    void doHandleMessage(Message msg) {
        ...
        switch (msg.what) {
                // 这里取出的其实就是InstallParams
                HandlerParams params = (HandlerParams) msg.obj;
                // 如果参数不为空则说明当前安装队列中有安装任务
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    // 开始安装流程
                    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的逻辑也发生了一些变化。

3.4、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来完成主要的工作。

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

3.4.2、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);
                Environment.getDataDirectory());
        final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                origin.resolvedPath, packageAbiOverride);
        if (sizeBytes >= 0) {
            try {
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        mPackageLite, origin.resolvedPath, installFlags,
                        packageAbiOverride);
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to free cache", e);
            }
        }
        ...
   }

3.4.3、handleReturnCode

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

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

3.7.4、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) {
                mContext.getContentResolver(), new File(args.getCodePath()));
    }
        // 当安装信息不为空时,尝试继续安装流程
        mParentInstallParams.tryProcessInstallRequest(args, mRet);
    } else {
        // 设置安装参数
        PackageInstalledInfo res = createPackageInstalledInfo(mRet);
        // 创建一个新线程,处理安装参数,进行安装
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,

    }
}
private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
    ...
        if (success) {
            for (InstallRequest request : apkInstallRequests) {
                // 如果之前安装失败,清除无用信息
                request.args.doPreInstall(request.installResult.returnCode);
            }
        }
     }

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

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

3.6、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(),
    ...
    //3.Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功。
    ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
            installResults,
            prepareResults,
            mSharedLibraries,
            Collections.unmodifiableMap(mPackages), versionInfos,
            lastStaticSharedLibSettings);
    ...
    //4.Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
    commitPackagesLocked(commitRequest);
    ...
    //5.完成APK的安装
    executePostCommitSteps(commitRequest);
}

3.7、安装过程细分为以下15步

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

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

3.7.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");
    }
}

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

3.7.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");
    }
}

3.7.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");
}

3.7.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");
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);
}

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

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

进入 [PackageManagerService.java] scanPackageTracedLI

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

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

3.7.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);

}

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

3.7.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(AndroidPackage pkg, int userId, int flags) {
        if (DEBUG_APP_DATA) {
        Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
        + Integer.toHexString(flags));
        }

    final PackageSetting ps;
    synchronized (mLock) {
            ps = mSettings.mPackages.get(pkg.getPackageName());
            }
    final String volumeUuid = pkg.getVolumeUuid();
    final String packageName = pkg.getPackageName();
    final int appId = UserHandle.getAppId(pkg.getUid());

    String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);

    Preconditions.checkNotNull(pkgSeInfo);

    final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
    long ceDataInode = -1;
    try {
        ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
        appId, seInfo, pkg.getTargetSdkVersion());
    } catch (InstallerException e) {
        if (pkg.isSystem()) {
            logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
            + ", but trying to recover: " + e);
            destroyAppDataLeafLIF(pkg, userId, flags);
            try {
                ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                appId, seInfo, pkg.getTargetSdkVersion());
                logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
            } catch (InstallerException e2) {
                logCriticalInfo(Log.DEBUG, "Recovery failed!");
            }
        } else {
            Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
        }
    }
    if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
         mArtManagerService.prepareAppProfiles(pkg, userId,
    /* updateReferenceProfileContent= */ false);
    }

    if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
        synchronized (mLock) {
            if (ps != null) {
                    ps.setCeDataInode(ceDataInode, userId);
                }
        }
    }
     prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
    }

3.7.15、 安装完成后,更新设置,更新安装锁等

总结

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

  • 将APK的信息通过IO流的形式写入到PackageInstaller.Session中。
  • 调用PackageInstaller.Session的commit方法,将APK的信息交由PKMS处理。
  • 拷贝APK
  • 最后进行安装

最终是交给installed守护进行完成真正的APK安装