init_common_service.c 22.0 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>
W
wenjun 已提交
27 28 29
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
30

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

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

Z
zhong_ning 已提交
50 51 52
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
Z
zhong_ning 已提交
53

S
sun_fan 已提交
54
static int SetAllAmbientCapability(void)
M
mamingshuai 已提交
55 56 57 58 59 60 61 62 63
{
    for (int i = 0; i <= CAP_LAST_CAP; ++i) {
        if (SetAmbientCapability(i) != 0) {
            return SERVICE_FAILURE;
        }
    }
    return SERVICE_SUCCESS;
}

W
wenjun 已提交
64 65
static int SetPerms(const Service *service)
{
Z
zhong_ning 已提交
66
    INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
67 68 69 70 71 72

    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 已提交
73
    if (service->servPerm.gIDCnt > 0) {
Z
zhong_ning 已提交
74 75
        INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
            "SetPerms, setgid for %s failed. %d", service->name, errno);
Z
zhong_ning 已提交
76 77
    }
    if (service->servPerm.gIDCnt > 1) {
X
xionglei6 已提交
78 79
        INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
            return SERVICE_FAILURE,
Z
zhong_ning 已提交
80
            "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
W
wenjun 已提交
81
    }
Z
zhong_ning 已提交
82 83
    if (service->servPerm.uID != 0) {
        if (setuid(service->servPerm.uID) != 0) {
Z
zhong_ning 已提交
84
            INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
Z
zhong_ning 已提交
85 86
            return SERVICE_FAILURE;
        }
W
wenjun 已提交
87 88 89 90 91
    }

    struct __user_cap_header_struct capHeader;
    capHeader.version = _LINUX_CAPABILITY_VERSION_3;
    capHeader.pid = 0;
Z
zhong_ning 已提交
92
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
93 94
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
95 96 97 98
            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 已提交
99 100 101 102 103 104 105 106 107
            }
            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]);
    }

    if (capset(&capHeader, capData) != 0) {
Z
zhong_ning 已提交
108
        INIT_LOGE("capset faild for service: %s, error: %d", service->name, errno);
W
wenjun 已提交
109 110
        return SERVICE_FAILURE;
    }
M
mamingshuai 已提交
111 112 113 114 115
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
            return SetAllAmbientCapability();
        }
        if (SetAmbientCapability(service->servPerm.caps[i]) != 0) {
Z
zhong_ning 已提交
116
            INIT_LOGE("SetAmbientCapability faild for service: %s", service->name);
M
mamingshuai 已提交
117 118 119
            return SERVICE_FAILURE;
        }
    }
W
wenjun 已提交
120 121 122
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
123
static void OpenConsole(void)
Z
zhong_ning 已提交
124
{
125
    const int stdError = 2;
Z
zhong_ning 已提交
126
    setsid();
H
huangshan 已提交
127
    WaitForFile("/dev/console", WAIT_MAX_SECOND);
Z
zhong_ning 已提交
128 129 130 131 132
    int fd = open("/dev/console", O_RDWR);
    if (fd >= 0) {
        ioctl(fd, TIOCSCTTY, 0);
        dup2(fd, 0);
        dup2(fd, 1);
133
        dup2(fd, stdError); // Redirect fd to 0, 1, 2
Z
zhong_ning 已提交
134 135
        close(fd);
    } else {
Z
zhong_ning 已提交
136
        INIT_LOGE("Open /dev/console failed. err = %d", errno);
Z
zhong_ning 已提交
137 138 139 140
    }
    return;
}

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

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

X
xionglei6 已提交
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 222 223 224
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 已提交
225 226 227 228 229 230 231 232 233
            int fd = dup(service->fds[i]);
            if (fd < 0) {
                INIT_LOGE("Duplicate file descriptors of Service \' %s \' failed. err = %d", service->name, errno);
                continue;
            }
            if (snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1, "%d ", fd) < 0) {
                INIT_LOGE("snprintf_s failed err=%d", errno);
                return;
            }
X
xionglei6 已提交
234 235 236 237 238
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
X
xionglei6 已提交
239 240 241 242
        if (snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s", service->name) < 0) {
            INIT_LOGE("snprintf_s failed err=%d", errno);
            return;
        }
