• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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