installd是一个native的守护进程,在init.rc中定义,如下:
service installd /system/bin/installd
class main
socket installd stream 600 system system
在安装应用的过程中,执行APK文件优化、创建、删除应用的数据文件等操作实际上是通过installd守护进程完成的。因为PMS所在进程SystemServer属于system用户组,没有root权限,不能完成在文件系统中更改目录、复制、删除文件等操作,因此这里引入了installd进程。
Android N中installd守护进程定义在frameworks/native/cmds/installd的Installd.rc文件中。
我们通过adb shell查看下installd进程是否是root用户,发现installd的用户是install,而不是root,那么intalld进程为什么可以对文件系统进行上面的操作呢?
ps | grep installd
install 404 1 2264 704 00b57be4 8b895b18 S /system/bin/installd
1、installd的初始化
installd模块的源码位于目录frameworks/native/cmds/installd,入口函数main()如下:
int main(const int argc, const char *argv[]) {
char buf[BUFFER_MAX];//BUFFER_MAX:1024: input buffer for commands
struct sockaddr addr;
socklen_t alen;
int lsocket, s, count;
int selinux_enabled = (is_selinux_enabled() > 0);
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);
}
drop_privileges();//变更installd进程的权限
lsocket = android_get_control_socket(SOCKET_PATH);//从环境变量ANDROID_SOCKET_INSTALLD中获取用于监听的本地socket
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);//接收连接
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;//执行命令
}
ALOGI("closing connection\n");
close(s);//关闭连接
}
return 0;
}
installd就是监听一个本地的socket,这个socket通过在init.rc文件中指定服务属性的方式创建。如果有socket连接进来,则通过socket读取命令字符串,然后执行命令。
在main函数中,installd通过调用initialize_globals()和initialize_directories()来完成初始化的工作。initialize_globals()函数将设置安装应用需要用到的目录名;initialize_directories()则创建所有用户的安装目录。
在上面的方法中都使用到了dir_rec_t结构体,那么这个结构体是如何定义的呢?如下:
typedef struct {
char* path;
size_t len;
} dir_rec_t;
在这个结构体中有两个成员变量:path、len,分别表示文件路径和文件路径长度。
同样使用到了android_system_dirs,定义如下:
dir_rec_array_t android_system_dirs;
typedef struct {
size_t count;
dir_rec_t* dirs;
} dir_rec_array_t;
在这个结构体中有两个成员变量:count、dirs;其中dirs又是dir_rec_t的结构体类型。
2、初始化全局变量initialize_globals
int initialize_globals() {
// Get the android data directory.从环境变量中读取数据存储路径,android_data_dir=/data/
if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) {
return -1;
}
// Get the android app directory.得到应用程序安装目录:android_app_dir=/data/app/
if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
return -1;
}
// Get the android protected app directory.得到应用程序私有目录:android_app_private_dir=/data/app-private/
if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
return -1;
}
// Get the android app native library directory.android_app_lib_dir=/data/app-lib/
if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
return -1;
}
// Get the sd-card ASEC mount point.从环境变量中取得sdcard ASEC的挂载点,android_asec_dir=/mnt/asec
if (get_path_from_env(&android_asec_dir, "AS