更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
hm_liteipc.c 文件参考

浏览源代码.

结构体

struct  IpcUsedNode
 注意 ipc节点和消息是两个概念, 一个消息会包含多个节点 更多...
 

函数

 SPIN_LOCK_INIT (g_ipcSpin)
 
STATIC int LiteIpcOpen (struct file *filep)
 LiteIpcOpen 以VFS方式为当前进程创建IPC消息池 更多...
 
STATIC int LiteIpcClose (struct file *filep)
 
STATIC int LiteIpcIoctl (struct file *filep, int cmd, unsigned long arg)
 真正的 IPC 控制操作 更多...
 
STATIC int LiteIpcMmap (struct file *filep, LosVmMapRegion *region)
 将参数线性区设为IPC专用区 更多...
 
STATIC UINT32 LiteIpcWrite (IpcContent *content)
 写IPC消息队列,从用户空间到内核空间 更多...
 
STATIC UINT32 GetTid (UINT32 serviceHandle, UINT32 *taskID)
 获取任务ID 更多...
 
STATIC UINT32 HandleSpecialObjects (UINT32 dstTid, IpcListNode *node, BOOL isRollback)
 
STATIC ProcIpcInfoLiteIpcPoolCreate (VOID)
 创建IPC消息内存池 更多...
 
LITE_OS_SEC_TEXT_INIT UINT32 OsLiteIpcInit (VOID)
 OsLiteIpcInit 初始化LiteIPC模块 更多...
 
 LOS_MODULE_INIT (OsLiteIpcInit, LOS_INIT_LEVEL_KMOD_EXTENDED)
 
LITE_OS_SEC_TEXT STATIC BOOL IsPoolMapped (ProcIpcInfo *ipcInfo)
 池是否已经映射 更多...
 
LITE_OS_SEC_TEXT STATIC INT32 DoIpcMmap (LosProcessCB *pcb, LosVmMapRegion *region)
 DoIpcMmap
做IPC层映射,将内核空间虚拟地址映射到用户空间,这样的好处是用户态下操作读写的背后是在读写内核态空间 如此用户地址和内核地址指向同一个物理地址 更多...
 
LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit (ProcIpcInfo *ipcInfo)
 初始化进程的IPC内存池 更多...
 
LITE_OS_SEC_TEXT ProcIpcInfoLiteIpcPoolReInit (const ProcIpcInfo *parent)
 LiteIpcPoolReInit 重新初始化进程的IPC消息内存池 更多...
 
STATIC VOID LiteIpcPoolDelete (ProcIpcInfo *ipcInfo, UINT32 processID)
 释放进程的IPC消息内存池 更多...
 
LITE_OS_SEC_TEXT UINT32 LiteIpcPoolDestroy (UINT32 processID)
 销毁指定进程的IPC池 更多...
 
LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfoLiteIpcTaskInit (VOID)
 申请并初始化一个任务IPC 更多...
 
LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser (UINT32 processID, VOID *buf)
 
LITE_OS_SEC_TEXT STATIC VOID * LiteIpcNodeAlloc (UINT32 processID, UINT32 size)
 注意这可是从内核空间的IPC池中申请内存 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcNodeFree (UINT32 processID, VOID *buf)
 从IPC内存池中释放一个IPC节点 更多...
 
LITE_OS_SEC_TEXT STATIC BOOL IsIpcNode (UINT32 processID, const VOID *buf)
 指定buf 是否是IPC节点,这个函数不应该命名为 Is...容易误导 ,应改为 Free... @note_thinking 更多...
 
LITE_OS_SEC_TEXT STATIC INTPTR GetIpcUserAddr (UINT32 processID, INTPTR kernelAddr)
 获得IPC用户空间地址 更多...
 
LITE_OS_SEC_TEXT STATIC INTPTR GetIpcKernelAddr (UINT32 processID, INTPTR userAddr)
 获得IPC内核空间地址 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer (const VOID *node, IpcListNode **outPtr)
 检查指定地址在当前进程已使用的BUF 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 GenerateServiceHandle (UINT32 taskID, HandleStatus status, UINT32 *serviceHandle)
 任务 注册服务,LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列, 一个任务可以创建多个服务 更多...
 
LITE_OS_SEC_TEXT STATIC VOID RefreshServiceHandle (UINT32 serviceHandle, UINT32 result)
 刷新指定服务, 多刷几次状态就变了, result != 0 时,服务停止 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess (UINT32 taskID, UINT32 serviceHandle)
 AddServiceAccess 配置访问权限,具有两层含义 更多...
 
LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess (UINT32 serviceHandle)
 参数服务是否有访问当前进程的权限,实际中会有A进程的任务去给B进程发送IPC信息,所以需要鉴权 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 SetIpcTask (VOID)
 将当前任务设置成进程ipc的任务ID 更多...
 
LITE_OS_SEC_TEXT BOOL IsIpcTaskSet (VOID)
 是否设置ipc任务ID 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID (UINT32 processID, UINT32 *ipcTaskID)
 获取IPC任务ID 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg (UINT32 processID, UINT32 serviceHandle)
 serviceHandle 给 processID 发送死亡/结束消息, serviceHandle 为 taskID 更多...
 
LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle (UINT32 taskID)
 删除指定的Service 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 SetCms (UINTPTR maxMsgSize)
 设置CMS 更多...
 
LITE_OS_SEC_TEXT STATIC BOOL IsCmsSet (VOID)
 
LITE_OS_SEC_TEXT STATIC BOOL IsCmsTask (UINT32 taskID)
 指定任务是否为 ServiceManager 更多...
 
LITE_OS_SEC_TEXT STATIC BOOL IsTaskAlive (UINT32 taskID)
 任务是否活跃 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandleFd (UINT32 processID, SpecialObj *obj, BOOL isRollback)
 按句柄方式处理, 参数 processID 往往不是当前进程 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandlePtr (UINT32 processID, SpecialObj *obj, BOOL isRollback)
 按指针方式处理 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandleSvc (UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
 按服务的方式处理,此处推断 Svc 应该是 service 的简写 @note_thinking 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandleObj (UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
 创建处理对象,好复杂, 消息套消息 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 CheckMsgSize (IpcMsg *msg)
 检查消息内容大小 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 CopyDataFromUser (IpcListNode *node, UINT32 bufSz, const IpcMsg *msg)
 
LITE_OS_SEC_TEXT STATIC BOOL IsValidReply (const IpcContent *content)
 是否有效回复 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 CheckPara (IpcContent *content, UINT32 *dstTid)
 检查参数,并获取目标 任务ID 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 CheckRecievedMsg (IpcListNode *node, IpcContent *content, LosTaskCB *tcb)
 检查收到的消息 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcRead (IpcContent *content)
 读取IPC消息 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle (IpcContent *con)
 处理 IPC 消息 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandleCmsCmd (CmsCmdContent *content)
 处理命令 更多...
 
LITE_OS_SEC_TEXT STATIC UINT32 HandleGetVersion (IpcVersion *version)
 

变量

STATIC LosMux g_serviceHandleMapMux
 
STATIC HandleInfo g_cmsTask
 整个系统只能有一个ServiceManager 更多...
 
STATIC HandleInfo g_serviceHandleMap [MAX_SERVICE_NUM]
 g_serviceHandleMap[0]为ServiceManager,这块鸿蒙的设计挺怪的,让人很懵逼 更多...
 
STATIC LOS_DL_LIST g_ipcPendlist
 挂起/待办链表,上面挂等待读/写消息的任务LosTaskCB 更多...
 
STATIC const struct file_operations_vfs g_liteIpcFops
 

详细描述

轻量级进程间通信 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-ipc.html

 
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2022-1-29
基本概念
    LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,
    不同于传统的System V IPC机制,LiteIPC主要是为RPC(Remote Procedure Call,即远程过程调用)而设计的,
    而且是通过设备文件的方式对上层提供接口的,而非传统的API函数方式。
    
    LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,
    而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的
    访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。

运行机制
    首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service
    任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为
    每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取
    IPC消息的读操作和代表发送IPC消息的写操作。
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-22

在文件 hm_liteipc.c 中定义.

函数说明

◆ AddServiceAccess()

LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess ( UINT32  taskID,
UINT32  serviceHandle 
)

AddServiceAccess 配置访问权限,具有两层含义

  1. taskID所在的进程可以访问 serviceHandle服务所属的任务
  2. serviceHandle服务所属的任务可以访问taskID所在的进程
    参数
    serviceHandle服务ID
    taskID
    返回
    参见

在文件 hm_liteipc.c559 行定义.

560{
561 UINT32 serviceTid = 0;
562 UINT32 ret = GetTid(serviceHandle, &serviceTid);//通过服务获取任务 ,注意 任务:服务 = 1:N
563 if (ret != LOS_OK) {
564 PRINT_ERR("Liteipc AddServiceAccess GetTid failed\n");
565 return ret;
566 }
567 LosTaskCB *tcb = OS_TCB_FROM_TID(serviceTid);
568 UINT32 processID = OS_TCB_FROM_TID(taskID)->processID;
569 LosProcessCB *pcb = OS_PCB_FROM_PID(processID);
570 if ((tcb->ipcTaskInfo == NULL) || (pcb->ipcInfo == NULL)) {
571 PRINT_ERR("Liteipc AddServiceAccess ipc not create! pid %u tid %u\n", processID, tcb->taskID);
572 return -EINVAL;
573 }
574 tcb->ipcTaskInfo->accessMap[processID] = TRUE;//允许任务访问所属进程,此处为任务所在的进程
575 pcb->ipcInfo->access[serviceTid] = TRUE;//允许所属进程访问任务
576 return LOS_OK;
577}
STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
获取任务ID
Definition: hm_liteipc.c:491
unsigned int UINT32
Definition: los_typedef.h:57
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT]
任务是否可以给其他进程发送IPC消息
Definition: hm_liteipc.h:100
UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT]
允许进程通过IPC访问哪些任务
Definition: hm_liteipc.h:96
ProcIpcInfo * ipcInfo
IpcTaskInfo * ipcTaskInfo
任务间通讯信息结构体
UINT32 taskID
函数调用图:
这是这个函数的调用关系图:

◆ CheckMsgSize()

LITE_OS_SEC_TEXT STATIC UINT32 CheckMsgSize ( IpcMsg msg)

检查消息内容大小

从用户空间拷贝消息数据到内核空间

在文件 hm_liteipc.c951 行定义.

函数调用图:
这是这个函数的调用关系图:

◆ CheckPara()

LITE_OS_SEC_TEXT STATIC UINT32 CheckPara ( IpcContent content,
UINT32 dstTid 
)

检查参数,并获取目标 任务ID

在文件 hm_liteipc.c1049 行定义.

