子曰:“苟正其身矣,于从政乎何有?不能正其身,如正人何?” 《论语》:子路篇
百篇博客系列篇.本篇为:
v72.xx 鸿蒙内核源码分析(Shell解析篇) | 应用窥视内核的窗口
进程管理相关篇为:
v02.06 鸿蒙内核源码分析(进程管理) | 谁在管理内核资源
v24.03 鸿蒙内核源码分析(进程概念) | 如何更好的理解进程
v45.05 鸿蒙内核源码分析(Fork) | 一次调用 两次返回
v46.05 鸿蒙内核源码分析(特殊进程) | 老鼠生儿会打洞
v47.02 鸿蒙内核源码分析(进程回收) | 临终托孤的短命娃
v48.05 鸿蒙内核源码分析(信号生产) | 年过半百 活力十足
v49.03 鸿蒙内核源码分析(信号消费) | 谁让CPU连续四次换栈运行
v71.03 鸿蒙内核源码分析(Shell编辑) | 两个任务 三个阶段
v72.01 鸿蒙内核源码分析(Shell解析) | 应用窥伺内核的窗口
系列篇从内核视角用一句话概括shell的底层实现为:两个任务,三个阶段。其本质是独立进程,因而划到进程管理模块。每次创建shell进程都会再创建两个任务。
客户端任务(ShellEntry): 负责接受来自终端(控制台)敲入的一个个字符,字符按VT规范组装成一句句的命令。
服务端任务(ShellTask): 对命令进行解析并执行,将结果输出到控制台。
而按命令生命周期可分三个阶段.
编辑: 鸿蒙在这个部分实现了一个简单的编辑器功能,处理控制台输入的每个字符,主要包括了对控制字符 例如 <ESC>,\t,\b,\n,\r,四个方向键0x41 ~ 0x44 的处理。
解析: 对编辑后的字符串进行解析,解析出命令项和参数项,找到对应的命令项执行函数。
执行: 命令可通过静态和动态两种方式注册到内核,解析出具体命令后在注册表中找到对应函数回调。将结果输出到控制台。
编辑部分由客户端任务完成,后两个部分由服务端任务完成,命令全局注册由内核完成。
本篇主要说 服务端任务 和 解析/执行过程.
客户端任务 和 编辑过程 已在(Shell编辑篇)中说明,请自行翻看.
总体过程第一步: 将支持的shell命令注册进全局链表,支持静态和动态两种方式,内容包括命令项,参数信息和回调函数.
第二步: 由独立任务解析出用户输入的命令行,拆分出命令项和参数内容
第三步: 通过命令项在全局链表中遍历找到已注册的回调函数,并执行.
结构体鸿蒙对命令的注册用了三个结构体,个人感觉前两个可以合成一个,降低代码阅读难度.
STATIC CmdModInfo g_cmdInfo;//shell 命令模块信息,上面挂了所有的命令项(ls,cd ,cp ==) typedef struct {//命令项 CmdType cmdType; //命令类型 //CMD_TYPE_EX:不支持标准命令参数输入,会把用户填写的命令关键字屏蔽掉,例如:输入ls /ramfs,传入给注册函数的参数只有/ramfs,而ls命令关键字并不会被传入。 //CMD_TYPE_STD:支持的标准命令参数输入,所有输入的字符都会通过命令解析后被传入。 const CHAR *cmdKey; //命令关键字,例如:ls 函数在Shell中访问的名称。 UINT32 paraNum; //调用的执行函数的入参最大个数,暂不支持。 CmdCallBackFunc cmdHook;//命令执行函数地址,即命令实际执行函数。 } CmdItem; typedef struct { //命令节点 LOS_DL_LIST list; //双向链表 CmdItem *cmd; //命令项 } CmdItemNode; /* global info for shell module */ typedef struct {//shell 模块的全局信息 CmdItemNode cmdList; //命令项节点 UINT32 listNum;//节点数量 UINT32 initMagicFlag;//初始魔法标签 0xABABABAB LosMux muxLock; //操作链表互斥锁 CmdVerifyTransID transIdHook;//暂不知何意 } CmdModInfo;解读
CmdItem为注册的内容载体结构体,cmdHook为回调函数,是命令的真正执行体.
通过双向链表CmdItemNode.list将所有命令穿起来
CmdModInfo记录命令数量和操作的互斥锁,shell的魔法数字为 0xABABABAB
第一步 | Shell 注册
静态宏方式注册,链接时处理
静态注册命令方式一般用在系统常用命令注册,鸿蒙已支持以下命令.
例如注册 ls命令
SHELLCMD_ENTRY(ls_shellcmd, CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs)