鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc(上)进程通讯内容

基本概念

LiteIPCOpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,为轻量级进程间通信组件,为面向服务的系统服务框架提供进程间通信能力,分为内核实现和用户态实现两部分,其中内核实现完成进程间消息收发、IPC内存管理、超时通知和死亡通知等功能;用户态提供序列化和反序列化能力,并完成IPC回调消息和死亡消息的分发。

我们主要讲解内核态实现部分,本想一篇说完,但发现它远比想象中的复杂和重要,所以分两篇说,通讯内容和通讯机制。通讯的内容就是消息,围绕着消息展开的结构体多达10几个,捋不清它们之间的关系肯定是搞不懂通讯的机制,所以咱们得先搞清楚关系再说流程。下图是笔者读完LiteIPC模块后绘制的消息封装图,可以说LiteIPC是内核涉及结构体最多的模块,请消化理解,本篇将围绕它展开。
[图片上传失败…(image-a29828-1715581843494)]

系列篇多次提过,内核的每个模块都至少围绕着一个重要结构体展开,抓住了它顺瓜摸藤就能把细节抹的清清楚楚,于LiteIPC,这个结构体就是IpcMsg 。

运行机制

typedef struct {//IPC 消息结构体MsgType        type;       	/**< cmd type, decide the data structure below | 命令类型,决定下面的数据结构*/SvcIdentity    target;    	/**< serviceHandle or targetTaskId, depending on type | 因命令类型不同而异*/UINT32         code;      	/**< service function code | 服务功能代码*/UINT32         flag;		///< 标签
#if (USE_TIMESTAMP == 1)UINT64         timestamp;	///< 时间戳,用于验证
#endifUINT32         dataSz;    	/**< size of data | 消息内容大小*/VOID           *data;		///< 消息的内容,真正要传递的消息,这个数据内容是指spObjNum个数据的内容,定位就靠offsetsUINT32         spObjNum;	///< 对象数量, 例如 spObjNum = 3时,offsets = [0,35,79],代表从data中读取 0 - 35给第一个对象,依次类推VOID           *offsets;	///< 偏移量,注意这里有多少个spObjNum就会有多少个偏移量,详见 CopyDataFromUser 来理解UINT32         processID; 	/**< filled by kernel, processId of sender/reciever | 由内核提供,发送/接收消息的进程ID*/UINT32         taskID;    	/**< filled by kernel, taskId of sender/reciever | 由内核提供,发送/接收消息的任务ID*/
#ifdef LOSCFG_SECURITY_CAPABILITY	UINT32         userID;		///< 用户IDUINT32         gid;			///< 组ID
#endif
} IpcMsg;