1050{
1051 UINT32 ret;
1052 IpcMsg *msg = content->outMsg;
1053 UINT32 flag = content->flag;
1054#if (USE_TIMESTAMP == 1)
1055 UINT64 now = LOS_CurrNanosec();
1056#endif
1057 if (((msg->dataSz > 0) && (msg->data == NULL)) ||
1058 ((msg->spObjNum > 0) && (msg->offsets == NULL)) ||
1059 (msg->dataSz > IPC_MSG_DATA_SZ_MAX) ||
1060 (msg->spObjNum > IPC_MSG_OBJECT_NUM_MAX) ||
1061 (msg->dataSz < msg->spObjNum * sizeof(SpecialObj))) {
1062 return -EINVAL;
1063 }
1064 switch (msg->type) {//消息类型
1065 case MT_REQUEST: //请求
1066 if (HasServiceAccess(msg->target.handle)) {//检查参数任务是否有权限访问当前进程
1067 ret = GetTid(msg->target.handle, dstTid);
1068 if (ret != LOS_OK) {
1069 return -EINVAL;
1070 }
1071 } else {
1072 PRINT_ERR("Liteipc %s, %d\n", __FUNCTION__, __LINE__);
1073 return -EACCES;
1074 }
1075#if (USE_TIMESTAMP == 1)
1076 msg->timestamp = now;//记录时间戳
1077#endif
1078 break;
1079 case MT_REPLY://回复
1080 case MT_FAILED_REPLY: //回复失败消息
1081 if ((flag & BUFF_FREE) != BUFF_FREE) {
1082 return -EINVAL;
1083 }
1084 if (!IsValidReply(content)) {
1085 return -EINVAL;
1086 }
1087#if (USE_TIMESTAMP == 1)
1088 if (now > msg->timestamp + LITEIPC_TIMEOUT_NS) {
1089#ifdef LOSCFG_KERNEL_HOOK
1090 ret = GetTid(msg->target.handle, dstTid);
1091 if (ret != LOS_OK) {
1092 *dstTid = INVAILD_ID;
1093 }
1094#endif
1095 OsHookCall(LOS_HOOK_TYPE_IPC_WRITE_DROP, msg, *dstTid,
1096 (*dstTid == INVAILD_ID) ? INVAILD_ID : OS_TCB_FROM_TID(*dstTid)->processID, 0);
1097 PRINT_ERR("Liteipc A timeout reply, request timestamp:%lld, now:%lld\n", msg->timestamp, now);
1098 return -ETIME;
1099 }
1100#endif
1101 *dstTid = msg->target.handle;
1102 break;
1103 case MT_DEATH_NOTIFY://死亡消息
1104 *dstTid = msg->target.handle;
1105#if (USE_TIMESTAMP == 1)
1106 msg->timestamp = now;
1107#endif
1108 break;
1109 default:
1110 PRINT_DEBUG("Unknow msg type:%d\n", msg->type);
1111 return -EINVAL;
1112 }
1113
1114 if (IsTaskAlive(*dstTid) == FALSE) {
1115 return -EINVAL;
1116 }
1117 return LOS_OK;
1118}
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_CurrNanosec(VOID)
获取自系统启动以来的纳秒数
Definition: los_hw_tick.c:62
LITE_OS_SEC_TEXT STATIC BOOL IsValidReply(const IpcContent *content)
是否有效回复
Definition: hm_liteipc.c:1030
LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
参数服务是否有访问当前进程的权限,实际中会有A进程的任务去给B进程发送IPC信息,所以需要鉴权
Definition: hm_liteipc.c:579
LITE_OS_SEC_TEXT STATIC BOOL IsTaskAlive(UINT32 taskID)
任务是否活跃
Definition: hm_liteipc.c:779
@ MT_FAILED_REPLY
回复失败
Definition: hm_liteipc.h:138
@ MT_DEATH_NOTIFY
死亡通知
Definition: hm_liteipc.h:139
@ MT_REPLY
回复
Definition: hm_liteipc.h:137
@ MT_REQUEST
请求
Definition: hm_liteipc.h:136
long unsigned int UINT64
Definition: los_typedef.h:66
UINT32 flag
Definition: hm_liteipc.h:204
IpcMsg * outMsg
Definition: hm_liteipc.h:205
UINT32 spObjNum
对象数量, 例如 spObjNum = 3时,offsets = [0,35,79],代表从data中读取 0 - 35给第一个对象,依次类推
Definition: hm_liteipc.h:181
SvcIdentity target
Definition: hm_liteipc.h:173
MsgType type
Definition: hm_liteipc.h:172
UINT32 dataSz
Definition: hm_liteipc.h:179
VOID * data
消息的内容,真正要传递的消息,这个数据内容是指spObjNum个数据的内容,定位就靠offsets
Definition: hm_liteipc.h:180
UINT64 timestamp
时间戳,用于验证
Definition: hm_liteipc.h:177
VOID * offsets
偏移量,注意这里有多少个spObjNum就会有多少个偏移量,详见 CopyDataFromUser 来理解
Definition: hm_liteipc.h:182
指定对象
Definition: hm_liteipc.h:127
UINT32 handle
Definition: hm_liteipc.h:116
函数调用图:
这是这个函数的调用关系图:

◆ CheckRecievedMsg()

LITE_OS_SEC_TEXT STATIC UINT32 CheckRecievedMsg ( IpcListNode node,
IpcContent content,
LosTaskCB tcb 
)

检查收到的消息

在文件 hm_liteipc.c1180 行定义.

1181{
1182 UINT32 ret = LOS_OK;
1183 if (node == NULL) {
1184 return -EINVAL;
1185 }
1186 switch (node->msg.type) { //消息类型
1187 case MT_REQUEST: //请求消息
1188 if ((content->flag & SEND) == SEND) {
1189 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1190 ret = -EINVAL;
1191 }
1192 break;
1193 case MT_FAILED_REPLY://回复失败
1194 ret = -ENOENT;
1195 /* fall-through */
1196 case MT_REPLY://回复
1197 if ((content->flag & SEND) != SEND) {
1198 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1199 ret = -EINVAL;
1200 }
1201#if (USE_TIMESTAMP == 1)
1202 if (node->msg.timestamp != content->outMsg->timestamp) {//检查时间戳
1203 PRINT_ERR("Recieve a unmatch reply, drop it\n");
1204 ret = -EINVAL;
1205 }
1206#else
1207 if ((node->msg.code != content->outMsg->code) ||
1208 (node->msg.target.token != content->outMsg->target.token)) {
1209 PRINT_ERR("Recieve a unmatch reply, drop it\n");
1210 ret = -EINVAL;
1211 }
1212#endif
1213 break;
1214 case MT_DEATH_NOTIFY:
1215 break;
1216 default:
1217 PRINT_ERR("Unknow msg type:%d\n", node->msg.type);
1218 ret = -EINVAL;
1219 }
1220 if (ret != LOS_OK) {
1221 OsHookCall(LOS_HOOK_TYPE_IPC_READ_DROP, &node->msg, tcb->waitFlag);
1222 (VOID)HandleSpecialObjects(LOS_CurTaskIDGet(), node, TRUE);
1223 (VOID)LiteIpcNodeFree(LOS_GetCurrProcessID(), (VOID *)node);
1224 } else {
1225 OsHookCall(LOS_HOOK_TYPE_IPC_READ, &node->msg, tcb->waitFlag);
1226 }
1227 return ret;
1228}
LITE_OS_SEC_TEXT UINT32 LOS_CurTaskIDGet(VOID)
Obtain current running task ID.
Definition: los_task.c:331
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcNodeFree(UINT32 processID, VOID *buf)
从IPC内存池中释放一个IPC节点
Definition: hm_liteipc.c:435
STATIC UINT32 HandleSpecialObjects(UINT32 dstTid, IpcListNode *node, BOOL isRollback)
Definition: hm_liteipc.c:912
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
Definition: los_process.c:2161
IpcMsg msg
内容体
Definition: hm_liteipc.h:192
UINT32 code
Definition: hm_liteipc.h:174
UINT32 token
Definition: hm_liteipc.h:117
UINT16 waitFlag
函数调用图:
这是这个函数的调用关系图:

◆ CheckUsedBuffer()

LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer ( const VOID *  node,
IpcListNode **  outPtr 
)

检查指定地址在当前进程已使用的BUF

在文件 hm_liteipc.c474 行定义.

475{
476 VOID *ptr = NULL;
478 IpcPool pool = pcb->ipcInfo->pool;//获取进程IPC内存池
479 if ((node == NULL) || ((INTPTR)node < (INTPTR)(pool.uvaddr)) ||
480 ((INTPTR)node > (INTPTR)(pool.uvaddr) + pool.poolSize)) {
481 return -EINVAL;
482 }
483 ptr = (VOID *)GetIpcKernelAddr(pcb->processID, (INTPTR)(node));//通过用户空间地址获取内核空间地址
484 if (IsIpcNode(pcb->processID, ptr) != TRUE) {//检查是否为IPC节点
485 return -EFAULT;
486 }
487 *outPtr = (IpcListNode *)ptr;//参数带走节点,内核空间地址
488 return LOS_OK;
489}
LITE_OS_SEC_TEXT STATIC INTPTR GetIpcKernelAddr(UINT32 processID, INTPTR userAddr)
获得IPC内核空间地址
Definition: hm_liteipc.c:467
LITE_OS_SEC_TEXT STATIC BOOL IsIpcNode(UINT32 processID, const VOID *buf)
指定buf 是否是IPC节点,这个函数不应该命名为 Is...容易误导 ,应改为 Free... @note_thinking
Definition: hm_liteipc.c:442
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
signed long INTPTR
Definition: los_typedef.h:69
LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层 用户态程序分别提供代表收取IPC消息的读操作和代表发送IPC消息的写操作。
Definition: hm_liteipc.h:82
UINT32 poolSize
ipc池大小
Definition: hm_liteipc.h:85
VOID * uvaddr
用户空间地址,由kvaddr映射而来的地址,这两个地址的关系一定要搞清楚,否则无法理解IPC的核心思想
Definition: hm_liteipc.h:83
IpcPool pool
ipc内存池,IPC操作所有涉及内核空间分配的内存均有此池提供
Definition: hm_liteipc.h:93
UINT32 processID
函数调用图:
这是这个函数的调用关系图:

◆ CopyDataFromUser()

LITE_OS_SEC_TEXT STATIC UINT32 CopyDataFromUser ( IpcListNode node,
UINT32  bufSz,
const IpcMsg msg 
)

在文件 hm_liteipc.c986 行定义.

987{
988 UINT32 ret;
989 ret = (UINT32)memcpy_s((VOID *)(&node->msg), bufSz - sizeof(LOS_DL_LIST), (const VOID *)msg, sizeof(IpcMsg));
990 if (ret != LOS_OK) {
991 PRINT_DEBUG("%s, %d, %u\n", __FUNCTION__, __LINE__, ret);
992 return ret;
993 }
994
995 if (msg->dataSz) {//消息的具体内容
996 node->msg.data = (VOID *)((UINTPTR)node + sizeof(IpcListNode));
997 ret = copy_from_user((VOID *)(node->msg.data), msg->data, msg->dataSz);//把真正的数据拷贝到其后
998 if (ret != LOS_OK) {
999 PRINT_DEBUG("%s, %d\n", __FUNCTION__, __LINE__);
1000 return ret;
1001 }
1002 } else {
1003 node->msg.data = NULL;
1004 }
1005
1006 if (msg->spObjNum) {//消息个数
1007 node->msg.offsets = (VOID *)((UINTPTR)node + sizeof(IpcListNode) + msg->dataSz);//将指针定位到放置偏移量的位置
1008 ret = copy_from_user((VOID *)(node->msg.offsets), msg->offsets, msg->spObjNum * sizeof(UINT32));//拷贝偏移量
1009 if (ret != LOS_OK) {
1010 PRINT_DEBUG("%s, %d, %x, %x, %d\n", __FUNCTION__, __LINE__, node->msg.offsets, msg->offsets, msg->spObjNum);
1011 return ret;
1012 }
1013 } else {
1014 node->msg.offsets = NULL;
1015 }
1016 ret = CheckMsgSize(&node->msg);
1017 if (ret != LOS_OK) {
1018 PRINT_DEBUG("%s, %d\n", __FUNCTION__, __LINE__);
1019 return ret;
1020 }
1021 node->msg.taskID = LOS_CurTaskIDGet();
1023#ifdef LOSCFG_SECURITY_CAPABILITY
1025 node->msg.gid = OsCurrProcessGet()->user->gid;
1026#endif
1027 return LOS_OK;
1028}
LITE_OS_SEC_TEXT STATIC UINT32 CheckMsgSize(IpcMsg *msg)
检查消息内容大小
Definition: hm_liteipc.c:951
unsigned long UINTPTR
Definition: los_typedef.h:68
UINT32 gid
组ID
Definition: hm_liteipc.h:187
UINT32 userID
用户ID
Definition: hm_liteipc.h:186
UINT32 processID
Definition: hm_liteipc.h:183
UINT32 taskID
Definition: hm_liteipc.h:184
User * user
进程的拥有者
UINT32 userID
用户ID [0,60000],0为root用户
UINT32 gid
用户组ID [0,60000],0为root用户组
函数调用图:
这是这个函数的调用关系图:

◆ DoIpcMmap()

LITE_OS_SEC_TEXT STATIC INT32 DoIpcMmap ( LosProcessCB pcb,
LosVmMapRegion region 
)

DoIpcMmap
做IPC层映射,将内核空间虚拟地址映射到用户空间,这样的好处是用户态下操作读写的背后是在读写内核态空间 如此用户地址和内核地址指向同一个物理地址