X
xionglei6 已提交
243 244 245 246 247
        if (setenv(envName, fdBuffer, 1) < 0) {
            INIT_LOGE("Failed to set env %s", envName);
        }
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
248 249
}

250 251
static int BindCpuCore(Service *service)
{
X
xlei1030 已提交
252
    if (service == NULL) {
253 254
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
255 256 257
    if (CPU_COUNT(&service->cpuSet) == 0) {
        return SERVICE_SUCCESS;
    }
M
Mupceet 已提交
258
#ifndef __LITEOS_A__
X
xlei1030 已提交
259 260 261 262
    int pid = getpid();
    if (sched_setaffinity(pid, sizeof(service->cpuSet), &service->cpuSet) != 0) {
        INIT_LOGE("%s set affinity between process(pid=%d) with CPU's core failed", service->name, pid);
        return SERVICE_FAILURE;
263
    }
X
xlei1030 已提交
264 265
    INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
#endif
266 267 268
    return SERVICE_SUCCESS;
}

X
xlei1030 已提交
269
static void ClearEnvironment(Service *service)
X
xionglei6 已提交
270
{
L
laiguizhong 已提交
271
    if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
X
xlei1030 已提交
272 273 274 275 276 277
        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGTERM);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
    }
X
xionglei6 已提交
278 279 280
    return;
}

W
wenjun 已提交
281 282
int ServiceStart(Service *service)
{
S
sun_fan 已提交
283
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
284 285 286
    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 已提交
287

W
wenjun 已提交
288
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
289
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
290 291
        return SERVICE_FAILURE;
    }
292
    struct stat pathStat = { 0 };
W
wenjun 已提交
293
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
294 295 296 297 298 299
    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 已提交
300
    if (pid == 0) {
X
xionglei6 已提交
301
        SetServiceEnterSandbox(service->pathArgs.argv[0], service->attribute);
X
xionglei6 已提交
302 303

        INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS, "access token failed %s", service->name);
X
xionglei6 已提交
304 305 306 307 308
        // deal start job
        if (service->serviceJobs.jobsName[JOB_ON_START] != NULL) {
            DoJobNow(service->serviceJobs.jobsName[JOB_ON_START]);
        }

X
xlei1030 已提交
309
        ClearEnvironment(service);
X
xionglei6 已提交
310

X
xionglei6 已提交
311
        if (!IsOnDemandService(service)) {
X
xionglei6 已提交
312
            INIT_ERROR_CHECK(CreateServiceSocket(service) >= 0, return SERVICE_FAILURE,
X
xionglei6 已提交
313 314
                "service %s exit! create socket failed!", service->name);
        }
X
xionglei6 已提交
315

X
xionglei6 已提交
316
        CreateServiceFile(service->fileCfg);
Z
zhong_ning 已提交
317 318 319
        if (service->attribute & SERVICE_ATTR_CONSOLE) {
            OpenConsole();
        }
X
xionglei6 已提交
320
        PublishHoldFds(service);
321 322
        INIT_CHECK_ONLY_ELOG(BindCpuCore(service) == SERVICE_SUCCESS,
            "binding core number failed for service %s", service->name);
323
        // permissions
X
add ut  
xionglei6 已提交
324 325
        INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! set perms failed! err %d.", service->name, errno);
326
        // write pid
X
add ut  
xionglei6 已提交
327 328
        INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, _exit(PROCESS_EXIT_CODE),
            "service %s exit! write pid failed!", service->name);
Q
Qin Fandong 已提交
329
        SetSecon(service);
330 331
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
332
    } else if (pid < 0) {
Z
zhong_ning 已提交
333
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
334 335
        return SERVICE_FAILURE;
    }
336
    INIT_LOGI("service %s starting pid %d", service->name, pid);
W
wenjun 已提交
337
    service->pid = pid;
X
xionglei6 已提交
338
    NotifyServiceChange(service, SERVICE_STARTED);
W
wenjun 已提交
339 340 341 342 343
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
344
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
X
xionglei6 已提交
345 346 347
    if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
    }
