diff --git a/services/BUILD.gn b/services/BUILD.gn index 0bbab6380bccc6025cd68621af905d43151a23c6..b52f41253171f90bd38f66fe6fa544c64f4c5e69 100755 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -41,6 +41,7 @@ if (defined(ohos_lite)) { "init/lite/init_reboot.c", "init/lite/init_service.c", "init/lite/init_signal_handler.c", + "init/lite/init_socket_manager.c", ] sources += init_common_sources @@ -106,6 +107,7 @@ if (defined(ohos_lite)) { "init/standard/init_reboot.c", "init/standard/init_service.c", "init/standard/init_signal_handler.c", + "init/standard/init_socket_manager.c", "init/standard/switch_root.c", ] diff --git a/services/init/include/init_service.h b/services/init/include/init_service.h index eac52a0f1c78b50e5552448c0f2208d252d4f992..48059cfac4b68e35ebfebd27dbfbb3c2215117f2 100755 --- a/services/init/include/init_service.h +++ b/services/init/include/init_service.h @@ -44,6 +44,7 @@ extern "C" { #define SERVICE_ATTR_DISABLED 0x040 // disabled #define SERVICE_ATTR_CONSOLE 0x080 // console #define SERVICE_ATTR_DYNAMIC 0x100 // dynamic service +#define SERVICE_ATTR_ONDEMAND 0x200 // ondemand, manage socket by init #define MAX_SERVICE_NAME 32 #define MAX_WRITEPID_FILES 100 diff --git a/services/init/include/init_service_manager.h b/services/init/include/init_service_manager.h index d163081906dd9d99a9542c62295cea9ea1c57ea3..5e9be14260ffcad5dce8aaeb80b9aaf23ff25365 100755 --- a/services/init/include/init_service_manager.h +++ b/services/init/include/init_service_manager.h @@ -46,10 +46,16 @@ typedef struct { int serviceCount; } ServiceSpace; +inline bool IsOnDemandService(Service *service) +{ + return !!(service->attribute & SERVICE_ATTR_ONDEMAND); +} Service *GetServiceByPid(pid_t pid); Service *GetServiceByName(const char *servName); cJSON *GetArrayItem(const cJSON *fileRoot, int *arrSize, const char *arrName); int ParseOneService(const cJSON *curItem, Service *service); +void SocketPollInit(int sockFd, const char* serviceName); +int CreateAndPollSocket(Service *service); void StartServiceByName(const char *serviceName, bool checkDynamic); void StopServiceByName(const char *serviceName); void StopAllServices(int flags); diff --git a/services/init/init_common_service.c b/services/init/init_common_service.c index 816a811e69b91b210f2c7ce340341cab7134c02b..59904195f8c41d2ac0f452638d8eac426653b3f4 100755 --- a/services/init/init_common_service.c +++ b/services/init/init_common_service.c @@ -32,6 +32,7 @@ #include "init_cmds.h" #include "init_log.h" #include "init_service.h" +#include "init_service_manager.h" #include "init_service_socket.h" #include "init_utils.h" #include "securec.h" @@ -203,8 +204,11 @@ int ServiceStart(Service *service) } int pid = fork(); if (pid == 0) { - int ret = CreateServiceSocket(service->socketCfg); - INIT_ERROR_CHECK(ret >= 0, _exit(PROCESS_EXIT_CODE), "service %s exit! create socket failed!", service->name); + if (!IsOnDemandService(service)) { + int ret = CreateServiceSocket(service->socketCfg); + INIT_ERROR_CHECK(ret >= 0, _exit(PROCESS_EXIT_CODE), + "service %s exit! create socket failed!", service->name); + } CreateServiceFile(service->fileCfg); if (service->attribute & SERVICE_ATTR_CONSOLE) { OpenConsole(); @@ -278,6 +282,20 @@ static int ExecRestartCmd(const Service *service) return SERVICE_SUCCESS; } +static void PollSocketAfresh(service) +{ + if (service->socketCfg == NULL) { + INIT_LOGE("service %s socket config is NULL!", service->name); + return; + } + ServiceSocket *tmpSock = service->socketCfg; + while (tmpSock != NULL) { + SocketPollInit(tmpSock->sockFd, service->name); + tmpSock = tmpSock->next; + } + return; +} + void ServiceReap(Service *service) { INIT_CHECK(service != NULL, return); @@ -290,7 +308,9 @@ void ServiceReap(Service *service) return; } - CloseServiceSocket(service->socketCfg); + if (!IsOnDemandService(service)) { + CloseServiceSocket(service->socketCfg); + } CloseServiceFile(service->fileCfg); // stopped by system-init itself, no need to restart even if it is not one-shot service if (service->attribute & SERVICE_ATTR_NEED_STOP) { @@ -321,6 +341,11 @@ void ServiceReap(Service *service) return; } } + // service no need to restart which socket managed by init until socket message detected + if (IsOnDemandService(service)) { + PollSocketAfresh(service); + return; + } int ret; if (service->restartArg != NULL) { diff --git a/services/init/init_service_manager.c b/services/init/init_service_manager.c index 293e877044a51642833995048ceba79bb7abf8b5..3fdc0dc17e1a67e20fd01f9709155f960be6a93b 100755 --- a/services/init/init_service_manager.c +++ b/services/init/init_service_manager.c @@ -24,6 +24,7 @@ #include "init.h" #include "init_jobs_internal.h" #include "init_log.h" +#include "init_param.h" #include "init_service_file.h" #include "init_service_socket.h" #include "init_utils.h" @@ -359,6 +360,9 @@ static int ParseServiceSocket(const cJSON *curArrItem, Service *curServ) break; } } + if (IsOnDemandService(curServ)) { + ret = CreateAndPollSocket(curServ); + } return ret; } @@ -466,11 +470,28 @@ static int GetDynamicService(const cJSON *curArrItem, Service *curServ) return SERVICE_SUCCESS; } +static int GetServiceOnDemand(const cJSON *curArrItem, Service *curServ) +{ + cJSON *item = cJSON_GetObjectItem(curArrItem, "ondemand"); + if (item == NULL) { + return SERVICE_SUCCESS; + } + + INIT_ERROR_CHECK(cJSON_IsBool(item), return SERVICE_FAILURE, + "Service : %s ondemand value only support bool.", curServ->name); + bool isOnDemand = (bool)cJSON_GetNumberValue(item); + INIT_INFO_CHECK(isOnDemand, return SERVICE_SUCCESS, + "Service : %s ondemand value is false, it will be manage socket by itself", curServ->name); + + curServ->attribute |= SERVICE_ATTR_ONDEMAND; + return SERVICE_SUCCESS; +} + static int CheckServiceKeyName(const cJSON *curService) { char *cfgServiceKeyList[] = { "name", "path", "uid", "gid", "once", "importance", "caps", "disabled", - "writepid", "critical", "socket", "console", "dynamic", "file", + "writepid", "critical", "socket", "console", "dynamic", "file", "ondemand", #ifdef WITH_SELINUX SECON_STR_IN_CFG, #endif // WITH_SELINUX @@ -533,6 +554,8 @@ int ParseOneService(const cJSON *curItem, Service *service) INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get caps for service %s", service->name); ret = GetDynamicService(curItem, service); INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get dynamic flag for service %s", service->name); + ret = GetServiceOnDemand(curItem, service); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get ondemand flag for service %s", service->name); return ret; } diff --git a/services/init/lite/init_socket_manager.c b/services/init/lite/init_socket_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..99b776ff0cb9ec69883928afce28ada337377e74 --- /dev/null +++ b/services/init/lite/init_socket_manager.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * 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 "init_service_manager.h" + +void SocketPollInit(int sockFd, const char* serviceName) +{ + return; +} + +int CreateAndPollSocket(Service *service) +{ + return 0; +} diff --git a/services/init/standard/init_socket_manager.c b/services/init/standard/init_socket_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..3c68204858d7f519527d621a933edeff728261ae --- /dev/null +++ b/services/init/standard/init_socket_manager.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * 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 +#include "init_log.h" +#include "init_param.h" +#include "init_service_manager.h" +#include "securec.h" +#include "uv.h" +#define POLL_HANDLER_COUNT 1024 + +uv_poll_t g_socketPollHandler[POLL_HANDLER_COUNT]; +static int handlerCounter = 0; + +static void UVSocketPollHandler(uv_poll_t* handle, int status, int events) +{ + if (handle == NULL) { + INIT_LOGE("handle is NULL!"); + return; + } + char paramName[PARAM_NAME_LEN_MAX] = { 0 }; + char paramValue[PARAM_VALUE_LEN_MAX] = { 0 }; + unsigned int len = PARAM_VALUE_LEN_MAX; + INIT_CHECK_ONLY_ELOG(snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.socket.%d", + handle->io_watcher.fd) >= 0, "snprintf_s paramName error %d ", errno); + int ret = SystemReadParam(paramName, paramValue, &len); + if (ret != 0) { + INIT_LOGE("Failed to read param, param name = %s", paramName); + } + INIT_LOGI("Socket information detected, sockFd:%d service name:%s", handle->io_watcher.fd, paramValue); + uv_poll_stop(handle); + StartServiceByName(paramValue, false); + return; +} + +static void SetSocketParam(Service *service) +{ + char paramName[PARAM_NAME_LEN_MAX] = { 0 }; + ServiceSocket *tmpSock = service->socketCfg; + while (tmpSock != NULL) { + INIT_CHECK_ONLY_ELOG(snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.socket.%d", + tmpSock->sockFd) >= 0, "snprintf_s paramName error %d ", errno); + SystemWriteParam(paramName, service->name); + (void)memset_s(paramName, PARAM_NAME_LEN_MAX, 0, PARAM_NAME_LEN_MAX); + tmpSock = tmpSock->next; + } +} + +void SocketPollInit(int sockFd, const char* serviceName) +{ + if (handlerCounter >= POLL_HANDLER_COUNT) { + INIT_LOGE("Socket poll handler is not enough!"); + return; + } + int ret = uv_poll_init_user_defined(uv_default_loop(), &g_socketPollHandler[handlerCounter], sockFd); + if (ret != 0) { + INIT_LOGE("Failed to init socket poll!"); + return; + } + ret = uv_poll_start(&g_socketPollHandler[handlerCounter], UV_READABLE, UVSocketPollHandler); + if (ret != 0) { + INIT_LOGE("Failed to start socket poll!"); + return; + } + handlerCounter += 1; + INIT_LOGI("Start to poll socket, sockFd:%d service name:%s", sockFd, serviceName); +} + +int CreateAndPollSocket(Service *service) +{ + int ret = CreateServiceSocket(service->socketCfg); + if (ret != 0) { + INIT_LOGE("Create socket failed!"); + return SERVICE_FAILURE; + } + SetSocketParam(service); + ServiceSocket *tmpSock = service->socketCfg; + while (tmpSock != NULL) { + SocketPollInit(tmpSock->sockFd, service->name); + tmpSock = tmpSock->next; + } + return 0; +}