参数
pcb
region
返回
参见

在文件 hm_liteipc.c214 行定义.

215{
216 UINT32 i;
217 INT32 ret = 0;
218 PADDR_T pa;
219 UINT32 uflags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_USER;
220 LosVmPage *vmPage = NULL;
221 VADDR_T uva = (VADDR_T)(UINTPTR)pcb->ipcInfo->pool.uvaddr;//用户空间地址
222 VADDR_T kva = (VADDR_T)(UINTPTR)pcb->ipcInfo->pool.kvaddr;//内核空间地址
223
224 (VOID)LOS_MuxAcquire(&pcb->vmSpace->regionMux);
225
226 for (i = 0; i < (region->range.size >> PAGE_SHIFT); i++) {//获取线性区页数,一页一页映射
227 pa = LOS_PaddrQuery((VOID *)(UINTPTR)(kva + (i << PAGE_SHIFT)));//通过内核空间查找物理地址
228 if (pa == 0) {
229 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
230 ret = -EINVAL;
231 break;
232 }
233 vmPage = LOS_VmPageGet(pa);//获取物理页框
234 if (vmPage == NULL) {//目的是检查物理页是否存在
235 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
236 ret = -EINVAL;
237 break;
238 }
239 STATUS_T err = LOS_ArchMmuMap(&pcb->vmSpace->archMmu, uva + (i << PAGE_SHIFT), pa, 1, uflags);//将物理页映射到用户空间
240 if (err < 0) {
241 ret = err;
242 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
243 break;
244 }
245 }
246 /* if any failure happened, rollback | 如果中间发生映射失败,则回滚*/
247 if (i != (region->range.size >> PAGE_SHIFT)) {
248 while (i--) {
249 pa = LOS_PaddrQuery((VOID *)(UINTPTR)(kva + (i << PAGE_SHIFT)));//查询物理地址
250 vmPage = LOS_VmPageGet(pa);//获取物理页框
251 (VOID)LOS_ArchMmuUnmap(&pcb->vmSpace->archMmu, uva + (i << PAGE_SHIFT), 1);//取消与用户空间的映射
252 LOS_PhysPageFree(vmPage);//释放物理页
253 }
254 }
255
256 (VOID)LOS_MuxRelease(&pcb->vmSpace->regionMux);
257 return ret;
258}
STATUS_T LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间 所谓的map就是生成L1,L2页表项的过程
Definition: los_arch_mmu.c:891
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
unsigned long PADDR_T
Definition: los_typedef.h:207
signed int INT32
Definition: los_typedef.h:60
unsigned long VADDR_T
Definition: los_typedef.h:208
int STATUS_T
Definition: los_typedef.h:215
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
Definition: los_vm_page.c:120
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
Definition: los_vm_phys.c:546
VOID * kvaddr
内核空间地址,IPC申请的是内核空间,但是会通过 DoIpcMmap 将这个地址映射到用户空间
Definition: hm_liteipc.h:84
LosVmSpace * vmSpace
UINT32 size
Definition: los_vm_map.h:85
LosVmMapRange range
Definition: los_vm_map.h:123
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
LosMux regionMux
Definition: los_vm_map.h:149
LosArchMmu archMmu
Definition: los_vm_map.h:157
函数调用图:
这是这个函数的调用关系图:

◆ EnableIpcNodeFreeByUser()

LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser ( UINT32  processID,
VOID *  buf 
)

在文件 hm_liteipc.c414 行定义.

415{
416 UINT32 intSave;
417 ProcIpcInfo *ipcInfo = OS_PCB_FROM_PID(processID)->ipcInfo;
418 IpcUsedNode *node = (IpcUsedNode *)malloc(sizeof(IpcUsedNode));//申请一个可使用的节点,这里是向内核堆空间申请内存
419 if (node != NULL) {
420 node->ptr = buf;//指向参数缓存
421 IPC_LOCK(intSave);
422 LOS_ListAdd(&ipcInfo->ipcUsedNodelist, &node->list);//将OBJ_PTR类型的消息 挂到进程已使用链表上
423 IPC_UNLOCK(intSave);
424 }
425}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a new node to a doubly linked list.
Definition: los_list.h:217
void * malloc(size_t size)
动态分配内存块大小
Definition: malloc.c:81
注意 ipc节点和消息是两个概念, 一个消息会包含多个节点
Definition: hm_liteipc.c:104
LOS_DL_LIST list
通过它挂到对应 ProcIpcInfo.ipUsedNodeList 上
Definition: hm_liteipc.c:105
VOID * ptr
指向ipc节点内容
Definition: hm_liteipc.c:106
进程IPC信息,见于进程结构体: LosProcessCB.ipcInfo
Definition: hm_liteipc.h:92
LOS_DL_LIST ipcUsedNodelist
已使用节点链表,上面挂 IpcUsedNode 节点, 申请IpcUsedNode的内存来自内核堆空间
Definition: hm_liteipc.h:95
函数调用图:
这是这个函数的调用关系图:

◆ GenerateServiceHandle()

LITE_OS_SEC_TEXT STATIC UINT32 GenerateServiceHandle ( UINT32  taskID,
HandleStatus  status,
UINT32 serviceHandle 
)

任务 注册服务,LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列, 一个任务可以创建多个服务

在文件 hm_liteipc.c512 行定义.

513{
514 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
515#if (USE_TASKID_AS_HANDLE == 1)
516 *serviceHandle = taskID ? taskID : LOS_CurTaskIDGet(); /* if taskID is 0, return curTaskID | 如果任务ID为0,返回当地任务ID ,那么请问0号任务是谁 ???*/
517 if (*serviceHandle != g_cmsTask.taskID) {
519 return LOS_OK;
520 }
521#else
522 for (UINT32 i = 1; i < MAX_SERVICE_NUM; i++) {//每个任务都可以注册成一个服务,所有服务的上限等于任务的数量
523 if (g_serviceHandleMap[i].status == HANDLE_NOT_USED) {//找一个可用的服务
524 g_serviceHandleMap[i].taskID = taskID;//为哪个任务所占有
525 g_serviceHandleMap[i].status = status;//修改状态
526 *serviceHandle = i;//带走占用第几个服务, 注意这里服务的ID和任务的ID并不一致
528 return LOS_OK;
529 }
530 }
531#endif
533 return -EINVAL;
534}
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
释放锁
Definition: los_mux.c:559
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
Definition: los_mux.c:437
STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM]
g_serviceHandleMap[0]为ServiceManager,这块鸿蒙的设计挺怪的,让人很懵逼
Definition: hm_liteipc.c:115
STATIC HandleInfo g_cmsTask
整个系统只能有一个ServiceManager
Definition: hm_liteipc.c:113
STATIC LosMux g_serviceHandleMapMux
Definition: hm_liteipc.c:111
@ HANDLE_NOT_USED
未使用
Definition: hm_liteipc.h:62
HandleStatus status
状态
Definition: hm_liteipc.h:72
UINT32 taskID
任务ID,以任务标识句柄
Definition: hm_liteipc.h:73
函数调用图:
这是这个函数的调用关系图:

◆ GetIpcKernelAddr()

LITE_OS_SEC_TEXT STATIC INTPTR GetIpcKernelAddr ( UINT32  processID,
INTPTR  userAddr 
)

获得IPC内核空间地址

在文件 hm_liteipc.c467 行定义.

468{
469 IpcPool pool = OS_PCB_FROM_PID(processID)->ipcInfo->pool;
470 INTPTR offset = (INTPTR)(pool.uvaddr) - (INTPTR)(pool.kvaddr); //先计算偏移量,注意这里应该是个负数,因为用户空间在低地址位
471 return userAddr - offset;
472}
这是这个函数的调用关系图:

◆ GetIpcTaskID()

LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID ( UINT32  processID,
UINT32 ipcTaskID 
)

获取IPC任务ID

在文件 hm_liteipc.c624 行定义.

625{
626 if (OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID == INVAILD_ID) {
627 return LOS_NOK;
628 }
629 *ipcTaskID = OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID;
630 return LOS_OK;
631}
这是这个函数的调用关系图:

◆ GetIpcUserAddr()

LITE_OS_SEC_TEXT STATIC INTPTR GetIpcUserAddr ( UINT32  processID,
INTPTR  kernelAddr 
)

获得IPC用户空间地址

在文件 hm_liteipc.c460 行定义.

461{
462 IpcPool pool = OS_PCB_FROM_PID(processID)->ipcInfo->pool;
463 INTPTR offset = (INTPTR)(pool.uvaddr) - (INTPTR)(pool.kvaddr);//先计算偏移量,注意这里应该是个负数,因为内核空间在高地址位
464 return kernelAddr + offset; //再获取用户空间地址
465}
这是这个函数的调用关系图:

◆ GetTid()

LITE_OS_SEC_TEXT STATIC UINT32 GetTid ( UINT32  serviceHandle,
UINT32 taskID 
)

获取任务ID

在文件 hm_liteipc.c491 行定义.

492{
493 if (serviceHandle >= MAX_SERVICE_NUM) {//超过任务数
494 return -EINVAL;
495 }
496 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
497#if (USE_TASKID_AS_HANDLE == 1)
498 *taskID = serviceHandle ? serviceHandle : g_cmsTask.taskID;
500 return LOS_OK;
501#else
502 if (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTED) {//必须得是已注册
503 *taskID = g_serviceHandleMap[serviceHandle].taskID;//获取已注册服务的任务ID
505 return LOS_OK;
506 }
508 return -EINVAL;
509#endif
510}
@ HANDLE_REGISTED
已注册
Definition: hm_liteipc.h:64
函数调用图:
这是这个函数的调用关系图:

◆ HandleCmsCmd()

LITE_OS_SEC_TEXT STATIC UINT32 HandleCmsCmd ( CmsCmdContent content)

处理命令

在文件 hm_liteipc.c1357 行定义.

1358{
1359 UINT32 ret = LOS_OK;
1360 CmsCmdContent localContent;//接受用户空间数据的栈空间
1361 if (content == NULL) {
1362 return -EINVAL;
1363 }
1364 if (IsCmsTask(LOS_CurTaskIDGet()) == FALSE) {//当前任务是否为ServiceManager
1365 return -EACCES;
1366 }
1367 if (copy_from_user((void *)(&localContent), (const void *)content, sizeof(CmsCmdContent)) != LOS_OK) {//将数据从用户空间拷贝到内核栈空间
1368 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1369 return -EINVAL;
1370 }
1371 switch (localContent.cmd) {
1372 case CMS_GEN_HANDLE: // 创建服务/添加权限
1373 if ((localContent.taskID != 0) && (IsTaskAlive(localContent.taskID) == FALSE)) {
1374 return -EINVAL;
1375 }
1376 ret = GenerateServiceHandle(localContent.taskID, HANDLE_REGISTED, &(localContent.serviceHandle));//注册服务,得到服务ID
1377 if (ret == LOS_OK) {
1378 ret = copy_to_user((void *)content, (const void *)(&localContent), sizeof(CmsCmdContent));//多了个服务ID,将数据拷贝回用户空间,
1379 }
1380 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);//此处的AddServiceAccess 标识着 ServiceManager可以访问所有服务
1381 AddServiceAccess(g_cmsTask.taskID, localContent.serviceHandle);//@note_thinking 此处好像漏了 #if (USE_TASKID_AS_HANDLE == 1)
1383 break;
1384 case CMS_REMOVE_HANDLE: // 删除服务
1385 if (localContent.serviceHandle >= MAX_SERVICE_NUM) {
1386 return -EINVAL;
1387 }
1388 RefreshServiceHandle(localContent.serviceHandle, -1);// -1 代表服务停止/清空,可供其他任务使用
1389 break;
1390 case CMS_ADD_ACCESS: //添加权限
1391 if (IsTaskAlive(localContent.taskID) == FALSE) {
1392 return -EINVAL;
1393 }
1394 return AddServiceAccess(localContent.taskID, localContent.serviceHandle);//双向绑定
1395 default:
1396 PRINT_DEBUG("Unknow cmd cmd:%d\n", localContent.cmd);
1397 return -EINVAL;
1398 }
1399 return ret;
1400}
LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess(UINT32 taskID, UINT32 serviceHandle)
AddServiceAccess 配置访问权限,具有两层含义
Definition: hm_liteipc.c:559
LITE_OS_SEC_TEXT STATIC VOID RefreshServiceHandle(UINT32 serviceHandle, UINT32 result)
刷新指定服务, 多刷几次状态就变了, result != 0 时,服务停止
Definition: hm_liteipc.c:536
LITE_OS_SEC_TEXT STATIC BOOL IsCmsTask(UINT32 taskID)
指定任务是否为 ServiceManager
Definition: hm_liteipc.c:765
LITE_OS_SEC_TEXT STATIC UINT32 GenerateServiceHandle(UINT32 taskID, HandleStatus status, UINT32 *serviceHandle)
任务 注册服务,LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列, 一个任务可以创建多个服务
Definition: hm_liteipc.c:512
@ CMS_REMOVE_HANDLE
删除服务
Definition: hm_liteipc.h:156
@ CMS_GEN_HANDLE
创建/注册服务
Definition: hm_liteipc.h:155
@ CMS_ADD_ACCESS
为服务添加权限
Definition: hm_liteipc.h:157
UINT32 serviceHandle
服务ID
Definition: hm_liteipc.h:163
CmsCmd cmd
命令 例如注册命令:给taskID注册一个serviceHandle返回用户空间
Definition: hm_liteipc.h:161
UINT32 taskID
任务ID
Definition: hm_liteipc.h:162
函数调用图:
这是这个函数的调用关系图:

