init_common_service.c 23.1 KB
Newer Older
W
wenjun 已提交
1
/*
Z
zhong_ning 已提交
2
 * Copyright (c) 2021 Huawei Device Co., Ltd.
W
wenjun 已提交
3 4 5 6 7 8 9 10 11 12 13 14
 * 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.
 */
15

W
wenjun 已提交
16
#include <errno.h>
Z
zhong_ning 已提交
17
#include <fcntl.h>
W
wenjun 已提交
18
#include <signal.h>
Z
zhong_ning 已提交
19
#include <stdlib.h>
M
mamingshuai 已提交
20
#include <string.h>
Z
zhong_ning 已提交
21 22 23
#ifdef __MUSL__
#include <stropts.h>
#endif
24
#include <sys/capability.h>
X
xionglei6 已提交
25
#include <sys/ioctl.h>
Z
zhong_ning 已提交
26
#include <sys/param.h>
M
Mupceet 已提交
27
#include <sys/resource.h>
W
wenjun 已提交
28 29 30
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
31

32
#include "init.h"
W
wenjun 已提交
33
#include "init_adapter.h"
Z
zhong_ning 已提交
34 35
#include "init_cmds.h"
#include "init_log.h"
X
xionglei6 已提交
36
#include "init_jobs_internal.h"
X
xionglei6 已提交
37
#include "init_service.h"
X
xionglei6 已提交
38
#include "init_service_manager.h"
Z
zhong_ning 已提交
39
#include "init_service_socket.h"
Z
zhong_ning 已提交
40
#include "init_utils.h"
X
xionglei6 已提交
41
#include "fd_holder_internal.h"
X
xionglei6 已提交
42
#include "loop_event.h"
Z
zhong_ning 已提交
43
#include "securec.h"
X
xionglei6 已提交
44
#include "service_control.h"
W
wenjun 已提交
45

Q
Qin Fandong 已提交
46
#ifdef WITH_SELINUX
X
xionglei6 已提交
47 48
#include "init_selinux_param.h"
#include <selinux/selinux.h>
Q
Qin Fandong 已提交
49 50
#endif // WITH_SELINUX

X
<feat>  
xiacong 已提交
51 52 53 54 55 56
#ifdef WITH_SECCOMP
#include "seccomp_policy.h"
#define APPSPAWN_NAME ("appspawn")
#define NWEBSPAWN_NAME ("nwebspawn")
#endif

Z
zhong_ning 已提交
57 58 59
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
Z
zhong_ning 已提交
60

S
sun_fan 已提交
61
static int SetAllAmbientCapability(void)
M
mamingshuai 已提交
62 63 64 65 66 67 68 69 70
{
    for (int i = 0; i <= CAP_LAST_CAP; ++i) {
        if (SetAmbientCapability(i) != 0) {
            return SERVICE_FAILURE;
        }
    }
    return SERVICE_SUCCESS;
}

X
<feat>  
xiacong 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84
#ifdef WITH_SECCOMP
static int SetSystemSeccompPolicy(const Service *service)
{
    if (strncmp(APPSPAWN_NAME, service->name, strlen(APPSPAWN_NAME)) \
        && strncmp(NWEBSPAWN_NAME, service->name, strlen(NWEBSPAWN_NAME))) {
        if (!SetSeccompPolicy(SYSTEM)) {
            INIT_LOGE("init seccomp failed, name is %s\n", service->name);
            return SERVICE_FAILURE;
        }
    }
    return SERVICE_SUCCESS;
}
#endif

W
wenjun 已提交
85 86
static int SetPerms(const Service *service)
{
Z
zhong_ning 已提交
87
    INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
88 89 90 91 92 93

    if (service->servPerm.gIDCnt == 0) {
        // use uid as gid
        INIT_ERROR_CHECK(setgid(service->servPerm.uID) == 0, return SERVICE_FAILURE,
            "SetPerms, setgid for %s failed. %d", service->name, errno);
    }
Z
zhong_ning 已提交
94
    if (service->servPerm.gIDCnt > 0) {
Z
zhong_ning 已提交
95 96
        INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
            "SetPerms, setgid for %s failed. %d", service->name, errno);
Z
zhong_ning 已提交
97 98
    }
    if (service->servPerm.gIDCnt > 1) {
X
xionglei6 已提交
99 100
        INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
            return SERVICE_FAILURE,
Z
zhong_ning 已提交
101
            "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
W
wenjun 已提交
102
    }
