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只是应用程序安装/卸载过程中的一个辅助子系统。千万不要被其命名迷惑,以为其承担了安装/卸载过程的所有任务。