◆ HandleFd()

LITE_OS_SEC_TEXT STATIC UINT32 HandleFd ( UINT32  processID,
SpecialObj obj,
BOOL  isRollback 
)

按句柄方式处理, 参数 processID 往往不是当前进程

在文件 hm_liteipc.c798 行定义.

799{
800 int ret;
801 if (isRollback == FALSE) { // 不回滚
802 ret = CopyFdToProc(obj->content.fd, processID);//目的是将两个不同进程fd都指向同一个系统fd,共享FD的感觉
803 if (ret < 0) {//返回 processID 的 新 fd
804 return ret;
805 }
806 obj->content.fd = ret; // 记录 processID 的新FD, 可用于回滚
807 } else {// 回滚时关闭进程FD
808 ret = CloseProcFd(obj->content.fd, processID);
809 if (ret < 0) {
810 return ret;
811 }
812 }
813
814 return LOS_OK;
815}
ObjContent content
内容
Definition: hm_liteipc.h:129
UINT32 fd
文件描述符
Definition: hm_liteipc.h:122
int CopyFdToProc(int fd, unsigned int targetPid)
拷贝一个进程FD给指定的进程,使两个进程的FD都指向同一个系统FD
Definition: vfs_procfd.c:378
int CloseProcFd(int procFd, unsigned int targetPid)
关闭进程FD
Definition: vfs_procfd.c:431
函数调用图:
这是这个函数的调用关系图:

◆ HandleGetVersion()

LITE_OS_SEC_TEXT STATIC UINT32 HandleGetVersion ( IpcVersion version)

在文件 hm_liteipc.c1402 行定义.

1403{
1404 UINT32 ret = LOS_OK;
1405 IpcVersion localIpcVersion;
1406 if (version == NULL) {
1407 return -EINVAL;
1408 }
1409
1410 localIpcVersion.driverVersion = DRIVER_VERSION;
1411 ret = copy_to_user((void *)version, (const void *)(&localIpcVersion), sizeof(IpcVersion));
1412 if (ret != LOS_OK) {
1413 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1414 }
1415 return ret;
1416}
int32_t driverVersion
Definition: hm_liteipc.h:144
这是这个函数的调用关系图:

◆ HandleObj()

LITE_OS_SEC_TEXT STATIC UINT32 HandleObj ( UINT32  dstTid,
SpecialObj obj,
BOOL  isRollback 
)

创建处理对象,好复杂, 消息套消息

在文件 hm_liteipc.c891 行定义.

