Android系统APP安装流程

更多内容,欢迎关注公众号: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系统手机上安装软件的三种方法 很多朋友初用安卓手机,可能都会比较陌生。下面就介绍一下如何在安卓系统安装软件。在Android平台上安装文件的后缀名一般为“.apk”(如果你下载的软件是rar或者zip的话请解压之后再安装),和WM平台上的安装文件的后缀名“.exe”或者S60平台上的安装文件的后缀名“.sis或.sisx”相似。所以只要看到“.apk”结尾的文件就肯定是安装文件了。 在安装软件之前我们首先要对手机进行一系列的设置。在手机程序菜单中点“设置”进入,然后点击“应用程序”选项,在打开菜单中将“未知源”选项勾选中。然后进入“开发”子选项,勾选“USB 调试”选项。这样就完成了手机的设置。 完成如上准备工作后就可以进行软件的安装工作了。常用的安装方法一共有三种,下面我依次来为大家讲解。 方法一 使用Android系统的手机最简单的软件安装方法是进入件Market或者也叫电子市场(如果提示需要设置Gmail的话请参看链接)中下载安装。使用非常简单,只需用手指拖出程序菜单,点击Market(或者叫电子市场)图标进入该程序。 然后在搜索框(search)中填写你需要的软件名称搜索即可,或者在软件分类和推荐软件列表中找到你要安装的软件点击下载安装即可,如果是免费软件会显示为“Free”,如果是收费软件的话会提示软件的费用为“$xx”。 利用Market下载和安装都非常方便,但是此方法的缺点是非常浪费流量(就算软件是免费的,但是网络流量还是要收费的哦!),所以此法只推荐在连接Wifi(如果你Wifi不会设置的话,可以参看该链接)的情况下使用。另外如果你想安装收费软件,但是又不想花钱那么你可以按照下边的方法安装你在论坛或网站下载的以“.apk”为后缀名的破解版软件。 方法二 如果你的手机所刷的固件是安卓自制的固件话,那么你的的手机中可能已经集成了“APK安装器”,你只需要把要安装的文件用读卡器拷贝到内存卡中。然后在在手机程序菜单中点“设置”进入,然后点击“应用程序”选项,拖动菜单到下端可以看到“APK安装器”,点击进入。 安装器会自动搜索你内存卡中的安装程序,你只需选择要安装的程序名称点击安装即可。 如果你的手机使用的是原生的或者没有集成程序安装器的ROM那么你需要去Market中下载一款名为App Installer(其实就是软件安装器)的软件。在Market中下载安装完成后,在程序菜单中就可以找到刚安装App Installer了,使用方法同上。 方法三 直接使用电脑安装软件。使用“APK安装器”可以直接连接PC中将电脑中的软件安装到你的手机中。不过前提是必须先要安装Android手机的USB驱动,否则电脑无法识别所连接的手机,点击下载USB驱动程序,下载完成解压安装即可。 USB驱动安装完成后电脑就可以将你的手机自动识别为移动磁盘了。这是再点击下载“APK安装器”,下载安装完成后将该压缩包解压,然后点击运行该程序。该程序会自动关联电脑中的apk程序,安装软件时只需双击apk安装文件即可。该程序会帮助你自动将软件安装到你的手机里。
Android 13 系统中,应用程序的安装流程延续了早期版本的核心机制,同时在安全性、权限控制和用户交互方面进行了增强。安装流程主要由 `PackageManagerService`(PMS)主导,并涉及 APK 文件解析、签名验证、权限确认、Dex 优化、应用注册等多个步骤。 APK 文件解析是安装流程的起始环节,系统会解析 APK 中的 `AndroidManifest.xml` 文件,提取应用的包名、组件声明(如 Activity、Service)、权限请求、图标和标签等信息。这些信息是后续安装决策的重要依据[^1]。 安装过程中,系统会对 APK 的签名进行验证。Android 要求所有 APK 必须经过签名,若设备上已存在同包名但签名不同的应用,系统会拒绝安装,除非用户手动卸载旧版本。这一机制确保了应用更新的安全性和一致性。 在用户交互层面,若通过 PackageInstaller 安装(如从文件管理器选择 APK 安装),系统会提示用户确认权限请求。Android 13 对权限模型进行了优化,特别是在敏感权限(如位置、摄像头、麦克风)方面增加了更精细的控制选项,用户可以选择“仅一次”、“始终允许”或“拒绝”等不同授权级别。 安装流程中,系统会根据 `AndroidManifest.xml` 中的 `installLocation` 属性决定应用安装位置。默认情况下,应用安装在内部存储中,但也可以选择安装到外部存储(如 SD 卡)。 在安装完成后,系统会在 `/data/data/<package_name>` 路径下为应用创建私有数据目录,用于存放数据库、SharedPreferences、缓存等数据。这一过程确保了应用数据的隔离性和安全性。 Android 13 使用 ART(Android Runtime)进行 Dex 优化,安装时会执行 dex2oat 过程,将 `.dex` 文件编译为设备专用的本地代码,以提升运行时性能。这一优化过程由 `InstallD` 守护进程负责执行,确保应用在首次启动时具备良好的性能表现。 安装完成后,应用的信息会被注册到 `PackageManagerService` 中,该服务负责管理所有已安装应用的元数据、权限信息、组件声明等。此外,系统还会发送 `ACTION_PACKAGE_ADDED` 广播,通知其他应用或系统组件有新的应用被安装。 对于不同的安装方式,Android 13 提供了统一的安装接口。例如,通过 ADB 命令安装时,系统会启动 `pm` 脚本并调用 `Pm.java` 中的方法,最终调用 `PMS.installStage()` 完成安装;而通过 PackageInstaller 安装时,则由 `packageinstaller.apk` 处理用户界面和安装流程。 ### 示例命令(ADB 安装) ```bash adb install app-release.apk ``` 覆盖安装命令: ```bash adb install -r app-release.apk ``` 其中 `-r` 参数表示重新安装应用,并保留原有数据。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值