解读

  • 第一个type,通讯的本质就是你来我往,异常当然也要考虑

      typedef enum {	MT_REQUEST,	///< 请求MT_REPLY,	///< 回复MT_FAILED_REPLY,///< 回复失败MT_DEATH_NOTIFY,///< 通知死亡MT_NUM} MsgType;
  • 第二个targetLiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的访问权限(只有有权限的任务Task可以向对应的Service发送IPC消息)。首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取IPC消息的读操作和代表发送IPC消息的写操作。

    /// SVC(service)服务身份证 typedef struct {UINT32         handle;  //service 服务ID, 范围[0,最大任务ID]UINT32         token;	//由应用层带入UINT32         cookie;	//由应用层带入} SvcIdentity;
  • codetimestamp由应用层设定,用于确保回复正确有效,详见CheckRecievedMsg
  • dataSzdataspObjNumoffsets这四个需连在一起理解,是重中之重。其实消息又分成三种类型(对象)
      typedef enum {OBJ_FD,		///< 文件句柄OBJ_PTR,	///< 指针OBJ_SVC		///< 服务,用于设置权限} ObjType;typedef union {UINT32      fd; 	///< 文件描述符BuffPtr     ptr;	///< 缓存的开始地址,即:指针,消息从用户空间来时,要将内容拷贝到内核空间SvcIdentity  svc;	///< 服务,用于设置访问权限} ObjContent;typedef struct { // IpcMsg->data 包含三种子消息,也要将它们读到内核空间ObjType     type; ///< 类型ObjContent  content;///< 内容} SpecialObj;

这三种对象都打包在data中,总长度是dataSzspObjNum表示个数,offsets是个整型数组,标记了对应第几个对象在data中的位置,这样就很容易从data读到对象的数据。
UINT32 fd类型对象通讯的实现是通过两个进程间共享同一个fd来实现通讯,具体实现函数为HandleFd

    /// 按句柄方式处理, 参数 processID 往往不是当前进程LITE_OS_SEC_TEXT STATIC UINT32 HandleFd(UINT32 processID, SpecialObj *obj, BOOL isRollback){int ret;if (isRollback == FALSE) { // 不回滚ret = CopyFdToProc(obj->content.fd, processID);//目的是将两个不同进程fd都指向同一个系统fd,共享FD的感觉if (ret < 0) {//返回 processID 的 新 fdreturn ret;}obj->content.fd = ret; // 记录 processID 的新FD, 可用于回滚} else {// 回滚时关闭进程FDret = CloseProcFd(obj->content.fd, processID);if (ret < 0) {return ret;}}

SvcIdentity svc用于设置进程<->任务之间彼此访问权限,具体实现函数为HandleSvc

    /// 按服务的方式处理,此处推断 Svc 应该是 service 的简写 @note_thinkingLITE_OS_SEC_TEXT STATIC UINT32 HandleSvc(UINT32 dstTid, const SpecialObj *obj, BOOL isRollback){UINT32 taskID = 0;if (isRollback == FALSE) {if (IsTaskAlive(obj->content.svc.handle) == FALSE) {PRINT_ERR("Liteipc HandleSvc wrong svctid\n");return -EINVAL;}if (HasServiceAccess(obj->content.svc.handle) == FALSE) {PRINT_ERR("Liteipc %s, %d\n", __FUNCTION__, __LINE__);return -EACCES;}if (GetTid(obj->content.svc.handle, &taskID) == 0) {//获取参数消息服务ID所属任务if (taskID == OS_PCB_FROM_PID(OS_TCB_FROM_TID(taskID)->processID)->ipcInfo->ipcTaskID) {//如果任务ID一样,即任务ID为ServiceManagerAddServiceAccess(dstTid, obj->content.svc.handle);}}}return LOS_OK;}

BuffPtr ptr 是通过指针传值,具体实现函数为HandlePtr,对应结构体为BuffPtr

      typedef struct {UINT32         buffSz;  ///< 大小VOID           *buff;	///< 内容 内核需要将内容从用户空间拷贝到内核空间的动作 } BuffPtr;/// 按指针方式处理LITE_OS_SEC_TEXT STATIC UINT32 HandlePtr(UINT32 processID, SpecialObj *obj, BOOL isRollback){VOID *buf = NULL;UINT32 ret;if ((obj->content.ptr.buff == NULL) || (obj->content.ptr.buffSz == 0)) {return -EINVAL;}if (isRollback == FALSE) {if (LOS_IsUserAddress((vaddr_t)(UINTPTR)(obj->content.ptr.buff)) == FALSE) { // 判断是否为用户空间地址PRINT_ERR("Liteipc Bad ptr address\n"); //不在用户空间时return -EINVAL;}buf = LiteIpcNodeAlloc(processID, obj->content.ptr.buffSz);//在内核空间分配内存接受来自用户空间的数据if (buf == NULL) {PRINT_ERR("Liteipc DealPtr alloc mem failed\n");return -EINVAL;}ret = copy_from_user(buf, obj->content.ptr.buff, obj->content.ptr.buffSz);//从用户空间拷贝数据到内核空间if (ret != LOS_OK) {LiteIpcNodeFree(processID, buf);return ret;}//这里要说明下 obj->content.ptr.buff的变化,虽然都是用户空间的地址,但第二次已经意义变了,虽然数据一样,但指向的是申请经过拷贝后的内核空间obj->content.ptr.buff = (VOID *)GetIpcUserAddr(processID, (INTPTR)buf);//获取进程 processID的用户空间地址,如此用户空间操作buf其实操作的是内核空间EnableIpcNodeFreeByUser(processID, (VOID *)buf);//创建一个IPC节点,挂到可使用链表上,供读取} else {(VOID)LiteIpcNodeFree(processID, (VOID *)GetIpcKernelAddr(processID, (INTPTR)obj->content.ptr.buff));//在内核空间释放IPC节点}return LOS_OK;}
  • processIDtaskID则由内核填充,应用层是感知不到进程和任务的,暴露给它是服务ID,SvcIdentity.handle,上层使用时只需向服务发送/读取消息,而服务是由内核创建,绑定在任务和进程上。所以只要有服务ID就能查询到对应的进程和任务ID。
  • userIDgid涉及用户和组安全模块,请查看系列相关篇。

进程和任务

再说两个结构体 ProcIpcInfoIpcTaskInfo
LiteIPC实现的是进程间的通讯,所以在进程控制块中肯定有它的位置存在,即:ProcIpcInfo

typedef struct {IpcPool pool;				///< ipc内存池,IPC操作所有涉及内核空间分配的内存均有此池提供UINT32 ipcTaskID;			///< 指定能ServiceManager的任务IDLOS_DL_LIST ipcUsedNodelist;///< 已使用节点链表,上面挂 IpcUsedNode 节点, 申请IpcUsedNode的内存来自内核堆空间UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT];	///< 允许进程通过IPC访问哪些任务
} ProcIpcInfo;

而进程只是管家,真正让内核忙飞的是任务,在任务控制块中也应有LiteIPC一席之地,即:IpcTaskInfo

typedef struct {LOS_DL_LIST     msgListHead;///< 上面挂的是一个个的 ipc节点 上面挂 IpcListNode,申请IpcListNode的内存来自进程IPC内存池BOOL            accessMap[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 此处是不是应该用 LOSCFG_BASE_CORE_PROCESS_LIMIT ? @note_thinking ///< 任务是否可以给其他进程发送IPC消息
} IpcTaskInfo;

两个结构体不复杂,把发送/回复的消息挂到对应的链表上,并提供进程<->任务间彼此访问权限功能accessaccessMap,由谁来设置权限呢 ? 上面已经说过了是 HandleSvc

IPC内存池

还有最后一个结构体IpcPool

typedef struct {//用户空间和内核空间的消息传递通过偏移量计算VOID   *uvaddr;	///< 用户空间地址,由kvaddr映射而来的地址,这两个地址的关系一定要搞清楚,否则无法理解IPC的核心思想VOID   *kvaddr;	///< 内核空间地址,IPC申请的是内核空间,但是会通过 DoIpcMmap 将这个地址映射到用户空间UINT32 poolSize; ///< ipc池大小
} IpcPool;

它是LiteIPC实现通讯机制的基础,是内核设计很巧妙的地方,实现了在用户态读取内核态数据的功能。请想想它是如何做到的 ?

鸿蒙全栈开发全新学习指南

也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线【包含了大厂APP实战项目开发】

本路线共分为四个阶段:

第一阶段:鸿蒙初中级开发必备技能

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:gitee.com/MNxiaona/733GH

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/326182.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

测试人的福音:开源流量回放工具快速上手实践

笔者前段时间在参加测开大会时了解到了一款开源的自动化回归测试工具 AREX。主要是通过复制线上真实流量到测试环境进行回归测试&#xff0c;同时还做到了接口返回值的比对和写接口的验证&#xff0c;回放不会产生真实的数据或者调用&#xff0c;都是基于 Mock 数据的&#xff…

5分钟学设计模式:简单工厂与美食街的不期而遇

大家好&#xff0c;我是知微。 写代码好几年&#xff0c;是不是还纠结于这些问题&#xff1a; 面对一堆if-else&#xff0c;代码越写越长&#xff0c;维护起来比攀登珠穆朗玛峰还难每次只敢小心翼翼改个小功能&#xff0c;生怕程序突然“嘭”一声&#xff0c;全炸了想学习大佬…

18.Docker学习

1.Docker应用场景 Docker借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地&#xff0c;Docker&#xff08;模板&#xff09;将软件运往各个环境&#xff08;测试环境和生产环境拉取镜像&#xff08;实例&#xff09;&#xff09;&#xff0c;相当于是一个模子刻出来的 …

计算机毕业设计springboot+vue高校教师职称评审评定系统605z3

技术栈 前端&#xff1a;vue.jsElementUI 开发工具&#xff1a;IDEA 或者eclipse都支持 编程语言: java 框架&#xff1a; ssm/springboot 数据库: mysql 版本不限 数据库工具&#xff1a;Navicat/SQLyog都可以 详细技术&#xff1a;javaspringbootvueMYSQLMAVEN 本系统采用in…

Google Pixel4手机刷机+Root+逆向环境详细教程

Google Pixel4手机刷机Root逆向环境配置详细教程 刷机工具下载 Windows10、Google Pixel4手机当前安卓10系统、adb工具、要刷的谷歌原生的Android11最新刷机包、安装google usb驱动、美版临时twrp-3.6.0_11-0-flame.img和美版永久twrp-installer-3.6.0_11-0-flame.zip、Magis…

如何使用Shortemall自动扫描URL短链接中的隐藏内容

关于Shortemall Shortemall是一款针对URL地址安全与Web内容安全的强大工具&#xff0c;该工具基于纯Python开发&#xff0c;专为Web安全方向设计&#xff0c;可以帮助广大研究人员以自动化的形式扫描URL短链接中的隐藏内容。 Shortemall的全名为ShortEm All&#xff0c;该工具…

乡村振兴与乡村旅游深度融合:依托乡村自然和文化资源,发展乡村旅游产业,促进农民增收致富,打造特色美丽乡村

目录 一、引言 二、乡村振兴与乡村旅游的内在联系 三、依托乡村自然和文化资源发展乡村旅游产业 &#xff08;一&#xff09;挖掘乡村自然资源优势&#xff0c;打造特色旅游品牌 &#xff08;二&#xff09;挖掘乡村文化资源内涵&#xff0c;丰富旅游活动内容 四、促进农…

IP SSL怎么签发使用

IP证书的签发首先是需要有一个可供绑定的IP地址&#xff0c;作为常用数字证书之一&#xff0c;IP证书也因为其广泛的应用范围而深得用户的青睐和喜欢。 部署IP证书后&#xff0c;可以实现该IP地址的https访问&#xff0c;过程和域名证书相差不多。 IP证书和域名证书的区别 很…

接收区块链的CCF会议--NDSS 2025 截止7.10 附录用率

会议名称&#xff1a;Network and Distributed System Security Symposium (NDSS) CCF等级&#xff1a;CCF A类学术会议 类别&#xff1a;网络与信息安全 录用率&#xff1a;2024年接收率19.5% Submissions are solicited in, but not limited to, the following areas: Ant…

《系统管理学报》期刊投稿经验与流程分享(一轮退修,历时3月)

双非研二&#xff0c;三作&#xff08;导师一作&#xff0c;师哥二作&#xff09;&#xff0c;《系统管理学报》期刊录用 投稿网址&#xff1a;https://xtglxb.sjtu.edu.cn/journalx_jgxb/authorLogOn.action 投稿&收稿&#xff1a;2022年12月26日初审&#xff1a;2023年…

强大的开源项目RAG-GPT:5分钟实现LLM大模型应用到你的网站!

强大的开源项目RAG-GPT&#xff1a;5分钟实现LLM大模型应用到你的网站&#xff01; 引言 随着chatgpt等大型语言模型&#xff08;LLM&#xff09;能力越来越强大&#xff0c;如何将这些模型精准地应用于特定垂直领域&#xff0c;让各行业开发者快速利用LLM赋能也成为热点和痛…

WS2811 单线 256 级灰度三通道恒流 LED 驱动器芯片 IC

产品概述 WS2811 是三通道LED驱动控制专用电路&#xff0c;芯片内部包含了智能数字接口数据锁存信号整形放大驱动电路&#xff0c;还包含有高精度的内部振荡器和15V高压可编程定电流输出驱动器。同时&#xff0c;为了降低电源纹波&#xff0c;3个通道有一定的延时导通功…

4.1 文本相似度(二)

目录 1 文本相似度评估 2 代码 2.1 load_dataset 方法 2.2 AutoTokenizer、AutoModelForSequenceClassification 1 文本相似度评估 对两个文本拼接起来&#xff0c;然后作为一个样本喂给模型&#xff0c;作为一个二分类的任务&#xff1b; 数据处理的方式以及训练的基本流程…

2024最新版JavaScript逆向爬虫教程-------基础篇之无限debugger的原理与绕过

目录 一、无限debugger的原理与绕过1.1 案例介绍1.2 实现原理1.3 绕过debugger方法1.3.1 禁用所有断点1.3.2 禁用局部断点1.3.3 替换文件1.3.4 函数置空与hook 二、补充2.1 改写JavaScript文件2.2 浏览器开发者工具中出现的VM开头的JS文件是什么&#xff1f; 三、实战 一、无限…

一篇文章掌握所有国债期货的基本交易策略介绍

国债期货是一种基本的利率衍生品&#xff0c;根据交易者交易目的不同&#xff0c;可以将期货交易行为分为三类&#xff1a;套期保值、套利交易和投机交易。套期保值是投资者为了避免现有或将来预期的投资组合价值受市场利率变动的影响&#xff0c;而在国债期货市场上采取抵消性…

2023年30米分辨率土地利用遥感监测数据

改革开放以来&#xff0c;中国经济的快速发展对土地利用模式产生了深刻的影响。同时&#xff0c;中国又具有复杂的自然环境背景和广阔的陆地面积&#xff0c;其土地利用变化不仅对国家发展&#xff0c;也对全球环境变化产生了深刻的影响。为了恢复和重建我国土地利用变化的现代…

六、Redis五种常用数据结构-zset

zset是Redis的有序集合数据类型&#xff0c;但是其和set一样是不能重复的。但是相比于set其又是有序的。set的每个数据都有一个double类型的分数&#xff0c;zset正是根据这个分数来进行数据间的排序从小到大。有序集合中的元素是唯一的&#xff0c;但是分数(score)是可以重复的…

LeetCode416:分割等和子集

题目描述 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 解题思想 [1,5,11,5] 和为22&#xff0c;其中一半为 11。如果能寻找到若干数的和为11则成立可以抽象为一个0-1背包问题&#xff1a;容…

浮点数的由来及运算解析

数学是自然科学的皇后&#xff0c;计算机的设计初衷是科学计算。计算机的最基本功能是需要存储整数、实数&#xff0c;及对整数和实数进行算术四则运算。 但是在计算机从业者的眼中&#xff0c;我们知道的数学相关的基本数据类型通常是整型、浮点型、布尔型。整型又分为int8&a…

给centos机器打个样格式化挂载磁盘(新机器)

文章目录 一、先安装lvm2二、观察磁盘三、磁盘分区四、建PV五、建VG六、创建LV七、在LV上创建文件系统八、挂载到/home&#xff08;1&#xff09;临时挂载&#xff08;2&#xff09;永久挂载 九、最后reboot一下 一、先安装lvm2 yum install lvm2二、观察磁盘 三、磁盘分区 四…