892{
893 UINT32 ret;
894 UINT32 processID = OS_TCB_FROM_TID(dstTid)->processID;//获取目标任务所在进程
895 switch (obj->type) {
896 case OBJ_FD://fd:文件描述符
897 ret = HandleFd(processID, obj, isRollback);
898 break;
899 case OBJ_PTR://指针方式消息
900 ret = HandlePtr(processID, obj, isRollback);
901 break;
902 case OBJ_SVC://服务类消息
903 ret = HandleSvc(dstTid, (SpecialObj *)obj, isRollback);
904 break;
905 default:
906 ret = -EINVAL;
907 break;
908 }
909 return ret;
910}
LITE_OS_SEC_TEXT STATIC UINT32 HandleFd(UINT32 processID, SpecialObj *obj, BOOL isRollback)
按句柄方式处理, 参数 processID 往往不是当前进程
Definition: hm_liteipc.c:798
LITE_OS_SEC_TEXT STATIC UINT32 HandleSvc(UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
按服务的方式处理,此处推断 Svc 应该是 service 的简写 @note_thinking
Definition: hm_liteipc.c:847
LITE_OS_SEC_TEXT STATIC UINT32 HandlePtr(UINT32 processID, SpecialObj *obj, BOOL isRollback)
按指针方式处理
Definition: hm_liteipc.c:817
@ OBJ_PTR
指针
Definition: hm_liteipc.h:106
@ OBJ_FD
文件句柄
Definition: hm_liteipc.h:105
@ OBJ_SVC
服务
Definition: hm_liteipc.h:107
ObjType type
类型
Definition: hm_liteipc.h:128
函数调用图:
这是这个函数的调用关系图:

◆ HandlePtr()

LITE_OS_SEC_TEXT STATIC UINT32 HandlePtr ( UINT32  processID,
SpecialObj obj,
BOOL  isRollback 
)

按指针方式处理

在文件 hm_liteipc.c817 行定义.

818{
819 VOID *buf = NULL;
820 UINT32 ret;
821 if ((obj->content.ptr.buff == NULL) || (obj->content.ptr.buffSz == 0)) {
822 return -EINVAL;
823 }
824 if (isRollback == FALSE) {
825 if (LOS_IsUserAddress((vaddr_t)(UINTPTR)(obj->content.ptr.buff)) == FALSE) { // 判断是否为用户空间地址
826 PRINT_ERR("Liteipc Bad ptr address\n"); //不在用户空间时
827 return -EINVAL;
828 }
829 buf = LiteIpcNodeAlloc(processID, obj->content.ptr.buffSz);//在内核空间分配内存接受来自用户空间的数据
830 if (buf == NULL) {
831 PRINT_ERR("Liteipc DealPtr alloc mem failed\n");
832 return -EINVAL;
833 }
834 ret = copy_from_user(buf, obj->content.ptr.buff, obj->content.ptr.buffSz);//从用户空间拷贝数据到内核空间
835 if (ret != LOS_OK) {
836 LiteIpcNodeFree(processID, buf);
837 return ret;
838 }//这里要说明下 obj->content.ptr.buff的变化,虽然都是用户空间的地址,但第二次已经意义变了,虽然数据一样,但指向的是申请经过拷贝后的内核空间
839 obj->content.ptr.buff = (VOID *)GetIpcUserAddr(processID, (INTPTR)buf);//获取进程 processID的用户空间地址,如此用户空间操作buf其实操作的是内核空间
840 EnableIpcNodeFreeByUser(processID, (VOID *)buf);//创建一个IPC节点,挂到可使用链表上,供读取
841 } else {
842 (VOID)LiteIpcNodeFree(processID, (VOID *)GetIpcKernelAddr(processID, (INTPTR)obj->content.ptr.buff));//在内核空间释放IPC节点
843 }
844 return LOS_OK;
845}
LITE_OS_SEC_TEXT STATIC INTPTR GetIpcUserAddr(UINT32 processID, INTPTR kernelAddr)
获得IPC用户空间地址
Definition: hm_liteipc.c:460
LITE_OS_SEC_TEXT STATIC VOID * LiteIpcNodeAlloc(UINT32 processID, UINT32 size)
注意这可是从内核空间的IPC池中申请内存
Definition: hm_liteipc.c:427
LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser(UINT32 processID, VOID *buf)
Definition: hm_liteipc.c:414
unsigned long vaddr_t
Definition: los_typedef.h:206
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
虚拟地址是否在用户空间
Definition: los_vm_map.h:275
VOID * buff
内容 内核需要将内容从用户空间拷贝到内核空间的动作
Definition: hm_liteipc.h:112
UINT32 buffSz
大小
Definition: hm_liteipc.h:111
BuffPtr ptr
缓存的开始地址,即:指针,消息从用户空间来时,要将内容拷贝到内核空间
Definition: hm_liteipc.h:123
函数调用图:
这是这个函数的调用关系图:

◆ HandleSpecialObjects()

LITE_OS_SEC_TEXT STATIC UINT32 HandleSpecialObjects ( UINT32  dstTid,
IpcListNode node,
BOOL  isRollback 
)

在文件 hm_liteipc.c912 行定义.

913{
914 UINT32 ret = LOS_OK;
915 IpcMsg *msg = &(node->msg);
916 INT32 i;
917 SpecialObj *obj = NULL;
918 UINT32 *offset = (UINT32 *)(UINTPTR)(msg->offsets);//拿到消息偏移量
919 if (isRollback) {//如果需要回滚
920 i = msg->spObjNum;
921 goto EXIT;
922 }
923 for (i = 0; i < msg->spObjNum; i++) {//遍历消息个数
924 if (offset[i] > msg->dataSz - sizeof(SpecialObj)) {
925 ret = -EINVAL;
926 goto EXIT;
927 }
928 if ((i > 0) && (offset[i] < offset[i - 1] + sizeof(SpecialObj))) {
929 ret = -EINVAL;
930 goto EXIT;
931 }
932 obj = (SpecialObj *)((UINTPTR)msg->data + offset[i]);//一个个拿消息对象
933 if (obj == NULL) {
934 ret = -EINVAL;
935 goto EXIT;
936 }
937 ret = HandleObj(dstTid, obj, FALSE);//一个个处理对象,三种消息对象
938 if (ret != LOS_OK) {
939 goto EXIT;
940 }
941 }
942 return LOS_OK;
943EXIT://异常回滚处理
944 for (i--; i >= 0; i--) {
945 obj = (SpecialObj *)((UINTPTR)msg->data + offset[i]);
946 (VOID)HandleObj(dstTid, obj, TRUE);
947 }
948 return ret;
949}
LITE_OS_SEC_TEXT STATIC UINT32 HandleObj(UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
创建处理对象,好复杂, 消息套消息
Definition: hm_liteipc.c:891
函数调用图:
这是这个函数的调用关系图:

◆ HandleSvc()

LITE_OS_SEC_TEXT STATIC UINT32 HandleSvc ( UINT32  dstTid,
SpecialObj obj,
BOOL  isRollback 
)

按服务的方式处理,此处推断 Svc 应该是 service 的简写 @note_thinking

在文件 hm_liteipc.c847 行定义.

848{
849 UINT32 taskID = 0;
850 if (isRollback == FALSE) {
851 if (obj->content.svc.handle == -1) {
852 if (obj->content.svc.token != 1) {
853 PRINT_ERR("Liteipc HandleSvc wrong svc token\n");
854 return -EINVAL;
855 }
856 UINT32 selfTid = LOS_CurTaskIDGet();
857 LosTaskCB *tcb = OS_TCB_FROM_TID(selfTid);
858 if (tcb->ipcTaskInfo == NULL) {
860 }
861 uint32_t serviceHandle = 0;
862 UINT32 ret = GenerateServiceHandle(selfTid, HANDLE_REGISTED, &serviceHandle);
863 if (ret != LOS_OK) {
864 PRINT_ERR("Liteipc GenerateServiceHandle failed.\n");
865 return ret;
866 }
867 obj->content.svc.handle = serviceHandle;
868 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
869 AddServiceAccess(dstTid, serviceHandle);
871 }
872 if (IsTaskAlive(obj->content.svc.handle) == FALSE) {
873 PRINT_ERR("Liteipc HandleSvc wrong svctid\n");
874 return -EINVAL;
875 }
876 if (HasServiceAccess(obj->content.svc.handle) == FALSE) {
877 PRINT_ERR("Liteipc %s, %d, svchandle:%d, tid:%d\n", __FUNCTION__, __LINE__, obj->content.svc.handle, LOS_CurTaskIDGet());
878 return -EACCES;
879 }
880 LosTaskCB *taskCb = OS_TCB_FROM_TID(obj->content.svc.handle);
881 if (taskCb->ipcTaskInfo == NULL) {
882 taskCb->ipcTaskInfo = LiteIpcTaskInit();
883 }
884 if (GetTid(obj->content.svc.handle, &taskID) == 0) {//获取参数消息服务ID所属任务
885 AddServiceAccess(dstTid, obj->content.svc.handle);
886 }
887 }
888 return LOS_OK;
889}
LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo * LiteIpcTaskInit(VOID)
申请并初始化一个任务IPC
Definition: hm_liteipc.c:400
SvcIdentity svc
服务,用于设置访问权限
Definition: hm_liteipc.h:124
函数调用图:
这是这个函数的调用关系图:

◆ HasServiceAccess()

LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess ( UINT32  serviceHandle)

参数服务是否有访问当前进程的权限,实际中会有A进程的任务去给B进程发送IPC信息,所以需要鉴权

在文件 hm_liteipc.c579 行定义.

580{
581 UINT32 serviceTid = 0;
582 UINT32 curProcessID = LOS_GetCurrProcessID();//获取当前进程ID
583 UINT32 ret;
584 if (serviceHandle >= MAX_SERVICE_NUM) {
585 return FALSE;
586 }
587 if (serviceHandle == 0) {
588 return TRUE;
589 }
590 ret = GetTid(serviceHandle, &serviceTid);//获取参数服务所属任务ID
591 if (ret != LOS_OK) {
592 PRINT_ERR("Liteipc HasServiceAccess GetTid failed\n");
593 return FALSE;
594 }
595 if (OS_TCB_FROM_TID(serviceTid)->processID == curProcessID) {//如果任务所在进程就是当前进程,直接返回OK
596 return TRUE;
597 }
598
599 if (OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo == NULL) {//如果参数任务没有开通处理IPC信息功能
600 return FALSE;
601 }
602
603 return OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo->accessMap[curProcessID];//返回任务访问进程的权限
604}
函数调用图:
这是这个函数的调用关系图:

◆ IsCmsSet()

LITE_OS_SEC_TEXT STATIC BOOL IsCmsSet ( VOID  )

是否设置了 ServiceManager 整个系统只能有一个ServiceManager,而Service可以有多个。 ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。

在文件 hm_liteipc.c752 行定义.

753{
754 BOOL ret;
755 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
756#if (USE_TASKID_AS_HANDLE == 1)
757 ret = g_cmsTask.status == HANDLE_REGISTED; //已注册ServiceManager
758#else
759 ret = g_serviceHandleMap[0].status == HANDLE_REGISTED;//已注册 ServiceManager
760#endif
762 return ret;
763}
size_t BOOL
Definition: los_typedef.h:88
函数调用图:
这是这个函数的调用关系图:

◆ IsCmsTask()

LITE_OS_SEC_TEXT STATIC BOOL IsCmsTask ( UINT32  taskID)

指定任务是否为 ServiceManager

在文件 hm_liteipc.c765 行定义.

766{
767 BOOL ret;
768 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
769#if (USE_TASKID_AS_HANDLE == 1)
770 ret = IsCmsSet() ? (OS_TCB_FROM_TID(taskID)->processID == OS_TCB_FROM_TID(g_cmsTask.taskID)->processID) : FALSE;//对比任务的进程和已注册ServiceManager是否一致
771#else
772 ret = IsCmsSet() ? (OS_TCB_FROM_TID(taskID)->processID ==
773 OS_TCB_FROM_TID(g_serviceHandleMap[0].taskID)->processID) : FALSE; // g_serviceHandleMap[0] 为 ServiceManager, 把ServiceManager和service放一块很怪!!! @note_thinking
774#endif
776 return ret;
777}
LITE_OS_SEC_TEXT STATIC BOOL IsCmsSet(VOID)
Definition: hm_liteipc.c:752
函数调用图:
这是这个函数的调用关系图:

◆ IsIpcNode()

LITE_OS_SEC_TEXT STATIC BOOL IsIpcNode ( UINT32  processID,
const VOID *  buf 
)

指定buf 是否是IPC节点,这个函数不应该命名为 Is...容易误导 ,应改为 Free... @note_thinking

在文件 hm_liteipc.c442 行定义.

443{
444 IpcUsedNode *node = NULL;
445 UINT32 intSave;
446 ProcIpcInfo *ipcInfo = OS_PCB_FROM_PID(processID)->ipcInfo;//获取进程的IPC信息
447 IPC_LOCK(intSave);
448 LOS_DL_LIST_FOR_EACH_ENTRY(node, &ipcInfo->ipcUsedNodelist, IpcUsedNode, list) {//遍历已使用IPC节点
449 if (node->ptr == buf) {//如果一致
450 LOS_ListDelete(&node->list);//从已使用链表上摘除
451 IPC_UNLOCK(intSave);
452 free(node);//释放内核堆内存
453 return TRUE;
454 }
455 }
456 IPC_UNLOCK(intSave);
457 return FALSE;
458}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
void free(void *ptr)
释放ptr所指向的内存空间
Definition: malloc.c:66
函数调用图:
这是这个函数的调用关系图:

◆ IsIpcTaskSet()

LITE_OS_SEC_TEXT BOOL IsIpcTaskSet ( VOID  )

是否设置ipc任务ID

在文件 hm_liteipc.c616 行定义.

617{
618 if (OsCurrProcessGet()->ipcInfo->ipcTaskID == INVAILD_ID) {
619 return FALSE;
620 }
621 return TRUE;
622}
函数调用图:

◆ IsPoolMapped()

LITE_OS_SEC_TEXT STATIC BOOL IsPoolMapped ( ProcIpcInfo ipcInfo)

池是否已经映射

在文件 hm_liteipc.c198 行定义.

199{
200 return (ipcInfo->pool.uvaddr != NULL) && (ipcInfo->pool.kvaddr != NULL) &&
201 (ipcInfo->pool.poolSize != 0);
202}
这是这个函数的调用关系图:

◆ IsTaskAlive()

LITE_OS_SEC_TEXT STATIC BOOL IsTaskAlive ( UINT32  taskID)

任务是否活跃

在文件 hm_liteipc.c779 行定义.

780{
781 LosTaskCB *tcb = NULL;
782 if (OS_TID_CHECK_INVALID(taskID)) { //检查是否存在
783 return FALSE;
784 }
785 tcb = OS_TCB_FROM_TID(taskID); //获取任务控制块
786 if (!OsTaskIsUserMode(tcb)) {
787 return FALSE;
788 }
789 if (OsTaskIsUnused(tcb)) {
790 return FALSE;
791 }
792 if (OsTaskIsInactive(tcb)) {//任务是否活跃
793 return FALSE;
794 }
795 return TRUE;
796}
STATIC INLINE BOOL OsTaskIsInactive(const LosTaskCB *taskCB)
STATIC INLINE BOOL OsTaskIsUserMode(const LosTaskCB *taskCB)
Definition: los_task_pri.h:265
STATIC INLINE BOOL OsTaskIsUnused(const LosTaskCB *taskCB)
任务是否在使用
Definition: los_task_pri.h:255
函数调用图:
这是这个函数的调用关系图:

◆ IsValidReply()

LITE_OS_SEC_TEXT STATIC BOOL IsValidReply ( const IpcContent content)

是否有效回复

在文件 hm_liteipc.c1030 行定义.

1031{
1032 UINT32 curProcessID = LOS_GetCurrProcessID();
1033 IpcListNode *node = (IpcListNode *)GetIpcKernelAddr(curProcessID, (INTPTR)(content->buffToFree));//通过用户空间地址获取内核地址
1034 IpcMsg *requestMsg = &node->msg;
1035 IpcMsg *replyMsg = content->outMsg;
1036 UINT32 reqDstTid = 0;
1037 /* Check whether the reply matches the request */
1038 if ((requestMsg->type != MT_REQUEST) || //判断条件
1039 (requestMsg->flag == LITEIPC_FLAG_ONEWAY) ||
1040 (replyMsg->timestamp != requestMsg->timestamp) ||
1041 (replyMsg->target.handle != requestMsg->taskID) ||
1042 (GetTid(requestMsg->target.handle, &reqDstTid) != 0) ||
1043 (OS_TCB_FROM_TID(reqDstTid)->processID != curProcessID)) {
1044 return FALSE;
1045 }
1046 return TRUE;
1047}
@ LITEIPC_FLAG_ONEWAY
Definition: hm_liteipc.h:168
VOID * buffToFree
Definition: hm_liteipc.h:207
UINT32 flag
标签
Definition: hm_liteipc.h:175
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcClose()

LITE_OS_SEC_TEXT STATIC int LiteIpcClose ( struct file filep)

在文件 hm_liteipc.c193 行定义.

194{
195 return 0;
196}

◆ LiteIpcIoctl()

LITE_OS_SEC_TEXT int LiteIpcIoctl ( struct file filep,
int  cmd,
unsigned long  arg 
)

真正的 IPC 控制操作

在文件 hm_liteipc.c1418 行定义.

1419{
1420 UINT32 ret = LOS_OK;
1422 ProcIpcInfo *ipcInfo = pcb->ipcInfo;
1423
1424 if (ipcInfo == NULL) {
1425 PRINT_ERR("Liteipc pool not create!\n");
1426 return -EINVAL;
1427 }
1428
1429 if (IsPoolMapped(ipcInfo) == FALSE) {
1430 PRINT_ERR("Liteipc Ipc pool not init, need to mmap first!\n");
1431 return -ENOMEM;
1432 }
1433 // 整个系统只能有一个ServiceManager,而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,
1434 // 二是负责管理Service的访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。
1435 switch (cmd) {
1436 case IPC_SET_CMS:
1437 return (INT32)SetCms(arg); //设置ServiceManager , 整个系统只能有一个ServiceManager
1438 case IPC_CMS_CMD: // 控制命令,创建/删除/添加权限
1439 return (INT32)HandleCmsCmd((CmsCmdContent *)(UINTPTR)arg);
1440 case IPC_GET_VERSION:
1441 return (INT32)HandleGetVersion((IpcVersion *)(UINTPTR)arg);
1442 case IPC_SET_IPC_THREAD://
1443 if (IsCmsSet() == FALSE) {//如果还没有指定 ServiceManager
1444 PRINT_ERR("Liteipc ServiceManager not set!\n");
1445 return -EINVAL;
1446 }
1447 return (INT32)SetIpcTask();//将当前任务设置成当前进程的IPC任务ID
1448 case IPC_SEND_RECV_MSG://发送和接受消息,代表消息内容
1449 if (arg == 0) {
1450 return -EINVAL;
1451 }
1452 if (IsCmsSet() == FALSE) {
1453 PRINT_ERR("Liteipc ServiceManager not set!\n");
1454 return -EINVAL;
1455 }
1456 ret = LiteIpcMsgHandle((IpcContent *)(UINTPTR)arg);//处理IPC消息
1457 if (ret != LOS_OK) {
1458 return (INT32)ret;
1459 }
1460 break;
1461 default:
1462 PRINT_ERR("Unknow liteipc ioctl cmd:%d\n", cmd);
1463 return -EINVAL;
1464 }
1465 return (INT32)ret;
1466}
LITE_OS_SEC_TEXT STATIC UINT32 HandleCmsCmd(CmsCmdContent *content)
处理命令
Definition: hm_liteipc.c:1357
LITE_OS_SEC_TEXT STATIC BOOL IsPoolMapped(ProcIpcInfo *ipcInfo)
池是否已经映射
Definition: hm_liteipc.c:198
LITE_OS_SEC_TEXT STATIC UINT32 SetIpcTask(VOID)
将当前任务设置成进程ipc的任务ID
Definition: hm_liteipc.c:606
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle(IpcContent *con)
处理 IPC 消息
Definition: hm_liteipc.c:1287
LITE_OS_SEC_TEXT STATIC UINT32 HandleGetVersion(IpcVersion *version)
Definition: hm_liteipc.c:1402
LITE_OS_SEC_TEXT STATIC UINT32 SetCms(UINTPTR maxMsgSize)
设置CMS
Definition: hm_liteipc.c:725
IPC消息内容结构体,记录消息周期
Definition: hm_liteipc.h:203
函数调用图:

◆ LiteIpcMmap()

LITE_OS_SEC_TEXT STATIC int LiteIpcMmap ( struct file filep,
LosVmMapRegion region 
)

将参数线性区设为IPC专用区

在文件 hm_liteipc.c260 行定义.

261{
262 int ret = 0;
263 LosVmMapRegion *regionTemp = NULL;
265 ProcIpcInfo *ipcInfo = pcb->ipcInfo;
266 //被映射的线性区不能在常量和私有数据区
267 if ((ipcInfo == NULL) || (region == NULL) || (region->range.size > LITE_IPC_POOL_MAX_SIZE) ||
269 ret = -EINVAL;
270 goto ERROR_REGION_OUT;
271 }
272 if (IsPoolMapped(ipcInfo)) {//已经用户空间和内核空间之间存在映射关系了
273 return -EEXIST;
274 }
275 if (ipcInfo->pool.uvaddr != NULL) {//ipc池已在进程空间有地址
276 regionTemp = LOS_RegionFind(pcb->vmSpace, (VADDR_T)(UINTPTR)ipcInfo->pool.uvaddr);//在指定进程空间中找到所在线性区
277 if (regionTemp != NULL) {
278 (VOID)LOS_RegionFree(pcb->vmSpace, regionTemp);//先释放线性区
279 }
280 // 建议加上 ipcInfo->pool.uvaddr = NULL; 同下
281 }
282 ipcInfo->pool.uvaddr = (VOID *)(UINTPTR)region->range.base;//将指定的线性区和ipc池虚拟地址绑定
283 if (ipcInfo->pool.kvaddr != NULL) {//如果存在内核空间地址
284 LOS_VFree(ipcInfo->pool.kvaddr);//因为要重新映射,所以必须先释放掉物理内存
285 ipcInfo->pool.kvaddr = NULL; //从效果上看, 这句话可以不加,但加上看着更舒服, uvaddr 和 kvaddr 一对新人迎接美好未来
286 }
287 /* use vmalloc to alloc phy mem */
288 ipcInfo->pool.kvaddr = LOS_VMalloc(region->range.size);//从内核动态空间中申请线性区,分配同等量的物理内存,做好 内核 <-->物理内存的映射
289 if (ipcInfo->pool.kvaddr == NULL) {//申请物理内存失败, 肯定是玩不下去了.
290 ret = -ENOMEM; //返回没有内存了
291 goto ERROR_REGION_OUT;
292 }
293 /* do mmap */
294 ret = DoIpcMmap(pcb, region);//对uvaddr和kvaddr做好映射关系,如此用户态下通过操作uvaddr达到操作kvaddr的目的
295 if (ret) {
296 goto ERROR_MAP_OUT;
297 }
298 /* ipc pool init | ipc单独创建了内存池管理*/
299 if (LOS_MemInit(ipcInfo->pool.kvaddr, region->range.size) != LOS_OK) {//初始化ipc池
300 ret = -EINVAL;
301 goto ERROR_MAP_OUT;
302 }
303 ipcInfo->pool.poolSize = region->range.size;//ipc池大小为线性区大小
304 return 0;
305ERROR_MAP_OUT:
306 LOS_VFree(ipcInfo->pool.kvaddr);
307ERROR_REGION_OUT:
308 if (ipcInfo != NULL) {
309 ipcInfo->pool.uvaddr = NULL;
310 ipcInfo->pool.kvaddr = NULL;
311 }
312 return ret;
313}
UINT32 LOS_MemInit(VOID *pool, UINT32 size)
LOS_MemInit 初始化一块指定的动态内存池,大小为size 初始一个内存池后生成一个内存池控制头、尾节点EndNode,剩余的内存被标记为FreeNode内存节点。
Definition: los_memory.c:1021
LITE_OS_SEC_TEXT STATIC INT32 DoIpcMmap(LosProcessCB *pcb, LosVmMapRegion *region)
DoIpcMmap 做IPC层映射,将内核空间虚拟地址映射到用户空间,这样的好处是用户态下操作读写的背后是在读写内核态空间 如此用户地址和内核地址指向同一个物理地址
Definition: hm_liteipc.c:214
VOID LOS_VFree(const VOID *addr)
STATIC INLINE BOOL LOS_IsRegionPermUserReadOnly(LosVmMapRegion *region)
permanent 用户进程永久/常驻区
Definition: los_vm_map.h:239
LosVmMapRegion * LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
查找线性区 根据起始地址在进程空间内查找是否存在
Definition: los_vm_map.c:414
STATIC INLINE BOOL LOS_IsRegionFlagPrivateOnly(LosVmMapRegion *region)
是否为私有线性区
Definition: los_vm_map.h:245
STATUS_T LOS_RegionFree(LosVmSpace *space, LosVmMapRegion *region)
释放进程空间指定线性区
Definition: los_vm_map.c:694
VOID * LOS_VMalloc(size_t size)
VADDR_T base
Definition: los_vm_map.h:84
函数调用图:

◆ LiteIpcMsgHandle()

LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle ( IpcContent con)

处理 IPC 消息

在文件 hm_liteipc.c1287 行定义.

1288{
1289 UINT32 ret = LOS_OK;
1290 IpcContent localContent;
1291 IpcContent *content = &localContent;
1292 IpcMsg localMsg;
1293 IpcMsg *msg = &localMsg;
1294 IpcListNode *nodeNeedFree = NULL;
1295
1296 if (copy_from_user((void *)content, (const void *)con, sizeof(IpcContent)) != LOS_OK) {
1297 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1298 return -EINVAL;
1299 }
1300
1301 if ((content->flag & BUFF_FREE) == BUFF_FREE) { //释放buf
1302 ret = CheckUsedBuffer(content->buffToFree, &nodeNeedFree);
1303 if (ret != LOS_OK) {
1304 PRINT_ERR("CheckUsedBuffer failed:%d\n", ret);
1305 return ret;
1306 }
1307 }
1308
1309 if ((content->flag & SEND) == SEND) { // 向外发送
1310 if (content->outMsg == NULL) {
1311 PRINT_ERR("content->outmsg is null\n");
1312 ret = -EINVAL;
1313 goto BUFFER_FREE;
1314 }// 1. 先将用户空间过来的消息拷贝到内核空间 (先拷贝壳)
1315 if (copy_from_user((void *)msg, (const void *)content->outMsg, sizeof(IpcMsg)) != LOS_OK) {
1316 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1317 ret = -EINVAL;
1318 goto BUFFER_FREE;
1319 }
1320 content->outMsg = msg;// outMsg 指向内核空间
1321 if ((content->outMsg->type < 0) || (content->outMsg->type >= MT_DEATH_NOTIFY)) {
1322 PRINT_ERR("LiteIpc unknown msg type:%d\n", content->outMsg->type);
1323 ret = -EINVAL;
1324 goto BUFFER_FREE;
1325 }
1326 ret = LiteIpcWrite(content);//写消息
1327 if (ret != LOS_OK) {
1328 PRINT_ERR("LiteIpcWrite failed\n");
1329 goto BUFFER_FREE;
1330 }
1331 }
1332BUFFER_FREE:
1333 if (nodeNeedFree != NULL) {
1334 UINT32 freeRet = LiteIpcNodeFree(LOS_GetCurrProcessID(), nodeNeedFree);
1335 ret = (freeRet == LOS_OK) ? ret : freeRet;
1336 }
1337 if (ret != LOS_OK) {
1338 return ret;
1339 }
1340
1341 if ((content->flag & RECV) == RECV) {//接收到消息
1342 ret = LiteIpcRead(content);
1343 if (ret != LOS_OK) {
1344 PRINT_ERR("LiteIpcRead failed ERROR: %d\n", (INT32)ret);
1345 return ret;
1346 }
1347 UINT32 offset = LOS_OFF_SET_OF(IpcContent, inMsg);
1348 ret = copy_to_user((char*)con + offset, (char*)content + offset, sizeof(IpcMsg *));
1349 if (ret != LOS_OK) {
1350 PRINT_ERR("%s, %d, %d\n", __FUNCTION__, __LINE__, ret);
1351 return -EINVAL;
1352 }
1353 }
1354 return ret;
1355}
LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer(const VOID *node, IpcListNode **outPtr)
检查指定地址在当前进程已使用的BUF
Definition: hm_liteipc.c:474
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcRead(IpcContent *content)
读取IPC消息
Definition: hm_liteipc.c:1230
STATIC UINT32 LiteIpcWrite(IpcContent *content)
写IPC消息队列,从用户空间到内核空间
Definition: hm_liteipc.c:1120
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcNodeAlloc()

LITE_OS_SEC_TEXT STATIC VOID * LiteIpcNodeAlloc ( UINT32  processID,
UINT32  size 
)

注意这可是从内核空间的IPC池中申请内存

在文件 hm_liteipc.c427 行定义.

428{
429 VOID *ptr = LOS_MemAlloc(OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, size);//kvaddr实际指向了内核空间
430 PRINT_INFO("LiteIpcNodeAlloc pid:%d, pool:%x buf:%x size:%d\n",
431 processID, OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, ptr, size);
432 return ptr;
433}
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcNodeFree()

LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcNodeFree ( UINT32  processID,
VOID *  buf 
)

从IPC内存池中释放一个IPC节点

在文件 hm_liteipc.c435 行定义.

436{
437 PRINT_INFO("LiteIpcNodeFree pid:%d, pool:%x buf:%x\n",
438 processID, OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, buf);
439 return LOS_MemFree(OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, buf);
440}
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcOpen()

LITE_OS_SEC_TEXT STATIC int LiteIpcOpen ( struct file filep)

LiteIpcOpen 以VFS方式为当前进程创建IPC消息池

参数
filep
返回
参见

在文件 hm_liteipc.c178 行定义.

179{
181 if (pcb->ipcInfo != NULL) {
182 return 0;
183 }
184
185 pcb->ipcInfo = LiteIpcPoolCreate();
186 if (pcb->ipcInfo == NULL) {
187 return -ENOMEM;
188 }
189
190 return 0;
191}
STATIC ProcIpcInfo * LiteIpcPoolCreate(VOID)
创建IPC消息内存池
Definition: hm_liteipc.c:325
函数调用图:

◆ LiteIpcPoolCreate()

LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo * LiteIpcPoolCreate ( VOID  )

创建IPC消息内存池

在文件 hm_liteipc.c325 行定义.

326{
327 ProcIpcInfo *ipcInfo = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcIpcInfo));//从内核堆内存中申请IPC控制体
328 if (ipcInfo == NULL) {
329 return NULL;
330 }
331
332 (VOID)memset_s(ipcInfo, sizeof(ProcIpcInfo), 0, sizeof(ProcIpcInfo));
333
334 (VOID)LiteIpcPoolInit(ipcInfo);
335 return ipcInfo;
336}
UINT8 * m_aucSysMem1
系统动态内存池地址的起始地址 @note_thinking 能否不要用 0,1来命名核心变量 ???
Definition: los_memory.c:108
LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
初始化进程的IPC内存池
Definition: hm_liteipc.c:315
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcPoolDelete()

