Android系统APP安装流程

编程入门 行业动态 更新时间:2024-10-24 15:15:18

更多内容,欢迎关注公众号:tmac_lover

这篇文章介绍一下Android里安装一个apk文件的完整流程,我们以pm install安装一个新的app为例介绍。

1. pm命令

当我们使用

pm install -r /sdcard/test.apk

这样的pm命令来安装app的时候, 最终调用的是Pm.java的runInstall()方法

private int runInstall() {
    ... ...

     mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,
        installerPackageName, verificationParams, abi, userId);

    ... ...
}

最后通过binder调用PackageManagerService.java的installPackageAsUser()方法,然后就开始真正的进行apk的安装工作。可以看到,pm install命令进行app安装的时候,
是不会经过PackageInstaller的。

2. PackageManagerService

installPackageAsUser()方法里实现apk的安装主要可以分三个阶段。我们先看下总体流程图:

2.1 准备阶段

在进行app安装之前,需要先做一些准备工作。

public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride, int userId) {
    ... ...

    final Message msg = mHandler.obtainMessage(INIT_COPY);
    msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
            null, verificationParams, user, packageAbiOverride, null);
    mHandler.sendMessage(msg);

}

这里先构造了一个InstallParams对象,这里存放一些app文件安装需要的信息,比如apk文件的路径,安装时的flags, 以及安装完成之后的回调等等。然后通过Handler发送一条INIT_COPY消息。

class PackageHandler extends Handler {
    void doHandleMessage(Message msg) {
        switch (msg.what) {
            case INIT_COPY: {
                if (!mBound) {
                    // 第一次安装app, 会连接DefaultContainerService
                    if (!connectToService()) {
                        params.serviceError();
                        return;
                    } else {
                        // 然后将app安装请求放到mPendingInstalls里
                        mPendingInstalls.add(idx, params);
                    }
                } else {
                    // 如果不是第一次安装app, DefaultContainerService已经是连接状态,
                    // 直接将app安装请求放到mPendingInstalls里
                    mPendingInstalls.add(idx, params);
                    if (idx == 0) {
                        mHandler.sendEmptyMessage(MCS_BOUND);
                    }
                }
                break;
            }
            case MCS_BOUND: {
                // 不管是哪种情况,INIT_COPY之后,一定会再发一个MSC_BOUND的消息
                // 这里开始调用InstallParams类的startCopy()方法
                if (params.startCopy()) {
                    if (mPendingInstalls.size() > 0) {
                        mPendingInstalls.remove(0);
                    }
                    // 如果mPendingInstalls里还有等待安装的app, 依次执行
                    if (mPendingInstalls.size() == 0) {
                        if (mBound) {
                            removeMessages(MCS_UNBIND);
                            Message ubmsg = obtainMessage(MCS_UNBIND);
                            sendMessageDelayed(ubmsg, 10000);
                        }
                    } else {
                        mHandler.sendEmptyMessage(MCS_BOUND);
                    }
                }
            }
        }
    }
}

总结一下,在安装app之前的准备工作主要有:
1. 构造一个InstallParams对象,这个对象里包含了apk文件的信息和一些安装相关的参数
2. 发送INIT_COPY消息,这时如果没有连接DefaultContainerService, 先连接这个service;还有就是将apk安装请求放入mPendingInstalls里
3. 再发送MCS_BOUND消息,调用InstallParams对象的startCopy()方法开始安装app;如果有多个app等待安装,循环发MSC_BOUND消息,执行安装操作

2.2 handleStartCopy

前面的准备工作最后,调用InstallParams对象的startCopy()方法开始app的安装工作,startCopy()里分为两部分,handleStartCopy()和handleReturnCode()。先看下handleStartCopy()流程图:

  • 图中第2步获取app安装的基本信息;先通过parsePackageLite()提取apk包中的信息,然后依据AndroidManifest.xml里的”android:installLocation”属性和apk安装需要的大小以及目标分区的剩余空间大小来决定app最终是安装在data分区,还是sdcard上。
  • 第6步installLocationPolicy()方法对第2步返回的apk信息做进一步确认。如果系统中已经安装过此app, 需要确认新安装的app版本号是否比之前的高;同时还会根据上一步获取的安装位置信息设置app安装需要的Flag
  • 第7步copyApk()方法完成将需要安装的apk文件拷贝到要安装的分区的一个零时文件夹里,并重命名为base.apk,比如/data/app/vmdl1309479077.tmp/base.apk下。同时还会将.apk包里的.so库拷贝到/data/app/vmdl1309479077.tmp/libs下

