Android安装服务installd源码分析

在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。


PackageManagerService通过套接字的方式访问installd服务进程,在Android启动脚本init.rc中通过服务配置启动了installd服务进程。


通过以上配置,init进程就会启动installd服务进程了。installd源码位于frameworks/base/cmds/installd


installd服务进程的入口函数:

  1. int main(const int argc, const char *argv[]) {  
  2.     char buf[BUFFER_MAX];  
  3.     struct sockaddr addr;  
  4.     socklen_t alen;  
  5.     int lsocket, s, count;  
  6.     //初始化一些全局变量   
  7.     if (initialize_globals() < 0) {  
  8.         ALOGE("Could not initialize globals; exiting.\n");  
  9.         exit(1);  
  10.     }  
  11.     //初始化安装目录   
  12.     if (initialize_directories() < 0) {  
  13.         ALOGE("Could not create directories; exiting.\n");  
  14.         exit(1);  
  15.     }  
  16.     //取得installd套接字的句柄,系统中的所有socket以ANDROID_SOCKET_[name]为键,socket句柄为值的方式保存在//环境变量中   
  17.     lsocket = android_get_control_socket(SOCKET_PATH);  
  18.     if (lsocket < 0) {  
  19.         ALOGE("Failed to get socket from environment: %s\n", strerror(errno));  
  20.         exit(1);  
  21.     }  
  22.     //监听该socket   
  23.     if (listen(lsocket, 5)) {  
  24.         ALOGE("Listen on socket failed: %s\n", strerror(errno));  
  25.         exit(1);  
  26.     }  
  27.     //修改该socket的属性   
  28.     fcntl(lsocket, F_SETFD, FD_CLOEXEC);  
  29.     for (;;) {  
  30.         alen = sizeof(addr);  
  31.         //循环等待接收客户端的请求   
  32.         s = accept(lsocket, &addr, &alen);  
  33.         if (s < 0) {  
  34.             ALOGE("Accept failed: %s\n", strerror(errno));  
  35.             continue;  
  36.         }  
  37.         //接收到客户端的请求后,修改客户端请求socket属性   
  38.         fcntl(s, F_SETFD, FD_CLOEXEC);  
  39.         ALOGI("new connection\n");  
  40.         //循环读取客户端socket中的内容,直到读取内容为空为止   
  41.         //客户端发送的数据格式:| 数据长度 | 数据内容 |   
  42.         for (;;) {  
  43.             unsigned short count;  
  44.             //读取数据长度,读取成功返回0,反之返回-1   
  45.             if (readx(s, &count, sizeof(count))) {  
  46.                 ALOGE("failed to read size\n");  
  47.                 break;  
  48.             }  
  49.             //如果读取成功,但是读取的数据长度超出1024字节,同样停止读取   
  50.             if ((count < 1) || (count >= BUFFER_MAX)) {  
  51.                 ALOGE("invalid size %d\n", count);  
  52.                 break;  
  53.             }  
  54.             //读取数据内容,读取成功返回0,反之返回-1   
  55.             if (readx(s, buf, count)) {  
  56.                 ALOGE("failed to read command\n");  
  57.                 break;  
  58.             }  
  59.             buf[count] = 0;  
  60.             //执行客户端发送过来的命令   
  61.             if (execute(s, buf)) break;  
  62.         }  
  63.         //执行完客户端的请求后,关闭该socket连接,继续进入接收请求模式   
  64.         ALOGI("closing connection\n");  
  65.         close(s);  
  66.     }  
  67.     return 0;  
  68. }  
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)变量初始化

  1. int initialize_globals() {  
  2.     //从环境变量中读取数据存储目录,在Android启动脚本init.rc中配置了ANDROID_DATA   
  3.     //环境变量,export ANDROID_DATA /data ,因此变量android_data_dir=/data/   
  4.     if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) {  
  5.         return -1;  
  6.     }  
  7.     // 得到应用程序安装目录android_app_dir=/data/app/   
  8.     if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {  
  9.         return -1;  
  10.     }  
  11.     //得到应用程序私有目录android_app_private_dir=/data/app-private/   
  12.     if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {  
  13.         return -1;  
  14.     }  
  15.     //从环境变量中取得sd-card ASEC的挂载点,在启动脚本init.rc中也有配置:export ASEC_MOUNTPOINT /mnt/asec   
  16.     //因此android_asec_dir=/mnt/asec/   
  17.     if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) {  
  18.         return -1;  
  19.     }  
  20.     //定义android_system_dirs变量并分配存储空间   
  21.     android_system_dirs.count = 2;  
  22.     android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t));  
  23.     if (android_system_dirs.dirs == NULL) {  
  24.         ALOGE("Couldn't allocate array for dirs; aborting\n");  
  25.         return -1;  
  26.     }  
  27.     //从环境变量中取得android根目录,在启动脚本init.rc中也有配置:export ANDROID_ROOT /system   
  28.     // 因此android_system_dirs.dirs[0]=/system/   
  29.     if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) {  
  30.         free_globals();  
  31.         return -1;  
  32.     }  
  33.     //android_system_dirs.dirs[0]=/system/app/   
  34.     char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR);  
  35.     android_system_dirs.dirs[0].path = system_app_path;  
  36.     android_system_dirs.dirs[0].len = strlen(system_app_path);  
  37.     android_app_preload_dir.path = "/system/preloadapp/";  
  38.     android_app_preload_dir.len = strlen(android_app_preload_dir.path);  
  39.     android_system_dirs.dirs[1].path = "/vendor/app/";  
  40.     android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);  
  41.     return 0;  
  42. }  
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)初始化目录

  1. int initialize_directories() {  
  2.     // user_data_dir=/data/user   
  3.     char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);  
  4.     // legacy_data_dir=/data/data   
  5.     char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);  
  6.     // primary_data_dir=/data/user/0   
  7.     char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX,  
  8.             "0");  
  9.     int ret = -1;  
  10.     if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) {  
  11.         ret = 0;  
  12.         //如果/data/user目录不存在,则创建该目录   
  13.         if (access(user_data_dir, R_OK) < 0) {  
  14.             if (mkdir(user_data_dir, 0711) < 0) {  
  15.                 return -1;  
  16.             }  
  17.             //修改目录权限及所有属性   
  18.             if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {  
  19.                 return -1;  
  20.             }  
  21.             if (chmod(user_data_dir, 0711) < 0) {  
  22.                 return -1;  
  23.             }  
  24.         }  
  25.         // Make the /data/user/0 symlink to /data/data if necessary   
  26.         if (access(primary_data_dir, R_OK) < 0) {  
  27.               ret = symlink(legacy_data_dir, primary_data_dir);  
  28.         }  
  29.         free(user_data_dir);  
  30.         free(legacy_data_dir);  
  31.         free(primary_data_dir);  
  32.     }  
  33.     return ret;  
  34. }  
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)执行客户发送过来的请求命令

  1. static int execute(int s, char cmd[BUFFER_MAX])  
  2. {  
  3.     //#define BUFFER_MAX    1024  /* input buffer for commands */   
  4.     char reply[REPLY_MAX]; //#define REPLY_MAX     256   /* largest reply allowed */   
  5.     char *arg[TOKEN_MAX+1];//#define TOKEN_MAX     8     /* 命令参数最多8个 */   
  6.     unsigned i;  
  7.     unsigned n = 0;  
  8.     unsigned short count;  
  9.     int ret = -1;  
  10.     reply[0] = 0;  
  11.     //arg[0]为命令名称,命令格式:[name arg1 arg2 arg3 arg4]   
  12.     arg[0] = cmd;  
  13.     //计算命令参数个数   
  14.     while (*cmd) {  
  15.         if (isspace(*cmd)) {  
  16.             *cmd++ = 0;  
  17.             n++;  
  18.             arg[n] = cmd;  
  19.             if (n == TOKEN_MAX) {  
  20.                 ALOGE("too many arguments\n");  
  21.                 goto done;  
  22.             }  
  23.         }  
  24.         cmd++;  
  25.     }  
  26.     //根据命令名称匹配命令数组cmds中的命令   
  27.     for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {  
  28.         //命令名称比较   
  29.         if (!strcmp(cmds[i].name,arg[0])) {  
  30.             //判断该命令的参数个数是否满足要求   
  31.             if (n != cmds[i].numargs) {  
  32.                 ALOGE("%s requires %d arguments (%d given)\n",cmds[i].name, cmds[i].numargs, n);  
  33.             } else {  
  34.                 //调用命令执行函数,执行命令   
  35.                 ret = cmds[i].func(arg + 1, reply);  
  36.             }  
  37.             goto done;  
  38.         }  
  39.     }  
  40.     ALOGE("unsupported command '%s'\n", arg[0]);  
  41. done:  
  42.     //格式化返回结果   
  43.     if (reply[0]) {  
  44.         n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);  
  45.     } else {  
  46.         n = snprintf(cmd, BUFFER_MAX, "%d", ret);  
  47.     }  
  48.     if (n > BUFFER_MAX) n = BUFFER_MAX;  
  49.     //返回结果数据长度   
  50.     count = n;  
  51.     //写结果数据长度   
  52.     if (writex(s, &count, sizeof(count))) return -1;  
  53.     //写结果数据   
  54.     if (writex(s, cmd, count)) return -1;  
  55.     return 0;  
  56. }  
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服务可执行的命令

  1. struct cmdinfo cmds[] = {  
  2.  // { 命令名称,         参数个数,命令执行函数}   
  3.     { "ping",                 0, do_ping },  
  4.     { "install",              3, do_install },  
  5.     { "dexopt",               3, do_dexopt },  
  6.     { "movedex",              2, do_move_dex },  
  7.     { "rmdex",                1, do_rm_dex },  
  8.     { "remove",               2, do_remove },  
  9.     { "rename",               2, do_rename },  
  10.     { "fixuid",               3, do_fixuid },  
  11.     { "freecache",            1, do_free_cache },  
  12.     { "rmcache",              1, do_rm_cache },  
  13.     { "protect",              2, do_protect },  
  14.     { "getsize",              4, do_get_size },  
  15.     { "rmuserdata",           2, do_rm_user_data },  
  16.     { "movefiles",            0, do_movefiles },  
  17.     { "linklib",              2, do_linklib },  
  18.     { "unlinklib",            1, do_unlinklib },  
  19.     { "mkuserdata",           3, do_mk_user_data },  
  20.     { "rmuser",               1, do_rm_user },  
  21.     { "cloneuserdata",        3, do_clone_user_data },  
  22. };  
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)应用程序安装

  1. static int do_install(char **arg, char reply[REPLY_MAX])  
  2. {  
  3.     return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */  
  4. }  
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函数来安装

  1. int install(const char *pkgname, uid_t uid, gid_t gid)  
  2. {  
  3.     char pkgdir[PKG_PATH_MAX];//程序目录路径最长为256   
  4.     char libdir[PKG_PATH_MAX];//程序lib路径最长为256   
  5.     //权限判断   
  6.     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {  
  7.         ALOGE("invalid uid/gid: %d %d\n", uid, gid);  
  8.         return -1;  
  9.     }  
  10.     //组合应用程序安装目录pkgdir=/data/data/应用程序包名   
  11.     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {  
  12.         ALOGE("cannot create package path\n");  
  13.         return -1;  
  14.     }  
  15.     //组合应用程序库目录libdir=/data/data/应用程序包名/lib   
  16.     if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {  
  17.         ALOGE("cannot create package lib path\n");  
  18.         return -1;  
  19.     }  
  20.     //创建目录pkgdir=/data/data/应用程序包名   
  21.     if (mkdir(pkgdir, 0751) < 0) {  
  22.         ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));  
  23.         return -errno;  
  24.     }  
  25.     //修改/data/data/应用程序包名目录的权限   
  26.     if (chmod(pkgdir, 0751) < 0) {  
  27.         ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));  
  28.         unlink(pkgdir);  
  29.         return -errno;  
  30.     }  
  31.     //创建目录libdir=/data/data/应用程序包名/lib   
  32.     if (mkdir(libdir, 0755) < 0) {  
  33.         ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));  
  34.         unlink(pkgdir);  
  35.         return -errno;  
  36.     }  
  37.     //修改/data/data/应用程序包名/lib目录的权限   
  38.     if (chmod(libdir, 0755) < 0) {  
  39.         ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));  
  40.         unlink(libdir);  
  41.         unlink(pkgdir);  
  42.         return -errno;  
  43.     }  
  44.     //修改/data/data/应用程序包名目录的所有权限   
  45.     if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {  
  46.         ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));  
  47.         unlink(libdir);  
  48.         unlink(pkgdir);  
  49.         return -errno;  
  50.     }  
  51.     //修改/data/data/应用程序包名/lib目录的所有权限   
  52.     if (chown(pkgdir, uid, gid) < 0) {  
  53.         ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));  
  54.         unlink(libdir);  
  55.         unlink(pkgdir);  
  56.         return -errno;  
  57.     }  
  58.     return 0;  
  59. }  
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;
}
组合应用程序安装目录路径:

  1. int create_pkg_path(char path[PKG_PATH_MAX],  
  2.                     const char *pkgname,  
  3.                     const char *postfix,  
  4.                     uid_t persona)  
  5. {  
  6.     size_t uid_len;  
  7.     char* persona_prefix;  
  8.     //postfix=""   
  9.     //persona=0   
  10.     if (persona == 0) {  
  11.         persona_prefix = PRIMARY_USER_PREFIX;// "data/"   
  12.         uid_len = 0;  
  13.     } else {  
  14.         persona_prefix = SECONDARY_USER_PREFIX;// "user/"   
  15.         uid_len = snprintf(NULL, 0"%d", persona);  
  16.     }  
  17.     // /data/data/   
  18.     const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;  
  19.     char prefix[prefix_len + 1];  
  20.     char *dst = prefix;  
  21.     size_t dst_size = sizeof(prefix);  
  22.     //dst=/data/data/   
  23.     if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0  
  24.             || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {  
  25.         ALOGE("Error building prefix for APK path");  
  26.         return -1;  
  27.     }  
  28.     if (persona != 0) {  
  29.         int ret = snprintf(dst, dst_size, "%d/", persona);  
  30.         if (ret < 0 || (size_t) ret != uid_len + 1) {  
  31.             ALOGW("Error appending UID to APK path");  
  32.             return -1;  
  33.         }  
  34.     }  
  35.     dir_rec_t dir; //设置安装目录,由于uid为0,因此安装目录为/data/data/   
  36.     dir.path = prefix;  
  37.     dir.len = prefix_len;  
  38.     return create_pkg_path_in_dir(path, &dir, pkgname, postfix);  
  39. }  
  40.   
  41. int create_pkg_path_in_dir(char path[PKG_PATH_MAX],  
  42.                                 const dir_rec_t* dir,  
  43.                                 const char* pkgname,  
  44.                                 const char* postfix)  
  45. {  
  46.      const size_t postfix_len = strlen(postfix); //postfix_len= 0   
  47.      const size_t pkgname_len = strlen(pkgname);  
  48.      //apk包名最长不允许超过128个字符   
  49.      if (pkgname_len > PKG_NAME_MAX) {  
  50.          return -1;  
  51.      }  
  52.      //检查包名命名是否规范   
  53.      if (is_valid_package_name(pkgname) < 0) {  
  54.          return -1;  
  55.      }  
  56.      //检查包名和目录路径长度是否超过256个字符   
  57.      if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) {  
  58.          return -1;  
  59.      }  
  60.      char *dst = path;  
  61.      size_t dst_size = PKG_PATH_MAX;  
  62.      //最终的安装目录为/data/data/应用程序包名/postfix   
  63.      if (append_and_increment(&dst, dir->path, &dst_size) < 0  
  64.              || append_and_increment(&dst, pkgname, &dst_size) < 0  
  65.              || append_and_increment(&dst, postfix, &dst_size) < 0) {  
  66.          ALOGE("Error building APK path");  
  67.          return -1;  
  68.      }  
  69.      return 0;  
  70. }  
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)应用程序卸载

