add: socket service start ondemand

Signed-off-by: xionglei6 <xionglei6@huawei.com>
This commit is contained in:
xionglei6 2021-12-24 17:58:28 +08:00
parent b6ee22cccd
commit 4be5c06ffb
7 changed files with 180 additions and 4 deletions

View File

@ -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",
]

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <sys/epoll.h>
#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;
}