W
wenjun 已提交
348 349 350 351 352
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
353
    CloseServiceSocket(service);
X
xionglei6 已提交
354
    CloseServiceFile(service->fileCfg);
X
xionglei6 已提交
355 356 357 358 359
    // 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 已提交
360 361 362 363

    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
    }
X
add ut  
xionglei6 已提交
364 365
    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 已提交
366
    NotifyServiceChange(service, SERVICE_STOPPING);
Z
zhong_ning 已提交
367
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
X
xionglei6 已提交
368
    service->pid = -1;
W
wenjun 已提交
369 370 371
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
372
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
373
{
X
xionglei6 已提交
374 375
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
        return false, "input params error.");
S
sun_fan 已提交
376 377 378 379
    time_t curTime = time(NULL);
    if (service->crashCnt == 0) {
        service->firstCrashTime = curTime;
        ++service->crashCnt;
X
xionglei6 已提交
380 381 382
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
383 384 385 386 387
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
388
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
389
            return false;
Z
zhong_ning 已提交
390 391
        }
    }
S
sun_fan 已提交
392
    return true;
Z
zhong_ning 已提交
393 394
}

X
xionglei6 已提交
395
static int ExecRestartCmd(Service *service)
Z
zhong_ning 已提交
396
{
397
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
X
xionglei6 已提交
398 399 400
    if (service->restartArg == NULL) {
        return SERVICE_SUCCESS;
    }
401 402 403
    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 已提交
404
    }
405
    free(service->restartArg);
X
xionglei6 已提交
406
    service->restartArg = NULL;
Z
zhong_ning 已提交
407 408 409
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
410
static void CheckServiceSocket(Service *service)
X
xionglei6 已提交
411 412 413 414 415 416
{
    if (service->socketCfg == NULL) {
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
X
xionglei6 已提交
417 418 419 420
        if (tmpSock->sockFd <= 0) {
            INIT_LOGE("Invaid socket %s for service", service->name);
            tmpSock = tmpSock->next;
        }
421
        SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
422 423 424 425 426
        tmpSock = tmpSock->next;
    }
    return;
}

W
wenjun 已提交
427 428
void ServiceReap(Service *service)
{
429 430
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
431
    service->pid = -1;
X
xionglei6 已提交
432
    NotifyServiceChange(service, SERVICE_STOPPED);
433

Z
zhong_ning 已提交
434
    if (service->attribute & SERVICE_ATTR_INVALID) {
435
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
436 437
        return;
    }
438

X
xionglei6 已提交
439 440 441 442 443
    // 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 已提交
444
    if (!IsOnDemandService(service)) {
X
xionglei6 已提交
445
        CloseServiceSocket(service);
X
xionglei6 已提交
446
    }
X
xionglei6 已提交
447
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
448 449 450 451 452 453
    // 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;
    }
454

W
wenjun 已提交
455 456 457 458 459 460 461
    // 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;
        }
462
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
463
    }
464 465

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
466
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
S
sun_fan 已提交
467
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
468
                service->name, service->crashCount);
469
            ExecReboot("reboot");
S
sun_fan 已提交
470 471
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
X
xionglei6 已提交
472
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
473
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
474
            return;
W
wenjun 已提交
475 476
        }
    }
X
xionglei6 已提交
477 478
    // service no need to restart which socket managed by init until socket message detected
    if (IsOnDemandService(service)) {
X
xionglei6 已提交
479
        CheckServiceSocket(service);
X
xionglei6 已提交
480 481
        return;
    }
482

X
xionglei6 已提交
483 484 485 486 487
    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]);
488 489
    }
    ret = ServiceStart(service);
X
xionglei6 已提交
490
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
W
wenjun 已提交
491 492
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 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

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 已提交
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583

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 已提交
584
        INIT_LOGE("Start service \' %s \' in timer failed", service->name);
X
xionglei6 已提交
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
    }
}

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);
    if (status != LE_SUCCESS) {
        INIT_LOGE("Start service timer for service \' %s \' failed, status = %d", service->name, status);
        return;
    }
    EnableServiceTimer(service);
}