STATIC VOID LiteIpcPoolDelete ( ProcIpcInfo ipcInfo,
UINT32  processID 
)

释放进程的IPC消息内存池

在文件 hm_liteipc.c360 行定义.

361{
362 UINT32 intSave;
363 IpcUsedNode *node = NULL;
364 if (ipcInfo->pool.kvaddr != NULL) {//如果占用内核空间线性区
365 LOS_VFree(ipcInfo->pool.kvaddr);//释放线性区
366 ipcInfo->pool.kvaddr = NULL;
367 IPC_LOCK(intSave);
368 while (!LOS_ListEmpty(&ipcInfo->ipcUsedNodelist)) {//对进程的IPC已被读取的链表遍历
369 node = LOS_DL_LIST_ENTRY(ipcInfo->ipcUsedNodelist.pstNext, IpcUsedNode, list);//一个个读取
370 LOS_ListDelete(&node->list);//将自己从链表上摘出去
371 free(node);//释放向内核堆内存申请的 sizeof(IpcUsedNode) 空间
372 }
373 IPC_UNLOCK(intSave);
374 }
375 /* remove process access to service | 删除进程对服务的访问,这里的服务指的就是任务*/
376 for (UINT32 i = 0; i < MAX_SERVICE_NUM; i++) {//双方断交
377 if (ipcInfo->access[i] == TRUE) {//允许访问
378 ipcInfo->access[i] = FALSE; //设为不允许访问
379 if (OS_TCB_FROM_TID(i)->ipcTaskInfo != NULL) {//任务有IPC时
380 OS_TCB_FROM_TID(i)->ipcTaskInfo->accessMap[processID] = FALSE;//同样设置任务也不允许访问进程
381 }
382 }
383 }
384}
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
Definition: los_list.h:321
struct LOS_DL_LIST * pstNext
Definition: los_list.h:84
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcPoolDestroy()

