1 /*
2 * Copyright (c) 2020 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "liteipc_adapter.h"
17 #include "ipc_log.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <sched.h>
23 #include <signal.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30 #include <time.h>
31 #include "liteipc.h"
32 #include "utils_list.h"
33 #include "securec.h"
34
35 #define ENABLE_IPC_CB_TIMER YES
36
37 static IpcContext* g_context = NULL;
38 static pthread_mutex_t g_ipcContextMutex = PTHREAD_MUTEX_INITIALIZER;
39
40 typedef struct {
41 bool usedFlag;
42 IpcMsgHandler hdler;
43 void* arg;
44 } IpcMsgHandlerPair;
45
46 typedef struct {
47 UTILS_DL_LIST list;
48 uint32_t handle;
49 IpcMsgHandlerPair hdlerPairs[MAX_DEATHCB_PER_SVC];
50 size_t size;
51 bool isCallbackRuning;
52 } Testament;
53
54 typedef struct {
55 UTILS_DL_LIST list;
56 uint32_t token;
57 IpcMsgHandlerPair hdlerPair;
58 #if (ENABLE_IPC_CB_TIMER == YES)
59 uint32_t mode;
60 uint32_t timeout;
61 timer_t timerId;
62 #endif
63 } AnonymousApi;
64
65 typedef void (*TimerHandler)(int);
66
67 typedef struct {
68 pthread_mutex_t mutex;
69 int32_t handleId;
70 bool threadWorking;
71 UTILS_DL_LIST apis;
72 UTILS_DL_LIST testaments;
73 } IpcCallckCb;
74
75 static IpcCallckCb g_ipcCallbackCb = {
76 .mutex = PTHREAD_MUTEX_INITIALIZER,
77 .handleId = -1,
78 .threadWorking = false
79 };
80
81 #define DEATH_HANDLE UINT32_MAX
82 #define MAX_ERR_STR 60
83
84 #define NS_PER_MS 1000000ULL
85 #define NS_PER_SEC 1000000000ULL
86
87 static void Perror(int msgErrno);
88
89 #define LOG(level, format, ...) \
90 do { \
91 IPC_LOG(level, "[%s : %d]" format, \
92 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
93 } while (0)
94
95 #define LOG_ERRNO(format, ...) \
96 do { \
97 IPC_LOG_ERROR("[%s : %d]" format, \
98 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
99 Perror(errno); \
100 } while (0)
101
102 #define RETURN_IF_IPC_IOCTL_FAILED(retVal) \
103 do { \
104 if (ret < 0) { \
105 LOG_ERRNO("Liteipc driver ioctl failed."); \
106 return (retVal); \
107 } \
108 } while (0)
109
Perror(int msgErrno)110 static void Perror(int msgErrno)
111 {
112 char errbuf[MAX_ERR_STR];
113 int rv = strerror_r(msgErrno, errbuf, sizeof(errbuf));
114 if (rv == -1) {
115 IPC_LOG_ERROR("[errno:%d]", msgErrno);
116 } else {
117 IPC_LOG_ERROR("[errnoStr:%s]", errbuf);
118 }
119 }
120
InitCallbackCb()121 static inline void InitCallbackCb()
122 {
123 UtilsListInit(&g_ipcCallbackCb.apis);
124 UtilsListInit(&g_ipcCallbackCb.testaments);
125 }
126
GetLiteIpcContext(size_t mmapSize,IpcContext * context)127 static int32_t GetLiteIpcContext(size_t mmapSize, IpcContext* context)
128 {
129 void* addr = NULL;
130 int32_t fd = -1;
131 IpcContext* con = NULL;
132
133 if (g_context != NULL) {
134 if (context != NULL) {
135 *context = *g_context;
136 }
137 return LITEIPC_OK;
138 }
139
140 if (pthread_mutex_lock(&g_ipcContextMutex) != 0) {
141 LOG_ERRNO("Get ipc context mutex failed.");
142 return LITEIPC_EINTNL;
143 }
144 if (g_context == NULL) {
145 fd = open(LITEIPC_DRIVER, O_RDONLY);
146 if (fd == -1) {
147 LOG_ERRNO("Open liteipc driver failed.");
148 goto OPEN_ERR;
149 }
150 /* 0 means use default size */
151 if (mmapSize == 0) {
152 mmapSize = MMAP_DEFAULT_SIZE;
153 }
154 addr = mmap(NULL, mmapSize, PROT_READ, MAP_PRIVATE, fd, 0);
155 if (addr == MAP_FAILED) {
156 LOG_ERRNO("Mmap failed.(size=%zu)", mmapSize);
157 goto MMAP_ERR;
158 }
159
160 con = malloc(sizeof(IpcContext));
161 if (con == NULL) {
162 LOG(ERROR, "Malloc failed.(size=%zu)", sizeof(IpcContext));
163 goto MALLOC_ERR;
164 }
165 con->fd = fd;
166 con->mmapSize = mmapSize;
167 InitCallbackCb();
168 g_context = con;
169 }
170 if (context != NULL) {
171 *context = *g_context;
172 }
173 pthread_mutex_unlock(&g_ipcContextMutex);
174 return LITEIPC_OK;
175
176 MALLOC_ERR:
177 munmap(addr, mmapSize);
178 MMAP_ERR:
179 close(fd);
180 OPEN_ERR:
181 pthread_mutex_unlock(&g_ipcContextMutex);
182 return LITEIPC_EINTNL;
183 }
184
OpenLiteIpc(size_t mmapSize)185 IpcContext* OpenLiteIpc(size_t mmapSize)
186 {
187 if ((mmapSize == 0) || (mmapSize > MMAP_MAX_SIZE)) {
188 LOG(ERROR, "MmapSize not available");
189 return NULL;
190 }
191 return (IpcContext*)(intptr_t)(GetLiteIpcContext(mmapSize, NULL) == LITEIPC_OK);
192 }
193
ResetLiteIpc()194 void ResetLiteIpc()
195 {
196 if (g_context != NULL) {
197 free(g_context);
198 g_context = NULL;
199 }
200 pthread_mutex_init(&g_ipcContextMutex, NULL);
201 g_ipcCallbackCb.handleId = -1;
202 g_ipcCallbackCb.threadWorking = false;
203 pthread_mutex_init(&(g_ipcCallbackCb.mutex), NULL);
204 }
205
CloseLiteIpc(IpcContext * context)206 void CloseLiteIpc(IpcContext* context)
207 {
208 }
209
SetSaManager(const IpcContext * con,size_t maxMsgSize)210 int32_t SetSaManager(const IpcContext* con, size_t maxMsgSize)
211 {
212 IpcContext context;
213 int32_t ret = GetLiteIpcContext(0, &context);
214 if (ret != LITEIPC_OK) {
215 LOG(ERROR, "GetLiteIpcContext failed.");
216 return ret;
217 }
218
219 ret = ioctl(context.fd, IPC_SET_CMS, maxMsgSize);
220 RETURN_IF_IPC_IOCTL_FAILED(LITEIPC_EBADF);
221
222 return LITEIPC_OK;
223 }
224
AddServiceAccess(SvcIdentity sid,pid_t pid)225 int32_t AddServiceAccess(SvcIdentity sid, pid_t pid)
226 {
227 IpcContext context;
228 int32_t ret = GetLiteIpcContext(0, &context);
229 if (ret != LITEIPC_OK) {
230 LOG(ERROR, "GetLiteIpcContext failed.");
231 return ret;
232 }
233
234 CmsCmdContent content = {
235 .cmd = CMS_ADD_ACCESS,
236 .taskID = pid,
237 .serviceHandle = sid.handle
238 };
239 ret = ioctl(context.fd, IPC_CMS_CMD, &content);
240 RETURN_IF_IPC_IOCTL_FAILED(LITEIPC_EBADF);
241
242 return LITEIPC_OK;
243 }
244
GenServiceHandle(SvcIdentity * sid,pid_t tid)245 int32_t GenServiceHandle(SvcIdentity* sid, pid_t tid)
246 {
247 IpcContext context;
248 int32_t ret;
249
250 if (sid == NULL) {
251 LOG(ERROR, "Invalid parameter, sid is null pointer.");
252 return LITEIPC_EINVAL;
253 }
254
255 ret = GetLiteIpcContext(0, &context);
256 if (ret != LITEIPC_OK) {
257 LOG(ERROR, "GetLiteIpcContext failed.");
258 return ret;
259 }
260
261 CmsCmdContent content = {
262 .cmd = CMS_GEN_HANDLE,
263 .taskID = tid
264 };
265 ret = ioctl(context.fd, IPC_CMS_CMD, &content);
266 RETURN_IF_IPC_IOCTL_FAILED(LITEIPC_EBADF);
267
268 sid->handle = content.serviceHandle;
269 return LITEIPC_OK;
270 }
271
StartLoop(const IpcContext * con,IpcMsgHandler func,void * arg)272 int32_t StartLoop(const IpcContext* con, IpcMsgHandler func, void* arg)
273 {
274 IpcContext context;
275 int32_t ret;
276
277 if (func == NULL) {
278 return LITEIPC_EINVAL;
279 }
280
281 ret = GetLiteIpcContext(0, &context);
282 if (ret != LITEIPC_OK) {
283 LOG(ERROR, "GetLiteIpcContext failed.");
284 return ret;
285 }
286
287 while (1) {
288 IpcContent content = {.flag = RECV};
289 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
290 if (ret < 0) {
291 LOG_ERRNO("Bad ioctl request.");
292 continue;
293 }
294
295 IpcIo io;
296 IpcIoInitFromMsg(&io, content.inMsg);
297 /* Dispatch the receiving message */
298 (void)func(con, content.inMsg, &io, arg);
299 }
300
301 return LITEIPC_OK;
302 }
303
GetToken(const void * ipcMsg,uint32_t * token)304 int32_t GetToken(const void* ipcMsg, uint32_t* token)
305 {
306 if ((ipcMsg == NULL) || (token == NULL)) {
307 LOG(ERROR, "Invalid parameter, null pointer.");
308 return LITEIPC_EINVAL;
309 }
310
311 const IpcMsg* in = (const IpcMsg*)ipcMsg;
312 *token = in->target.token;
313 return LITEIPC_OK;
314 }
315
GetCode(const void * ipcMsg,uint32_t * code)316 int32_t GetCode(const void* ipcMsg, uint32_t* code)
317 {
318 if ((ipcMsg == NULL) || (code == NULL)) {
319 LOG(ERROR, "Invalid parameter, null pointer.");
320 return LITEIPC_EINVAL;
321 }
322
323 const IpcMsg* in = (const IpcMsg*)ipcMsg;
324 *code = in->code;
325 return LITEIPC_OK;
326 }
327
GetFlag(const void * ipcMsg,uint32_t * flag)328 int32_t GetFlag(const void* ipcMsg, uint32_t* flag)
329 {
330 if ((ipcMsg == NULL) || (flag == NULL)) {
331 LOG(ERROR, "Invalid parameter, null pointer.");
332 return LITEIPC_EINVAL;
333 }
334
335 const IpcMsg* in = (const IpcMsg*)ipcMsg;
336 *flag = in->flag;
337 return LITEIPC_OK;
338 }
339
GetCallingTid(const void * ipcMsg)340 pid_t GetCallingTid(const void* ipcMsg)
341 {
342 if (ipcMsg == NULL) {
343 LOG(ERROR, "Invalid parameter, null pointer.");
344 return LITEIPC_EINVAL;
345 }
346
347 const IpcMsg* in = (const IpcMsg*)ipcMsg;
348 return (pid_t)in->taskID;
349 }
350
GetCallingPid(const void * ipcMsg)351 pid_t GetCallingPid(const void* ipcMsg)
352 {
353 if (ipcMsg == NULL) {
354 LOG(ERROR, "Invalid parameter, null pointer.");
355 return LITEIPC_EINVAL;
356 }
357
358 const IpcMsg* in = (const IpcMsg*)ipcMsg;
359 return (pid_t)in->processID;
360 }
361
GetCallingUid(const void * ipcMsg)362 pid_t GetCallingUid(const void* ipcMsg)
363 {
364 if (ipcMsg == NULL) {
365 LOG(ERROR, "Invalid parameter, null pointer.");
366 return LITEIPC_EINVAL;
367 }
368
369 const IpcMsg* in = (const IpcMsg*)ipcMsg;
370 return (pid_t)in->userID;
371 }
372
GetCallingGid(const void * ipcMsg)373 pid_t GetCallingGid(const void* ipcMsg)
374 {
375 if (ipcMsg == NULL) {
376 LOG(ERROR, "Invalid parameter, null pointer.");
377 return LITEIPC_EINVAL;
378 }
379
380 const IpcMsg* in = (const IpcMsg*)ipcMsg;
381 return (pid_t)in->gid;
382 }
383
CheckIpcIo(IpcIo * data)384 static int32_t CheckIpcIo(IpcIo* data)
385 {
386 uint32_t totalSize;
387 /* It's OK if data is null */
388 if (data == NULL) {
389 return LITEIPC_OK;
390 }
391 if ((IpcIoAvailable(data) == false) ||
392 (data->bufferCur == NULL) ||
393 (data->bufferBase == NULL) ||
394 (data->offsetsCur == NULL) ||
395 (data->offsetsBase == NULL) ||
396 ((intptr_t)data->bufferBase < (intptr_t)data->offsetsCur)) {
397 return LITEIPC_EINVAL;
398 }
399 totalSize = data->bufferCur - data->bufferBase + ((char*)data->offsetsCur - (char*)data->offsetsBase);
400 if (totalSize > IPC_IO_DATA_MAX) {
401 LOG(ERROR, "IpcIo data too big, please use IpcIoPushDataBuff to push big data.");
402 return LITEIPC_EINVAL;
403 }
404 return LITEIPC_OK;
405 }
406
SendRequest(const IpcContext * con,SvcIdentity sid,uint32_t code,IpcIo * data,IpcIo * reply,IpcFlag flag,uintptr_t * ptr)407 int32_t SendRequest(const IpcContext* con, SvcIdentity sid, uint32_t code,
408 IpcIo* data, IpcIo* reply, IpcFlag flag, uintptr_t* ptr)
409 {
410 IpcContext context;
411 int32_t ret;
412
413 if ((flag > LITEIPC_FLAG_ONEWAY) || ((flag == LITEIPC_FLAG_DEFAULT) && (ptr == NULL))) {
414 LOG(ERROR, "Invalid parameter, null pointer.");
415 ret = LITEIPC_EINVAL;
416 goto TRAN_EXIT;
417 }
418
419 ret = CheckIpcIo(data);
420 if (ret != LITEIPC_OK) {
421 LOG(ERROR, "CheckIpcIo failed.");
422 goto TRAN_EXIT;
423 }
424
425 ret = GetLiteIpcContext(0, &context);
426 if (ret != LITEIPC_OK) {
427 LOG(ERROR, "GetLiteIpcContext failed.");
428 goto TRAN_EXIT;
429 }
430
431 IpcMsg msg = {
432 .type = MT_REQUEST,
433 .target = sid,
434 .code = code,
435 .flag = flag,
436 .dataSz = (data == NULL) ? 0 : data->bufferCur - data->bufferBase,
437 .data = (data == NULL) ? NULL : data->bufferBase,
438 .offsets = (data == NULL) ? NULL : data->offsetsBase,
439 .spObjNum = (data == NULL) ? 0 : ((char*)data->offsetsCur - (char*)data->offsetsBase) / sizeof(size_t)
440 };
441 IpcContent content = {.outMsg = &msg};
442 content.flag = (flag == LITEIPC_FLAG_ONEWAY) ? SEND : (SEND | RECV);
443 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
444 if (ret < 0) {
445 LOG_ERRNO("Liteipc driver ioctl failed.");
446 ret = (errno == ENOENT) ? LITEIPC_ENOENT : LITEIPC_EBADF;
447 goto TRAN_EXIT;
448 }
449
450 if (flag != LITEIPC_FLAG_ONEWAY) {
451 if (reply != NULL) {
452 IpcIoInitFromMsg(reply, content.inMsg);
453 }
454 *ptr = (uintptr_t)content.inMsg;
455 }
456 ret = LITEIPC_OK;
457
458 TRAN_EXIT:
459 IpcIoFreeDataBuff(data);
460 return ret;
461 }
462
SendReply(const IpcContext * con,void * ipcMsg,IpcIo * reply)463 int32_t SendReply(const IpcContext* con, void* ipcMsg, IpcIo* reply)
464 {
465 IpcContext context;
466 int32_t ret;
467
468 if (ipcMsg == NULL) {
469 LOG(ERROR, "Invalid parameter, null pointer.");
470 ret = LITEIPC_EINVAL;
471 goto SEND_EXIT;
472 }
473
474 ret = CheckIpcIo(reply);
475 if (ret != LITEIPC_OK) {
476 LOG(ERROR, "CheckIpcIo failed.");
477 goto SEND_EXIT;
478 }
479
480 ret = GetLiteIpcContext(0, &context);
481 if (ret != LITEIPC_OK) {
482 LOG(ERROR, "GetLiteIpcContext failed.");
483 goto SEND_EXIT;
484 }
485
486 IpcMsg* in = (IpcMsg*)ipcMsg;
487 IpcMsg out = {
488 .type = MT_REPLY,
489 .target.handle = in->taskID,
490 .code = in->code,
491 .flag = in->flag,
492 .timestamp = in->timestamp,
493 .dataSz = (reply == NULL) ? 0 : reply->bufferCur - reply->bufferBase,
494 .data = (reply == NULL) ? NULL : (void*)reply->bufferBase,
495 .offsets = (reply == NULL) ? NULL : reply->offsetsBase,
496 .spObjNum = (reply == NULL) ? 0 : ((char*)reply->offsetsCur - (char*)reply->offsetsBase) / sizeof(size_t)
497 };
498 IpcContent content = {
499 .flag = SEND | BUFF_FREE,
500 .outMsg = &out,
501 .buffToFree = in
502 };
503
504 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
505 if (ret < 0) {
506 LOG_ERRNO("Liteipc driver ioctl failed.");
507 ret = LITEIPC_EBADF;
508 }
509
510 SEND_EXIT:
511 IpcIoFreeDataBuff(reply);
512 return ret;
513 }
514
FreeBuffer(const IpcContext * con,void * ptr)515 int32_t FreeBuffer(const IpcContext* con, void* ptr)
516 {
517 (void)con;
518 IpcContext context;
519 int32_t ret;
520
521 if (ptr == NULL) {
522 LOG(ERROR, "Invalid parameter, null pointer.");
523 return LITEIPC_EINVAL;
524 }
525
526 ret = GetLiteIpcContext(0, &context);
527 if (ret != LITEIPC_OK) {
528 LOG(ERROR, "GetLiteIpcContext failed.");
529 return ret;
530 }
531
532 IpcContent content = {
533 .flag = BUFF_FREE,
534 .buffToFree = (IpcMsg*)ptr
535 };
536 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
537 RETURN_IF_IPC_IOCTL_FAILED(LITEIPC_EBADF);
538
539 return ret;
540 }
541
SendFailedReply(IpcMsg * in)542 static void SendFailedReply(IpcMsg* in)
543 {
544 IpcContext context;
545 int32_t ret;
546
547 if (in == NULL) {
548 LOG(ERROR, "Invalid parameter, null pointer.");
549 return;
550 }
551
552 ret = GetLiteIpcContext(0, &context);
553 if (ret != LITEIPC_OK) {
554 LOG(ERROR, "GetLiteIpcContext failed.");
555 return;
556 }
557
558 IpcMsg out = {
559 .type = MT_FAILED_REPLY,
560 .target.handle = in->taskID,
561 .code = in->code,
562 .flag = in->flag,
563 .timestamp = in->timestamp,
564 .dataSz = 0,
565 .data = NULL,
566 .offsets = NULL,
567 .spObjNum = 0
568 };
569 IpcContent content = {
570 .flag = SEND | BUFF_FREE,
571 .outMsg = &out,
572 .buffToFree = in
573 };
574
575 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
576 if (ret < 0) {
577 LOG_ERRNO("Liteipc driver ioctl failed.");
578 }
579 }
580
581 typedef struct {
582 uint32_t num;
583 void* msg;
584 IpcIo io;
585 IpcMsgHandlerPair* cbs;
586 } HdlerArg;
587
588 static void RemoveDeathCallback(uint32_t handle);
CallbackBatchHandler(void * arg)589 static void* CallbackBatchHandler(void* arg)
590 {
591 pthread_detach(pthread_self());
592 HdlerArg* hdlerArg = (HdlerArg*)arg;
593 IpcMsg* msg = hdlerArg->msg;
594 uint32_t handle = msg->target.token;
595 uint32_t i;
596
597 for (i = 0; i < hdlerArg->num; i++) {
598 if (hdlerArg->cbs[i].usedFlag == true) {
599 (hdlerArg->cbs[i].hdler)(0, hdlerArg->msg, &hdlerArg->io, hdlerArg->cbs[i].arg);
600 }
601 }
602 free(arg);
603 if (msg->type == MT_DEATH_NOTIFY) {
604 RemoveDeathCallback(handle);
605 FreeBuffer(NULL, msg);
606 }
607 return NULL;
608 }
609
610 #if (ENABLE_IPC_CB_TIMER == YES)
IpcTimeout2Timerspec(uint32_t timeoutMs)611 static struct itimerspec IpcTimeout2Timerspec(uint32_t timeoutMs)
612 {
613 struct itimerspec its;
614 uint64_t nanosecs;
615 nanosecs = (uint64_t)timeoutMs * NS_PER_MS;
616 its.it_value.tv_sec = nanosecs / NS_PER_SEC;
617 its.it_value.tv_nsec = nanosecs % NS_PER_SEC;
618 its.it_interval.tv_sec = 0;
619 its.it_interval.tv_nsec = 0;
620 return its;
621 }
622 #endif
623
GetIpcCallback(IpcMsg * msg,HdlerArg * arg)624 static void GetIpcCallback(IpcMsg* msg, HdlerArg* arg)
625 {
626 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
627 LOG_ERRNO("Get callback mutex failed.");
628 return;
629 }
630 IpcIoInitFromMsg(&arg->io, msg);
631 arg->msg = msg;
632
633 AnonymousApi* node = NULL;
634 UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_ipcCallbackCb.apis, AnonymousApi, list)
635 {
636 if (node->token == msg->target.token) {
637 arg->num = 1;
638 arg->cbs = &node->hdlerPair;
639 #if (ENABLE_IPC_CB_TIMER == YES)
640 if ((node->timerId != IPC_INVAILD_TIMER_ID) && (node->mode == RESET_AFTER_USE)) {
641 struct itimerspec its = IpcTimeout2Timerspec(node->timeout);
642 timer_settime(node->timerId, 0, &its, 0);
643 }
644 #endif
645 (void)pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
646 return;
647 }
648 }
649 arg->num = 0;
650 arg->cbs = NULL;
651 (void)pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
652 }
653
GetDeathCallback(IpcMsg * msg,HdlerArg * arg)654 static void GetDeathCallback(IpcMsg* msg, HdlerArg* arg)
655 {
656 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
657 LOG_ERRNO("Get callback mutex failed.");
658 return;
659 }
660 IpcIoInitFromMsg(&arg->io, msg);
661 arg->msg = msg;
662
663 Testament* node = NULL;
664 UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_ipcCallbackCb.testaments, Testament, list)
665 {
666 if (node->handle == msg->target.token) {
667 node->isCallbackRuning = true;
668 arg->num = MAX_DEATHCB_PER_SVC;
669 arg->cbs = node->hdlerPairs;
670 (void)pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
671 return;
672 }
673 }
674 arg->num = 0;
675 arg->cbs = NULL;
676 (void)pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
677 }
678
CallbackDispatch(void * arg)679 static void* CallbackDispatch(void* arg)
680 {
681 IpcContext context;
682 int32_t ret = GetLiteIpcContext(0, &context);
683 if (ret != LITEIPC_OK) {
684 LOG(ERROR, "GetLiteIpcContext failed.");
685 return (void*)(intptr_t)LITEIPC_EBADF;
686 }
687
688 ret = ioctl(context.fd, IPC_SET_IPC_THREAD, 0);
689 RETURN_IF_IPC_IOCTL_FAILED((void*)(intptr_t)LITEIPC_EBADF);
690 g_ipcCallbackCb.handleId = ret;
691 g_ipcCallbackCb.threadWorking = true;
692
693 while (1) {
694 IpcContent content = {.flag = RECV};
695 ret = ioctl(context.fd, IPC_SEND_RECV_MSG, &content);
696 if (ret < 0) {
697 continue;
698 }
699
700 HdlerArg* tArg = (HdlerArg*)malloc(sizeof(HdlerArg));
701 if (tArg == NULL) {
702 goto ERROR_MALLOC;
703 }
704
705 switch (content.inMsg->type) {
706 case MT_DEATH_NOTIFY:
707 GetDeathCallback(content.inMsg, tArg);
708 break;
709 case MT_REQUEST:
710 GetIpcCallback(content.inMsg, tArg);
711 break;
712 default:
713 LOG(ERROR, "Callback thread received an unrecognized message.(type=%d)", content.inMsg->type);
714 goto ERROR_MSG;
715 }
716
717 if (tArg->num == 0) {
718 goto ERROR_MSG;
719 }
720 pthread_t tid;
721 ret = pthread_create(&tid, NULL, CallbackBatchHandler, tArg);
722 if (ret == 0) {
723 continue;
724 }
725 LOG_ERRNO("Create handle thread failed.");
726
727 ERROR_MSG:
728 free(tArg);
729 ERROR_MALLOC:
730 if ((content.inMsg->type == MT_REQUEST) && (content.inMsg->flag == LITEIPC_FLAG_DEFAULT)) {
731 SendFailedReply(content.inMsg);
732 } else {
733 (void)FreeBuffer(NULL, content.inMsg);
734 }
735 }
736 g_ipcCallbackCb.threadWorking = false;
737 return NULL;
738 }
739
StartCallbackDispatch(void)740 static int32_t StartCallbackDispatch(void)
741 {
742 pthread_attr_t threadAttr;
743 pthread_attr_init(&threadAttr);
744 pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
745
746 pthread_t tid;
747 int32_t ret = pthread_create(&tid, &threadAttr, CallbackDispatch, NULL);
748 if (ret != 0) {
749 LOG_ERRNO("Create callback dispatch thread failed.");
750 return LITEIPC_EINTNL;
751 }
752
753 struct timespec spark, now;
754 clock_gettime(CLOCK_REALTIME, &spark);
755 sched_yield();
756 while (!g_ipcCallbackCb.threadWorking) {
757 clock_gettime(CLOCK_REALTIME, &now);
758 if (now.tv_sec - spark.tv_sec > 1) {
759 LOG(ERROR, "Wait callback thread starting timeout.");
760 return LITEIPC_EINTNL;
761 }
762 sched_yield();
763 }
764 return LITEIPC_OK;
765 }
766
767 #if (ENABLE_IPC_CB_TIMER == YES)
TimeoutHandler(int signo,void * arg)768 static void TimeoutHandler(int signo, void *arg)
769 {
770 AnonymousApi* node = (AnonymousApi*)arg;
771 SvcIdentity sid = {
772 .handle = g_ipcCallbackCb.handleId,
773 .token = node->token
774 };
775 UnregisterIpcCallback(sid);
776 }
777
StartIpcCbTimer(uint32_t mode,uint32_t timeoutMs,AnonymousApi * node,timer_t * timerId)778 int32_t StartIpcCbTimer(uint32_t mode, uint32_t timeoutMs, AnonymousApi* node, timer_t* timerId)
779 {
780 int ret;
781 struct itimerspec its;
782 struct sigevent sev;
783 struct sigaction sa;
784
785 sa.sa_flags = 0;
786 sa.sa_handler = (TimerHandler)TimeoutHandler;
787 sigemptyset(&sa.sa_mask);
788 ret = sigaction(SIGUSR1, &sa, NULL);
789 if (ret != 0) {
790 LOG(ERROR, "sigaction failed.");
791 return LITEIPC_EINTNL;
792 }
793
794 /* Create the timer */
795 memset_s(&sev, sizeof(struct sigevent), 0, sizeof(struct sigevent));
796 sev.sigev_notify = SIGEV_SIGNAL;
797 sev.sigev_signo = SIGUSR1;
798 sev.sigev_value.sival_ptr = node;
799 ret = timer_create(CLOCK_REALTIME, &sev, timerId);
800 if (ret != 0) {
801 LOG(ERROR, "timer_create failed.");
802 return LITEIPC_EINTNL;
803 }
804
805 /* Start the timer */
806 its = IpcTimeout2Timerspec(timeoutMs);
807 ret = timer_settime(*timerId, 0, &its, NULL);
808 if (ret != 0) {
809 LOG(ERROR, "timer_settime failed.");
810 timer_delete(*timerId);
811 return LITEIPC_EINTNL;
812 }
813
814 return LITEIPC_OK;
815 }
816 #endif
817
RegisterIpcCallback(IpcMsgHandler func,uint32_t mode,uint32_t timeoutMs,SvcIdentity * sid,void * arg)818 int32_t RegisterIpcCallback(IpcMsgHandler func, uint32_t mode, uint32_t timeoutMs, SvcIdentity* sid, void* arg)
819 {
820 #if (ENABLE_IPC_CB_TIMER == YES)
821 timer_t timerId = NULL;
822 #endif
823 if ((func == NULL) || (sid == NULL) || (mode > RESET_AFTER_USE) || (timeoutMs < IPC_TIMEOUT_MIN)) {
824 return LITEIPC_EINVAL;
825 }
826 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
827 LOG_ERRNO("Get callback mutex failed.");
828 return LITEIPC_EINTNL;
829 }
830
831 int ret = LITEIPC_OK;
832 /* Start callback thread if it's not working */
833 if (!g_ipcCallbackCb.threadWorking) {
834 ret = StartCallbackDispatch();
835 if (ret != LITEIPC_OK) {
836 goto ERROR;
837 }
838 }
839
840 AnonymousApi* node = (AnonymousApi*)malloc(sizeof(AnonymousApi));
841 if (node == NULL) {
842 LOG(ERROR, "Malloc failed.(size=%zu)", sizeof(AnonymousApi));
843 ret = LITEIPC_EINTNL;
844 goto ERROR;
845 }
846 node->token = (uint32_t)(uintptr_t)node;
847 node->hdlerPair.usedFlag = true;
848 node->hdlerPair.hdler = func;
849 node->hdlerPair.arg = arg;
850 #if (ENABLE_IPC_CB_TIMER == YES)
851 /* if timeout is not forever, create and start a cb timer */
852 if (timeoutMs != IPC_WAIT_FOREVER) {
853 ret = StartIpcCbTimer(mode, timeoutMs, node, &timerId);
854 if (ret != LITEIPC_OK) {
855 LOG(ERROR, "StartIpcCbTimer failed.");
856 free(node);
857 goto ERROR;
858 }
859 node->timerId = timerId;
860 } else {
861 node->timerId = IPC_INVAILD_TIMER_ID;
862 }
863 node->mode = mode;
864 node->timeout = timeoutMs;
865 #endif
866 UtilsListAdd(&g_ipcCallbackCb.apis, &node->list);
867 sid->token = node->token;
868 sid->handle = g_ipcCallbackCb.handleId;
869
870 ERROR:
871 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
872 return ret;
873 }
874
UnregisterIpcCallback(SvcIdentity sid)875 int32_t UnregisterIpcCallback(SvcIdentity sid)
876 {
877 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
878 LOG_ERRNO("Get callback mutex failed.");
879 return LITEIPC_EINTNL;
880 }
881
882 AnonymousApi* node = NULL;
883 AnonymousApi* next = NULL;
884 if (sid.handle != g_ipcCallbackCb.handleId) {
885 LOG(ERROR, "Not a ipc callback sid.");
886 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
887 return LITEIPC_EINVAL;
888 }
889 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcCallbackCb.apis, AnonymousApi, list)
890 {
891 if (node->token == sid.token) {
892 #if (ENABLE_IPC_CB_TIMER == YES)
893 if (node->timerId != IPC_INVAILD_TIMER_ID) {
894 timer_delete(node->timerId);
895 }
896 #endif
897 UtilsListDelete(&node->list);
898 free(node);
899 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
900 return LITEIPC_OK;
901 }
902 }
903
904 LOG(ERROR, "Input sid not exist.");
905 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
906
907 return LITEIPC_OK;
908 }
909
SetDeathHandlerPair(Testament * node,uint32_t index,IpcMsgHandler func,void * arg)910 static inline uint32_t SetDeathHandlerPair(Testament* node, uint32_t index, IpcMsgHandler func, void* arg)
911 {
912 node->hdlerPairs[index].usedFlag = true;
913 node->hdlerPairs[index].hdler = func;
914 node->hdlerPairs[index].arg = arg;
915 return index;
916 }
917
RegisterDeathCallback(const IpcContext * context,SvcIdentity sid,IpcMsgHandler func,void * arg,uint32_t * cbId)918 int32_t RegisterDeathCallback(const IpcContext* context, SvcIdentity sid, IpcMsgHandler func, void* arg, uint32_t* cbId)
919 {
920 int i;
921 int ret = LITEIPC_OK;
922 Testament* node = NULL;
923
924 if ((func == NULL) || (cbId == NULL)) {
925 return LITEIPC_EINVAL;
926 }
927
928 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
929 LOG_ERRNO("Get callback mutex failed.");
930 return LITEIPC_EINTNL;
931 }
932
933 /* Start callback thread if it's not working */
934 if (!g_ipcCallbackCb.threadWorking && (ret = StartCallbackDispatch()) != LITEIPC_OK) {
935 ret = LITEIPC_EINTNL;
936 goto UNLOCK_RETURN;
937 }
938
939 UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_ipcCallbackCb.testaments, Testament, list)
940 {
941 if (node->handle != sid.handle) {
942 continue;
943 }
944
945 if (node->size == MAX_DEATHCB_PER_SVC) {
946 LOG(ERROR, "Reach max num on this svc:%d", sid.handle);
947 ret = LITEIPC_EINTNL;
948 goto UNLOCK_RETURN;
949 }
950 for (i = 0; i < MAX_DEATHCB_PER_SVC; i++) {
951 if (node->hdlerPairs[i].usedFlag == false) {
952 node->size++;
953 *cbId = SetDeathHandlerPair(node, i, func, arg);
954 break;
955 }
956 }
957 goto UNLOCK_RETURN;
958 }
959 node = (Testament*)malloc(sizeof(Testament));
960 if (node == NULL) {
961 LOG(ERROR, "Malloc failed.(size=%zu)", sizeof(Testament));
962 ret = LITEIPC_ENOMEM;
963 goto UNLOCK_RETURN;
964 }
965 (void)memset_s(node, sizeof(Testament), 0, sizeof(Testament));
966 node->handle = sid.handle;
967 node->size = 1;
968 *cbId = SetDeathHandlerPair(node, 0, func, arg);
969 UtilsListAdd(&g_ipcCallbackCb.testaments, &node->list);
970
971 UNLOCK_RETURN:
972 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
973 return ret;
974 }
975
UnregisterDeathCallback(SvcIdentity sid,uint32_t cbId)976 int32_t UnregisterDeathCallback(SvcIdentity sid, uint32_t cbId)
977 {
978 Testament* node = NULL;
979 Testament* next = NULL;
980 if (cbId >= MAX_DEATHCB_PER_SVC) {
981 LOG(ERROR, "Wrong cbId:%u.", cbId);
982 return LITEIPC_EINVAL;
983 }
984 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
985 LOG_ERRNO("Get callback mutex failed.");
986 return LITEIPC_EINTNL;
987 }
988 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcCallbackCb.testaments, Testament, list)
989 {
990 if (node->handle == sid.handle) {
991 if ((node->isCallbackRuning == false) && (node->hdlerPairs[cbId].usedFlag == true)) {
992 node->hdlerPairs[cbId].usedFlag = false;
993 node->size--;
994 if (node->size == 0) {
995 UtilsListDelete(&node->list);
996 free(node);
997 }
998 }
999 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
1000 return LITEIPC_OK;
1001 }
1002 }
1003 LOG(ERROR, "Input sid not exist.");
1004 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
1005
1006 return LITEIPC_OK;
1007 }
1008
RemoveDeathCallback(uint32_t handle)1009 static void RemoveDeathCallback(uint32_t handle)
1010 {
1011 Testament* node = NULL;
1012 Testament* next = NULL;
1013
1014 if (pthread_mutex_lock(&g_ipcCallbackCb.mutex) != 0) {
1015 LOG_ERRNO("Get callback mutex failed.");
1016 return;
1017 }
1018 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcCallbackCb.testaments, Testament, list)
1019 {
1020 if (node->handle == handle) {
1021 UtilsListDelete(&node->list);
1022 free(node);
1023 break;
1024 }
1025 }
1026 pthread_mutex_unlock(&g_ipcCallbackCb.mutex);
1027 }
1028
BinderAcquire(const IpcContext * context,uint32_t handle)1029 int32_t BinderAcquire(const IpcContext* context, uint32_t handle)
1030 {
1031 return LITEIPC_OK;
1032 }
1033
BinderRelease(const IpcContext * context,uint32_t handle)1034 int32_t BinderRelease(const IpcContext* context, uint32_t handle)
1035 {
1036 return LITEIPC_OK;
1037 }
1038