应用程序卸载过程其实就是删除应用程序安装文件
  1. static int do_remove(char **arg, char reply[REPLY_MAX])  
  2. {  
  3.     return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */  
  4. }  
  5.   
  6. int uninstall(const char *pkgname, uid_t persona)  
  7. {  
  8.     char pkgdir[PKG_PATH_MAX];  
  9.     //根据包名得到应用程序安装目录路径   
  10.     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))  
  11.         return -1;  
  12.     /*删除安装目录及目录下的文件 */  
  13.     return delete_dir_contents(pkgdir, 1, NULL);  
  14. }  
  15.   
  16. int delete_dir_contents(const char *pathname,  
  17.                         int also_delete_dir,  
  18.                         const char *ignore)  
  19. {  
  20.     int res = 0;  
  21.     DIR *d;  
  22.     //打开应用程序安装目录   
  23.     d = opendir(pathname);  
  24.     if (d == NULL) {  
  25.         ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));  
  26.         return -errno;  
  27.     }  
  28.     //删除安装目录下的文件   
  29.     res = _delete_dir_contents(d, ignore);  
  30.     closedir(d);  
  31.     //删除安装目录   
  32.     if (also_delete_dir) {  
  33.         if (rmdir(pathname)) {  
  34.             ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));  
  35.             res = -1;  
  36.         }  
  37.     }  
  38.     return res;  
  39. }  
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)应用程序安装包优化过程

  1. static int do_dexopt(char **arg, char reply[REPLY_MAX])  
  2. {  
  3.     return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])); /* apk_path, uid, is_public */  
  4. }  
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文件优化
  1. int dexopt(const char *apk_path, uid_t uid, int is_public)  
  2. {  
  3.     //例如:apk_path=system/app/Music.apk   
  4.     struct utimbuf ut;  
  5.     struct stat apk_stat, dex_stat;  
  6.     char dex_path[PKG_PATH_MAX];//PKG_PATH_MAX=256   
  7.     char dexopt_flags[PROPERTY_VALUE_MAX];//PKG_PATH_MAX=92   
  8.     char *end;  
  9.     int res, zip_fd=-1, odex_fd=-1;  
  10.     if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {  
  11.         return -1;  
  12.     }  
  13.     //读取安装包优化标志位   
  14.     property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");  
  15.     //dex_path=system/app/Music.apk   
  16.     strcpy(dex_path, apk_path);  
  17.     //判断dex_path的后缀   
  18.     end = strrchr(dex_path, '.');  
  19.     if (end != NULL) {  
  20.         strcpy(end, ".odex");  
  21.         if (stat(dex_path, &dex_stat) == 0) {  
  22.             return 0;  
  23.         }  
  24.     }  
  25.     //dex_path=/data/dalvik-cache/[system@app@Music.apk]@classes.dex   
  26.     if (create_cache_path(dex_path, apk_path)) {  
  27.         return -1;  
  28.     }  
  29.     memset(&apk_stat, 0, sizeof(apk_stat));  
  30.     //获取apk文件信息   
  31.     stat(apk_path, &apk_stat);  
  32.     //以只读方式打开apk文件   
  33.     zip_fd = open(apk_path, O_RDONLY, 0);  
  34.     if (zip_fd < 0) {  
  35.         ALOGE("dexopt cannot open '%s' for input\n", apk_path);  
  36.         return -1;  
  37.     }  
  38.     //删除dex文件   
  39.     unlink(dex_path);  
  40.     //打开dex文件,如果文件不存在,则自动创建该文件   
  41.     odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);  
  42.     if (odex_fd < 0) {  
  43.         ALOGE("dexopt cannot open '%s' for output\n", dex_path);  
  44.         goto fail;  
  45.     }  
  46.     //修改dex文件的所有者属性   
  47.     if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {  
  48.         ALOGE("dexopt cannot chown '%s'\n", dex_path);  
  49.         goto fail;  
  50.     }  
  51.     //修改dex文件的权限   
  52.     if (fchmod(odex_fd,  
  53.                S_IRUSR|S_IWUSR|S_IRGRP |  
  54.                (is_public ? S_IROTH : 0)) < 0) {  
  55.         ALOGE("dexopt cannot chmod '%s'\n", dex_path);  
  56.         goto fail;  
  57.     }  
  58.     ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);  
  59.     pid_t pid;  
  60.     //创建一个线程来执行apk优化   
  61.     pid = fork();  
  62.     if (pid == 0) {  
  63.         if (setgid(uid) != 0) {  
  64.             ALOGE("setgid(%d) failed during dexopt\n", uid);  
  65.             exit(64);  
  66.         }  
  67.         if (setuid(uid) != 0) {  
  68.             ALOGE("setuid(%d) during dexopt\n", uid);  
  69.             exit(65);  
  70.         }  
  71.         if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {  
  72.             ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));  
  73.             exit(66);  
  74.         }  
  75.         //优化apk包文件,zip_fd为apk文件句柄,odex_fd为dex文件句柄,dexopt_flags为优化标志位   
  76.         run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);  
  77.         exit(67);   /* only get here on exec failure */  
  78.     } else {  
  79.         res = wait_dexopt(pid, apk_path);  
  80.         if (res != 0) {  
  81.             ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);  
  82.             goto fail;  
  83.         }  
  84.     }  
  85.     ut.actime = apk_stat.st_atime;  
  86.     ut.modtime = apk_stat.st_mtime;  
  87.     utime(dex_path, &ut);  
  88.     close(odex_fd);  
  89.     close(zip_fd);  
  90.     return 0;  
  91.   
  92. fail:  
  93.     if (odex_fd >= 0) {  
  94.         close(odex_fd);  
  95.         unlink(dex_path);  
  96.     }  
  97.     if (zip_fd >= 0) {  
  98.         close(zip_fd);  
  99.     }  
  100.     return -1;  
  101. }  
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;
}
创建了一个新的线程来执行安装包优化任务
  1. static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,  
  2.     const char* dexopt_flags)  
  3. {  
  4.     //input_file_name为apk的路径   
  5.     static const char* DEX_OPT_BIN = "/system/bin/dexopt";  
  6.     static const int MAX_INT_LEN = 12;        
  7.     char zip_num[MAX_INT_LEN];  
  8.     char odex_num[MAX_INT_LEN];  
  9.     sprintf(zip_num, "%d", zip_fd);//apk文件句柄   
  10.     sprintf(odex_num, "%d", odex_fd);//dex文件句柄   
  11.     //调用/system/bin/dexopt工具来优化apk文件   
  12.     execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,  
  13.         dexopt_flags, (char*) NULL);  
  14.     ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));  
  15. }  
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/目录下:


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值