LITE_OS_SEC_TEXT UINT32 LiteIpcPoolDestroy ( UINT32  processID)

销毁指定进程的IPC池

在文件 hm_liteipc.c386 行定义.

387{
388 LosProcessCB *pcb = OS_PCB_FROM_PID(processID);
389
390 if (pcb->ipcInfo == NULL) {
391 return LOS_NOK;
392 }
393
396 pcb->ipcInfo = NULL;
397 return LOS_OK;
398}
STATIC VOID LiteIpcPoolDelete(ProcIpcInfo *ipcInfo, UINT32 processID)
释放进程的IPC消息内存池
Definition: hm_liteipc.c:360
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcPoolInit()

LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit ( ProcIpcInfo ipcInfo)

初始化进程的IPC内存池

在文件 hm_liteipc.c315 行定义.

316{
317 ipcInfo->pool.uvaddr = NULL;
318 ipcInfo->pool.kvaddr = NULL;
319 ipcInfo->pool.poolSize = 0;
320 ipcInfo->ipcTaskID = INVAILD_ID;
321 LOS_ListInit(&ipcInfo->ipcUsedNodelist);//上面将挂已使用的节点
322 return LOS_OK;
323}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
UINT32 ipcTaskID
指定能ServiceManager的任务ID
Definition: hm_liteipc.h:94
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcPoolReInit()

LITE_OS_SEC_TEXT ProcIpcInfo * LiteIpcPoolReInit ( const ProcIpcInfo parent)

LiteIpcPoolReInit 重新初始化进程的IPC消息内存池

参数
parent
返回
参见

在文件 hm_liteipc.c346 行定义.

347{
348 ProcIpcInfo *ipcInfo = LiteIpcPoolCreate();
349 if (ipcInfo == NULL) {
350 return NULL;
351 }
352
353 ipcInfo->pool.uvaddr = parent->pool.uvaddr;//用户空间地址继续沿用
354 ipcInfo->pool.kvaddr = NULL;
355 ipcInfo->pool.poolSize = 0;
356 ipcInfo->ipcTaskID = INVAILD_ID;
357 return ipcInfo;
358}
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcRead()

LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcRead ( IpcContent content)

读取IPC消息

在文件 hm_liteipc.c1230 行定义.

1231{
1232 UINT32 intSave, ret;
1233 UINT32 selfTid = LOS_CurTaskIDGet();//当前任务ID
1234 LOS_DL_LIST *listHead = NULL;
1235 LOS_DL_LIST *listNode = NULL;
1236 IpcListNode *node = NULL;
1237 UINT32 syncFlag = (content->flag & SEND) && (content->flag & RECV);//同步标签
1238 UINT32 timeout = syncFlag ? LOS_MS2Tick(LITEIPC_TIMEOUT_MS) : LOS_WAIT_FOREVER;
1239
1240 LosTaskCB *tcb = OS_TCB_FROM_TID(selfTid);//获取当前任务实体
1241 if (tcb->ipcTaskInfo == NULL) {//如果任务还没有赋予IPC功能
1242 tcb->ipcTaskInfo = LiteIpcTaskInit();//初始化任务的IPC
1243 }
1244
1245 listHead = &(tcb->ipcTaskInfo->msgListHead);//获取IPC信息头节点
1246 do {//注意这里是个死循环
1247 SCHEDULER_LOCK(intSave);
1248 if (LOS_ListEmpty(listHead)) {//链表为空 ?
1249 OsTaskWaitSetPendMask(OS_TASK_WAIT_LITEIPC, OS_INVALID_VALUE, timeout);//设置当前任务要等待的信息
1250 OsHookCall(LOS_HOOK_TYPE_IPC_TRY_READ, syncFlag ? MT_REPLY : MT_REQUEST, tcb->waitFlag);//向hook模块输入等待日志信息
1251 ret = tcb->ops->wait(tcb, &g_ipcPendlist, timeout);//将任务挂到全局链表上,任务进入等IPC信息,等待时间(timeout),此处产生调度,将切换到别的任务执行
1252 //如果一个消息在超时前到达,则任务会被唤醒执行,返回就不是LOS_ERRNO_TSK_TIMEOUT
1253 if (ret == LOS_ERRNO_TSK_TIMEOUT) {//如果发生指定的时间还没有IPC到达时
1254 OsHookCall(LOS_HOOK_TYPE_IPC_READ_TIMEOUT, syncFlag ? MT_REPLY : MT_REQUEST, tcb->waitFlag);//打印任务等待IPC时发生 回复/请求超时
1255 SCHEDULER_UNLOCK(intSave);
1256 return -ETIME;
1257 }
1258
1259 if (OsTaskIsKilled(tcb)) {//如果发生任务被干掉了的异常
1260 OsHookCall(LOS_HOOK_TYPE_IPC_KILL, syncFlag ? MT_REPLY : MT_REQUEST, tcb->waitFlag);//打印任务在等待IPC期间被干掉了的
1261 SCHEDULER_UNLOCK(intSave);
1262 return -ERFKILL;
1263 }
1264
1265 SCHEDULER_UNLOCK(intSave);
1266 } else {//有IPC节点数据时
1267 listNode = LOS_DL_LIST_FIRST(listHead);//拿到首个节点
1268 LOS_ListDelete(listNode);//从链表上摘掉节点,读后即焚
1269 node = LOS_DL_LIST_ENTRY(listNode, IpcListNode, listNode);//获取节点实体
1270 SCHEDULER_UNLOCK(intSave);
1271 ret = CheckRecievedMsg(node, content, tcb);//检查收到的信息
1272 if (ret == LOS_OK) {//信息没问题
1273 break;
1274 }
1275 if (ret == -ENOENT) { /* It means that we've recieved a failed reply | 收到异常回复*/
1276 return ret;
1277 }
1278 }
1279 } while (1);
1280 node->msg.data = (VOID *)GetIpcUserAddr(LOS_GetCurrProcessID(), (INTPTR)(node->msg.data));//转成用户空间地址
1281 node->msg.offsets = (VOID *)GetIpcUserAddr(LOS_GetCurrProcessID(), (INTPTR)(node->msg.offsets));//转成用户空间的偏移量
1282 content->inMsg = (VOID *)GetIpcUserAddr(LOS_GetCurrProcessID(), (INTPTR)(&(node->msg)));//转成用户空间数据结构
1283 EnableIpcNodeFreeByUser(LOS_GetCurrProcessID(), (VOID *)node);//创建一个空闲节点,并挂到进程IPC已使用节点链表上
1284 return LOS_OK;
1285}
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
毫秒转换成Tick
Definition: los_sys.c:101
STATIC LOS_DL_LIST g_ipcPendlist
挂起/待办链表,上面挂等待读/写消息的任务LosTaskCB
Definition: hm_liteipc.c:117
LITE_OS_SEC_TEXT STATIC UINT32 CheckRecievedMsg(IpcListNode *node, IpcContent *content, LosTaskCB *tcb)
检查收到的消息
Definition: hm_liteipc.c:1180
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
设置事件阻塞掩码,即设置任务的等待事件.
Definition: los_task_pri.h:289
STATIC INLINE BOOL OsTaskIsKilled(const LosTaskCB *taskCB)
Definition: los_task_pri.h:260
IpcMsg * inMsg
Definition: hm_liteipc.h:206
LOS_DL_LIST msgListHead
上面挂的是一个个的 ipc节点 上面挂 IpcListNode,申请IpcListNode的内存来自进程IPC内存池
Definition: hm_liteipc.h:99
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
const SchedOps * ops
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcRemoveServiceHandle()

LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle ( UINT32  taskID)

删除指定的Service

在文件 hm_liteipc.c661 行定义.

662{
663 UINT32 j;
664 LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
665 IpcTaskInfo *ipcTaskInfo = taskCB->ipcTaskInfo;
666 if (ipcTaskInfo == NULL) {
667 return;
668 }
669
670#if (USE_TASKID_AS_HANDLE == 1) // 任务ID当做句柄使用
671
672 UINT32 intSave;
673 LOS_DL_LIST *listHead = NULL;
674 LOS_DL_LIST *listNode = NULL;
675 IpcListNode *node = NULL;
676 UINT32 processID = taskCB->processID;
677
678 listHead = &(ipcTaskInfo->msgListHead);// ipc 节点链表
679 do {// 循环删除 任务IPC上挂的各个节点
680 SCHEDULER_LOCK(intSave);
681 if (LOS_ListEmpty(listHead)) {//空判
682 SCHEDULER_UNLOCK(intSave);
683 break;
684 } else {
685 listNode = LOS_DL_LIST_FIRST(listHead); //拿到首个节点
686 LOS_ListDelete(listNode); //删除节点
687 node = LOS_DL_LIST_ENTRY(listNode, IpcListNode, listNode);//获取节点所在结构体 IpcListNode
688 SCHEDULER_UNLOCK(intSave);
689 (VOID)HandleSpecialObjects(taskCB->taskID, node, TRUE);//处理节点
690 (VOID)LiteIpcNodeFree(processID, (VOID *)node);//释放节点占用的进程空间
691 }
692 } while (1);
693
694 ipcTaskInfo->accessMap[processID] = FALSE;
695 for (j = 0; j < MAX_SERVICE_NUM; j++) {
696 if (ipcTaskInfo->accessMap[j] == TRUE) {
697 ipcTaskInfo->accessMap[j] = FALSE;
698 (VOID)SendDeathMsg(j, taskCB->taskID); //给进程发送taskCB死亡的消息
699 }
700 }
701#else
702 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
703 for (UINT32 i = 1; i < MAX_SERVICE_NUM; i++) {
704 if ((g_serviceHandleMap[i].status != HANDLE_NOT_USED) && (g_serviceHandleMap[i].taskID == taskCB->taskID)) {
706 g_serviceHandleMap[i].taskID = INVAILD_ID;
707 break;
708 }
709 }
711 /* run deathHandler */
712 if (i < MAX_SERVICE_NUM) {
713 for (j = 0; j < MAX_SERVICE_NUM; j++) {
714 if (ipcTaskInfo->accessMap[j] == TRUE) {
715 (VOID)SendDeathMsg(j, i);
716 }
717 }
718 }
719#endif
720
721 (VOID)LOS_MemFree(m_aucSysMem1, ipcTaskInfo);
722 taskCB->ipcTaskInfo = NULL;
723}
LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHandle)
serviceHandle 给 processID 发送死亡/结束消息, serviceHandle 为 taskID
Definition: hm_liteipc.c:633
UINT32 processID
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcTaskInit()

LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo * LiteIpcTaskInit ( VOID  )

申请并初始化一个任务IPC

在文件 hm_liteipc.c400 行定义.

401{
402 IpcTaskInfo *taskInfo = LOS_MemAlloc((VOID *)m_aucSysMem1, sizeof(IpcTaskInfo));
403 if (taskInfo == NULL) {
404 return NULL;
405 }
406
407 (VOID)memset_s(taskInfo, sizeof(IpcTaskInfo), 0, sizeof(IpcTaskInfo));
408 LOS_ListInit(&taskInfo->msgListHead);
409 return taskInfo;
410}
函数调用图:
这是这个函数的调用关系图:

◆ LiteIpcWrite()

LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcWrite ( IpcContent content)

写IPC消息队列,从用户空间到内核空间

在文件 hm_liteipc.c1120 行定义.

1121{
1122 UINT32 ret, intSave;
1123 UINT32 dstTid;
1124
1125 IpcMsg *msg = content->outMsg;
1126
1127 ret = CheckPara(content, &dstTid);//获取目标任务ID
1128 if (ret != LOS_OK) {
1129 return ret;
1130 }
1131
1132 LosTaskCB *tcb = OS_TCB_FROM_TID(dstTid);//目标任务实体
1133 LosProcessCB *pcb = OS_PCB_FROM_PID(tcb->processID);//目标进程实体
1134 if (pcb->ipcInfo == NULL) {
1135 PRINT_ERR("pid %u Liteipc not create\n", tcb->processID);
1136 return -EINVAL;
1137 }
1138 //这里为什么要申请msg->dataSz,因为IpcMsg中的真正数据体 data是个指针,它的大小是dataSz . 同时申请存储偏移量空间
1139 UINT32 bufSz = sizeof(IpcListNode) + msg->dataSz + msg->spObjNum * sizeof(UINT32);//这句话是理解上层消息在内核空间数据存放的关键!!! @note_good
1140 IpcListNode *buf = (IpcListNode *)LiteIpcNodeAlloc(tcb->processID, bufSz);//向内核空间申请bufSz大小内存
1141 if (buf == NULL) {
1142 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1143 return -ENOMEM;
1144 }//IpcListNode的第一个成员变量就是IpcMsg
1145 ret = CopyDataFromUser(buf, bufSz, (const IpcMsg *)msg);//将消息内容拷贝到内核空间,包括消息控制体+内容体+偏移量
1146 if (ret != LOS_OK) {
1147 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1148 goto ERROR_COPY;
1149 }
1150
1151 if (tcb->ipcTaskInfo == NULL) {//如果任务还没有IPC信息
1152 tcb->ipcTaskInfo = LiteIpcTaskInit();//初始化这个任务的IPC信息模块,因为消息来了要处理了
1153 }
1154
1155 ret = HandleSpecialObjects(dstTid, buf, FALSE);//处理消息
1156 if (ret != LOS_OK) {
1157 PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
1158 goto ERROR_COPY;
1159 }
1160 /* add data to list and wake up dest task *///向列表添加数据并唤醒目标任务
1161 SCHEDULER_LOCK(intSave);
1162 LOS_ListTailInsert(&(tcb->ipcTaskInfo->msgListHead), &(buf->listNode));//把消息控制体挂到目标任务的IPC链表头上
1163 OsHookCall(LOS_HOOK_TYPE_IPC_WRITE, &buf->msg, dstTid, tcb->processID, tcb->waitFlag);
1164 if (tcb->waitFlag == OS_TASK_WAIT_LITEIPC) {//如果这个任务在等这个消息,注意这个tcb可不是当前任务
1165 OsTaskWakeClearPendMask(tcb);//撕掉对应标签
1166 tcb->ops->wake(tcb);
1167 SCHEDULER_UNLOCK(intSave);
1168 LOS_MpSchedule(OS_MP_CPU_ALL);//设置调度方式,所有CPU核发生一次调度,这里非要所有CPU都调度吗?
1169 //可不可以查询下该任务挂在哪个CPU上,只调度对应CPU呢? 注者在此抛出思考 @note_thinking
1170 LOS_Schedule();//发起调度
1171 } else {
1172 SCHEDULER_UNLOCK(intSave);
1173 }
1174 return LOS_OK;
1175ERROR_COPY:
1176 LiteIpcNodeFree(OS_TCB_FROM_TID(dstTid)->processID, buf);//拷贝发生错误就要释放内核堆内存,那可是好大一块堆内存啊
1177 return ret;
1178}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
Definition: los_list.h:244
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
Definition: los_sched.c:469
LITE_OS_SEC_TEXT STATIC UINT32 CheckPara(IpcContent *content, UINT32 *dstTid)
检查参数,并获取目标 任务ID
Definition: hm_liteipc.c:1049
LITE_OS_SEC_TEXT STATIC UINT32 CopyDataFromUser(IpcListNode *node, UINT32 bufSz, const IpcMsg *msg)
Definition: hm_liteipc.c:986
VOID LOS_MpSchedule(UINT32 target)
Definition: los_mp.c:76
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
Definition: los_task_pri.h:298
LOS_DL_LIST listNode
通过它挂到LosTaskCB.msgListHead链表上
Definition: hm_liteipc.h:193
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
函数调用图:
这是这个函数的调用关系图:

◆ LOS_MODULE_INIT()

LOS_MODULE_INIT ( OsLiteIpcInit  ,
LOS_INIT_LEVEL_KMOD_EXTENDED   
)

◆ OsLiteIpcInit()

LITE_OS_SEC_TEXT_INIT UINT32 OsLiteIpcInit ( VOID  )

OsLiteIpcInit 初始化LiteIPC模块

返回
参见

在文件 hm_liteipc.c147 行定义.

148{
149 UINT32 ret;
150#if (USE_TASKID_AS_HANDLE == 1) //两种管理方式,一种是 任务ID == service ID
151 g_cmsTask.status = HANDLE_NOT_USED;//默认未使用
152#else
153 (void)memset_s(g_serviceHandleMap, sizeof(g_serviceHandleMap), 0, sizeof(g_serviceHandleMap));
154#endif
156 if (ret != LOS_OK) {
157 return ret;
158 }
159 ret = (UINT32)register_driver(LITEIPC_DRIVER, &g_liteIpcFops, LITEIPC_DRIVER_MODE, NULL);//注册字符驱动程序,从此支持文件访问LiteIpc
160 if (ret != LOS_OK) {
161 PRINT_ERR("register lite_ipc driver failed:%d\n", ret);
162 }
164
165 return ret;
166}
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
STATIC const struct file_operations_vfs g_liteIpcFops
Definition: hm_liteipc.c:133
ARG_NUM_3 ARG_NUM_1 ARG_NUM_2 ARG_NUM_2 ARG_NUM_3 ARG_NUM_1 ARG_NUM_4 ARG_NUM_2 ARG_NUM_2 ARG_NUM_5 ARG_NUM_2 void
函数调用图:

◆ RefreshServiceHandle()

LITE_OS_SEC_TEXT STATIC VOID RefreshServiceHandle ( UINT32  serviceHandle,
UINT32  result 
)

刷新指定服务, 多刷几次状态就变了, result != 0 时,服务停止

在文件 hm_liteipc.c536 行定义.

537{
538#if (USE_TASKID_AS_HANDLE == 0)
539 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
540 if ((result == LOS_OK) && (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTING)) {//如果状态为注册中
541 g_serviceHandleMap[serviceHandle].status = HANDLE_REGISTED; // 变成已注册
542 } else {
543 g_serviceHandleMap[serviceHandle].status = HANDLE_NOT_USED; // 变成未使用
544 }
546#endif
547}
@ HANDLE_REGISTING
注册中
Definition: hm_liteipc.h:63
函数调用图:
这是这个函数的调用关系图:

◆ SendDeathMsg()

LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg ( UINT32  processID,
UINT32  serviceHandle 
)

serviceHandle 给 processID 发送死亡/结束消息, serviceHandle 为 taskID

在文件 hm_liteipc.c633 行定义.

634{
635 UINT32 ipcTaskID;
636 UINT32 ret;
637 IpcContent content;
638 IpcMsg msg;
639 LosProcessCB *pcb = OS_PCB_FROM_PID(processID);//获取指定进程控制块
640
641 if (pcb->ipcInfo == NULL) {
642 return -EINVAL;
643 }
644
645 pcb->ipcInfo->access[serviceHandle] = FALSE;
646
647 ret = GetIpcTaskID(processID, &ipcTaskID);//获取操作该进程IPC的任务ID, processID 下的某个 taskID
648 if (ret != LOS_OK) {
649 return -EINVAL;
650 }
651 content.flag = SEND;
652 content.outMsg = &msg;
653 (void)memset_s(content.outMsg, sizeof(IpcMsg), 0, sizeof(IpcMsg));
654 content.outMsg->type = MT_DEATH_NOTIFY;
655 content.outMsg->target.handle = ipcTaskID;
656 content.outMsg->target.token = serviceHandle;
657 content.outMsg->code = 0;
658 return LiteIpcWrite(&content);
659}
LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
获取IPC任务ID
Definition: hm_liteipc.c:624
函数调用图:
这是这个函数的调用关系图:

◆ SetCms()

LITE_OS_SEC_TEXT STATIC UINT32 SetCms ( UINTPTR  maxMsgSize)

设置CMS

在文件 hm_liteipc.c725 行定义.

726{
727 if (maxMsgSize < sizeof(IpcMsg)) {
728 return -EINVAL;
729 }
730 (VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
731#if (USE_TASKID_AS_HANDLE == 1)
733 g_cmsTask.status = HANDLE_REGISTED; // 已注册 ServiceManager
734 g_cmsTask.taskID = LOS_CurTaskIDGet();//将当前任务设置为 ServiceManager
735 g_cmsTask.maxMsgSize = maxMsgSize; //最大消息内容
737 return LOS_OK;
738 }
739#else
740 if (g_serviceHandleMap[0].status == HANDLE_NOT_USED) {
741 g_serviceHandleMap[0].status = HANDLE_REGISTED;// 已注册 ServiceManager
742 g_serviceHandleMap[0].taskID = LOS_CurTaskIDGet();//将当前任务设置为 ServiceManager
744 return LOS_OK;
745 }
746#endif
748 return -EEXIST;
749}
UINTPTR maxMsgSize
最大消息大小
Definition: hm_liteipc.h:74
函数调用图:
这是这个函数的调用关系图:

◆ SetIpcTask()

LITE_OS_SEC_TEXT STATIC UINT32 SetIpcTask ( VOID  )

将当前任务设置成进程ipc的任务ID

在文件 hm_liteipc.c606 行定义.

607{
608 if (OsCurrProcessGet()->ipcInfo->ipcTaskID == INVAILD_ID) { //未设置时
611 }
612 PRINT_ERR("Liteipc curprocess %d IpcTask already set!\n", OsCurrProcessGet()->processID);
613 return -EINVAL;
614}
函数调用图:
这是这个函数的调用关系图:

◆ SPIN_LOCK_INIT()

SPIN_LOCK_INIT ( g_ipcSpin  )

变量说明

◆ g_cmsTask

STATIC HandleInfo g_cmsTask

整个系统只能有一个ServiceManager

在文件 hm_liteipc.c113 行定义.

◆ g_ipcPendlist

STATIC LOS_DL_LIST g_ipcPendlist

挂起/待办链表,上面挂等待读/写消息的任务LosTaskCB

在文件 hm_liteipc.c117 行定义.

◆ g_liteIpcFops

STATIC const struct file_operations_vfs g_liteIpcFops
初始值:
= {
.open = LiteIpcOpen,
.close = LiteIpcClose,
.ioctl = LiteIpcIoctl,
.mmap = LiteIpcMmap,
}
STATIC int LiteIpcMmap(struct file *filep, LosVmMapRegion *region)
将参数线性区设为IPC专用区
Definition: hm_liteipc.c:260
STATIC int LiteIpcOpen(struct file *filep)
LiteIpcOpen 以VFS方式为当前进程创建IPC消息池
Definition: hm_liteipc.c:178
STATIC int LiteIpcClose(struct file *filep)
Definition: hm_liteipc.c:193
STATIC int LiteIpcIoctl(struct file *filep, int cmd, unsigned long arg)
真正的 IPC 控制操作
Definition: hm_liteipc.c:1418

在文件 hm_liteipc.c133 行定义.

◆ g_serviceHandleMap

STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM]

g_serviceHandleMap[0]为ServiceManager,这块鸿蒙的设计挺怪的,让人很懵逼

在文件 hm_liteipc.c115 行定义.

◆ g_serviceHandleMapMux

STATIC LosMux g_serviceHandleMapMux

在文件 hm_liteipc.c111 行定义.