所以handleStartCopy()主要的工作就是将要安装的apk文件和使用的.so库拷贝到要安装的分区的零时目录下

2.3 handleReturnCode

handleReturnCode里会完成app安装的剩余动作,并发送安装成功的广播。

  • 第4步installPackageLI()方法里完成了安装app的核心工作,后面专门分析。
  • 第8步通过Handler发送POST_INSTALL消息,这个消息的处理函数如下:
class PackageHandler extends Handler {
    void doHandleMessage(Message msg) {
        switch (msg.what) {
            ... ...

            case POST_INSTALL: {
                ... ...
                // 发送ACTION_PACKAGE_ADDED这条广播
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                        packageName, extras, null, null, firstUsers);
                if (args.observer != null) {
                    // 如果有回调的话,调用回调方法, 通知app安装完成
                    args.observer.onPackageInstalled(res.name, res.returnCode,
                            res.returnMsg, extras);
                }
                ... ...
                break;
            }
        }
    }
}

在收到POST_INSTALL消息后,主要完成两条操作:

  • 发送ACTION_PACKAGE_ADDED广播
  • 如果在调用installPackageAsUser()方法时有传入IPackageInstallObserver2作为回调,则调用回调方法报告安装状态

接下来看下第4步installPackageLI()方法:

  • 第2步parsePackage()通过解析apk包和apk包里的AndroidManifest.xml,解析出所有apk的信息,放到Package对象中。
  • 第3步collectCertificates()方法对apk文件进行签收校验,确保apk文件没有被更改过以及签名正确。第4步通过collectManifestDigest()方法获取AndroidManifest.xml的摘要值。
  • 第5步derivePackageAbi()方法通过apk包里使用的so库确定app进程的abi,关于abi,可以查看之前的一篇文章:
  • 第6步performDexOpt()通过socket和installd通信,将apk包里的classes.dex转化为虚拟机可以直接运行的文件格式,关于dex优化,可以查看之前的一篇文章:
  • 第7步doRename()方法将前面handleStartCopy()里的零时文件夹/data/app/vmdl1309479077更改成/data/app/$(package_name),这个新的文件夹将是app安装后的最终目录
  • 第8步installNewPackageLI()将完成一个新的app的安装,如果是安装之前已经存在的apk, 则这里调用的是replacePackageLI()

接下来看看installNewPackageLI()方法的流程:

  • verifySignaturesLP()使用上一步中collectCertificates()里获取的签名信息进行验证,主要分两步:一是如果是安装一个系统中已经存在的同名app, 则和已经存在的app签名进行对比,保证两者签名相同;二是如果系统中已经存在和正在安装的app有相同UID的app,
    则需要保证安装app的签名和已经存在的使用相同UID的app签名相同。
  • createDataDirsLI()方法创建app的数据目录,例如: /data/data/${package_name}/
  • adjustCpuAbisForSharedUserLPw()方法保证如果新安装的app使用了”android:sharedUID”, 它会将它的abi调整成和系统中使用相同uid的其它app一样的abi
  • 接下来就会在mSettings中写入正在安装app的信息,比如安装路径,数据目录路径,签名信息,abi信息等。最终将这些信息存在/data/system/packages.xml中。同时还会将AndroidManifest.xml中的四大组件以及权限等信息,存到PackageManagerService的对应数组里,
    这样以后通过startActivity之类的方法打开相应的组件时,就可以找到相应的组件是否存在。需要注意的是,这些四大组件以及权限信息,只是保存在内存中,每次系统开机时,都会重新扫描apk文件,然后将它们再次存到内存中使用。

3. 小结

关于新安装一个apk的大概流程就介绍完了;当然Android系统因为要兼容各种各样的情况,关于安装apk的代码实际上比上面分析的更加的复杂,但是无论有多少if else,核心原理和流程还是和上面分析的一样。希望大家能够对着代码自己弄解清楚。

更多推荐

Android系统APP安装流程

本文发布于:2023-06-14 07:29:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1451254.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:流程   系统   Android   APP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!