在之前的博客中已经提到过,当SystemServer创建PKMS时,在其构造函数中传入了一个Installer对象。
Installer是一个系统服务,可以和installd通信,完成一些重要的工作,例如利用dexopt函数对APK文件进行dex优化;存储空间不足时,利用freeCache函数清理存储空间。
接下来,我们就分析一下installd及一些重要工作的流程。
一、installd的初始化
1、installd启动
在init.rc中,有以下代码片段:
.......
service installd /system/bin/installd
class main
socket installd stream 600 system system
.......
容易看出installd将作为service被init进程启动,同时会创建一个名为installd的socket。
在frameworks/native/cmds/installd/installd.cpp中:
int main(const int argc, char *argv[]) {
return android::installd::installd_main(argc, argv);
}
static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
.........
//以下初始化全局变量,包括创建data下的一些目录等
if (!initialize_globals()) {
ALOGE("Could not initialize globals; exiting.\n");
exit(1);
}
if (initialize_directories() < 0) {
ALOGE("Could not create directories; exiting.\n");
exit(1);
}
...........
//得到"installd" socket
lsocket = android_get_control_socket(SOCKET_PATH);
...........
//"installd"变成服务端
if (listen(lsocket, 5)) {
ALOGE("Listen on socket failed: %s\n", strerror(errno));
exit(1);
}
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
for (;;) {
alen = sizeof(addr);
//接受Java层的installer服务连接,形成与之连接的socket "s"
s = accept(lsocket, &addr, &alen);
..........
fcntl(s, F_SETFD, FD_CLOEXEC);
..........
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;
}
//读取cmd
if (readx(s, buf, count)) {
ALOGE("failed to read command\n");
break;
}
..........
buf[count] = 0;
//执行cmd
if (execute(s, buf)) break;
}
.........
close(s);
}
return 0;
}
上面的代码中,我们省去了selinux相关的代码,只保留主干。
从主干代码容易看出,installd整体的结构非常简单,其实就是启动后,获取作为服务端的socket “installd”;
然后,监听”installd”,等待Java层installer服务的连接及命令的到来。
2、命令处理方式
一旦installd收到命令后,将调用execute函数进行处理,其代码如下:
static int execute(int s, char cmd[BUFFER_MAX]) {
char reply[REPLY_MAX];
char *arg[TOKEN_MAX+1];
.......
arg[0] = cmd;
//解析参数的个数
while (*cmd) {
//当发现空格时
if (isspace(*cmd)) {
*cmd++ = 0;
//参数个数+1
n++;
//保存参数
arg[n] = cmd;
if (n == TOKEN_MAX) {
ALOGE("too many arguments\n");
goto done;
}
}
if (*cmd) {
cmd++;
}
}
//cmds为一个数组,保存了不同命令及对应的处理函数
for (i = 0; i < sizeof(cmds) /