在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。
PackageManagerService通过套接字的方式访问installd服务进程,在Android启动脚本init.rc中通过服务配置启动了installd服务进程。
通过以上配置,init进程就会启动installd服务进程了。installd源码位于frameworks/base/cmds/installd
installd服务进程的入口函数:
int main(const int argc, const char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; int lsocket, s, count; //初始化一些全局变量 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); } //取得installd套接字的句柄,系统中的所有socket以ANDROID_SOCKET_[name]为键,socket句柄为值的方式保存在//环境变量中 lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); exit(1); } //监听该socket if (listen(lsocket, 5)) { ALOGE("Listen on socket failed: %s\n", strerror(errno)); exit(1); } //修改该socket的属性 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; } //接收到客户端的请求后,修改客户端请求socket属性 fcntl(s, F_SETFD, FD_CLOEXEC); ALOGI("new connection\n"); //循环读取客户端socket中的内容,直到读取内容为空为止 //客户端发送的数据格式:| 数据长度 | 数据内容 | for (;;) { unsigned short count; //读取数据长度,读取成功返回0,反之返回-1 if (readx(s, &count, sizeof(count))) { ALOGE("failed to read size\n"); break; } //如果读取成功,但是读取的数据长度超出1024字节,同样停止读取 if ((count < 1) || (count >= BUFFER_MAX)) { ALOGE("invalid size %d\n", count); break; } //读取数据内容,读取成功返回0,反之返回-1 if (readx(s, buf, count)) { ALOGE("failed to read command\n"); break; } buf[count] = 0; //执行客户端发送过来的命令 if (execute(s, buf)) break; } //执行完客户端的请求后,关闭该socket连接,继续进入接收请求模式 ALOGI("closing connection\n"); close(s); } return 0;}该函数首先初始化一些变量就安装目录,然后从环境变量中取得installd套件字的句柄值,然后进入监听此socket,当客户端发送过来请求时,接收客户端的请求,并读取客户端发送过来的命令数据,并根据读取的客户端命令来执行命令操作。
1)变量初始化
int initialize_globals() { //从环境变量中读取数据存储目录,在Android启动脚本init.rc中配置了ANDROID_DATA //环境变量,export ANDROID_DATA /data ,因此变量android_data_dir=/data/ if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) { return -1; } // 得到应用程序安装目录android_app_dir=/data/app/ if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) { return -1; } //得到应用程序私有目录android_app_private_dir=/data/app-private/ if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) { return -1; } //从环境变量中取得sd-card ASEC的挂载点,在启动脚本init.rc中也有配置:export ASEC_MOUNTPOINT /mnt/asec //因此android_asec_dir=/mnt/asec/ if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) { return -1; } //定义android_system_dirs变量并分配存储空间 android_system_dirs.count = 2; android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t)); if (android_system_dirs.dirs == NULL) { ALOGE("Couldn't allocate array for dirs; aborting\n"); return -1; } //从环境变量中取得android根目录,在启动脚本init.rc中也有配置:export ANDROID_ROOT /system // 因此android_system_dirs.dirs[0]=/system/ if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) { free_globals(); return -1; } //android_system_dirs.dirs[0]=/system/app/ char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR); android_system_dirs.dirs[0].path = system_app_path; android_system_dirs.dirs[0].len = strlen(system_app_path); android_app_preload_dir.path = "/system/preloadapp/"; android_app_preload_dir.len = strlen(android_app_preload_dir.path); android_system_dirs.dirs[1].path = "/vendor/app/"; android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path); return 0;}
2)初始化目录
int initialize_directories() { // user_data_dir=/data/user char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX); // legacy_data_dir=/data/data char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX); // primary_data_dir=/data/user/0 char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0"); int ret = -1; if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) { ret = 0; //如果/data/user目录不存在,则创建该目录 if (access(user_data_dir, R_OK) < 0) { if (mkdir(user_data_dir, 0711) < 0) { return -1; } //修改目录权限及所有属性 if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { return -1; } if (chmod(user_data_dir, 0711) < 0) { return -1; } } // Make the /data/user/0 symlink to /data/data if necessary if (access(primary_data_dir, R_OK) < 0) { ret = symlink(legacy_data_dir, primary_data_dir); } free(user_data_dir); free(legacy_data_dir); free(primary_data_dir); } return ret;}
3)执行客户发送过来的请求命令
static int execute(int s, char cmd[BUFFER_MAX]){ //#define BUFFER_MAX 1024 /* input buffer for commands */ char reply[REPLY_MAX]; //#define REPLY_MAX 256 /* largest reply allowed */ char *arg[TOKEN_MAX+1];//#define TOKEN_MAX 8 /* 命令参数最多8个 */ unsigned i; unsigned n = 0; unsigned short count; int ret = -1; reply[0] = 0; //arg[0]为命令名称,命令格式:[name arg1 arg2 arg3 arg4] arg[0] = cmd; //计算命令参数个数 while (*cmd) { if (isspace(*cmd)) { *cmd++ = 0; n++; arg[n] = cmd; if (n == TOKEN_MAX) { ALOGE("too many arguments\n"); goto done; } } cmd++; } //根据命令名称匹配命令数组cmds中的命令 for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { //命令名称比较 if (!strcmp(cmds[i].name,arg[0])) { //判断该命令的参数个数是否满足要求 if (n != cmds[i].numargs) { ALOGE("%s requires %d arguments (%d given)\n",cmds[i].name, cmds[i].numargs, n); } else { //调用命令执行函数,执行命令 ret = cmds[i].func(arg + 1, reply); } goto done; } } ALOGE("unsupported command '%s'\n", arg[0]);done: //格式化返回结果 if (reply[0]) { n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply); } else { n = snprintf(cmd, BUFFER_MAX, "%d", ret); } if (n > BUFFER_MAX) n = BUFFER_MAX; //返回结果数据长度 count = n; //写结果数据长度 if (writex(s, &count, sizeof(count))) return -1; //写结果数据 if (writex(s, cmd, count)) return -1; return 0;}
4)installd服务可执行的命令
struct cmdinfo cmds[] = { // { 命令名称, 参数个数,命令执行函数} { "ping", 0, do_ping }, { "install", 3, do_install }, { "dexopt", 3, do_dexopt }, { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, { "remove", 2, do_remove }, { "rename", 2, do_rename }, { "fixuid", 3, do_fixuid }, { "freecache", 1, do_free_cache }, { "rmcache", 1, do_rm_cache }, { "protect", 2, do_protect }, { "getsize", 4, do_get_size }, { "rmuserdata", 2, do_rm_user_data }, { "movefiles", 0, do_movefiles }, { "linklib", 2, do_linklib }, { "unlinklib", 1, do_unlinklib }, { "mkuserdata", 3, do_mk_user_data }, { "rmuser", 1, do_rm_user }, { "cloneuserdata", 3, do_clone_user_data },};
5)应用程序安装
static int do_install(char **arg, char reply[REPLY_MAX]){ return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */}直接调用frameworks\base\cmds\installd\commands.c中的install函数来安装
int install(const char *pkgname, uid_t uid, gid_t gid){ char pkgdir[PKG_PATH_MAX];//程序目录路径最长为256 char libdir[PKG_PATH_MAX];//程序lib路径最长为256 //权限判断 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { ALOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; } //组合应用程序安装目录pkgdir=/data/data/应用程序包名 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { ALOGE("cannot create package path\n"); return -1; } //组合应用程序库目录libdir=/data/data/应用程序包名/lib if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) { ALOGE("cannot create package lib path\n"); return -1; } //创建目录pkgdir=/data/data/应用程序包名 if (mkdir(pkgdir, 0751) < 0) { ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); return -errno; } //修改/data/data/应用程序包名目录的权限 if (chmod(pkgdir, 0751) < 0) { ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); unlink(pkgdir); return -errno; } //创建目录libdir=/data/data/应用程序包名/lib if (mkdir(libdir, 0755) < 0) { ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno)); unlink(pkgdir); return -errno; } //修改/data/data/应用程序包名/lib目录的权限 if (chmod(libdir, 0755) < 0) { ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno)); unlink(libdir); unlink(pkgdir); return -errno; } //修改/data/data/应用程序包名目录的所有权限 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) { ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno)); unlink(libdir); unlink(pkgdir); return -errno; } //修改/data/data/应用程序包名/lib目录的所有权限 if (chown(pkgdir, uid, gid) < 0) { ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); unlink(libdir); unlink(pkgdir); return -errno; } return 0;}组合应用程序安装目录路径:
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, const char *postfix, uid_t persona){ size_t uid_len; char* persona_prefix; //postfix="" //persona=0 if (persona == 0) { persona_prefix = PRIMARY_USER_PREFIX;// "data/" uid_len = 0; } else { persona_prefix = SECONDARY_USER_PREFIX;// "user/" uid_len = snprintf(NULL, 0, "%d", persona); } // /data/data/ const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/; char prefix[prefix_len + 1]; char *dst = prefix; size_t dst_size = sizeof(prefix); //dst=/data/data/ if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { ALOGE("Error building prefix for APK path"); return -1; } if (persona != 0) { int ret = snprintf(dst, dst_size, "%d/", persona); if (ret < 0 || (size_t) ret != uid_len + 1) { ALOGW("Error appending UID to APK path"); return -1; } } dir_rec_t dir; //设置安装目录,由于uid为0,因此安装目录为/data/data/ dir.path = prefix; dir.len = prefix_len; return create_pkg_path_in_dir(path, &dir, pkgname, postfix);}int create_pkg_path_in_dir(char path[PKG_PATH_MAX], const dir_rec_t* dir, const char* pkgname, const char* postfix){ const size_t postfix_len = strlen(postfix); //postfix_len= 0 const size_t pkgname_len = strlen(pkgname); //apk包名最长不允许超过128个字符 if (pkgname_len > PKG_NAME_MAX) { return -1; } //检查包名命名是否规范 if (is_valid_package_name(pkgname) < 0) { return -1; } //检查包名和目录路径长度是否超过256个字符 if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) { return -1; } char *dst = path; size_t dst_size = PKG_PATH_MAX; //最终的安装目录为/data/data/应用程序包名/postfix if (append_and_increment(&dst, dir->path, &dst_size) < 0 || append_and_increment(&dst, pkgname, &dst_size) < 0 || append_and_increment(&dst, postfix, &dst_size) < 0) { ALOGE("Error building APK path"); return -1; } return 0;}
6)应用程序卸载
应用程序卸载过程其实就是删除应用程序安装文件
static int do_remove(char **arg, char reply[REPLY_MAX]){ return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */}int uninstall(const char *pkgname, uid_t persona){ char pkgdir[PKG_PATH_MAX]; //根据包名得到应用程序安装目录路径 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) return -1; /*删除安装目录及目录下的文件 */ return delete_dir_contents(pkgdir, 1, NULL);}int delete_dir_contents(const char *pathname, int also_delete_dir, const char *ignore){ int res = 0; DIR *d; //打开应用程序安装目录 d = opendir(pathname); if (d == NULL) { ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); return -errno; } //删除安装目录下的文件 res = _delete_dir_contents(d, ignore); closedir(d); //删除安装目录 if (also_delete_dir) { if (rmdir(pathname)) { ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); res = -1; } } return res;}
7)应用程序安装包优化过程
static int do_dexopt(char **arg, char reply[REPLY_MAX]){ return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])); /* apk_path, uid, is_public */}直接调用dexopt函数来执行apk文件优化
int dexopt(const char *apk_path, uid_t uid, int is_public){ //例如:apk_path=system/app/Music.apk struct utimbuf ut; struct stat apk_stat, dex_stat; char dex_path[PKG_PATH_MAX];//PKG_PATH_MAX=256 char dexopt_flags[PROPERTY_VALUE_MAX];//PKG_PATH_MAX=92 char *end; int res, zip_fd=-1, odex_fd=-1; if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } //读取安装包优化标志位 property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); //dex_path=system/app/Music.apk strcpy(dex_path, apk_path); //判断dex_path的后缀 end = strrchr(dex_path, '.'); if (end != NULL) { strcpy(end, ".odex"); if (stat(dex_path, &dex_stat) == 0) { return 0; } } //dex_path=/data/dalvik-cache/[[email protected]@Music.apk]@classes.dex if (create_cache_path(dex_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); //获取apk文件信息 stat(apk_path, &apk_stat); //以只读方式打开apk文件 zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { ALOGE("dexopt cannot open '%s' for input\n", apk_path); return -1; } //删除dex文件 unlink(dex_path); //打开dex文件,如果文件不存在,则自动创建该文件 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (odex_fd < 0) { ALOGE("dexopt cannot open '%s' for output\n", dex_path); goto fail; } //修改dex文件的所有者属性 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { ALOGE("dexopt cannot chown '%s'\n", dex_path); goto fail; } //修改dex文件的权限 if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("dexopt cannot chmod '%s'\n", dex_path); goto fail; } ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; //创建一个线程来执行apk优化 pid = fork(); if (pid == 0) { if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) during dexopt\n", uid); exit(65); } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); exit(66); } //优化apk包文件,zip_fd为apk文件句柄,odex_fd为dex文件句柄,dexopt_flags为优化标志位 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); exit(67); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; utime(dex_path, &ut); close(odex_fd); close(zip_fd); return 0;fail: if (odex_fd >= 0) { close(odex_fd); unlink(dex_path); } if (zip_fd >= 0) { close(zip_fd); } return -1;}创建了一个新的线程来执行安装包优化任务
static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, const char* dexopt_flags){ //input_file_name为apk的路径 static const char* DEX_OPT_BIN = "/system/bin/dexopt"; static const int MAX_INT_LEN = 12; char zip_num[MAX_INT_LEN]; char odex_num[MAX_INT_LEN]; sprintf(zip_num, "%d", zip_fd);//apk文件句柄 sprintf(odex_num, "%d", odex_fd);//dex文件句柄 //调用/system/bin/dexopt工具来优化apk文件 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name, dexopt_flags, (char*) NULL); ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));}整个优化过程是通过system目录下的dexopt工具来完成的。这里直接使用该工具来完成apk优化。优化后的dex文件位于/data/dalvik-cache/目录下:
