8.3.2 Installd中的命令
Installd是定义在init.rc中的Daemon Service,其随系统开机启动,其实现代码位于frameworks/base/cmds/installd/目录下。
Installd启动后,在其main函数中,通过accept方法接收客户端的Socket连接请求。接收到连接请求后,首先通过readx读取客户端请求数据;然后通过execute方法解析请求中包含的cmd命令,并对符合条件的命令进行匹配和执行。命令匹配的过程是,将接收到的cmd命令与内部的cmds数组中第一列元素进行比较;比较成功后,验证参数个数是否匹配;所有匹配都成功,会执行cmds数组第三列中函数指针指向的函数。代码如下:
static int execute(int s, char cmd[BUFFER_MAX])
{
……
for(i=0;i<sizeof(cmds)/sizeof(cmds[0]);i++){
if(!strcmp(cmds[i].name, arg[0])){
if(n!=cmds[i].numargs){
LOGE("%s requires%d arguments(%d given)\n",
cmds[i].name, cmds[i].numargs, n);
}else{
ret=cmds[i].func(arg+1,reply);
}
goto done;
}
}
……
}
可见,Installd中命令执行的枢纽是cmds数组,该数组定义于frameworks/base/cmds/installd/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},
{"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},
};
cmds[]中存储的是cmdinfo类型的元素,该元素是一个结构体,定义如下:
struct cmdinfo{
const char*name;
unsigned numargs;
int(func)(char*arg, char reply[REPLY_MAX]);
};
cmdinfo中第一个成员name表示Installer中定义的命令名,第二个成员numargs是该命令的参数个数,第三个成员func是一个函数指针,指向Installd中对应于Installer的cmd。每一个cmdinfo元素其实是一个从Installer到Installd的映射。
需要注意的是,cmdinfo中第一个元素与Installer中的命令名一致,与方法名并不一致。对于Installer.install方法,实际执行的是installd.do_install方法,该方法最终调用了commands.c中的install方法完成APK数据目录的创建。代码如下:
int install(const char*pkgname, uid_t uid, gid_t gid)
{
char pkgdir[PKG_PATH_MAX];
char libdir[PKG_PATH_MAX];
//过滤不合法uid和gid
if((uid<AID_SYSTEM)||(gid<AID_SYSTEM)){
return-1;
}
//创建/data/data/xxx package目录
if(create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX,0)){
return-1;
}
//创建/data/data/xxx package/lib目录
if(create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX,0)){
return-1;
}
if(mkdir(pkgdir,0751)<0){
return-errno;
}
if(chmod(pkgdir,0751)<0){
unlink(pkgdir);
return-errno;
}
if(chown(pkgdir, uid, gid)<0){
unlink(pkgdir);
return-errno;
}
if(mkdir(libdir,0755)<0){
unlink(pkgdir);
return-errno;
}
if(chmod(libdir,0755)<0){
unlink(libdir);
unlink(pkgdir);
return-errno;
}
if(chown(libdir, AID_SYSTEM, AID_SYSTEM)<0){
unlink(libdir);
unlink(pkgdir);
return-errno;
}
return 0;
}
commands.c中的install方法只是创建了应用程序的数据目录,并对该目录做权限处理。
注意 通过上述对Installer和Installd的分析可以看出,Installer和Installd只是应用程序安装/卸载过程中的一个辅助子系统。千万不要被其命名迷惑,以为其承担了安装/卸载过程的所有任务。