更多内容,欢迎关注公众号:tmac_lover
这篇文章介绍一下Android里安装一个apk文件的完整流程,我们以pm install安装一个新的app为例介绍。
当我们使用
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的。
installPackageAsUser()方法里实现apk的安装主要可以分三个阶段。我们先看下总体流程图:
在进行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消息,执行安装操作
前面的准备工作最后,调用InstallParams对象的startCopy()方法开始app的安装工作,startCopy()里分为两部分,handleStartCopy()和handleReturnCode()。先看下handleStartCopy()流程图:
所以handleStartCopy()主要的工作就是将要安装的apk文件和使用的.so库拷贝到要安装的分区的零时目录下
handleReturnCode里会完成app安装的剩余动作,并发送安装成功的广播。
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消息后,主要完成两条操作:
接下来看看installNewPackageLI()方法的流程:
关于新安装一个apk的大概流程就介绍完了;当然Android系统因为要兼容各种各样的情况,关于安装apk的代码实际上比上面分析的更加的复杂,但是无论有多少if else,核心原理和流程还是和上面分析的一样。希望大家能够对着代码自己弄解清楚。