前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android PMS处理APK的安装

Android PMS处理APK的安装

作者头像
用户1269200
发布2018-07-30 10:36:20
1.3K0
发布2018-07-30 10:36:20
举报
文章被收录于专栏:刘望舒刘望舒

前言

阅读本文前最好阅读Android PMS处理APK的复制这篇文章,因为它和本篇文章本来是一篇文章,由于公号文章的字数限制,被拆分为了两篇文章,这一篇我们接着来学习PMS处理APK的安装。

1.安装APK

照例先来查看安装APK的时序图。

我们回到APK的复制调用链的头部方法:HandlerParams的startCopy方法,在注释4处会调用handleReturnCode方法,它的实现在InstallParams中,如下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

代码语言:javascript
复制
 void handleReturnCode() {
    if (mArgs != null) {
        processPendingInstall(mArgs, mRet);
    }
}

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    //安装前处理
                    args.doPreInstall(res.returnCode);//1
                    synchronized (mInstallLock) {
                        installPackageTracedLI(args, res);//2
                    }
                    //安装后收尾
                    args.doPostInstall(res.returnCode, res.uid);//3
                }
              ...
            }
        });
    }

handleReturnCode方法中只调用了processPendingInstall方法,注释1处用于检查APK的状态的,在安装前确保安装环境的可靠,如果不可靠会清除复制的APK文件,注释3处用于处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件。主要来看注释2处的installPackageTracedLI方法,其内部会调用PMS的installPackageLI方法。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

代码语言:javascript
复制
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    ...
    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 {
        //解析APK
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);//1
    } catch (PackageParserException e) {
        res.setError("Failed parse during installPackageLI", e);
        return;
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    ...
    pp = null;
    String oldCodePath = null;
    boolean systemApp = false;
    synchronized (mPackages) {
        // 检查APK是否存在
        if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            String oldName = mSettings.getRenamedPackageLPr(pkgName);//获取没被改名前的包名
            if (pkg.mOriginalPackages != null
                    && pkg.mOriginalPackages.contains(oldName)
                    && mPackages.containsKey(oldName)) {
                pkg.setPackageName(oldName);//2
                pkgName = pkg.packageName;
                replace = true;//设置标志位表示是替换安装
                if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
                        + oldName + " pkgName=" + pkgName);
            } 
            ...
        }
        PackageSetting ps = mSettings.mPackages.get(pkgName);
        //查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息
        if (ps != null) {//3
            if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
            PackageSetting signatureCheckPs = ps;
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
                if (libraryEntry != null) {
                    signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
                }
            }
            //检查签名的正确性
            if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
                if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                            + pkg.packageName + " upgrade keys do not match the "
                            + "previously installed version");
                    return;
                }
            } 
            ...
        }

        int N = pkg.permissions.size();
        for (int i = N-1; i >= 0; i--) {
           //遍历每个权限,对权限进行处理
            PackageParser.Permission perm = pkg.permissions.get(i);
            BasePermission bp = mSettings.mPermissions.get(perm.info.name);

            }
        }
    }
    if (systemApp) {
        if (onExternal) {
            //系统APP不能在SD卡上替换安装
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
            return;
        } else if (instantApp) {
            //系统APP不能被Instant App替换
            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
            return;
        }
    }
    ...
    //重命名临时文件
    if (!args.doRename(res.returnCode, pkg, oldCodePath)) {//4
        res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
        return;
    }

    startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);

    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
            "installPackageLI")) {

        if (replace) {//5
         //替换安装   
           ...
            replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, res, args.installReason);
        } else {
        //安装新的APK
            installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res, args.installReason);
        }
    }

    synchronized (mPackages) {
        final PackageSetting ps = mSettings.mPackages.get(pkgName);
        if (ps != null) {
            //更新应用程序所属的用户
            res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            ps.setUpdateAvailable(false /*updateAvailable*/);
        }
        ...
    }
}

installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:

  1. 创建PackageParser解析APK。
  2. 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装。
  3. 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换。
  4. 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。
  5. 系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换。
  6. 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。

这里我们以新安装APK为例,会调用PMS的installNewPackageLIF方法。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

代码语言:javascript
复制
 private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
            int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
            PackageInstalledInfo res, int installReason) {
        ...
        try {
            //扫描APK
            PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
                    System.currentTimeMillis(), user);
            //更新Settings信息
            updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                //安装成功后,为新安装的应用程序准备数据
                prepareAppDataAfterInstallLIF(newPackage);

            } else {
                //安装失败则删除APK
                deletePackageLIF(pkgName, UserHandle.ALL, false, null,
                        PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
            }
        } catch (PackageManagerException e) {
            res.setError("Package couldn't be installed in " + pkg.codePath, e);
        }
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

installNewPackageLIF主要做了以下3件事:

  1. 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
  2. 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
  3. 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。

安装APK的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。

2.总结

本文和上一篇文章Android PMS处理APK的复制主要讲解了PMS是如何处理APK复制和安装的,主要有几个步骤:

1. PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。

2. PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。

3. 复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 刘望舒 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 1.安装APK
      • 2.总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档