summaryrefslogtreecommitdiffstats
path: root/systemservice/task_manager/server/src/tskm_svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'systemservice/task_manager/server/src/tskm_svc.cpp')
-rw-r--r--systemservice/task_manager/server/src/tskm_svc.cpp970
1 files changed, 970 insertions, 0 deletions
diff --git a/systemservice/task_manager/server/src/tskm_svc.cpp b/systemservice/task_manager/server/src/tskm_svc.cpp
new file mode 100644
index 00000000..2f9abc1e
--- /dev/null
+++ b/systemservice/task_manager/server/src/tskm_svc.cpp
@@ -0,0 +1,970 @@
+/*
+ * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "system_service/tskm_svc.h"
+#include <string.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <errno.h>
+
+#include <native_service/ns_np_service_if.h>
+#include <string>
+
+#include "tskm_debug.h"
+#include "tskm_util.h"
+#include "tskm_port_pf.h"
+#include "tskm_port_subsys.h"
+#include "tskm_comm.h"
+
+
+/*********************************************************
+ * Is the target event of the service handler?
+
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t isSvcEvent(const TSKM_EVENT_INFO_t* p_ev) {
+ switch (p_ev->event) {
+ case TSKM_EV_PRI_REP_CONNECT:
+ case TSKM_EV_PRI_REP_DISCONNECT:
+ case TSKM_EV_PRI_RES_WAKEUP:
+ case TSKM_EV_PRI_RES_DOWN:
+ case TSKM_EV_PRI_RES_DEBUGDUMP:
+ case TSKM_EV_PRI_REQ_EXIT:
+ case TSKM_EV_SVC_REP_TERM:
+ return TSKM_TRUE;
+ break;
+ default:
+ break;
+ }
+ return TSKM_FALSE;
+}
+
+/*********************************************************
+ * Get service context
+ *********************************************************/
+TSKM_STATIC TSKM_SVC_CTX_t*
+getSvcCtxBySvcId(TSKM_SVCS_CTX_t* p_svcs, TSKM_SVCID_t svcId) {
+ uint32_t ii;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ if (p_svcs->svcList[ii].attr->svcId == svcId) {
+ return &p_svcs->svcList[ii];
+ }
+ }
+ TSKM_ASSERT(0);
+ return NULL;
+}
+
+/*********************************************************
+ * Get service context
+ *********************************************************/
+TSKM_STATIC TSKM_SVC_CTX_t*
+getSvcCtxByPid(TSKM_SVCS_CTX_t* p_svcs, pid_t pid) {
+ uint32_t ii;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ if (p_svcs->svcList[ii].pid == pid) {
+ return &p_svcs->svcList[ii];
+ }
+ }
+ return NULL;
+}
+
+/*********************************************************
+ * Get service context
+ *********************************************************/
+TSKM_STATIC TSKM_SVC_CTX_t*
+getSvcCtxByName(TSKM_SVCS_CTX_t* p_svcs, const char *p_name) { // LCOV_EXCL_START 6: Because the condition cannot be set
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ uint32_t ii;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ if (0
+ == strncmp(p_svcs->svcList[ii].attr->name, p_name,
+ strlen(p_svcs->svcList[ii].attr->name))) {
+ return &p_svcs->svcList[ii];
+ }
+ }
+ return NULL;
+}
+// LCOV_EXCL_STOP
+/*********************************************************
+ * Issuing a start request to the service
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t wakeupRequest(TSKM_SVC_CTX_t* p_svc,
+ TSKM_GSTEP_REQ_INFO_t* p_req) {
+ TSKM_EVENT_INFO_t ev;
+ int ret;
+ bzero(&ev, sizeof(ev));
+
+ ev.event = TSKM_EV_PRI_REQ_WAKEUP;
+ ev.errCode = TSKM_E_OK;
+ ev.prm.reqWakeup.svcId = p_svc->attr->svcId;
+ ev.prm.reqWakeup.localStep = p_req->localStep;
+ ev.prm.reqWakeup.isDynamic =
+ (p_svc->attr->lifeCycle == TSKM_SVC_LC_DYNAMIC) ? TSKM_TRUE : TSKM_FALSE;
+ // Since there is no startup in the P_CWORD72_ but only communication in the ALL/LAST,
+ // the startup information is optimized including the startup information in the communication of the WakeupRequest.
+ memcpy(&ev.prm.reqWakeup.bootInfo, &p_svc->bootInfo,
+ sizeof(ev.prm.reqWakeup.bootInfo));
+ memcpy(&ev.prm.reqWakeup.extBootInfo, &p_svc->extBootInfo,
+ sizeof(ev.prm.reqWakeup.extBootInfo));
+
+ ret = tskm_sockSend(p_svc->connFd, &ev);
+ if (ret <= 0) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ p_svc->waitResCnt++;
+ p_svc->state = TSKM_SVC_WAKEUP;
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Touch services and extend EXIT timeouts
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t reqTouch(TSKM_SVC_CTX_t* p_svc) {
+#define TSKM_BUF_LEN ( 4 * ( sizeof(struct inotify_event) ) ) /* read size */
+ TSKM_ERR_t funcRet = TSKM_E_NG;
+ char touchFileName[32];
+ BOOL isNeedRetry = FALSE;
+
+ int iFd = p_svc->iFd;
+ int wd = 0;
+
+ TSKM_EVENT_INFO_t ev;
+ int ret;
+ bzero(&ev, sizeof(ev));
+
+ // Create monitoring files
+ tskm_pf_mkTouchFileName(p_svc->pid, touchFileName);
+ if (0 != tskm_pf_touch(touchFileName)) {
+ goto ERROR;
+ }
+
+ // Synchronize by iNortify
+ wd = inotify_add_watch(iFd, touchFileName, IN_DELETE_SELF);
+ if (wd == -1) {
+ TSKM_ASSERT_ERRNO(0);
+ goto ERROR;
+ }
+
+ // Send Touch request
+ ev.event = TSKM_EV_PRI_REQ_TOUCH;
+ ev.errCode = TSKM_E_OK;
+ ret = tskm_sockSend(p_svc->connFd, &ev);
+ if (ret <= 0) {
+ // Immediately after the nonresident service process terminates, since the TaskManager service status is other than DORMANT
+ // (mainly DOWN), the socket may be discarded and communication may fail, so retry
+ funcRet = TSKM_E_RETRY;
+ TSKM_PRINTF(TSKM_LOG_WARN, "ret = %d", ret);
+ goto ERROR;
+ }
+
+ // Wait for Touch completion
+ while (1) {
+ int maxFd = 0;
+ int ret;
+ fd_set fds;
+ FD_ZERO(&fds);
+ struct timeval timeout = { 0 };
+ timeout.tv_sec = TSKM_CFG_TOUCH_TIMEOUT;
+
+ FD_SET(iFd, &fds);
+ maxFd = iFd;
+
+ ret = select(maxFd + 1, &fds, NULL, NULL, &timeout);
+ if (ret == 0) {
+ TSKM_ASSERT_PRINT(0, "TIMEOUT:%s", touchFileName); // Timeout occurs
+ isNeedRetry = TRUE;
+ break;
+ } else if (ret < 1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ }
+
+ if (FD_ISSET(iFd, &fds)) {
+ int length;
+ uint8_t buf[TSKM_BUF_LEN];
+
+ length = static_cast<int>(read(iFd, buf, TSKM_BUF_LEN));
+ if (length < 0) {
+ TSKM_ASSERT_ERRNO(0);
+ goto ERROR;
+ }
+ struct inotify_event *event = (struct inotify_event *) buf;
+ if (event->mask & IN_DELETE_SELF) {
+ TSKM_PRINTF(TSKM_LOG_STATE, "TouchOK");
+ wd = 0;
+ // When a file is deleted, the association with the monitoring target is automatically released and inotify_rm_watch is no longer needed.
+ break;
+ } else {
+ TSKM_ASSERT_PRINT(0, "%x", event->mask);
+ }
+ }
+ }
+
+ if (isNeedRetry) {
+ funcRet = TSKM_E_RETRY;
+ } else {
+ funcRet = TSKM_E_OK;
+ }
+
+ ERROR: if (wd > 0) {
+ TSKM_ASSERT_ERRNO(0 == inotify_rm_watch(iFd, wd))
+ }
+
+ if (access(touchFileName, F_OK) == 0) {
+ // Timeout care
+ unlink(touchFileName);
+ }
+
+ return funcRet;
+}
+
+/*********************************************************
+ * Availability Monitoring Callbacks for Services
+ *********************************************************/
+EFrameworkunifiedStatus OnSvcAvailability(HANDLE hApp) { // LCOV_EXCL_START 6: Because the condition cannot be set
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ PCSTR availabilityName;
+ TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
+ TSKM_SVC_CTX_t* p_svc;
+
+ availabilityName = FrameworkunifiedGetLastNotification(hApp);
+
+ std::string str = availabilityName;
+
+// unsigned int position;
+// if (std::string::npos != (position = static_cast<unsigned int>(str.find("/Availability", 0)))) {
+ ssize_t position;
+ if (0 <= (position = str.find("/Availability", 0))) {
+ str.erase(position, position + strlen("/Availability"));
+ }
+
+ p_svc = getSvcCtxByName(&p_main->svcs, str.c_str());
+ if (p_svc) {
+ p_svc->isAvailable = FrameworkunifiedIsServiceAvailable(hApp) ? TSKM_TRUE : TSKM_FALSE;
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s Availability %s", p_svc->attr->name,
+ (p_svc->isAvailable == TSKM_TRUE) ? "TRUE" : "FALSE");
+ }
+
+ return eFrameworkunifiedStatusOK;
+}
+// LCOV_EXCL_STOP
+/*********************************************************
+ * Starting Availability Monitoring of Services
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t startWatchAvailability(TSKM_SVC_CTX_t* p_svc) {
+ TSKM_ERR_t funcRet = TSKM_E_OK;
+
+ // LCOV_EXCL_BR_START 8: Since the condition is checked by the caller, it is not true.
+ if (p_svc->attr->type == TSKM_SVC_TYPE_UNKNONW) {
+ // LCOV_EXCL_BR_STOP
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ p_svc->isAvailable = TSKM_TRUE; // LCOV_EXCL_LINE 8: Since the condition is checked by the caller, it is not true.
+ } else {
+ EFrameworkunifiedStatus taskmanagerStatus;
+ TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
+ SS_String availabilityName = p_svc->attr->name;
+
+ availabilityName.append("/Availability");
+
+ taskmanagerStatus = FrameworkunifiedSubscribeNotificationWithCallback(p_main->hApp,
+ availabilityName.c_str(),
+ OnSvcAvailability);
+ if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
+ TSKM_ASSERT(0);
+ funcRet = TSKM_E_NG;
+ }
+ }
+
+ return funcRet;
+}
+
+/*********************************************************
+ * Service startup sub
+ *********************************************************/
+void svcExec_Process(TSKM_SVC_CTX_t* p_svc) {
+ TSKM_ERR_t funcRet;
+
+ if (p_svc->attr->type == TSKM_SVC_TYPE_NATIVE) {
+ p_svc->state = TSKM_SVC_WAITCONNECT;
+ TSKM_PRINTF(TSKM_LOG_DEBUG, "[ST:%d] WAIT_EXEC", p_svc->pid);
+ funcRet = startWatchAvailability(p_svc);
+ if (TSKM_E_OK != funcRet) {
+ TSKM_ASSERT(0);
+ p_svc->isAvailable = TSKM_TRUE;
+ }
+ } else {
+ p_svc->state = TSKM_SVC_RUNNING;
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] RUN", p_svc->pid);
+ p_svc->isAvailable = TSKM_TRUE;
+ }
+ return;
+}
+
+/*********************************************************
+ * Service startup main
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t svcExec(TSKM_SVC_CTX_t* p_svc) {
+ TSKM_ERR_t funcRet = TSKM_E_NG;
+ pid_t pid;
+
+ if (p_svc == NULL) { // LCOV_EXCL_BR_LINE 6:double check
+ // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ TSKM_ASSERT(0);
+ goto ERROR;
+ // LCOV_EXCL_STOP
+ }
+
+ if (p_svc->state == TSKM_SVC_DISABLE) {
+ // Prohibited startup
+ TSKM_ASSERT(0);
+ return TSKM_E_STATE;
+ } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
+ return TSKM_E_OK;
+ } else if (p_svc->state != TSKM_SVC_DORMANT) {
+ // Already started
+ funcRet = reqTouch(p_svc);
+ if (TSKM_E_OK != funcRet) {
+ TSKM_PRINTF(TSKM_LOG_WARN, "funcRet = %d", funcRet);
+ goto ERROR;
+ }
+ return TSKM_E_OK;
+ }
+
+ pid = tskm_pf_createProc(p_svc->attr);
+ if (pid <= 0) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ TSKM_PRINTF(TSKM_LOG_STATE, "EXEC %s:%d", p_svc->attr->name, pid);
+
+ p_svc->pid = pid;
+ p_svc->waitReqCnt = 0;
+
+ // Startup service
+ svcExec_Process(p_svc);
+
+ funcRet = TSKM_E_OK;
+ ERROR: return funcRet;
+}
+
+/*********************************************************
+ * Issuing a start request to the service
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t svcWakeupRequest(TSKM_SVC_CTX_t* p_svc,
+ TSKM_GSTEP_REQ_INFO_t* p_req) {
+ 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)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return TSKM_E_STATE; // LCOV_EXCL_LINE 6: Since this function has always been called after checking
+ } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
+ // Remember it once and issue a request when the CONNECT completes.
+ p_svc->request[p_svc->waitReqCnt] = *p_req;
+ p_svc->waitReqCnt++;
+ } else {
+ TSKM_ERR_t tskmRet;
+ tskmRet = wakeupRequest(p_svc, p_req);
+ TSKM_ERR_CHK_DFT;
+ }
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Service reboot processing
+ *********************************************************/
+TSKM_STATIC TSKM_ERR_t svcErrTermPost(TSKM_SVC_CTX_t* p_svc) {
+ TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
+
+ TSKM_PRINTF(TSKM_LOG_SYSTEMDATA, "ERR TERM SVC(%s:%d)", p_svc->attr->name,
+ p_svc->pid);
+
+ 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)
+ TSKM_ERROR_REBOOT_t rebootInfo;
+
+ TSKM_ASSERT(0);
+ memset(&rebootInfo, 0, sizeof(TSKM_ERROR_REBOOT_t));
+ rebootInfo.type = TSKM_ERROR_REBOOT_NORMAL;
+ snprintf(rebootInfo.log.messageStr, TSKM_LOGGING_MSG_STR_SIZE,
+ "TaskManager:SVC ErrTerm");
+ tskm_sub_reboot(&rebootInfo);
+ } else {
+ TSKM_LOGGING_INFO_t logInfo;
+ logInfo.type = TSKM_LOGGING_TYPE_MODULE_LOGS;
+
+ snprintf(logInfo.messageStr, TSKM_LOGGING_MSG_STR_SIZE,
+ "TaskManager:SVC ErrTerm");
+ tskm_sub_logging(&logInfo);
+
+ if (p_svc->attr->lifeCycle == TSKM_SVC_LC_ALWAYS_RECOVERABLE) {
+ TSKM_ERR_t ret;
+ TSKM_GSTEP_REQ_INFO_t req = { 0 };
+
+ ret = svcExec(p_svc);
+
+ if (TSKM_E_OK != ret) {
+ TSKM_ASSERT_PRINT(0, "ret = %d", ret);
+ goto ERROR;
+ } else if (p_svc->state == TSKM_SVC_WAITCONNECT) {
+ // In the state waiting for execution
+ req.svcId = p_svc->attr->svcId;
+ req.localStep = TSKM_LSTEP_ALL;
+ ret = svcWakeupRequest(p_svc, &req);
+ if (TSKM_E_OK != ret) {
+ TSKM_ASSERT_PRINT(0, "ret = %d", ret);
+ goto ERROR;
+ }
+ }
+ }
+ }
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Connection handler
+ * ret:TRUE SVC status changed
+ * ret:FALSE SVC status not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t connectHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ uint32_t ii;
+
+ TSKM_ASSERT(p_svc->state == TSKM_SVC_WAITCONNECT);
+
+ p_svc->connFd = p_inEv->prm.repConnect.connFd;
+ p_svc->state = TSKM_SVC_WAKEUP;
+ TSKM_PRINTF(TSKM_LOG_DEBUG, "[ST:%d] WAKEUP", p_svc->pid);
+
+ p_svc->waitResCnt = 0;
+
+ if (p_svc->waitReqCnt) {
+ for (ii = 0; ii < p_svc->waitReqCnt; ii++) {
+ TSKM_ASSERT(TSKM_E_OK == wakeupRequest(p_svc, &p_svc->request[ii]));
+ }
+ p_svc->waitReqCnt = 0;
+ }
+
+ return TSKM_TRUE;
+}
+
+/*********************************************************
+ * Disconnection handler
+ * ret:TRUE SVC status changed
+ * ret:FALSE SVC status not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t disConnectHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ // No status change
+
+ return TSKM_TRUE;
+}
+
+/*********************************************************
+ * Response handler for the activation request
+ * ret:TRUE SVC status changed
+ * ret:FALSE SVC status not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t resWakeupHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ TSKM_ASSERT(p_svc->state == TSKM_SVC_WAKEUP);
+ TSKM_ASSERT(p_svc->waitResCnt > 0);
+ TSKM_BOOL_t isStateChg = TSKM_FALSE;
+
+ if (p_svc->isShmDone == TSKM_FALSE && p_inEv->prm.resWakeup.isShmDone) {
+ p_svc->isShmDone = TSKM_TRUE;
+ isStateChg = TSKM_TRUE;
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s:SHM DONE", p_svc->attr->name);
+ }
+ if (p_svc->isStepDone == TSKM_FALSE && p_inEv->prm.resWakeup.isStepDone) {
+ p_svc->isStepDone = TSKM_TRUE;
+ isStateChg = TSKM_TRUE;
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "%s:STEP DONE", p_svc->attr->name);
+ }
+
+ if (p_svc->waitResCnt > 0) {
+ p_svc->waitResCnt--;
+ if (p_svc->waitResCnt == 0) { // Transition when the wait runs out
+ if (p_inEv->prm.resWakeup.isLast) {
+ p_svc->state = TSKM_SVC_RUNNING; // Startup completed
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] RUN", p_svc->pid);
+ }
+ isStateChg = TSKM_TRUE;
+ }
+ }
+ return isStateChg;
+}
+
+/*********************************************************
+ * Response handler for the termination request
+ * ret:TRUE SVC state changed
+ * ret:FALSE SVC state not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t resDownHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ TSKM_ASSERT(p_svc->state == TSKM_SVC_DOWN);
+ TSKM_ASSERT(p_svc->waitResCnt > 0);
+ TSKM_BOOL_t isStateChg = TSKM_FALSE;
+
+ TSKM_PRINTF(TSKM_LOG_DEBUG, "pid:%d waitCnt:%d", p_svc->pid,
+ p_svc->waitResCnt);
+ if (p_svc->waitResCnt > 0) {
+ p_svc->waitResCnt--;
+ if (p_svc->waitResCnt == 0) { // Transition when the wait runs out
+ if (p_inEv->prm.resWakeup.isLast) {
+ p_svc->state = TSKM_SVC_FINDOWN; // Termination complete
+ TSKM_PRINTF(TSKM_LOG_SVCSTATE, "[ST:%d] FIN_DOWN", p_svc->pid);
+ }
+ isStateChg = TSKM_TRUE;
+ }
+ }
+ return isStateChg;
+}
+
+/*********************************************************
+ * Response Handlers for DebugDump Requests
+ * ret:TRUE SVC state changed
+ * ret:FALSE SVC state not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t resDebugDumpHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ TSKM_BOOL_t isStateChg = TSKM_FALSE;
+ TSKM_EV_PRI_EX_RES_DEBUGDUMP_PRM_t *p_prm;
+
+ if (!p_inEv->hasExtend || !p_inEv->extendPrm) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+
+ p_prm = (TSKM_EV_PRI_EX_RES_DEBUGDUMP_PRM_t *) p_inEv->extendPrm; // NOLINT (readability/casting)
+
+ // FALSE is specified here because the required service names have been added in the PrimaryLib.
+ tskm_sub_debugDumpRes(FALSE, p_prm->dumpMsg);
+
+ ERROR: return isStateChg;
+}
+
+/*********************************************************
+ * Service termination request
+ * ret:TRUE SVC state changed
+ * ret:FALSE SVC state not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t reqExit(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ int ret;
+ TSKM_ERR_t tskmRet;
+ TSKM_ASSERT(p_svc->state == TSKM_SVC_RUNNING);
+ TSKM_ASSERT(p_svc->waitResCnt == 0);
+ TSKM_GSTEP_REQ_INFO_t req = { 0 };
+
+ req.svcId = p_svc->attr->svcId;
+ req.localStep = TSKM_LSTEP_ALL;
+ tskmRet = tskm_svcDownRequest(p_svc, &req);
+ TSKM_ERR_CHK_DFT;
+
+ return TSKM_TRUE;
+
+ // LCOV_EXCL_START 8: dead code
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ ERROR: ret = tskm_pf_terminateProcGroup(static_cast<uint16_t>(p_svc->pid));
+ if (ret != 0) { // LCOV_EXCL_BR_LINE 8: dead code
+ TSKM_PRINTF(TSKM_LOG_WARN, "ret = %d", ret);
+ }
+
+ return TSKM_TRUE;
+ // LCOV_EXCL_STOP
+}
+
+/*********************************************************
+ * Service termination handler
+ * ret:TRUE SVC state changed
+ * ret:FALSE SVC state not changed
+ *********************************************************/
+TSKM_STATIC TSKM_BOOL_t repTermHandle(TSKM_SVC_CTX_t* p_svc,
+ const TSKM_EVENT_INFO_t* p_inEv) {
+ int ret;
+
+ // Check error
+ if (p_svc->attr->lifeCycle == TSKM_SVC_LC_DYNAMIC) {
+ if (p_svc->state != TSKM_SVC_DOWN) {
+ // A STATE other than DOWN does not terminate.
+ TSKM_PRINTF(TSKM_LOG_ERROR, "ERR TERM %s(%d) waitCnt:%d",
+ p_svc->attr->name, p_svc->pid, p_svc->waitResCnt);
+ TSKM_ASSERT(0);
+ }
+ } else {
+ // The resident service terminated.
+ TSKM_PRINTF(TSKM_LOG_ERROR, "ERR TERM %s(%d) waitCnt:%d", p_svc->attr->name,
+ p_svc->pid, p_svc->waitResCnt);
+ TSKM_ASSERT(0);
+ }
+
+ TSKM_PRINTF(TSKM_LOG_STATE, "[ST:%d] DORMANT", p_svc->pid);
+
+ p_svc->state = TSKM_SVC_DORMANT;
+ p_svc->waitResCnt = 0;
+ p_svc->pid = 0;
+
+ if (p_svc->attr->type == TSKM_SVC_TYPE_NATIVE) {
+ EFrameworkunifiedStatus taskmanagerStatus;
+ TSKM_MAIN_CTX_t* p_main = tskm_getMainCtx();
+ SS_String availabilityName = p_svc->attr->name;
+ availabilityName.append("/Availability");
+
+ taskmanagerStatus = FrameworkunifiedUnsubscribeNotificationWithCallback(
+ p_main->hApp, availabilityName.c_str());
+ if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
+ TSKM_ASSERT(0);
+ }
+
+ p_svc->isAvailable = TSKM_FALSE;
+ p_svc->watchCnt = 0;
+
+ HANDLE hMq = McOpenSender(FRAMEWORKUNIFIED_NS_NPSERVICE);
+ if (NULL == hMq) { // LCOV_EXCL_BR_LINE 4: NSFW error case.
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ TSKM_ASSERT(0); // LCOV_EXCL_LINE 4: NSFW error case.
+ } else {
+ ServiceAvailability availInfo = { };
+
+ snprintf(availInfo.cServiceName, MAX_NAME_SIZE_APP, "%s",
+ p_svc->attr->name);
+ availInfo.eServiceAvailability = eFrameworkunifiedServiceNotAvailable;
+
+ taskmanagerStatus = NPPublishNotification(hMq, p_svc->attr->name,
+ availabilityName.c_str(), &availInfo,
+ sizeof(availInfo));
+ if (eFrameworkunifiedStatusOK != taskmanagerStatus) {
+ TSKM_ASSERT(0);
+ }
+
+ taskmanagerStatus = McClose(hMq);
+ if (eFrameworkunifiedStatusOK != taskmanagerStatus) { // LCOV_EXCL_BR_LINE 4: NSFW error case.
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ TSKM_ASSERT(0); // LCOV_EXCL_LINE 4: NSFW error case.
+ }
+ }
+ }
+
+ if (p_inEv->errCode != TSKM_E_OK) {
+ p_svc->errTermCnt++;
+ // Notify 'NG' at Relaunch after abnormal termination
+ p_svc->bootInfo.resetStatus = e_SS_SM_RESET_STATUS_NG;
+
+ ret = svcErrTermPost(p_svc);
+ if (ret != TSKM_E_OK) {
+ TSKM_ASSERT(0);
+ }
+ } else {
+ // NONE is notified at Relaunch after normal completion.
+ p_svc->bootInfo.resetStatus = e_SS_SM_RESET_STATUS_NONE;
+ }
+
+ return TSKM_TRUE;
+}
+
+/*********************************************************
+ * Get service context
+ *********************************************************/
+TSKM_SVC_CTX_t*
+tskm_svcsGetSvcBySvcId(TSKM_SVCS_CTX_t* p_svcs, TSKM_SVCID_t svcId) {
+ return getSvcCtxBySvcId(p_svcs, svcId);
+}
+
+/*********************************************************
+ * Get service context
+ *********************************************************/
+TSKM_SVC_CTX_t*
+tskm_svcsGetSvcByPid(TSKM_SVCS_CTX_t* p_svcs, pid_t pid) {
+ return getSvcCtxByPid(p_svcs, pid);
+}
+
+/*********************************************************
+ * Check for waiting services
+ *********************************************************/
+TSKM_BOOL_t tskm_svcsIsWaiting(TSKM_SVCS_CTX_t* p_svcs) {
+ uint32_t ii;
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ if (p_svcs->svcList[ii].waitResCnt > 0
+ || p_svcs->svcList[ii].state == TSKM_SVC_WAITCONNECT) {
+ return TSKM_TRUE;
+ }
+ }
+ return TSKM_FALSE;
+}
+
+/*********************************************************
+ * Check if ShutdownWait services are terminated
+ *********************************************************/
+TSKM_SVC_WAIT_STATE_t tskm_svcsGetSvcTermWaitState(TSKM_SVCS_CTX_t* p_svcs) {
+ uint32_t ii;
+ TSKM_SVC_WAIT_STATE_t waitState = TSKM_SVC_WAIT_NONE;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ if (p_svcs->svcList[ii].attr->shotdownWait) {
+ // Check shutdownWait SVC Only
+ if (p_svcs->svcList[ii].state != TSKM_SVC_DORMANT) {
+ // DORMANT is terminated or not started, so no checking is required
+ if (TSKM_SVC_LC_DYNAMIC != p_svcs->svcList[ii].attr->lifeCycle
+ && p_svcs->svcList[ii].state != TSKM_SVC_FINDOWN) { // Check of termination of resident SVCs
+ waitState = TSKM_SVC_WAIT_BOTH;
+ break;
+ } else if (TSKM_SVC_LC_DYNAMIC == p_svcs->svcList[ii].attr->lifeCycle) { // Check of termination of non-resident SVCs
+ waitState = TSKM_SVC_WAIT_TRANSIENT;
+ }
+ }
+ }
+ }
+ return waitState;
+}
+
+/*********************************************************
+ * Update boot info of all services
+ *********************************************************/
+TSKM_ERR_t tskm_svcsSetBootInfo(TSKM_SVCS_CTX_t* p_svcs,
+ T_SS_SM_START_DataStructType* p_info,
+ T_SS_SM_START_ExtDataStructType *p_exInfo) {
+ uint32_t ii = 0;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ p_svcs->svcList[ii].bootInfo = *p_info;
+ p_svcs->svcList[ii].extBootInfo = *p_exInfo;
+ }
+ return TSKM_E_OK;
+}
+
+/*********************************************************
+ * Terminates a running non-resident services
+ *********************************************************/
+TSKM_ERR_t tskm_svcsAvtiveSvcTerm(TSKM_SVCS_CTX_t* p_svcs) {
+ uint32_t ii;
+
+ for (ii = 0; ii < p_svcs->svcNum; ii++) {
+ TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
+
+ if (TSKM_SVC_LC_DYNAMIC == p_svc->attr->lifeCycle && // Non-resident SVC
+ TSKM_SVC_RUNNING == p_svc->state && p_svc->waitResCnt == 0) { // Running
+ TSKM_ERR_t tskmRet;
+ TSKM_GSTEP_REQ_INFO_t req = { 0 };
+
+ req.svcId = p_svc->attr->svcId;
+ req.localStep = TSKM_LSTEP_ALL;
+ tskmRet = tskm_svcDownRequest(p_svc, &req);
+ TSKM_ERR_CHK_DFT;
+ }
+ }
+
+ return TSKM_E_OK;
+
+ ERROR:
+ return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Calls back the DebugDump of the running services
+ *********************************************************/
+TSKM_ERR_t tskm_svcsCallDebugDump(TSKM_SVCS_CTX_t* p_svcs) {
+ for (uint32_t ii = 0; ii < p_svcs->svcNum; ii++) {
+ TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
+
+ if (TSKM_SVC_RUNNING == p_svc->state) { // Running
+ TSKM_EVENT_INFO_t ev;
+ bzero(&ev, sizeof(ev));
+
+ // Send DebugDump request
+ ev.event = TSKM_EV_PRI_REQ_DEBUGDUMP;
+ ev.errCode = TSKM_E_OK;
+ if (0 >= tskm_sockSend(p_svc->connFd, &ev)) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ }
+ }
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Calls back the LowMemory of the running services
+ *********************************************************/
+TSKM_ERR_t tskm_svcsCallLowMem(TSKM_SVCS_CTX_t* p_svcs) {
+ for (uint32_t ii = 0; ii < p_svcs->svcNum; ii++) {
+ TSKM_SVC_CTX_t* p_svc = &p_svcs->svcList[ii];
+ if (TSKM_SVC_RUNNING == p_svc->state) { // Running
+ TSKM_EVENT_INFO_t ev;
+ bzero(&ev, sizeof(ev));
+
+ // Send LowMemory detection notification
+ ev.event = TSKM_EV_PRI_REP_LOWMEM;
+ ev.errCode = TSKM_E_OK;
+ if (0 >= tskm_sockSend(p_svc->connFd, &ev)) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ }
+ }
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Event handler
+ *********************************************************/
+TSKM_ERR_t tskm_svcEventHandle(TSKM_SVC_CTX_t* p_svc, TSKM_EVENT_INFO_t* p_ev) {
+ TSKM_FUNC_IN();
+ TSKM_BOOL_t isStateChg = TSKM_FALSE;
+
+ if (isSvcEvent(p_ev) == TSKM_FALSE) {
+ // If it is not an event for the service, it will be sent as follows.
+ TSKM_FUNC_OUT();
+ return TSKM_E_OK;
+ }
+
+ switch (p_ev->event) {
+ case TSKM_EV_PRI_REP_CONNECT: // Connection Registration from Service
+ isStateChg = connectHandle(p_svc, p_ev);
+ break;
+ case TSKM_EV_PRI_REP_DISCONNECT: // Disconnection Registration from Service
+ isStateChg = disConnectHandle(p_svc, p_ev);
+ break;
+ case TSKM_EV_PRI_RES_WAKEUP: // Response to a startup request from a service
+ isStateChg = resWakeupHandle(p_svc, p_ev);
+ break;
+ case TSKM_EV_PRI_RES_DOWN:
+ isStateChg = resDownHandle(p_svc, p_ev);
+ break;
+ case TSKM_EV_PRI_RES_DEBUGDUMP:
+ isStateChg = resDebugDumpHandle(p_svc, p_ev);
+ break;
+ case TSKM_EV_PRI_REQ_EXIT:
+ isStateChg = reqExit(p_svc, p_ev);
+ break;
+ case TSKM_EV_SVC_REP_TERM: // Service termination
+ isStateChg = repTermHandle(p_svc, p_ev);
+ break;
+ default:
+ break;
+ }
+
+ // Overwrite service state change
+ if (isStateChg) {
+ p_ev->event = TSKM_EV_LCL_CHG_SVC_STATE;
+ p_ev->prm.chgSvc.svcId = p_svc->attr->svcId;
+ } else {
+ p_ev->event = TSKM_EV_NOP;
+ }
+
+ TSKM_FUNC_OUT();
+ return TSKM_E_OK;
+}
+/*********************************************************
+ * Startup service
+ *********************************************************/
+TSKM_ERR_t tskm_svcExec(TSKM_SVC_CTX_t* p_svc) {
+ return svcExec(p_svc);
+}
+
+/*********************************************************
+ * Issue a startup request to the service
+ *********************************************************/
+TSKM_ERR_t tskm_svcWakeupRequest(TSKM_SVC_CTX_t* p_svc,
+ TSKM_GSTEP_REQ_INFO_t* p_req) {
+ return svcWakeupRequest(p_svc, p_req);
+}
+
+/*********************************************************
+ * Issue a termination request to the service
+ *********************************************************/
+TSKM_ERR_t tskm_svcDownRequest(TSKM_SVC_CTX_t* p_svc,
+ TSKM_GSTEP_REQ_INFO_t* p_req) {
+ int ret;
+ TSKM_EVENT_INFO_t ev;
+
+ bzero(&ev, sizeof(ev));
+
+ if (tskm_svcIsCommunicatable(p_svc) == TSKM_FALSE) {
+ return TSKM_E_OK;
+ }
+
+ ev.event = TSKM_EV_PRI_REQ_DOWN;
+ ev.errCode = TSKM_E_OK;
+ ev.prm.reqDown.localStep = p_req->localStep;
+
+ ret = tskm_sockSend(p_svc->connFd, &ev);
+ if (ret <= 0) {
+ TSKM_ASSERT(0);
+ goto ERROR;
+ }
+ p_svc->waitResCnt++;
+ p_svc->state = TSKM_SVC_DOWN;
+
+ return TSKM_E_OK;
+ ERROR: return TSKM_E_NG;
+}
+
+/*********************************************************
+ * Prohibit starting service
+ *********************************************************/
+TSKM_ERR_t tskm_svcDisableRequest(TSKM_SVC_CTX_t* p_svc) {
+ if (p_svc->state == TSKM_SVC_DORMANT || p_svc->state == TSKM_SVC_DISABLE) {
+ p_svc->state = TSKM_SVC_DISABLE;
+ return TSKM_E_OK;
+ }
+ return TSKM_E_STATE;
+}
+
+/*********************************************************
+ * Allow starting service
+ *********************************************************/
+TSKM_ERR_t tskm_svcEnableRequest(TSKM_SVC_CTX_t* p_svc) {
+ if (p_svc->state == TSKM_SVC_DISABLE) {
+ p_svc->state = TSKM_SVC_DORMANT;
+ }
+ return TSKM_E_OK;
+}
+
+/*********************************************************
+ * Queriy whether the service is ready for communication
+ *********************************************************/
+TSKM_BOOL_t tskm_svcIsCommunicatable(TSKM_SVC_CTX_t* p_svc) {
+ TSKM_BOOL_t ret = TSKM_FALSE;
+ if (p_svc == NULL || p_svc->attr->type == TSKM_SVC_TYPE_UNKNONW) {
+ } else {
+ switch (p_svc->state) {
+ case TSKM_SVC_WAKEUP:
+ case TSKM_SVC_RUNNING:
+ case TSKM_SVC_DOWN:
+ ret = TSKM_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+} // LCOV_EXCL_BR_LINE 10: Final line
+