Z
zhong_ning 已提交
103 104
    if (service->servPerm.uID != 0) {
        if (setuid(service->servPerm.uID) != 0) {
Z
zhong_ning 已提交
105
            INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
Z
zhong_ning 已提交
106 107
            return SERVICE_FAILURE;
        }
W
wenjun 已提交
108 109 110 111 112
    }

    struct __user_cap_header_struct capHeader;
    capHeader.version = _LINUX_CAPABILITY_VERSION_3;
    capHeader.pid = 0;
Z
zhong_ning 已提交
113
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
114 115
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
116 117 118 119
            for (int j = 0; j < CAP_NUM; ++j) {
                capData[j].effective = FULL_CAP;
                capData[j].permitted = FULL_CAP;
                capData[j].inheritable = FULL_CAP;
W
wenjun 已提交
120 121 122 123 124 125 126 127
            }
            break;
        }
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].effective |= CAP_TO_MASK(service->servPerm.caps[i]);
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].permitted |= CAP_TO_MASK(service->servPerm.caps[i]);
        capData[CAP_TO_INDEX(service->servPerm.caps[i])].inheritable |= CAP_TO_MASK(service->servPerm.caps[i]);
    }

L
laiguizhong 已提交
128
    INIT_ERROR_CHECK(capset(&capHeader, capData) == 0, return SERVICE_FAILURE,
129
        "capset failed for service: %s, error: %d", service->name, errno);
M
mamingshuai 已提交
130 131 132 133
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
            return SetAllAmbientCapability();
        }
L
laiguizhong 已提交
134
        INIT_ERROR_CHECK(SetAmbientCapability(service->servPerm.caps[i]) == 0, return SERVICE_FAILURE,
135
            "SetAmbientCapability failed for service: %s", service->name);
M
mamingshuai 已提交
136
    }
W
wenjun 已提交
137 138 139
    return SERVICE_SUCCESS;
}

140
static int WritePid(const Service *service)
S
sun_fan 已提交
141
{
142 143 144 145
    const int maxPidStrLen = 50;
    char pidString[maxPidStrLen];
    pid_t childPid = getpid();
    int len = snprintf_s(pidString, maxPidStrLen, maxPidStrLen - 1, "%d", childPid);
X
add ut  
xionglei6 已提交
146
    INIT_ERROR_CHECK(len > 0, return SERVICE_FAILURE, "Failed to format pid for service %s", service->name);
147 148
    for (int i = 0; i < service->writePidArgs.count; i++) {
        if (service->writePidArgs.argv[i] == NULL) {
S
sun_fan 已提交
149
            continue;
S
sun_fan 已提交
150
        }
151 152 153 154 155 156 157 158
        FILE *fd = NULL;
        char *realPath = GetRealPath(service->writePidArgs.argv[i]);
        if (realPath != NULL) {
            fd = fopen(realPath, "wb");
        } else {
            fd = fopen(service->writePidArgs.argv[i], "wb");
        }
        if (fd != NULL) {
X
add ut  
xionglei6 已提交
159 160
            INIT_CHECK_ONLY_ELOG((int)fwrite(pidString, 1, len, fd) == len,
                "Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString);
161 162 163 164 165 166 167
            (void)fclose(fd);
        } else {
            INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]);
        }
        if (realPath != NULL) {
            free(realPath);
        }
X
xionglei6 已提交
168
        INIT_LOGV("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString);
S
sun_fan 已提交
169
    }
170
    return SERVICE_SUCCESS;
S
sun_fan 已提交
171 172
}

X
xionglei6 已提交
173
void SetSecon(Service *service)
Q
Qin Fandong 已提交
174 175
{
#ifdef WITH_SELINUX
M
Mupceet 已提交
176
    if (service->secon != NULL) {
Q
Qin Fandong 已提交
177 178
        if (setexeccon(service->secon) < 0) {
            INIT_LOGE("failed to set service %s's secon (%s).", service->name, service->secon);
R
renwei 已提交
179
            _exit(PROCESS_EXIT_CODE);
Q
Qin Fandong 已提交
180 181 182
        } else {
            INIT_LOGI("service %s secon set to %s.", service->name, service->secon);
        }
R
renwei 已提交
183
    } else {
L
laiguizhong 已提交
184 185
        INIT_ERROR_CHECK(!(setexeccon("u:r:limit_domain:s0") < 0), _exit(PROCESS_EXIT_CODE),
            "failed to set service %s's secon (%s).", service->name, "u:r:limit_domain:s0");
186
        INIT_LOGE("Please set secon field in service %s's cfg file, limit_domain will be blocked", service->name);
Q
Qin Fandong 已提交
187 188 189 190
    }
#endif // WITH_SELINUX
}

X
xionglei6 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
void CloseServiceFds(Service *service, bool needFree)
{
    if (service == NULL) {
        return;
    }

    INIT_LOGI("Closing service \' %s \' fds", service->name);
    // fdCount > 0, There is no reason fds is NULL
    if (service->fdCount != 0) {
        size_t fdCount = service->fdCount;
        int *fds = service->fds;
        for (size_t i = 0; i < fdCount; i++) {
            INIT_LOGV("Closing fd: %d", fds[i]);
            close(fds[i]);
            fds[i] = -1;
        }
    }
    service->fdCount = 0;
    if (needFree && service->fds != NULL) {
        free(service->fds);
        service->fds = NULL;
    }
}

static void PublishHoldFds(Service *service)
{
    INIT_ERROR_CHECK(service != NULL, return, "Publish hold fds with invalid service");
    char fdBuffer[MAX_FD_HOLDER_BUFFER] = {};
    if (service->fdCount > 0 && service->fds != NULL) {
        size_t pos = 0;
        for (size_t i = 0; i < service->fdCount; i++) {
X
xionglei6 已提交
222 223 224 225 226
            int fd = dup(service->fds[i]);
            if (fd < 0) {
                INIT_LOGE("Duplicate file descriptors of Service \' %s \' failed. err = %d", service->name, errno);
                continue;
            }
L
laiguizhong 已提交
227 228
            INIT_ERROR_CHECK(!(snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1,
                "%d ", fd) < 0), return, "snprintf_s failed err=%d", errno);
X
xionglei6 已提交
229 230 231 232 233
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
L
laiguizhong 已提交
234 235 236
        INIT_ERROR_CHECK(!(snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s",
            service->name) < 0), return, "snprintf_s failed err=%d", errno);
        INIT_CHECK_ONLY_ELOG(!(setenv(envName, fdBuffer, 1) < 0), "Failed to set env %s", envName);
X
xionglei6 已提交
237 238
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
239 240
}

241 242
static int BindCpuCore(Service *service)
{
X
xlei1030 已提交
243
    if (service == NULL) {
244 245
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
246 247 248
    if (CPU_COUNT(&service->cpuSet) == 0) {
        return SERVICE_SUCCESS;
    }
M
Mupceet 已提交
249
#ifndef __LITEOS_A__
X
xlei1030 已提交
250
    int pid = getpid();
L
laiguizhong 已提交
251 252
    INIT_ERROR_CHECK(sched_setaffinity(pid, sizeof(service->cpuSet), &service->cpuSet) == 0,
        return SERVICE_FAILURE, "%s set affinity between process(pid=%d) with CPU's core failed", service->name, pid);
X
xlei1030 已提交
253 254
    INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
#endif
255 256 257
    return SERVICE_SUCCESS;
}

X
xlei1030 已提交
258
static void ClearEnvironment(Service *service)
X
xionglei6 已提交
259
{
L
laiguizhong 已提交
260
    if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
X
xlei1030 已提交
261 262 263 264 265 266
        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGTERM);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
    }
X
xionglei6 已提交
267 268 269
    return;
}

M
Mupceet 已提交
270 271
static int InitServicePropertys(Service *service)
{
272
    INIT_ERROR_CHECK(service != NULL, return -1, "Invalid parameter.");
M
Mupceet 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    SetServiceEnterSandbox(service->pathArgs.argv[0], service->attribute);
    INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS, "access token failed %s", service->name);
    // deal start job
    if (service->serviceJobs.jobsName[JOB_ON_START] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_START]);
    }
    ClearEnvironment(service);

    if (!IsOnDemandService(service)) {
        INIT_ERROR_CHECK(CreateServiceSocket(service) >= 0, return -1,
            "service %s exit! create socket failed!", service->name);
    }

    CreateServiceFile(service->fileCfg);
    if (service->attribute & SERVICE_ATTR_CONSOLE) {
        OpenConsole();
    }

    PublishHoldFds(service);
    INIT_CHECK_ONLY_ELOG(BindCpuCore(service) == SERVICE_SUCCESS,
        "binding core number failed for service %s", service->name);
X
<feat>  
xiacong 已提交
294 295 296 297 298 299

#ifdef WITH_SECCOMP
    INIT_ERROR_CHECK(SetSystemSeccompPolicy(service) == SERVICE_SUCCESS, return -1,
        "service %s exit! set seccomp failed! err %d.", service->name, errno);
#endif
    
M
Mupceet 已提交
300 301 302
    // permissions
    INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
        "service %s exit! set perms failed! err %d.", service->name, errno);
X
<feat>  
xiacong 已提交
303
    
M
Mupceet 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    // write pid
    INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
        "service %s exit! write pid failed!", service->name);
    SetSecon(service);
    return 0;
}

void EnterServiceSandbox(Service *service)
{
    INIT_ERROR_CHECK(InitServicePropertys(service) == 0, return, "Failed init service property");
    if (service->importance != 0) {
        if (setpriority(PRIO_PROCESS, 0, service->importance) != 0) {
            INIT_LOGE("setpriority failed for %s, importance = %d, err=%d",
                service->name, service->importance, errno);
                _exit(0x7f); // 0x7f: user specified
        }
    }
L
laiguizhong 已提交
321
#ifndef STARTUP_INIT_TEST
M
Mupceet 已提交
322 323 324 325
    char *argv[] = { (char *)"/bin/sh", NULL };
    INIT_CHECK_ONLY_ELOG(execv(argv[0], argv) == 0,
        "service %s execv sh failed! err %d.", service->name, errno);
    _exit(PROCESS_EXIT_CODE);
L
laiguizhong 已提交
326
#endif
M
Mupceet 已提交
327 328
}

W
wenjun 已提交
329 330
int ServiceStart(Service *service)
{
S
sun_fan 已提交
331
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
332 333 334
    INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "service : %s had started already.", service->name);
    INIT_ERROR_CHECK(service->pathArgs.count > 0,
        return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name);
X
xionglei6 已提交
335

W
wenjun 已提交
336
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
337
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
338 339
        return SERVICE_FAILURE;
    }
340
    struct stat pathStat = { 0 };
W
wenjun 已提交
341
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
342 343 344 345 346 347
    if (stat(service->pathArgs.argv[0], &pathStat) != 0) {
        service->attribute |= SERVICE_ATTR_INVALID;
        INIT_LOGE("start service %s invalid, please check %s.", service->name, service->pathArgs.argv[0]);
        return SERVICE_FAILURE;
    }
    int pid = fork();
W
wenjun 已提交
348
    if (pid == 0) {
M
Mupceet 已提交
349
        INIT_ERROR_CHECK(InitServicePropertys(service) == 0, return SERVICE_FAILURE, "Failed init service property");
350 351
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
352
    } else if (pid < 0) {
Z
zhong_ning 已提交
353
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
354 355
        return SERVICE_FAILURE;
    }
356
    INIT_LOGI("service %s starting pid %d", service->name, pid);
W
wenjun 已提交
357
    service->pid = pid;
X
xionglei6 已提交
358
    NotifyServiceChange(service, SERVICE_STARTED);
W
wenjun 已提交
359 360 361 362 363
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
364
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
X
xionglei6 已提交
365 366 367
    if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
    }
W
wenjun 已提交
368 369 370 371 372
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
373
    CloseServiceSocket(service);
X
xionglei6 已提交
374
    CloseServiceFile(service->fileCfg);
X
xionglei6 已提交
375 376 377 378 379
    // Service stop means service is killed by init or command(i.e stop_service) or system is rebooting
    // There is no reason still to hold fds
    if (service->fdCount != 0) {
        CloseServiceFds(service, true);
    }
X
xionglei6 已提交
380 381 382 383

    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
    }
X
add ut  
xionglei6 已提交
384 385
    INIT_ERROR_CHECK(kill(service->pid, SIGKILL) == 0, return SERVICE_FAILURE,
        "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
X
xionglei6 已提交
386
    NotifyServiceChange(service, SERVICE_STOPPING);
Z
zhong_ning 已提交
387
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
X
xionglei6 已提交
388
    service->pid = -1;
W
wenjun 已提交
389 390 391
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
392
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
393
{
X
xionglei6 已提交
394 395
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
        return false, "input params error.");
S
sun_fan 已提交
396 397 398 399
    time_t curTime = time(NULL);
    if (service->crashCnt == 0) {
        service->firstCrashTime = curTime;
        ++service->crashCnt;
X
xionglei6 已提交
400 401 402
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
403 404 405 406 407
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
408
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
409
            return false;
Z
zhong_ning 已提交
410 411
        }
    }
S
sun_fan 已提交
412
    return true;
Z
zhong_ning 已提交
413 414
}

X
xionglei6 已提交
415
static int ExecRestartCmd(Service *service)
Z
zhong_ning 已提交
416
{
417
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
X
xionglei6 已提交
418 419 420
    if (service->restartArg == NULL) {
        return SERVICE_SUCCESS;
    }
421 422 423
    for (int i = 0; i < service->restartArg->cmdNum; i++) {
        INIT_LOGI("ExecRestartCmd cmdLine->cmdContent %s ", service->restartArg->cmds[i].cmdContent);
        DoCmdByIndex(service->restartArg->cmds[i].cmdIndex, service->restartArg->cmds[i].cmdContent);
Z
zhong_ning 已提交
424
    }
425
    free(service->restartArg);
X
xionglei6 已提交
426
    service->restartArg = NULL;
Z
zhong_ning 已提交
427 428 429
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
430
static void CheckServiceSocket(Service *service)
X
xionglei6 已提交
431 432 433 434 435 436
{
    if (service->socketCfg == NULL) {
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
X
xionglei6 已提交
437
        if (tmpSock->sockFd <= 0) {
438
            INIT_LOGE("Invalid socket %s for service", service->name);
X
xionglei6 已提交
439 440
            tmpSock = tmpSock->next;
        }
441
        SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
442 443 444 445 446
        tmpSock = tmpSock->next;
    }
    return;
}

W
wenjun 已提交
447 448
void ServiceReap(Service *service)
{
449 450
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
451
    service->pid = -1;
X
xionglei6 已提交
452
    NotifyServiceChange(service, SERVICE_STOPPED);
453

Z
zhong_ning 已提交
454
    if (service->attribute & SERVICE_ATTR_INVALID) {
455
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
456 457
        return;
    }
458

X
xionglei6 已提交
459 460 461 462 463
    // If the service set timer
    // which means the timer handler will start the service
    // Init should not start it automatically.
    INIT_CHECK(IsServiceWithTimerEnabled(service) == 0, return);

X
xionglei6 已提交
464
    if (!IsOnDemandService(service)) {
X
xionglei6 已提交
465
        CloseServiceSocket(service);
X
xionglei6 已提交
466
    }
X
xionglei6 已提交
467
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
468 469 470 471 472 473
    // stopped by system-init itself, no need to restart even if it is not one-shot service
    if (service->attribute & SERVICE_ATTR_NEED_STOP) {
        service->attribute &= (~SERVICE_ATTR_NEED_STOP);
        service->crashCnt = 0;
        return;
    }
474

W
wenjun 已提交
475 476 477 478 479 480 481
    // for one-shot service
    if (service->attribute & SERVICE_ATTR_ONCE) {
        // no need to restart
        if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
            service->attribute &= (~SERVICE_ATTR_NEED_STOP);
            return;
        }
482
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
483
    }
484 485

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
486
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
S
sun_fan 已提交
487
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
488
                service->name, service->crashCount);
489
            ExecReboot("reboot");
S
sun_fan 已提交
490 491
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
X
xionglei6 已提交
492
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
493
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
494
            return;
W
wenjun 已提交
495 496
        }
    }
X
xionglei6 已提交
497 498
    // service no need to restart which socket managed by init until socket message detected
    if (IsOnDemandService(service)) {
X
xionglei6 已提交
499
        CheckServiceSocket(service);
X
xionglei6 已提交
500 501
        return;
    }
502

X
xionglei6 已提交
503 504 505 506 507
    int ret = ExecRestartCmd(service);
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);

    if (service->serviceJobs.jobsName[JOB_ON_RESTART] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_RESTART]);
508 509
    }
    ret = ServiceStart(service);
X
xionglei6 已提交
510
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
W
wenjun 已提交
511 512
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573

int UpdaterServiceFds(Service *service, int *fds, size_t fdCount)
{
    if (service == NULL) {
        INIT_LOGE("Invalid service info");
        return -1;
    }

    if (fdCount == 0) {
        INIT_LOGE("Update service fds with fdCount is 0, ignore.");
        return 0;
    }

    // if service->fds is NULL, allocate new memory to hold the fds
    // else if service->fds is not NULL, we will try to override it.
    // There are two cases:
    // 1) service->fdCount != fdCount:
    //  It is not easy to re-use the memory of service->fds, so we have to free the memory first
    //  then re-allocate memory to store new fds
    // 2) service->fdCount == fdCount
    //  A situation we happy to meet, just override it.

    int ret = 0;
    if (service->fdCount == fdCount) {
        // case 2
        CloseServiceFds(service, false);
        if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
            INIT_LOGE("Failed to copy fds to service");
            // Something wrong happened, maybe service->fds is broken, clear it.
            free(service->fds);
            service->fds = NULL;
            service->fdCount = 0;
            ret = -1;
        } else {
            service->fdCount = fdCount;
        }
    } else {
        if (service->fdCount > 0) {
            // case 1
            CloseServiceFds(service, true);
        }
        service->fds = calloc(fdCount + 1, sizeof(int));
        if (service->fds == NULL) {
            INIT_LOGE("Service \' %s \' failed to allocate memory for fds", service->name);
            ret = -1;
        } else {
            if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
                INIT_LOGE("Failed to copy fds to service");
                // Something wrong happened, maybe service->fds is broken, clear it.
                free(service->fds);
                service->fds = NULL;
                service->fdCount = 0;
                return -1;
            } else {
                service->fdCount = fdCount;
            }
        }
    }
    INIT_LOGI("Hold fd for service \' %s \' done", service->name);
    return ret;
}
X
xionglei6 已提交
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

void ServiceStopTimer(Service *service)
{
    INIT_ERROR_CHECK(service != NULL, return, "Stop timer with invalid service");
    if (IsServiceWithTimerEnabled(service)) {
        // Stop timer first
        if (service->timer) {
            LE_StopTimer(LE_GetDefaultLoop(), service->timer);
        }
        service->timer = NULL;
        DisableServiceTimer(service);
    }
}

static void ServiceTimerStartProcess(const TimerHandle handler, void *context)
{
    UNUSED(handler);
    Service *service = (Service *)context;

    if (service == NULL) {
        INIT_LOGE("Service timer process with invalid service");
        return;
    }

    // OK, service is ready to start.
    // Before start the service, stop service timer.
    // make sure it will not enter timer handler next time.
    ServiceStopTimer(service);
    int ret = ServiceStart(service);
    if (ret != SERVICE_SUCCESS) {
X
xionglei6 已提交
604
        INIT_LOGE("Start service \' %s \' in timer failed", service->name);
X
xionglei6 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
    }
}

void ServiceStartTimer(Service *service, uint64_t timeout)
{
    bool oldTimerClean = false;
    INIT_ERROR_CHECK(service != NULL, return, "Start timer with invalid service");
    // If the service already set a timer.
    // And a new request coming. close it and create a new one.
    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
        oldTimerClean = true;
    }
    LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &service->timer, ServiceTimerStartProcess,
        (void *)service);
    if (status != LE_SUCCESS) {
        INIT_LOGE("Create service timer for service \' %s \' failed, status = %d", service->name, status);
        if (oldTimerClean) {
            INIT_LOGE("previous timer is cleared");
        }
        return;
    }
    status = LE_StartTimer(LE_GetDefaultLoop(), service->timer, timeout, 1);
L
laiguizhong 已提交
628 629
    INIT_ERROR_CHECK(status == LE_SUCCESS, return,
        "Start service timer for service \' %s \' failed, status = %d", service->name, status);
X
xionglei6 已提交
630 631
    EnableServiceTimer(service);
}