企業(yè)公司做網(wǎng)站網(wǎng)絡(luò)推廣代理怎么做
系列篇從內(nèi)核視角用一句話概括shell
的底層實(shí)現(xiàn)為:兩個任務(wù),三個階段。其本質(zhì)是獨(dú)立進(jìn)程,因而劃到進(jìn)程管理模塊。每次創(chuàng)建shell
進(jìn)程都會再創(chuàng)建兩個任務(wù)。
- 客戶端任務(wù)(ShellEntry):?負(fù)責(zé)接受來自終端(控制臺)敲入的一個個字符,字符按
VT
規(guī)范組裝成一句句的命令。 - 服務(wù)端任務(wù)(ShellTask):?對命令進(jìn)行解析并執(zhí)行,將結(jié)果輸出到控制臺。
而按命令生命周期可分三個階段. - 編輯:?鴻蒙在這個部分實(shí)現(xiàn)了一個簡單的編輯器功能,處理控制臺輸入的每個字符,主要包括了對控制字符 例如?
<ESC>
,\t
,\b
,\n
,\r
,四個方向鍵0x41
?~?0x44
?的處理。 - 解析:?對編輯后的字符串進(jìn)行解析,解析出命令項(xiàng)和參數(shù)項(xiàng),找到對應(yīng)的命令項(xiàng)執(zhí)行函數(shù)。
- 執(zhí)行:?命令可通過靜態(tài)和動態(tài)兩種方式注冊到內(nèi)核,解析出具體命令后在注冊表中找到對應(yīng)函數(shù)回調(diào)。將結(jié)果輸出到控制臺。
編輯部分由客戶端任務(wù)完成,后兩個部分由服務(wù)端任務(wù)完成,命令全局注冊由內(nèi)核完成。
- 本篇主要說?服務(wù)端任務(wù)?和?解析/執(zhí)行過程.
- 客戶端任務(wù)?和?編輯過程?已在 (Shell編輯篇) 中說明,請自行翻看.
總體過程
- 第一步: 將支持的
shell
命令注冊進(jìn)全局鏈表,支持靜態(tài)和動態(tài)兩種方式,內(nèi)容包括命令項(xiàng),參數(shù)信息和回調(diào)函數(shù). - 第二步: 由獨(dú)立任務(wù)解析出用戶輸入的命令行,拆分出命令項(xiàng)和參數(shù)內(nèi)容
- 第三步: 通過命令項(xiàng)在全局鏈表中遍歷找到已注冊的回調(diào)函數(shù),并執(zhí)行.
結(jié)構(gòu)體
鴻蒙對命令的注冊用了三個結(jié)構(gòu)體,個人感覺前兩個可以合成一個,降低代碼閱讀難度.
STATIC CmdModInfo g_cmdInfo;//shell 命令模塊信息,上面掛了所有的命令項(xiàng)(ls,cd ,cp ==)typedef struct {//命令項(xiàng)CmdType cmdType; //命令類型//CMD_TYPE_EX:不支持標(biāo)準(zhǔn)命令參數(shù)輸入,會把用戶填寫的命令關(guān)鍵字屏蔽掉,例如:輸入ls /ramfs,傳入給注冊函數(shù)的參數(shù)只有/ramfs,而ls命令關(guān)鍵字并不會被傳入。//CMD_TYPE_STD:支持的標(biāo)準(zhǔn)命令參數(shù)輸入,所有輸入的字符都會通過命令解析后被傳入。const CHAR *cmdKey; //命令關(guān)鍵字,例如:ls 函數(shù)在Shell中訪問的名稱。UINT32 paraNum; //調(diào)用的執(zhí)行函數(shù)的入?yún)⒆畲髠€數(shù),暫不支持。CmdCallBackFunc cmdHook;//命令執(zhí)行函數(shù)地址,即命令實(shí)際執(zhí)行函數(shù)。
} CmdItem;
typedef struct { //命令節(jié)點(diǎn)LOS_DL_LIST list; //雙向鏈表CmdItem *cmd; //命令項(xiàng)
} CmdItemNode;/* global info for shell module */
typedef struct {//shell 模塊的全局信息CmdItemNode cmdList; //命令項(xiàng)節(jié)點(diǎn)UINT32 listNum;//節(jié)點(diǎn)數(shù)量UINT32 initMagicFlag;//初始魔法標(biāo)簽 0xABABABABLosMux muxLock; //操作鏈表互斥鎖CmdVerifyTransID transIdHook;//暫不知何意
} CmdModInfo;
解讀
CmdItem
為注冊的內(nèi)容載體結(jié)構(gòu)體,cmdHook
為回調(diào)函數(shù),是命令的真正執(zhí)行體.- 通過雙向鏈表
CmdItemNode.list
將所有命令穿起來 CmdModInfo
記錄命令數(shù)量和操作的互斥鎖,shell
的魔法數(shù)字為?0xABABABAB
第一步 | Shell 注冊
- 靜態(tài)宏方式注冊,鏈接時處理
靜態(tài)注冊命令方式一般用在系統(tǒng)常用命令注冊,鴻蒙已支持以下命令.
arp cat cd chgrp chmod chown cp cpup date dhclient dmesg dns format free help hwi ifconfig ipdebug kill log ls lsfd memcheck mkdir mount netstat oom partinfo partition ping ping6 pwd reset rm rmdir sem statfs su swtmr sync systeminfo task telnet test tftp touch umount uname watch writeproc
例如注冊?`ls`命令
SHELLCMD_ENTRY(ls_shellcmd, CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs)
需在鏈接選項(xiàng)中添加鏈接該新增命令項(xiàng)參數(shù),具體在liteos_tables_ldflags.mk
文件的LITEOS_TABLES_LDFLAGS
項(xiàng)下添加-uls_shellcmd
。至于SHELLCMD_ENTRY
是如何實(shí)現(xiàn)的在鏈接階段的注冊,請自行翻看 (內(nèi)聯(lián)匯編篇) ,有詳細(xì)說明實(shí)現(xiàn)細(xì)節(jié).
- 動態(tài)命令方式,運(yùn)行時處理
動態(tài)注冊命令方式一般用在用戶命令注冊,具體實(shí)現(xiàn)代碼如下:
osCmdReg(CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs){// ....//5.正式創(chuàng)建命令,掛入鏈表return OsCmdItemCreate(cmdType, cmdKey, paraNum, cmdProc);//不存在就注冊命令}//創(chuàng)建一個命令項(xiàng),例如 chmodSTATIC UINT32 OsCmdItemCreate(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNum, CmdCallBackFunc cmdProc){CmdItem *cmdItem = NULL;CmdItemNode *cmdItemNode = NULL;//1.構(gòu)造命令節(jié)點(diǎn)過程cmdItem = (CmdItem *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItem));if (cmdItem == NULL) {return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;}(VOID)memset_s(cmdItem, sizeof(CmdItem), '\0', sizeof(CmdItem));cmdItemNode = (CmdItemNode *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItemNode));if (cmdItemNode == NULL) {(VOID)LOS_MemFree(m_aucSysMem0, cmdItem);return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;}(VOID)memset_s(cmdItemNode, sizeof(CmdItemNode), '\0', sizeof(CmdItemNode));cmdItemNode->cmd = cmdItem; //命令項(xiàng) cmdItemNode->cmd->cmdHook = cmdProc;//回調(diào)函數(shù) osShellCmdLscmdItemNode->cmd->paraNum = paraNum;//`777`,'/home'cmdItemNode->cmd->cmdType = cmdType;//關(guān)鍵字類型cmdItemNode->cmd->cmdKey = cmdKey; //`chmod`//2.完成構(gòu)造后掛入全局鏈表(VOID)LOS_MuxLock(&g_cmdInfo.muxLock, LOS_WAIT_FOREVER);OsCmdAscendingInsert(cmdItemNode);//按升序方式插入g_cmdInfo.listNum++;//命令總數(shù)增加(VOID)LOS_MuxUnlock(&g_cmdInfo.muxLock);return LOS_OK;}
第二步 解析 | ShellTask
//shell 服務(wù)端任務(wù)初始化,這個任務(wù)負(fù)責(zé)解析和執(zhí)行命令
LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
{CHAR *name = NULL;TSK_INIT_PARAM_S initParam = {0};//輸入Shell命令的兩種方式if (shellCB->consoleID == CONSOLE_SERIAL) { //通過串口工具name = SERIAL_SHELL_TASK_NAME;} else if (shellCB->consoleID == CONSOLE_TELNET) {//通過遠(yuǎn)程工具name = TELNET_SHELL_TASK_NAME;} else {return LOS_NOK;}initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;//任務(wù)入口函數(shù),主要是解析shell命令initParam.usTaskPrio = 9; /* 9:shell task priority */initParam.auwArgs[0] = (UINTPTR)shellCB;initParam.uwStackSize = 0x3000;initParam.pcName = name;initParam.uwResved = LOS_TASK_STATUS_DETACHED;(VOID)LOS_EventInit(&shellCB->shellEvent);//初始化事件,以事件方式通知任務(wù)解析命令return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);//創(chuàng)建任務(wù)
}
LITE_OS_SEC_TEXT_MINOR UINT32 ShellTask(UINTPTR param1,UINTPTR param2,UINTPTR param3,UINTPTR param4)
{UINT32 ret;ShellCB *shellCB = (ShellCB *)param1;(VOID)param2;(VOID)param3;(VOID)param4;while (1) {PRINTK("\nOHOS # ");//讀取shell 輸入事件 例如: cat weharmony.net 命令ret = LOS_EventRead(&shellCB->shellEvent,0xFFF, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);if (ret == SHELL_CMD_PARSE_EVENT) {//獲得解析命令事件ShellCmdProcess(shellCB);//處理命令 } else if (ret == CONSOLE_SHELL_KEY_EVENT) {//退出shell事件break;}}OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdKeyLink);//OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdHistoryKeyLink);(VOID)LOS_EventDestroy(&shellCB->shellEvent);//注銷事件(VOID)LOS_MemFree((VOID *)m_aucSysMem0, shellCB);//釋放shell控制塊return 0;
}
解讀
-
任務(wù)優(yōu)先級和 客戶端任務(wù) 一樣同為?
9
-
指定內(nèi)核棧大小為
0x3000 = 12K
?,因任務(wù)負(fù)責(zé)命令的解析和執(zhí)行,所以需要更大的內(nèi)核空間. -
任務(wù)的入口函數(shù)
ShellTask
,一個死循環(huán)在以LOS_WAIT_FOREVER
方式死等事件發(fā)生.SHELL_CMD_PARSE_EVENT
?通知開始解析事件,該事件由 客戶端任務(wù)ShellEntry
檢測到回車鍵時發(fā)出.
STATIC VOID ShellNotify(ShellCB *shellCB){(VOID)LOS_EventWrite(&shellCB->shellEvent, SHELL_CMD_PARSE_EVENT);}
* `CONSOLE_SHELL_KEY_EVENT`?收到?`exit`命令時將發(fā)出該事件,退出`shell`回收資源
- 層層跟進(jìn)
ShellCmdProcess
,解析出命令項(xiàng)和參數(shù)內(nèi)容,最終跑到OsCmdExec
中遍歷 已注冊的命令表,找出命令對應(yīng)的函數(shù)完成回調(diào).
LITE_OS_SEC_TEXT_MINOR UINT32 OsCmdExec(CmdParsed *cmdParsed, CHAR *cmdStr){UINT32 ret;CmdCallBackFunc cmdHook = NULL;CmdItemNode *curCmdItem = NULL;UINT32 i;const CHAR *cmdKey = NULL;if ((cmdParsed == NULL) || (cmdStr == NULL) || (strlen(cmdStr) == 0)) {return (UINT32)OS_ERROR;}ret = OsCmdParse(cmdStr, cmdParsed);//解析出命令關(guān)鍵字,參數(shù)if (ret != LOS_OK) {goto OUT;}//遍歷命令注冊全局鏈表LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(g_cmdInfo.cmdList.list), CmdItemNode, list) {cmdKey = curCmdItem->cmd->cmdKey;if ((cmdParsed->cmdType == curCmdItem->cmd->cmdType) &&(strlen(cmdKey) == strlen(cmdParsed->cmdKeyword)) &&(strncmp(cmdKey, (CHAR *)(cmdParsed->cmdKeyword), strlen(cmdKey)) == 0)) {//找到命令的回調(diào)函數(shù) 例如: ls <-> osShellCmdLscmdHook = curCmdItem->cmd->cmdHook;break;}}ret = OS_ERROR;if (cmdHook != NULL) {//執(zhí)行命令,即回調(diào)函數(shù)ret = (cmdHook)(cmdParsed->paramCnt, (const CHAR **)cmdParsed->paramArray);}OUT:for (i = 0; i < cmdParsed->paramCnt; i++) {//無效的命令要釋放掉保存參數(shù)的內(nèi)存if (cmdParsed->paramArray[i] != NULL) {(VOID)LOS_MemFree(m_aucSysMem0, cmdParsed->paramArray[i]);cmdParsed->paramArray[i] = NULL;}}return (UINT32)ret;}
第三步 | 執(zhí)行
想知道有哪些系統(tǒng)shell
命令,可以搜索關(guān)鍵詞SHELLCMD_ENTRY
拿到所有通過靜態(tài)方式注冊的命令.
其中有網(wǎng)絡(luò)的,進(jìn)程的,任務(wù)的,內(nèi)存的 等等,此處列出幾個常用的shell
命令的實(shí)現(xiàn).
ls 命令
SHELLCMD_ENTRY(ls_shellcmd, CMD_TYPE_EX, "ls", XARGS, (CmdCallBackFunc)osShellCmdLs);/*******************************************************
命令功能
ls命令用來顯示當(dāng)前目錄的內(nèi)容。命令格式
ls [path]path為空時,顯示當(dāng)前目錄的內(nèi)容。
path為無效文件名時,顯示失敗,提示:
ls error: No such directory。
path為有效目錄路徑時,會顯示對應(yīng)目錄下的內(nèi)容。使用指南
ls命令顯示當(dāng)前目錄的內(nèi)容。
ls可以顯示文件的大小。
proc下ls無法統(tǒng)計文件大小,顯示為0。*******************************************************/
int osShellCmdLs(int argc, const char **argv)
{char *fullpath = NULL;const char *filename = NULL;int ret;char *shell_working_directory = OsShellGetWorkingDirtectory();//獲取當(dāng)前工作目錄if (shell_working_directory == NULL){return -1;}ERROR_OUT_IF(argc > 1, PRINTK("ls or ls [DIRECTORY]\n"), return -1);if (argc == 0)//木有參數(shù)時 -> #ls {ls(shell_working_directory);//執(zhí)行l(wèi)s 當(dāng)前工作目錄return 0;}filename = argv[0];//有參數(shù)時 -> #ls ../harmony or #ls /no such file or directoryret = vfs_normalize_path(shell_working_directory, filename, &fullpath);//獲取全路徑,注意這里帶出來fullpath,而fullpath已經(jīng)在內(nèi)核空間ERROR_OUT_IF(ret < 0, set_err(-ret, "ls error"), return -1);ls(fullpath);//執(zhí)行 ls 全路徑free(fullpath);//釋放全路徑,為啥要釋放,因?yàn)閒ullpath已經(jīng)由內(nèi)核空間分配return 0;
}
task 命令
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask);LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpTask(INT32 argc, const CHAR **argv)
{UINT32 flag = 0;
#ifdef LOSCFG_KERNEL_VMflag |= OS_PROCESS_MEM_INFO;
#endifif (argc >= 2) { /* 2: The task shell name restricts the parameters */goto TASK_HELP;}if (argc == 1) {if (strcmp("-a", argv[0]) == 0) {flag |= OS_PROCESS_INFO_ALL;} else if (strcmp("-i", argv[0]) == 0) {if (!OsShellShowTickRespo()) {return LOS_OK;}goto TASK_HELP;} else if (strcmp("-t", argv[0]) == 0) {if (!OsShellShowSchedParam()) {return LOS_OK;}goto TASK_HELP;} else {goto TASK_HELP;}}return OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, flag);TASK_HELP:PRINTK("Unknown option: %s\n", argv[0]);PRINTK("usage: task or task -a\n");return LOS_NOK;
}
cat 命令
SHELLCMD_ENTRY(cat_shellcmd, CMD_TYPE_EX, "cat", XARGS, (CmdCallBackFunc)osShellCmdCat);/*****************************************************************
cat用于顯示文本文件的內(nèi)容。cat [pathname]
cat weharmony.txt
*****************************************************************/
int osShellCmdCat(int argc, const char **argv)
{char *fullpath = NULL;int ret;unsigned int ca_task;struct Vnode *vnode = NULL;TSK_INIT_PARAM_S init_param;char *shell_working_directory = OsShellGetWorkingDirtectory();//顯示當(dāng)前目錄 pwdif (shell_working_directory == NULL){return -1;}ERROR_OUT_IF(argc != 1, PRINTK("cat [FILE]\n"), return -1);ret = vfs_normalize_path(shell_working_directory, argv[0], &fullpath);//由相對路徑獲取絕對路徑ERROR_OUT_IF(ret < 0, set_err(-ret, "cat error"), return -1);VnodeHold();ret = VnodeLookup(fullpath, &vnode, O_RDONLY);if (ret != LOS_OK){set_errno(-ret);perror("cat error");VnodeDrop();free(fullpath);return -1;}if (vnode->type != VNODE_TYPE_REG){set_errno(EINVAL);perror("cat error");VnodeDrop();free(fullpath);return -1;}VnodeDrop();(void)memset_s(&init_param, sizeof(init_param), 0, sizeof(TSK_INIT_PARAM_S));init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)osShellCmdDoCatShow;init_param.usTaskPrio = CAT_TASK_PRIORITY; //優(yōu)先級10init_param.auwArgs[0] = (UINTPTR)fullpath; //入口參數(shù)init_param.uwStackSize = CAT_TASK_STACK_SIZE;//內(nèi)核棧大小init_param.pcName = "shellcmd_cat"; //任務(wù)名稱init_param.uwResved = LOS_TASK_STATUS_DETACHED | OS_TASK_FLAG_SPECIFIES_PROCESS;init_param.processID = 2; /* 2: kProcess */ //內(nèi)核任務(wù)ret = (int)LOS_TaskCreate(&ca_task, &init_param);//創(chuàng)建任務(wù)顯示cat內(nèi)容if (ret != LOS_OK){free(fullpath);}return ret;
}
你能看明白這些命令的底層實(shí)現(xiàn)嗎? 如果看明白了,可能會不由得發(fā)出?原來如此?的感嘆!
鴻蒙全棧開發(fā)全新學(xué)習(xí)指南
也為了積極培養(yǎng)鴻蒙生態(tài)人才,讓大家都能學(xué)習(xí)到鴻蒙開發(fā)最新的技術(shù),針對一些在職人員、0基礎(chǔ)小白、應(yīng)屆生/計算機(jī)專業(yè)、鴻蒙愛好者等人群,整理了一套純血版鴻蒙(HarmonyOS Next)全棧開發(fā)技術(shù)的學(xué)習(xí)路線【包含了大廠APP實(shí)戰(zhàn)項(xiàng)目開發(fā)】。
本路線共分為四個階段:
第一階段:鴻蒙初中級開發(fā)必備技能
第二階段:鴻蒙南北雙向高工技能基礎(chǔ):gitee.com/MNxiaona/733GH
第三階段:應(yīng)用開發(fā)中高級就業(yè)技術(shù)
第四階段:全網(wǎng)首發(fā)-工業(yè)級南向設(shè)備開發(fā)就業(yè)技術(shù):gitee.com/MNxiaona/733GH
《鴻蒙 (Harmony OS)開發(fā)學(xué)習(xí)手冊》(共計892頁)
如何快速入門?
1.基本概念
2.構(gòu)建第一個ArkTS應(yīng)用
3.……
開發(fā)基礎(chǔ)知識:gitee.com/MNxiaona/733GH
1.應(yīng)用基礎(chǔ)知識
2.配置文件
3.應(yīng)用數(shù)據(jù)管理
4.應(yīng)用安全管理
5.應(yīng)用隱私保護(hù)
6.三方應(yīng)用調(diào)用管控機(jī)制
7.資源分類與訪問
8.學(xué)習(xí)ArkTS語言
9.……
基于ArkTS 開發(fā)
1.Ability開發(fā)
2.UI開發(fā)
3.公共事件與通知
4.窗口管理
5.媒體
6.安全
7.網(wǎng)絡(luò)與鏈接
8.電話服務(wù)
9.數(shù)據(jù)管理
10.后臺任務(wù)(Background Task)管理
11.設(shè)備管理
12.設(shè)備使用信息統(tǒng)計
13.DFX
14.國際化開發(fā)
15.折疊屏系列
16.……
鴻蒙開發(fā)面試真題(含參考答案):gitee.com/MNxiaona/733GH
鴻蒙入門教學(xué)視頻:
美團(tuán)APP實(shí)戰(zhàn)開發(fā)教學(xué):gitee.com/MNxiaona/733GH
寫在最后
- 如果你覺得這篇內(nèi)容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點(diǎn)贊,轉(zhuǎn)發(fā),有你們的 『點(diǎn)贊和評論』,才是我創(chuàng)造的動力。
- 關(guān)注小編,同時可以期待后續(xù)文章ing🚀,不定期分享原創(chuàng)知識。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)資源,請移步前往小編:
gitee.com/MNxiaona/733GH