Android—PMS: installPackagesLI

installPackagesLI

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

    private void installPackagesLI(List<InstallRequest> requests) {
        ....
        try {
            for (InstallRequest request : requests) {
                ....
                final PrepareResult prepareResult;
                try {
                    //1.成功准备好的安装软件包所需的数据集。这包括将用于扫描和协调包的数据。
                    prepareResult = preparePackageLI(request.args, request.installResult);
                } 
                ....
                try {
                    //2.根据prepare中收集的上下文查询解析后的包
                    final List<ScanResult> scanResults = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user);
                    ....
                } 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<String, ReconciledPackage> reconciledPackages;
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                    reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.mKeySetManagerService);
                }
                ....
            }
            //4.提交
            executePostCommitSteps(commitRequest);
        }
        ....
    }

1.准备 prepareResult = preparePackageLI(request.args, request.installResult);

    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
            throws PrepareFailure {
        .....
        //解析包AndroidManifest.xml文件,签名信息等。
        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);
        }
        .....
        //冻结安装包
        final PackageFreezer freezer =
                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
        boolean shouldCloseFreezerBeforeReturn = true;
        try {
            if (replace) {
                //更新包配置
                ...
                //如果是更新包还会判断是不是系统APP
                sysPkg = (isSystemApp(oldPackage));
                if (sysPkg) { 
                ...
                }
            } else { 
                //新包安装配置
                ...
            }
            ....
            //返回安装包的数据集
            return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
                    replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
                    ps, disabledPs, childPackages);
        }

preparePackageLI最主要的是

pkg = pp.parsePackage(tmpPackageFile, parseFlags);

\frameworks\base\core\java\android\content\pm\PackageParser.java

    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        return parsePackage(packageFile, flags, false /* useCaches */);
    }

    public Package parsePackage(File packageFile, int flags, boolean useCaches)
            throws PackageParserException {
        ....
        if (packageFile.isDirectory()) {
            parsed = parseClusterPackage(packageFile, flags);
        } else {
            //只有一个包走这里
            parsed = parseMonolithicPackage(packageFile, flags);
        }
        ....
        return parsed;
    }

    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        ....
        try {
            final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
            pkg.setCodePath(apkFile.getCanonicalPath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        }
        ....
    }

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        try {
            ....
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
            final Resources res = new Resources(assets, mMetrics, null);
            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }
            pkg.setVolumeUuid(volumeUuid);
            pkg.setApplicationVolumeUuid(volumeUuid);
            pkg.setBaseCodePath(apkPath);
            pkg.setSigningDetails(SigningDetails.UNKNOWN);
            return pkg;
        }
        ....
    }

parseBaseApk是具体的解析方法,这里的ANDROID_MANIFEST_FILENAME就是manifest文件了

    public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";

这里也去解析了资源文件等,最后都赋给了pkg这个Package对象,和Android四大组件相关的信息分别由activites、receivers、providers、services的list保存。

2.扫描 final List<ScanResult> scanResults = scanPackageTracedLI(prepareResult.packageToScan, prepareResult.parseFlags,prepareResult.scanFlags, System.currentTimeMillis(), request.args.user);

根据prepare中收集的上下文查询已解析的包。

扫描阶段会填充PackageSetting对象,PackageSetting生成之后会被记录到文件中,以后每次系统启动都会重新加载。

3.协调 reconciledPackages = reconcilePackagesLocked(reconcileRequest, mSettings.mKeySetManagerService);

验证安装包状态,以确保安装成功。协调新旧包,删除旧的package。

4.提交  commitPackagesLocked(commitRequest);

    private void commitPackagesLocked(final CommitRequest request) {

        for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
            if (reconciledPkg.prepareResult.replace) {
                PackageParser.Package oldPackage = mPackages.get(packageName);
                // 1.设置安装和更新时间
                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
                        System.currentTimeMillis());

                //系统应用
                if (reconciledPkg.prepareResult.system) {
                    // 2.系统应用-移除现有包,后面还会移除子包(已省略)
                    removePackageLI(oldPackage, true);        
                    .....
                    }
                } else {
                    try {
                        //3.非系统应用-删除包
                        executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
                                true, request.mAllUsers, true, pkg);
                    }
                    ....
                }
            }
            //4.提交包扫描并修改系统状态
            commitReconciledScanResultLocked(reconciledPkg);
            updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
                    res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);

            final PackageSetting ps = mSettings.mPackages.get(packageName);
            if (ps != null) {
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
                ps.setUpdateAvailable(false /*updateAvailable*/);
            }
            ....
        }
    }

提交阶段第4步比较关键。前面3阶段填充了Package对象和PackageSetting对象数据,现在需要将这些数据提交。

4.4 commitReconciledScanResultLocked(reconciledPkg);

    private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
            ....
            commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
                    (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
            ....
    }

    //将扫描包添加到系统中。当这个方法完成时,包将会可用于查询,解决等…
    private void commitPackageSettings(PackageParser.Package pkg,
            @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
            final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
        ....
        synchronized (mPackages) {
            //添加新的设置到mSettings
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);
            //将新设置添加到mPackages中
            mPackages.put(pkg.applicationInfo.packageName, pkg);
            //将包的键集添加到全局KeySetManagerService
            KeySetManagerService ksms = mSettings.mKeySetManagerService;
            ksms.addScannedPackageLPw(pkg);
            mComponentResolver.addAllComponents(pkg, chatty);
            .....
        }
    }

在此之前,四大组件信息等安装包信息都属于Package的私有财产,现在需要把它们登记注册到PKMS内部的财产管理对象中。这样,PKMS就可对外提供统一的组件信息,而不必拘泥于具体的Package。

5.善后工作executePostCommitSteps(commitRequest);

    private void executePostCommitSteps(CommitRequest commitRequest) {
        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
            .....
            //1.安装并准备/data/data下的文件夹
            prepareAppDataAfterInstallLIF(pkg);
            ....
            //2.dex2oat操作,用来将apk中的dex文件转换为oat文件
            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);
            }
            ...
        }
    }

prepareAppDataAfterInstallLIF(pkg);

    private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
        ....
        final UserManagerService um = sUserManager;
        UserManagerInternal umInternal = getUserManagerInternal();
        for (UserInfo user : um.getUsers(false /* excludeDying */)) {
            final int flags;
            if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
            } else if (umInternal.isUserRunning(user.id)) {
                flags = StorageManager.FLAG_STORAGE_DE;
            } else {
                continue;
            }

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

    private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags,
            boolean maybeMigrateAppData) {
        prepareAppDataLIF(pkg, userId, flags);

        if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) {
            // We may have just shuffled around app data directories, so
            // prepare them one more time
            prepareAppDataLIF(pkg, userId, flags);
        }
    }

    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
        ...
        try {
            ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                    appId, seInfo, app.targetSdkVersion);
        }
        ...
    }

跟到最后发现是交给mInstaller去做的,这里的mInstaller是个Binder代理对象,具体实现在\frameworks\native\cmds\installd\InstalldNativeService.cpp

std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
    std::string data(create_data_path(volume_uuid));
    if (volume_uuid == nullptr && userid == 0) {
        std::string legacy = StringPrintf("%s/data", data.c_str());
        struct stat sb;
        if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
            /* /data/data is dir, return /data/data for legacy system */
            return legacy;
        }
    }
    return StringPrintf("%s/user/%u", data.c_str(), userid);
}

这里返回data/data 

第5步executePostCommitSteps就是去建立用户数据文件夹,data/data;使用 dex2oat 把App编译成 oat 文件,并保存在 dalvik-cache 目录里;发送ACTION_PACKAGE_ADDED、ACTION_PACKAGE_REPLACED广播等等操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值