在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/[system@app@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/目录下:


更多相关文章

  1. android遇到的问题
  2. AndroidStudio生成签名文件失败时提示 key was created with err
  3. 【转】高通平台android 环境配置编译及开发经验总结
  4. 二、Tiny4412开发板运行安卓系统
  5. G1定制攻略
  6. 开源项目 log4android 使用方式详解
  7. android工程结构详细解析
  8. 项目中导入ActionBar的android-support-v7-appcompat.jar包
  9. 在Ubuntu 上搭建Android(安卓)内核编译环境

随机推荐

  1. EditText 光标不显示问题
  2. android拍照上传的效果是如何实现的
  3. Android开发问题 - Some projects cannot
  4. Android(安卓)生成不同服务器配置,不同APP
  5. Android 异常处理:java.lang.IllegalArgum
  6. JNI之------C调用java接口
  7. 查询遇到双引号
  8. Android(安卓)Studio进行APP图标更改的两
  9. 发送和拦截短信
  10. [Google Android] GCM: Getting Started