Android应用管理三 -- APK包的安装、卸载和优化(PackageManagerService)

installd是一个Android系统的native守护进程,负责apk的安装、卸载及优化过程。由于PMS进程权限限制,installd作为拥有相应权限的进程执行实际操作。本文详细解析installd的初始化、权限变更以及install命令的处理流程。
摘要由CSDN通过智能技术生成

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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值