应用程序的安装是通过包管理服务PackageManagerService完成的,常见的安装方式有以下几种:
① 内置APP随着系统启动PMS而安装。
② 使用adb install命令安装。
③ 通过系统内置的PackageInstaller应用安装。
④ 在一些手机厂商内置的应用商店下载,然后静默安装。
分析源码之后,会发现,其实只有两种方式,
一是系统内置应用通过PackageManagerService使用scanDirLi扫描指定目录下的apk安装。
二是第三方apk通过PackageManager直接或者间接的调用PMS的installPackageAsUser接口安装。
安装位置有两种:内置存储器和SD卡(Android6.0需要将SD卡转换为内置存储器才行)。
下文将介绍系统应用扫描安装、adb安装到内部存储器、apk安装到SD卡等情况的安装流程。
首先,我们看一下PackageManager的类关系:
PackageManagerService运行在system进程,为使其他进程使用,用到了binder通信,提供PackageManager接口供调用。
然后, 我们看一下系统APP的安装,之前说到系统APP安装是在系统启动PMS的时候,所以我们从SystemServer启动PMS开始看,下面是大概时序图
step2~step10, SystemServer在启动PMS之前,先启动了Installer这个SystemService,Installer新建一个InstallerConnection对象与installd的一个连接,通过socket通信,PMS每次执行安装、dexoat、卸载等操作时,需要调用Installer接口,然后Installer将封装后的命令通过socket发送给installd执行。
step17, 指定目录的路径传递给scanDirLi。
step18, 对目录下的apk文件逐个调用scanPackageLI方法,进行扫描解析。
step19, apk的解析是通过scanPackageLI新建的PackageParser对象完成的。
step20~step26, 主要是对AndroidManifest.xml文件的解析。
step27, 对签名文件的解析。
step28~step41, apk的安装,包含数据目录的创建/data/data/
接下来,简介adb安装apk到内置存储器的过程:
adb安装apk的主要过程如下:
1. 首先 apk会被push到手机的/data/local/tmp/目录(如果安装到sd卡,则会push到/sdcard/tmp/)。
2. 执行pm命令,调用PMS的installPackageAsUser接口,工作转移到PMS中。
3. 将apk的安装任务(HanderParams)交给工作线程PackageHandler,第三方apk的安装工作都是由PackageHandler完成的,PackageHandler的初始化是在PMS的构造方法中,准备将apk宝贝到/data/app/
4. INIT_COPY主要工作是连接DefaultContainerService服务,将安装任务(InstallParams)加到mPendingInstalls安装列表,等待服务连接成功。
5. 服务连接成功后,发送MCS_BOUND消息,取出安装任务(InstallParams),开始拷贝,新建安装参数(InstallArgs),拷贝时,是先新建一个临时目录,copy成功之后,将临时目录改成包名-
6. 拷贝成功后,新建一个线程,去解析apk执行
最后,看一下通过PackageInstaller将apk安装到SD卡的过程:
从图中流程可以看出,与刚才介绍的adb将apk安装到内部存储器的流程是差不多的(包括apk移动操作),只是安装位置不一样,安装参数(InstallArgs)的实现不一样。
MeasureParams: 计算APP占用存储空间时使用。
InstallParams: apk安装时使用。
FileInstallArgs:apk安装到内部存储器时使用。
AsecInstallArgs:apk安装到SD卡时使用或者安装FORWARDLOCK类型的apk。
MoveInstallArgs:apk从内部存储器移动到SD卡或者SD卡移动到内部存储器时使用。
InstallParams的handleStartCopy根据条件新建不同的InstallArgs对象:
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
}
好了,说到这里了,apk的更新与卸载,可以参照流程,继续学习。
再介绍一下installd进程,installd是个本地进程,代码在frameworks/native/cmds/installd目录,启动是在init进程中,
service installd /system/bin/installd
class main
socket installd stream 600 system system
直接看installd.cpp的main函数,
int main(const int argc __unused, char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
int lsocket, s;
int selinux_enabled = (is_selinux_enabled() > 0);
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv);
ALOGI("installd firing up\n");
union selinux_callback cb;
cb.func_log = log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
if (initialize_globals() < 0) { //初始化几个路径相关的全局变量
ALOGE("Could not initialize globals; exiting.\n");
exit(1);
}
if (initialize_directories() < 0) { //创建目录
ALOGE("Could not create directories; exiting.\n");
exit(1);
}
if (selinux_enabled && selinux_status_open(true) < 0) {
ALOGE("Could not open selinux status; exiting.\n");
exit(1);
}
lsocket = android_get_control_socket(SOCKET_PATH);//获得socket,"installd"
if (lsocket < 0) {
ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
exit(1);
}
if (listen(lsocket, 5)) { //开始监听socket
ALOGE("Listen on socket failed: %s\n", strerror(errno));
exit(1);
}
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
for (;;) { //进入循环
alen = sizeof(addr);
s = accept(lsocket, &addr, &alen);//收到InstallerConnection发送的数据
if (s < 0) {
ALOGE("Accept failed: %s\n", strerror(errno));
continue;
}
fcntl(s, F_SETFD, FD_CLOEXEC);
ALOGI("new connection\n");
for (;;) {
unsigned short count;
if (readx(s, &count, sizeof(count))) { //读取数据的长度
ALOGE("failed to read size\n");
break;
}
if ((count < 1) || (count >= BUFFER_MAX)) {
ALOGE("invalid size %d\n", count);
break;
}
if (readx(s, buf, count)) {//读取数据的内容
ALOGE("failed to read command\n");
break;
}
buf[count] = 0;
if (selinux_enabled && selinux_status_updated() > 0) {
selinux_android_seapp_context_reload();
}
if (execute(s, buf)) break; //解析命令,与cmds数组定义的命令匹配
}
ALOGI("closing connection\n");
close(s);
}
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },//测试socket是否连接成功
{ "install", 5, do_install },//创建app数据目录,如/data/data/vmdl.tmp
{ "dexopt", 9, do_dexopt },//对apk优化,调用的是dex2oat程序
{ "markbootcomplete", 1, do_mark_boot_complete },//好像没用到
{ "movedex", 3, do_move_dex },//classes.dex文件移动
{ "rmdex", 2, do_rm_dex },//classed.dex删除
{ "remove", 3, do_remove },//apk卸载
{ "rename", 2, do_rename },//目录重命名
{ "fixuid", 4, do_fixuid },//uid变动
{ "freecache", 2, do_free_cache },//释放app缓存空间
{ "rmcache", 3, do_rm_cache },//删除cache目录内容
{ "rmcodecache", 3, do_rm_code_cache },//删除code_cache目录内容
{ "getsize", 8, do_get_size },//获得指定app的大小
{ "rmuserdata", 3, do_rm_user_data },//删除用户数据
{ "cpcompleteapp", 6, do_cp_complete_app },
{ "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data },
{ "mkuserconfig", 1, do_mk_user_config },
{ "rmuser", 2, do_rm_user },
{ "idmap", 3, do_idmap },
{ "restorecondata", 4, do_restorecon_data },
{ "createoatdir", 2, do_create_oat_dir },
{ "rmpackagedir", 1, do_rm_package_dir },
{ "linkfile", 3, do_link_file }
};
struct cmdinfo的原型:
struct cmdinfo {
const char *name;
unsigned numargs;
int (*func)(char **arg, char reply[REPLY_MAX]);
};
未完待续,有不对的地方,请指正。