Init basesystem source codes.
[staging/basesystem.git] / systemservice / task_manager / server / src / tskm_svc.cpp
1 /*
2  * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "system_service/tskm_svc.h"
18 #include <string.h>
19 #include <stdlib.h>
20 #include <sys/inotify.h>
21 #include <errno.h>
22
23 #include <native_service/ns_np_service_if.h>
24 #include <string>
25
26 #include "tskm_debug.h"
27 #include "tskm_util.h"
28 #include "tskm_port_pf.h"
29 #include "tskm_port_subsys.h"
30 #include "tskm_comm.h"
31
32
33 /*********************************************************
34  *       Is the target event of the service handler?
35
36  *********************************************************/
37 TSKM_STATIC TSKM_BOOL_t isSvcEvent(const TSKM_EVENT_INFO_t* p_ev) {
38   switch (p_ev->event) {
39     case TSKM_EV_PRI_REP_CONNECT:
40     case TSKM_EV_PRI_REP_DISCONNECT:
41     case TSKM_EV_PRI_RES_WAKEUP:
42     case TSKM_EV_PRI_RES_DOWN:
43     case TSKM_EV_PRI_RES_DEBUGDUMP:
44     case TSKM_EV_PRI_REQ_EXIT:
45     case TSKM_EV_SVC_REP_TERM:
46       return TSKM_TRUE;
47       break;
48     default:
49       break;
50   }
51   return TSKM_FALSE;
52 }
53
54 /*********************************************************
55  *       Get service context
56  *********************************************************/
57 TSKM_STATIC TSKM_SVC_CTX_t*
58 getSvcCtxBySvcId(TSKM_SVCS_CTX_t* p_svcs, TSKM_SVCID_t svcId) {
59   uint32_t ii;
60
61   for (ii = 0; ii < p_svcs->svcNum; ii++) {
62     if (p_svcs->svcList[ii].attr->svcId == svcId) {
63       return &p_svcs->svcList[ii];
64     }
65   }
66   TSKM_ASSERT(0);
67   return NULL;
68 }
69
70 /*********************************************************
71  *       Get service context
72  *********************************************************/
73 TSKM_STATIC TSKM_SVC_CTX_t*
74 getSvcCtxByPid(TSKM_SVCS_CTX_t* p_svcs, pid_t pid) {
75   uint32_t ii;
76
77   for (ii = 0; ii < p_svcs->svcNum; ii++) {
78     if (p_svcs->svcList[ii].pid == pid) {
79       return &p_svcs->svcList[ii];
80     }
81   }
82   return NULL;
83 }
84
85 /*********************************************************
86  *       Get service context
87  *********************************************************/
88 TSKM_STATIC TSKM_SVC_CTX_t*
89 getSvcCtxByName(TSKM_SVCS_CTX_t* p_svcs, const char *p_name) {  // LCOV_EXCL_START 6: Because the condition cannot be set
90   AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
91   uint32_t ii;
92
93   for (ii = 0; ii < p_svcs->svcNum; ii++) {
94     if (0
95         == strncmp(p_svcs->svcList[ii].attr->name, p_name,
96                    strlen(p_svcs->svcList[ii].attr->name))) {
97       return &p_svcs->svcList[ii];
98     }
99   }
100   return NULL;
101 }
102 // LCOV_EXCL_STOP
103 /*********************************************************
104  *      Issuing a start request to the service
105  *********************************************************/
106 TSKM_STATIC TSKM_ERR_t wakeupRequest(TSKM_SVC_CTX_t* p_svc,
107                                      TSKM_GSTEP_REQ_INFO_t* p_req) {
108   TSKM_EVENT_INFO_t ev;
109   int ret;
110   bzero(&ev, sizeof(ev));
111
112   ev.event = TSKM_EV_PRI_REQ_WAKEUP;
113   ev.errCode = TSKM_E_OK;
114   ev.prm.reqWakeup.svcId = p_svc->attr->svcId;
115   ev.prm.reqWakeup.localStep = p_req->localStep;
116   ev.prm.reqWakeup.isDynamic =
117       (p_svc->attr->lifeCycle == TSKM_SVC_LC_DYNAMIC) ? TSKM_TRUE : TSKM_FALSE;
118   // Since there is no startup in the P_CWORD72_ but only communication in the ALL/LAST,
119   // the startup information is optimized including the startup information in the communication of the WakeupRequest.
120   memcpy(&ev.prm.reqWakeup.bootInfo, &p_svc->bootInfo,
121          sizeof(ev.prm.reqWakeup.bootInfo));
122   memcpy(&ev.prm.reqWakeup.extBootInfo, &p_svc->extBootInfo,
123          sizeof(ev.prm.reqWakeup.extBootInfo));
124
125   ret = tskm_sockSend(p_svc->connFd, &ev);
126   if (ret <= 0) {
127     TSKM_ASSERT(0);
128     goto ERROR;
129   }
130   p_svc->waitResCnt++;
131   p_svc->state = TSKM_SVC_WAKEUP;
132
133   return TSKM_E_OK;
134   ERROR: return TSKM_E_NG;
135 }
136
137 /*********************************************************
138  *       Touch services and extend EXIT timeouts
139  *********************************************************/
140 TSKM_STATIC TSKM_ERR_t reqTouch(TSKM_SVC_CTX_t* p_svc) {
141 #define TSKM_BUF_LEN     ( 4 * ( sizeof(struct inotify_event) ) )  /* read size */
142   TSKM_ERR_t funcRet = TSKM_E_NG;
143   char touchFileName[32];
144   BOOL isNeedRetry = FALSE;
145
146   int iFd = p_svc->iFd;
147   int wd = 0;
148
149   TSKM_EVENT_INFO_t ev;
150   int ret;
151   bzero(&ev, sizeof(ev));
152
153   // Create monitoring files
154   tskm_pf_mkTouchFileName(p_svc->pid, touchFileName);
155   if (0 != tskm_pf_touch(touchFileName)) {
156     goto ERROR;
157   }
158
159   // Synchronize by iNortify
160   wd = inotify_add_watch(iFd, touchFileName, IN_DELETE_SELF);
161   if (wd == -1) {
162     TSKM_ASSERT_ERRNO(0);
163     goto ERROR;
164   }
165
166   // Send Touch request
167   ev.event = TSKM_EV_PRI_REQ_TOUCH;
168   ev.errCode = TSKM_E_OK;
169   ret = tskm_sockSend(p_svc->connFd, &ev);
170   if (ret <= 0) {
171     // Immediately after the nonresident service process terminates, since the TaskManager service status is other than DORMANT
172     // (mainly DOWN), the socket may be discarded and communication may fail, so retry
173     funcRet = TSKM_E_RETRY;
174     TSKM_PRINTF(TSKM_LOG_WARN, "ret = %d", ret);
175     goto ERROR;
176   }
177
178   // Wait for Touch completion
179   while (1) {
180     int maxFd = 0;
181     int ret;
182     fd_set fds;
183     FD_ZERO(&fds);
184     struct timeval timeout = { 0 };
185     timeout.tv_sec = TSKM_CFG_TOUCH_TIMEOUT;
186
187     FD_SET(iFd, &fds);
188     maxFd = iFd;
189
190     ret = select(maxFd + 1, &fds, NULL, NULL, &timeout);
191     if (ret == 0) {
192       TSKM_ASSERT_PRINT(0, "TIMEOUT:%s", touchFileName);  // Timeout occurs
193       isNeedRetry = TRUE;
194       break;
195     } else if (ret < 1) {
196       if (errno == EINTR) {
197         continue;
198       } else {
199         TSKM_ASSERT(0);
200         goto ERROR;
201       }
202     }
203
204     if (FD_ISSET(iFd, &fds)) {
205       int length;
206       uint8_t buf[TSKM_BUF_LEN];
207
208       length = static_cast<int>(read(iFd, buf, TSKM_BUF_LEN));
209       if (length < 0) {
210         TSKM_ASSERT_ERRNO(0);
211         goto ERROR;
212       }
213       struct inotify_event *event = (struct inotify_event *) buf;
214       if (event->mask & IN_DELETE_SELF) {
215         TSKM_PRINTF(TSKM_LOG_STATE, "TouchOK");
216         wd = 0;
217         // When a file is deleted, the association with the monitoring target is automatically released and inotify_rm_watch is no longer needed.
218         break;
219       } else {
220         TSKM_ASSERT_PRINT(0, "%x", event->mask);
221       }
222     }
223   }
224
225   if (isNeedRetry) {
226     funcRet = TSKM_E_RETRY;
227   } else {
228     funcRet = TSKM_E_OK;
229   }
230
231   ERROR: if (wd > 0) {
232     TSKM_ASSERT_ERRNO(0 == inotify_rm_watch(iFd, wd))
233   }
234
235   if (access(touchFileName, F_OK) == 0) {
236     // Timeout care
237     unlink(touchFileName);
238   }
239
240   return funcRet;
241 }
242
243 /*********************************************************
244  *       Availability Monitoring Callbacks for Services
245  *********************************************************/
246 EFrameworkunifiedStatus OnSvcAvailability(HANDLE hApp) {  // LCOV_EXCL_START 6: Because the condition cannot be set
247   AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
248   PCSTR availabilityName;
249   TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
250   TSKM_SVC_CTX_t* p_svc;
251
252   availabilityName = FrameworkunifiedGetLastNotification(hApp);
253
254   std::string str = availabilityName;
255
256 //  unsigned int position;
257 //  if (std::string::npos != (position = static_cast<unsigned int>(str.find("/Availability", 0)))) {
258   ssize_t position;
259   if (0 <= (position = str.find("/Availability", 0))) {
260     str.erase(position, position + strlen("/Availability"));
261   }
262
263   p_svc = getSvcCtxByName(&p_main->svcs, str.c_str());
264   if (p_svc) {
265     p_svc->isAvailable = FrameworkunifiedIsServiceAvailable(hApp) ? TSKM_TRUE : TSKM_FALSE;
266     TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s Availability %s", p_svc->attr->name,
267                 (p_svc->isAvailable == TSKM_TRUE) ? "TRUE" : "FALSE");
268   }
269
270   return eFrameworkunifiedStatusOK;
271 }
272 // LCOV_EXCL_STOP
273 /*********************************************************
274  *       Starting Availability Monitoring of Services
275  *********************************************************/
276 TSKM_STATIC TSKM_ERR_t startWatchAvailability(TSKM_SVC_CTX_t* p_svc) {
277   TSKM_ERR_t funcRet = TSKM_E_OK;
278
279   // LCOV_EXCL_BR_START 8: Since the condition is checked by the caller, it is not true.
280   if (p_svc->attr->type == TSKM_SVC_TYPE_UNKNONW) {
281   // LCOV_EXCL_BR_STOP
282     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
283     p_svc->isAvailable = TSKM_TRUE;  // LCOV_EXCL_LINE 8: Since the condition is checked by the caller, it is not true.
284   } else {
285     EFrameworkunifiedStatus taskmanagerStatus;
286     TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
287     SS_String availabilityName = p_svc->attr->name;
288
289     availabilityName.append("/Availability");
290
291     taskmanagerStatus = FrameworkunifiedSubscribeNotificationWithCallback(p_main->hApp,
292                                                      availabilityName.c_str(),
293                                                      OnSvcAvailability);
294     if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
295       TSKM_ASSERT(0);
296       funcRet = TSKM_E_NG;
297     }
298   }
299
300   return funcRet;
301 }
302
303 /*********************************************************
304  *       Service startup sub
305  *********************************************************/
306 void svcExec_Process(TSKM_SVC_CTX_t* p_svc) {
307   TSKM_ERR_t funcRet;
308
309   if (p_svc->attr->type == TSKM_SVC_TYPE_NATIVE) {
310     p_svc->state = TSKM_SVC_WAITCONNECT;
311     TSKM_PRINTF(TSKM_LOG_DEBUG, "[ST:%d] WAIT_EXEC", p_svc->pid);
312     funcRet = startWatchAvailability(p_svc);
313     if (TSKM_E_OK != funcRet) {
314       TSKM_ASSERT(0);
315       p_svc->isAvailable = TSKM_TRUE;
316     }
317   } else {
318     p_svc->state = TSKM_SVC_RUNNING;
319     TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] RUN", p_svc->pid);
320     p_svc->isAvailable = TSKM_TRUE;
321   }
322   return;
323 }
324
325 /*********************************************************
326  *       Service startup main
327  *********************************************************/
328 TSKM_STATIC TSKM_ERR_t svcExec(TSKM_SVC_CTX_t* p_svc) {
329   TSKM_ERR_t funcRet = TSKM_E_NG;
330   pid_t pid;
331
332   if (p_svc == NULL) {  // LCOV_EXCL_BR_LINE 6:double check
333     // LCOV_EXCL_START 6: double check
334     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
335     TSKM_ASSERT(0);
336     goto ERROR;
337     // LCOV_EXCL_STOP
338   }
339
340   if (p_svc->state == TSKM_SVC_DISABLE) {
341     // Prohibited startup
342     TSKM_ASSERT(0);
343     return TSKM_E_STATE;
344   } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
345     return TSKM_E_OK;
346   } else if (p_svc->state != TSKM_SVC_DORMANT) {
347     // Already started
348     funcRet = reqTouch(p_svc);
349     if (TSKM_E_OK != funcRet) {
350       TSKM_PRINTF(TSKM_LOG_WARN, "funcRet = %d", funcRet);
351       goto ERROR;
352     }
353     return TSKM_E_OK;
354   }
355
356   pid = tskm_pf_createProc(p_svc->attr);
357   if (pid <= 0) {
358     TSKM_ASSERT(0);
359     goto ERROR;
360   }
361   TSKM_PRINTF(TSKM_LOG_STATE, "EXEC %s:%d", p_svc->attr->name, pid);
362
363   p_svc->pid = pid;
364   p_svc->waitReqCnt = 0;
365
366   // Startup service
367   svcExec_Process(p_svc);
368
369   funcRet = TSKM_E_OK;
370   ERROR: return funcRet;
371 }
372
373 /*********************************************************
374  *       Issuing a start request to the service
375  *********************************************************/
376 TSKM_STATIC TSKM_ERR_t svcWakeupRequest(TSKM_SVC_CTX_t* p_svc,
377                                         TSKM_GSTEP_REQ_INFO_t* p_req) {
378   if (p_svc == NULL || p_svc->state == TSKM_SVC_DISABLE) {  // LCOV_EXCL_BR_LINE 6: Since this function has always been called after checking // NOLINT(whitespace/line_length)
379     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
380     return TSKM_E_STATE;  // LCOV_EXCL_LINE 6: Since this function has always been called after checking
381   } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
382     // Remember it once and issue a request when the CONNECT completes.
383     p_svc->request[p_svc->waitReqCnt] = *p_req;
384     p_svc->waitReqCnt++;
385   } else {
386     TSKM_ERR_t tskmRet;
387     tskmRet = wakeupRequest(p_svc, p_req);
388     TSKM_ERR_CHK_DFT;
389   }
390
391   return TSKM_E_OK;
392   ERROR: return TSKM_E_NG;
393 }
394
395 /*********************************************************
396  *      Service reboot processing
397  *********************************************************/
398 TSKM_STATIC TSKM_ERR_t svcErrTermPost(TSKM_SVC_CTX_t* p_svc) {
399   TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
400
401   TSKM_PRINTF(TSKM_LOG_SYSTEMDATA, "ERR TERM SVC(%s:%d)", p_svc->attr->name,
402               p_svc->pid);
403
404   if (p_svc->attr->lifeCycle == TSKM_SVC_LC_ALWAYS || (p_svc->errTermCnt > p_svc->attr->retryCnt && (uint32_t) -1 != p_svc->attr->retryCnt)) {  // NOLINT(whitespace/line_length)
405     TSKM_ERROR_REBOOT_t rebootInfo;
406
407     TSKM_ASSERT(0);
408     memset(&rebootInfo, 0, sizeof(TSKM_ERROR_REBOOT_t));
409     rebootInfo.type = TSKM_ERROR_REBOOT_NORMAL;
410     snprintf(rebootInfo.log.messageStr, TSKM_LOGGING_MSG_STR_SIZE,
411              "TaskManager:SVC ErrTerm");
412     tskm_sub_reboot(&rebootInfo);
413   } else {
414     TSKM_LOGGING_INFO_t logInfo;
415     logInfo.type = TSKM_LOGGING_TYPE_MODULE_LOGS;
416
417     snprintf(logInfo.messageStr, TSKM_LOGGING_MSG_STR_SIZE,
418              "TaskManager:SVC ErrTerm");
419     tskm_sub_logging(&logInfo);
420
421     if (p_svc->attr->lifeCycle == TSKM_SVC_LC_ALWAYS_RECOVERABLE) {
422       TSKM_ERR_t ret;
423       TSKM_GSTEP_REQ_INFO_t req = { 0 };
424
425       ret = svcExec(p_svc);
426
427       if (TSKM_E_OK != ret) {
428         TSKM_ASSERT_PRINT(0, "ret = %d", ret);
429         goto ERROR;
430       } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
431         // In the state waiting for execution
432         req.svcId = p_svc->attr->svcId;
433         req.localStep = TSKM_LSTEP_ALL;
434         ret = svcWakeupRequest(p_svc, &req);
435         if (TSKM_E_OK != ret) {
436           TSKM_ASSERT_PRINT(0, "ret = %d", ret);
437           goto ERROR;
438         }
439       }
440     }
441   }
442
443   return TSKM_E_OK;
444   ERROR: return TSKM_E_NG;
445 }
446
447 /*********************************************************
448  *      Connection handler
449  * ret:TRUE     SVC status changed
450  * ret:FALSE    SVC status not changed
451  *********************************************************/
452 TSKM_STATIC TSKM_BOOL_t connectHandle(TSKM_SVC_CTX_t* p_svc,
453                                       const TSKM_EVENT_INFO_t* p_inEv) {
454   uint32_t ii;
455
456   TSKM_ASSERT(p_svc->state == TSKM_SVC_WAITCONNECT);
457
458   p_svc->connFd = p_inEv->prm.repConnect.connFd;
459   p_svc->state = TSKM_SVC_WAKEUP;
460   TSKM_PRINTF(TSKM_LOG_DEBUG, "[ST:%d] WAKEUP", p_svc->pid);
461
462   p_svc->waitResCnt = 0;
463
464   if (p_svc->waitReqCnt) {
465     for (ii = 0; ii < p_svc->waitReqCnt; ii++) {
466       TSKM_ASSERT(TSKM_E_OK == wakeupRequest(p_svc, &p_svc->request[ii]));
467     }
468     p_svc->waitReqCnt = 0;
469   }
470
471   return TSKM_TRUE;
472 }
473
474 /*********************************************************
475  *      Disconnection handler
476  * ret:TRUE     SVC status changed
477  * ret:FALSE    SVC status not changed
478  *********************************************************/
479 TSKM_STATIC TSKM_BOOL_t disConnectHandle(TSKM_SVC_CTX_t* p_svc,
480                                          const TSKM_EVENT_INFO_t* p_inEv) {
481   // No status change
482
483   return TSKM_TRUE;
484 }
485
486 /*********************************************************
487  *      Response handler for the activation request
488  * ret:TRUE     SVC status changed
489  * ret:FALSE    SVC status not changed
490  *********************************************************/
491 TSKM_STATIC TSKM_BOOL_t resWakeupHandle(TSKM_SVC_CTX_t* p_svc,
492                                         const TSKM_EVENT_INFO_t* p_inEv) {
493   TSKM_ASSERT(p_svc->state == TSKM_SVC_WAKEUP);
494   TSKM_ASSERT(p_svc->waitResCnt > 0);
495   TSKM_BOOL_t isStateChg = TSKM_FALSE;
496
497   if (p_svc->isShmDone == TSKM_FALSE && p_inEv->prm.resWakeup.isShmDone) {
498     p_svc->isShmDone = TSKM_TRUE;
499     isStateChg = TSKM_TRUE;
500     TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s:SHM DONE", p_svc->attr->name);
501   }
502   if (p_svc->isStepDone == TSKM_FALSE && p_inEv->prm.resWakeup.isStepDone) {
503     p_svc->isStepDone = TSKM_TRUE;
504     isStateChg = TSKM_TRUE;
505     TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s:STEP DONE", p_svc->attr->name);
506   }
507
508   if (p_svc->waitResCnt > 0) {
509     p_svc->waitResCnt--;
510     if (p_svc->waitResCnt == 0) {  // Transition when the wait runs out
511       if (p_inEv->prm.resWakeup.isLast) {
512         p_svc->state = TSKM_SVC_RUNNING;  // Startup completed
513         TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] RUN", p_svc->pid);
514       }
515       isStateChg = TSKM_TRUE;
516     }
517   }
518   return isStateChg;
519 }
520
521 /*********************************************************
522  *      Response handler for the termination request
523  * ret:TRUE     SVC state changed
524  * ret:FALSE    SVC state not changed
525  *********************************************************/
526 TSKM_STATIC TSKM_BOOL_t resDownHandle(TSKM_SVC_CTX_t* p_svc,
527                                       const TSKM_EVENT_INFO_t* p_inEv) {
528   TSKM_ASSERT(p_svc->state == TSKM_SVC_DOWN);
529   TSKM_ASSERT(p_svc->waitResCnt > 0);
530   TSKM_BOOL_t isStateChg = TSKM_FALSE;
531
532   TSKM_PRINTF(TSKM_LOG_DEBUG, "pid:%d waitCnt:%d", p_svc->pid,
533               p_svc->waitResCnt);
534   if (p_svc->waitResCnt > 0) {
535     p_svc->waitResCnt--;
536     if (p_svc->waitResCnt == 0) {  // Transition when the wait runs out
537       if (p_inEv->prm.resWakeup.isLast) {
538         p_svc->state = TSKM_SVC_FINDOWN;   // Termination complete
539         TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] FIN_DOWN", p_svc->pid);
540       }
541       isStateChg = TSKM_TRUE;
542     }
543   }
544   return isStateChg;
545 }
546
547 /*********************************************************
548  *      Response Handlers for DebugDump Requests
549  * ret:TRUE     SVC state changed
550  * ret:FALSE    SVC state not changed
551  *********************************************************/
552 TSKM_STATIC TSKM_BOOL_t resDebugDumpHandle(TSKM_SVC_CTX_t* p_svc,
553                                            const TSKM_EVENT_INFO_t* p_inEv) {
554   TSKM_BOOL_t isStateChg = TSKM_FALSE;
555   TSKM_EV_PRI_EX_RES_DEBUGDUMP_PRM_t *p_prm;
556
557   if (!p_inEv->hasExtend || !p_inEv->extendPrm) {
558     TSKM_ASSERT(0);
559     goto ERROR;
560   }
561
562   p_prm = (TSKM_EV_PRI_EX_RES_DEBUGDUMP_PRM_t *) p_inEv->extendPrm;  // NOLINT (readability/casting)
563
564   // FALSE is specified here because the required service names have been added in the PrimaryLib.
565   tskm_sub_debugDumpRes(FALSE, p_prm->dumpMsg);
566
567   ERROR: return isStateChg;
568 }
569
570 /*********************************************************
571  *      Service termination request
572  * ret:TRUE     SVC state changed
573  * ret:FALSE    SVC state not changed
574  *********************************************************/
575 TSKM_STATIC TSKM_BOOL_t reqExit(TSKM_SVC_CTX_t* p_svc,
576                                 const TSKM_EVENT_INFO_t* p_inEv) {
577   int ret;
578   TSKM_ERR_t tskmRet;
579   TSKM_ASSERT(p_svc->state == TSKM_SVC_RUNNING);
580   TSKM_ASSERT(p_svc->waitResCnt == 0);
581   TSKM_GSTEP_REQ_INFO_t req = { 0 };
582
583   req.svcId = p_svc->attr->svcId;
584   req.localStep = TSKM_LSTEP_ALL;
585   tskmRet = tskm_svcDownRequest(p_svc, &req);
586   TSKM_ERR_CHK_DFT;
587
588   return TSKM_TRUE;
589
590   // LCOV_EXCL_START 8: dead code
591   AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
592   ERROR: ret = tskm_pf_terminateProcGroup(static_cast<uint16_t>(p_svc->pid));
593   if (ret != 0) {  // LCOV_EXCL_BR_LINE 8: dead code
594     TSKM_PRINTF(TSKM_LOG_WARN, "ret = %d", ret);
595   }
596
597   return TSKM_TRUE;
598   // LCOV_EXCL_STOP
599 }
600
601 /*********************************************************
602  *      Service termination handler
603  * ret:TRUE     SVC state changed
604  * ret:FALSE    SVC state not changed
605  *********************************************************/
606 TSKM_STATIC TSKM_BOOL_t repTermHandle(TSKM_SVC_CTX_t* p_svc,
607                                       const TSKM_EVENT_INFO_t* p_inEv) {
608   int ret;
609
610   // Check error
611   if (p_svc->attr->lifeCycle == TSKM_SVC_LC_DYNAMIC) {
612     if (p_svc->state != TSKM_SVC_DOWN) {
613       // A STATE other than DOWN does not terminate.
614       TSKM_PRINTF(TSKM_LOG_ERROR, "ERR TERM %s(%d) waitCnt:%d",
615                   p_svc->attr->name, p_svc->pid, p_svc->waitResCnt);
616       TSKM_ASSERT(0);
617     }
618   } else {
619     // The resident service terminated.
620     TSKM_PRINTF(TSKM_LOG_ERROR, "ERR TERM %s(%d) waitCnt:%d", p_svc->attr->name,
621                 p_svc->pid, p_svc->waitResCnt);
622     TSKM_ASSERT(0);
623   }
624
625   TSKM_PRINTF(TSKM_LOG_STATE, "[ST:%d] DORMANT", p_svc->pid);
626
627   p_svc->state = TSKM_SVC_DORMANT;
628   p_svc->waitResCnt = 0;
629   p_svc->pid = 0;
630
631   if (p_svc->attr->type == TSKM_SVC_TYPE_NATIVE) {
632     EFrameworkunifiedStatus taskmanagerStatus;
633     TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
634     SS_String availabilityName = p_svc->attr->name;
635     availabilityName.append("/Availability");
636
637     taskmanagerStatus = FrameworkunifiedUnsubscribeNotificationWithCallback(
638         p_main->hApp, availabilityName.c_str());
639     if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
640       TSKM_ASSERT(0);
641     }
642
643     p_svc->isAvailable = TSKM_FALSE;
644     p_svc->watchCnt = 0;
645
646     HANDLE hMq = McOpenSender(FRAMEWORKUNIFIED_NS_NPSERVICE);
647     if (NULL == hMq) {   // LCOV_EXCL_BR_LINE 4: NSFW error case.
648       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
649       TSKM_ASSERT(0);  // LCOV_EXCL_LINE 4: NSFW error case.
650     } else {
651       ServiceAvailability availInfo = { };
652
653       snprintf(availInfo.cServiceName, MAX_NAME_SIZE_APP, "%s",
654                p_svc->attr->name);
655       availInfo.eServiceAvailability = eFrameworkunifiedServiceNotAvailable;
656
657       taskmanagerStatus = NPPublishNotification(hMq, p_svc->attr->name,
658                                         availabilityName.c_str(), &availInfo,
659                                         sizeof(availInfo));
660       if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
661         TSKM_ASSERT(0);
662       }
663
664       taskmanagerStatus = McClose(hMq);
665       if (eFrameworkunifiedStatusOK != taskmanagerStatus) {  // LCOV_EXCL_BR_LINE 4: NSFW error case.
666         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
667         TSKM_ASSERT(0);  // LCOV_EXCL_LINE 4: NSFW error case.
668       }
669     }
670   }
671
672   if (p_inEv->errCode != TSKM_E_OK) {
673     p_svc->errTermCnt++;
674     // Notify 'NG' at Relaunch after abnormal termination
675     p_svc->bootInfo.resetStatus = e_SS_SM_RESET_STATUS_NG;
676
677     ret = svcErrTermPost(p_svc);
678     if (ret != TSKM_E_OK) {
679       TSKM_ASSERT(0);
680     }
681   } else {
682     // NONE is notified at Relaunch after normal completion.
683     p_svc->bootInfo.resetStatus = e_SS_SM_RESET_STATUS_NONE;
684   }
685
686   return TSKM_TRUE;
687 }
688
689 /*********************************************************
690  *       Get service context
691  *********************************************************/
692 TSKM_SVC_CTX_t*
693 tskm_svcsGetSvcBySvcId(TSKM_SVCS_CTX_t* p_svcs, TSKM_SVCID_t svcId) {
694   return getSvcCtxBySvcId(p_svcs, svcId);
695 }
696
697 /*********************************************************
698  *       Get service context
699  *********************************************************/
700 TSKM_SVC_CTX_t*
701 tskm_svcsGetSvcByPid(TSKM_SVCS_CTX_t* p_svcs, pid_t pid) {
702   return getSvcCtxByPid(p_svcs, pid);
703 }
704
705 /*********************************************************
706  *       Check for waiting services
707  *********************************************************/
708 TSKM_BOOL_t tskm_svcsIsWaiting(TSKM_SVCS_CTX_t* p_svcs) {
709   uint32_t ii;
710   for (ii = 0; ii < p_svcs->svcNum; ii++) {
711     if (p_svcs->svcList[ii].waitResCnt > 0
712         || p_svcs->svcList[ii].state == TSKM_SVC_WAITCONNECT) {
713       return TSKM_TRUE;
714     }
715   }
716   return TSKM_FALSE;
717 }
718
719 /*********************************************************
720  *       Check if ShutdownWait services are terminated
721  *********************************************************/
722 TSKM_SVC_WAIT_STATE_t tskm_svcsGetSvcTermWaitState(TSKM_SVCS_CTX_t* p_svcs) {
723   uint32_t ii;
724   TSKM_SVC_WAIT_STATE_t waitState = TSKM_SVC_WAIT_NONE;
725
726   for (ii = 0; ii < p_svcs->svcNum; ii++) {
727     if (p_svcs->svcList[ii].attr->shotdownWait) {
728       // Check shutdownWait SVC Only
729       if (p_svcs->svcList[ii].state != TSKM_SVC_DORMANT) {
730         // DORMANT is terminated or not started, so no checking is required
731         if (TSKM_SVC_LC_DYNAMIC != p_svcs->svcList[ii].attr->lifeCycle
732             && p_svcs->svcList[ii].state != TSKM_SVC_FINDOWN) {  // Check of termination of resident SVCs
733           waitState = TSKM_SVC_WAIT_BOTH;
734           break;
735         } else if (TSKM_SVC_LC_DYNAMIC == p_svcs->svcList[ii].attr->lifeCycle) {  // Check of termination of non-resident SVCs
736           waitState = TSKM_SVC_WAIT_TRANSIENT;
737         }
738       }
739     }
740   }
741   return waitState;
742 }
743
744 /*********************************************************
745  *       Update boot info of all services
746  *********************************************************/
747 TSKM_ERR_t tskm_svcsSetBootInfo(TSKM_SVCS_CTX_t* p_svcs,
748                                 T_SS_SM_START_DataStructType* p_info,
749                                 T_SS_SM_START_ExtDataStructType *p_exInfo) {
750   uint32_t ii = 0;
751
752   for (ii = 0; ii < p_svcs->svcNum; ii++) {
753     p_svcs->svcList[ii].bootInfo = *p_info;
754     p_svcs->svcList[ii].extBootInfo = *p_exInfo;
755   }
756   return TSKM_E_OK;
757 }
758
759 /*********************************************************
760  *       Terminates a running non-resident services
761  *********************************************************/
762 TSKM_ERR_t tskm_svcsAvtiveSvcTerm(TSKM_SVCS_CTX_t* p_svcs) {
763   uint32_t ii;
764
765   for (ii = 0; ii < p_svcs->svcNum; ii++) {
766     TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
767
768     if (TSKM_SVC_LC_DYNAMIC == p_svc->attr->lifeCycle &&              // Non-resident SVC
769         TSKM_SVC_RUNNING == p_svc->state && p_svc->waitResCnt == 0) {  // Running
770       TSKM_ERR_t tskmRet;
771       TSKM_GSTEP_REQ_INFO_t req = { 0 };
772
773       req.svcId = p_svc->attr->svcId;
774       req.localStep = TSKM_LSTEP_ALL;
775       tskmRet = tskm_svcDownRequest(p_svc, &req);
776       TSKM_ERR_CHK_DFT;
777     }
778   }
779
780   return TSKM_E_OK;
781
782   ERROR:
783   return TSKM_E_NG;
784 }
785
786 /*********************************************************
787  *   Calls back the DebugDump of the running services
788  *********************************************************/
789 TSKM_ERR_t tskm_svcsCallDebugDump(TSKM_SVCS_CTX_t* p_svcs) {
790   for (uint32_t ii = 0; ii < p_svcs->svcNum; ii++) {
791     TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
792
793     if (TSKM_SVC_RUNNING == p_svc->state) {  // Running
794       TSKM_EVENT_INFO_t ev;
795       bzero(&ev, sizeof(ev));
796
797       // Send DebugDump request
798       ev.event = TSKM_EV_PRI_REQ_DEBUGDUMP;
799       ev.errCode = TSKM_E_OK;
800       if (0 >= tskm_sockSend(p_svc->connFd, &ev)) {
801         TSKM_ASSERT(0);
802         goto ERROR;
803       }
804     }
805   }
806
807   return TSKM_E_OK;
808   ERROR: return TSKM_E_NG;
809 }
810
811 /*********************************************************
812  *   Calls back the LowMemory of the running services
813  *********************************************************/
814 TSKM_ERR_t tskm_svcsCallLowMem(TSKM_SVCS_CTX_t* p_svcs) {
815   for (uint32_t ii = 0; ii < p_svcs->svcNum; ii++) {
816     TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
817     if (TSKM_SVC_RUNNING == p_svc->state) {  // Running
818       TSKM_EVENT_INFO_t ev;
819       bzero(&ev, sizeof(ev));
820
821       // Send LowMemory detection notification
822       ev.event = TSKM_EV_PRI_REP_LOWMEM;
823       ev.errCode = TSKM_E_OK;
824       if (0 >= tskm_sockSend(p_svc->connFd, &ev)) {
825         TSKM_ASSERT(0);
826         goto ERROR;
827       }
828     }
829   }
830
831   return TSKM_E_OK;
832   ERROR: return TSKM_E_NG;
833 }
834
835 /*********************************************************
836  *      Event handler
837  *********************************************************/
838 TSKM_ERR_t tskm_svcEventHandle(TSKM_SVC_CTX_t* p_svc, TSKM_EVENT_INFO_t* p_ev) {
839   TSKM_FUNC_IN();
840   TSKM_BOOL_t isStateChg = TSKM_FALSE;
841
842   if (isSvcEvent(p_ev) == TSKM_FALSE) {
843     // If it is not an event for the service, it will be sent as follows.
844     TSKM_FUNC_OUT();
845     return TSKM_E_OK;
846   }
847
848   switch (p_ev->event) {
849     case TSKM_EV_PRI_REP_CONNECT:   // Connection Registration from Service
850       isStateChg = connectHandle(p_svc, p_ev);
851       break;
852     case TSKM_EV_PRI_REP_DISCONNECT:   // Disconnection Registration from Service
853       isStateChg = disConnectHandle(p_svc, p_ev);
854       break;
855     case TSKM_EV_PRI_RES_WAKEUP:    // Response to a startup request from a service
856       isStateChg = resWakeupHandle(p_svc, p_ev);
857       break;
858     case TSKM_EV_PRI_RES_DOWN:
859       isStateChg = resDownHandle(p_svc, p_ev);
860       break;
861     case TSKM_EV_PRI_RES_DEBUGDUMP:
862       isStateChg = resDebugDumpHandle(p_svc, p_ev);
863       break;
864     case TSKM_EV_PRI_REQ_EXIT:
865       isStateChg = reqExit(p_svc, p_ev);
866       break;
867     case TSKM_EV_SVC_REP_TERM:      // Service termination
868       isStateChg = repTermHandle(p_svc, p_ev);
869       break;
870     default:
871       break;
872   }
873
874   // Overwrite service state change
875   if (isStateChg) {
876     p_ev->event = TSKM_EV_LCL_CHG_SVC_STATE;
877     p_ev->prm.chgSvc.svcId = p_svc->attr->svcId;
878   } else {
879     p_ev->event = TSKM_EV_NOP;
880   }
881
882   TSKM_FUNC_OUT();
883   return TSKM_E_OK;
884 }
885 /*********************************************************
886  *       Startup service
887  *********************************************************/
888 TSKM_ERR_t tskm_svcExec(TSKM_SVC_CTX_t* p_svc) {
889   return svcExec(p_svc);
890 }
891
892 /*********************************************************
893  *       Issue a startup request to the service
894  *********************************************************/
895 TSKM_ERR_t tskm_svcWakeupRequest(TSKM_SVC_CTX_t* p_svc,
896                                  TSKM_GSTEP_REQ_INFO_t* p_req) {
897   return svcWakeupRequest(p_svc, p_req);
898 }
899
900 /*********************************************************
901  *       Issue a termination request to the service
902  *********************************************************/
903 TSKM_ERR_t tskm_svcDownRequest(TSKM_SVC_CTX_t* p_svc,
904                                TSKM_GSTEP_REQ_INFO_t* p_req) {
905   int ret;
906   TSKM_EVENT_INFO_t ev;
907
908   bzero(&ev, sizeof(ev));
909
910   if (tskm_svcIsCommunicatable(p_svc) == TSKM_FALSE) {
911     return TSKM_E_OK;
912   }
913
914   ev.event = TSKM_EV_PRI_REQ_DOWN;
915   ev.errCode = TSKM_E_OK;
916   ev.prm.reqDown.localStep = p_req->localStep;
917
918   ret = tskm_sockSend(p_svc->connFd, &ev);
919   if (ret <= 0) {
920     TSKM_ASSERT(0);
921     goto ERROR;
922   }
923   p_svc->waitResCnt++;
924   p_svc->state = TSKM_SVC_DOWN;
925
926   return TSKM_E_OK;
927   ERROR: return TSKM_E_NG;
928 }
929
930 /*********************************************************
931  *       Prohibit starting service
932  *********************************************************/
933 TSKM_ERR_t tskm_svcDisableRequest(TSKM_SVC_CTX_t* p_svc) {
934   if (p_svc->state == TSKM_SVC_DORMANT || p_svc->state == TSKM_SVC_DISABLE) {
935     p_svc->state = TSKM_SVC_DISABLE;
936     return TSKM_E_OK;
937   }
938   return TSKM_E_STATE;
939 }
940
941 /*********************************************************
942  *       Allow starting service
943  *********************************************************/
944 TSKM_ERR_t tskm_svcEnableRequest(TSKM_SVC_CTX_t* p_svc) {
945   if (p_svc->state == TSKM_SVC_DISABLE) {
946     p_svc->state = TSKM_SVC_DORMANT;
947   }
948   return TSKM_E_OK;
949 }
950
951 /*********************************************************
952  *      Queriy whether the service is ready for communication
953  *********************************************************/
954 TSKM_BOOL_t tskm_svcIsCommunicatable(TSKM_SVC_CTX_t* p_svc) {
955   TSKM_BOOL_t ret = TSKM_FALSE;
956   if (p_svc == NULL || p_svc->attr->type == TSKM_SVC_TYPE_UNKNONW) {
957   } else {
958     switch (p_svc->state) {
959       case TSKM_SVC_WAKEUP:
960       case TSKM_SVC_RUNNING:
961       case TSKM_SVC_DOWN:
962         ret = TSKM_TRUE;
963         break;
964       default:
965         break;
966     }
967   }
968   return ret;
969 }  // LCOV_EXCL_BR_LINE 10: Final line
970