Android安装服务installd源码分析

在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/目录下:

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
第1章 搭建Android源码工作环境 1.1 Android系统架构 1.2 搭建开发环境 1.2.1 下载源码 1.2.2 编译源码 1.2.3 利用Eclipse调试system_process 1.3 本章小结 第2章 深入理解Java Binder和MessageQueue 2.1 概述 2.2 Java层中的Binder架构分析 2.2.1 Binder架构总览 2.2.2 初始化Java层Binder框架 2.2.3 addService实例分析 2.2.4 Java层Binder架构总结 2.3 心系两界的MessageQueue 2.3.1 MessageQueue的创建 2.3.2 提取消息 2.3.3 nativePollOnce函数分析 2.3.4 MessageQueue总结 2.4 本章小结 第3章 深入理解SystemServer 3.1 概述 3.2 SystemServer分析 3.2.1 main函数分析 3.2.2 Service群英会 3.3 EntropyService分析 3.4 DropBoxManagerService分析 3.4.1 DBMS构造函数分析 3.4.2 dropbox日志文件的添加 3.4.3 DBMS和settings数据库 3.5 DiskStatsService和DeviceStorageMonitorService分析 3.5.1 DiskStatsService分析 3.5.2 DeviceStorageManagerService分析 3.6 SamplingProfilerService分析 3.6.1 SamplingProfilerService构造函数分析 3.6.2 SamplingProfilerIntegration分析 3.7 ClipboardService分析 3.7.1 复制数据到剪贴板 3.7.2 从剪切板粘贴数据 3.7.3 CBS中的权限管理 3.8 本章小结 第4章 深入理解PackageManagerService 4.1 概述 4.2 初识PackageManagerService 4.3 PKMS的main函数分析 4.3.1 构造函数分析之前期准备工作 4.3.2 构造函数分析之扫描Package 4.3.3 构造函数分析之扫尾工作 4.3.4 PKMS构造函数总结 4.4 APK Installation分析 4.4.1 adb install分析 4.4.2 pm分析 4.4.3 installPackageWithVerification函数分析 4.4.4 APK 安装流程总结 4.4.5 Verification介绍 4.5 queryIntentActivities分析 4.5.1 Intent及IntentFilter介绍 4.5.2 Activity信息的管理 4.5.3 Intent 匹配查询分析 4.5.4 queryIntentActivities总结 4.6 installd及UserManager介绍 4.6.1 installd介绍 4.6.2 UserManager介绍 4.7 本章学习指导 4.8 本章小结 第5章 深入理解PowerManagerService 5.1 概述 5.2 初识PowerManagerService 5.2.1 PMS构造函数分析 5.2.2 init分析 5.2.3 systemReady分析 5.2.4 BootComplete处理 5.2.5 初识PowerManagerService总结 5.3 PMS WakeLock分析 5.3.1 WakeLock客户端分析 5.3.2 PMS acquireWakeLock分析 5.3.3 Power类及LightService类介绍 5.3.4 WakeLock总结 5.4 userActivity及Power按键处理分析 5.4.1 userActivity分析 5.4.2 Power按键处理分析 5.5 BatteryService及BatteryStatsService分析 5.5.1 BatteryService分析 5.5.2 BatteryStatsService分析 5.5.3 BatteryService及BatteryStatsService总结 5.6 本章学习指导 5.7 本章小结 第6章 深入理解ActivityManagerService 6.1 概述 6.2 初识ActivityManagerService 6.2.1 ActivityManagerService的main函数分析 6.2.2 AMS的 setSystemProcess分析 6.2.3 AMS的 installSystemProviders函数分析 6.2.4 AMS的 systemReady分析 6.2.5 初识ActivityManagerService总结 6.3 startActivity分析 6.3.1 从am说起 6.3.2 AMS的startActivityAndWait函数分析 6.3.3 startActivityLocked分析 6.4 Broadcast和BroadcastReceiver分析 6.4.1 registerReceiver流程分析 6.4.2 sendBroadcast流程分析 6.4.3 BROADCAST_INTENT_MSG消息处理函数 6.4.4 应用进程处理广播分析 6.4.5 广播处理总结 6.5 startService之按图索骥 6.5.1 Service知识介绍 6.5.2 startService流程图 6.6 AMS中的进程管理 6.6.1 Linux进程管理介绍 6.6.2 关于Android中的进程管理的介绍 6.6.3 AMS进程管理函数分析 6.6.4 AMS进程管理总结 6.7 App的 Crash处理 6.7.1 应用进程的Crash处理 6.7.2 AMS的handleApplicationCrash分析 6.7.3 AppDeathRecipient binderDied分析 6.7.4 App的Crash处理总结 6.8 本章学习指导 6.9 本章小结 第7章 深入理解ContentProvider 7.1 概述 7.2 MediaProvider的启动及创建 7.2.1 Context的getContentResolver函数分析 7.2.2 MediaStore.Image.Media的query函数分析 7.2.3 MediaProvider的启动及创建总结 7.3 SQLite创建数据库分析 7.3.1 SQLite及SQLiteDatabase家族 7.3.2 MediaProvider创建数据库分析 7.3.3 SQLiteDatabase创建数据库的分析总结 7.4 Cursor 的query函数的实现分析 7.4.1 提取query关键点 7.4.2 MediaProvider 的query分析 7.4.3 query关键点分析 7.4.4 Cursor query实现分析总结 7.5 Cursor close函数实现分析 7.5.1 客户端close的分析 7.5.2 服务端close的分析 7.5.3 finalize函数分析 7.5.4 Cursor close函数总结 7.6 ContentResolver openAssetFileDescriptor函数分析 7.6.1 openAssetFileDescriptor之客户端调用分析 7.6.2 ContentProvider的 openTypedAssetFile函数分析 7.6.3 跨进程传递文件描述符的探讨 7.6.4 openAssetFileDescriptor函数分析总结 7.7 本章学习指导 7.8 本章小结 第8章 深入理解ContentService和AccountManagerService 8.1 概述 8.2 数据更新通知机制分析 8.2.1 初识ContentService 8.2.2 ContentResovler 的registerContentObserver分析 8.2.3 ContentResolver的 notifyChange分析 8.2.4 数据更新通知机制总结和深入探讨 8.3 AccountManagerService分析 8.3.1 初识AccountManagerService 8.3.2 AccountManager addAccount分析 8.3.3 AccountManagerService的分析总结 8.4 数据同步管理SyncManager分析 8.4.1 初识SyncManager 8.4.2 ContentResolver 的requestSync分析 8.4.3 数据同步管理SyncManager分析总结 8.5 本章学习指导 8.6 本章小结

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值