企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
4.6.1 installd介绍 在前面对PKMS构造函数分析时介绍过一个Installer类型的对象mInstaller,它通过socket和后台服务installd交互,以完成一些重要操作。这里先回顾一下PKMS中mInstaller的调用方法: ~~~ mInstaller = new Installer();//创建一个Installer对象 //对某个APK文件进行dexopt优化 mInstaller.dexopt(paths[i], Process.SYSTEM_UID,true); //扫描完系统Package后,调用moveFiles函数 mInstaller.moveFiles(); //当存储空间不足时,调用该函数清理存储空间 mInstaller.freeCache(freeStorageSize); ~~~ Installer的种种行为都和其背后的installd有关。下面来分析installd。 1. installd概貌 installd是一个native进程,代码非常简单,其功能就是启动一个socket,然后处理来自Installer的命令,其代码如下: installd.c ~~~ int main(const int argc, const char *argv[]) { charbuf[BUFFER_MAX]; structsockaddr addr; socklen_t alen; intlsocket, s, count; // if (初始化全局变量,如果失败则退出) { initialize_globals(); initialize_directories(); ...... } ...... lsocket= android_get_control_socket(SOCKET_PATH); listen(lsocket, 5); fcntl(lsocket, F_SETFD, FD_CLOEXEC); for (;;){ alen= sizeof(addr); s =accept(lsocket, &addr, &alen); fcntl(s, F_SETFD, FD_CLOEXEC); for(;;) { unsigned short count; readx(s, &count, sizeof(count)); //执行installer发出的命令,具体解释见下文 execute(s, buf); } close(s); } return0; } ~~~ installd支持的命令及参数信息都保存在数据结构cmds中,代码如下: **installd.c** ~~~ 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 }, {"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 }, }; ~~~ 下面来分析相关的几个命令。 2. dexOpt命令分析 PKMS在需要对一个APK或jar包做dex优化时,会发送dexopt命令给installd,相应的处理函数为do_dexopt,代码如下: **installd.c** ~~~ static int do_dexopt(char **arg, charreply[REPLY_MAX]) { returndexopt(arg[0], atoi(arg[1]), atoi(arg[2])); } ~~~ **commands.c** ~~~ int dexopt(const char *apk_path, uid_t uid, intis_public) { structutimbuf ut; structstat apk_stat, dex_stat; chardex_path[PKG_PATH_MAX]; chardexopt_flags[PROPERTY_VALUE_MAX]; char*end; int res,zip_fd=-1, odex_fd=-1; ...... //取出系统级的dexopt_flags参数 property_get("dalvik.vm.dexopt-flags", dexopt_flags,""); strcpy(dex_path, apk_path); end =strrchr(dex_path, '.'); if (end!= NULL) { strcpy(end, ".odex"); if(stat(dex_path, &dex_stat) == 0) { return 0; } } //得到一个字符串,用于描述dex文件名,位于/data/dalvik-cache/下 if(create_cache_path(dex_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); stat(apk_path, &apk_stat); zip_fd =open(apk_path, O_RDONLY, 0); ...... unlink(dex_path); odex_fd= open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); ...... pid_tpid; pid =fork(); if (pid== 0) { ......//uid设置 //创建一个新进程,然后对exec dexopt进程进行dex优化 run_dexopt(zip_fd,odex_fd, apk_path, dexopt_flags); exit(67); } else { //installd将等待dexopt完成优化工作 res= wait_dexopt(pid, apk_path); ...... } ......//资源清理 return-1; } ~~~ 让人大跌眼镜的是,dex优化工作竟然由installd委派给dexopt进程来实现。dex优化后会生成一个dex文件,一般位于/data/dalvik-cache/目录中。这里给出一个示例,如图4-12所示。 :-: ![](http://img.blog.csdn.net/20150803111157859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图4-12 dex文件示例 >[info] **提示** :dexopt进程由android源码/dalvik/dexopt/OptMain.cpp定义。感兴趣的读者可深入研究dex优化的工作原理。 3. movefiles命令分析 PKMS扫描完系统Package后,将发送该命令给installd,相应处理函数的代码如下: **installd.c** ~~~ static int do_movefiles(char **arg, charreply[REPLY_MAX]) { returnmovefiles(); } [-->commands.c] int movefiles() { DIR *d; int dfd,subfd; structdirent *de; structstat s; charbuf[PKG_PATH_MAX+1]; intbufp, bufe, bufi, readlen; charsrcpkg[PKG_NAME_MAX]; chardstpkg[PKG_NAME_MAX]; charsrcpath[PKG_PATH_MAX]; chardstpath[PKG_PATH_MAX]; intdstuid=-1, dstgid=-1; inthasspace; //打开/system/etc/updatecmds/目录 d =opendir(UPDATE_COMMANDS_DIR_PREFIX); if (d ==NULL) { gotodone; } dfd =dirfd(d); while((de = readdir(d))) { ......//解析该目录下的文件,然后执行对应操作 } closedir(d); done: return0; } ~~~ 先来看/system/etc/updatecmds/目录下到底是什么文件,这里给出一个示例,如图4-13所示。 :-: ![](http://img.blog.csdn.net/20150803111217969?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图4-13 movefiles示例 以图4-13中最后两行为例,movefiles将把com.google.android.gsf下的databases目录转移到com.andorid.providers.im下。从文件中的注释可知,movefiles的功能和系统升级有关。 4. doFreeCache 第3章介绍了DeviceStorageMonitorService,当系统空间不够时,DSMS会调用PKMS的freeStorageAndNotify函数进行空间清理。该工作真正的实施者是installd,相应的处理命令为do_free_cache,其代码如下: **installd.c** ~~~ static int do_free_cache(char **arg, charreply[REPLY_MAX]) { returnfree_cache((int64_t)atoll(arg[0])); } ~~~ **commands.c** ~~~ int free_cache(int64_t free_size) { constchar *name; int dfd,subfd; DIR *d; structdirent *de; int64_tavail; avail =disk_free();//获取当前系统的剩余空间大小 if(avail < 0) return -1; if(avail >= free_size) return 0; d =opendir(android_data_dir.path);//打开/data/目录 dfd =dirfd(d); while((de = readdir(d))) { if (de->d_type != DT_DIR) continue; name= de->d_name; ......//略过.和..文件 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); //删除/data及各级子目录中的cache文件夹 delete_dir_contents_fd(subfd, "cache"); close(subfd); ......//如果剩余空间恢复正常,则返回 } closedir(d); return-1;//清理空间后,仍然不满足要求 } ~~~ installd的介绍就到此为止,这部分内容比较简单,读者完全可自行深入研究。