init_common_service.c 21.9 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>
21 22
#include <sched.h>
#include <stdio.h>
Z
zhong_ning 已提交
23 24 25
#ifdef __MUSL__
#include <stropts.h>
#endif
26
#include <sys/capability.h>
X
xionglei6 已提交
27
#include <sys/ioctl.h>
Z
zhong_ning 已提交
28
#include <sys/param.h>
W
wenjun 已提交
29 30 31
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
32

33
#include "init.h"
W
wenjun 已提交
34
#include "init_adapter.h"
Z
zhong_ning 已提交
35 36
#include "init_cmds.h"
#include "init_log.h"
X
xionglei6 已提交
37
#include "init_jobs_internal.h"
X
xionglei6 已提交
38
#include "init_service.h"
X
xionglei6 已提交
39
#include "init_service_manager.h"
Z
zhong_ning 已提交
40
#include "init_service_socket.h"
Z
zhong_ning 已提交
41
#include "init_utils.h"
X
xionglei6 已提交
42
#include "fd_holder_internal.h"
43
#include "loop_event.h"
Z
zhong_ning 已提交
44
#include "securec.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

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

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

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

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

    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);

    struct __user_cap_header_struct capHeader;
    capHeader.version = _LINUX_CAPABILITY_VERSION_3;
    capHeader.pid = 0;
Z
zhong_ning 已提交
96
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
97 98
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
99 100 101 102
            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 已提交
103 104 105 106 107 108 109 110 111
            }
            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 已提交
112
        INIT_LOGE("capset faild for service: %s, error: %d", service->name, errno);
W
wenjun 已提交
113 114
        return SERVICE_FAILURE;
    }
M
mamingshuai 已提交
115 116 117 118 119
    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 已提交
120
            INIT_LOGE("SetAmbientCapability faild for service: %s", service->name);
M
mamingshuai 已提交
121 122 123
            return SERVICE_FAILURE;
        }
    }
W
wenjun 已提交
124 125 126
    return SERVICE_SUCCESS;
}

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

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

X
xionglei6 已提交
178
void SetSecon(Service *service)
Q
Qin Fandong 已提交
179 180 181 182 183 184 185 186 187 188 189 190
{
#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);
        } else {
            INIT_LOGI("service %s secon set to %s.", service->name, service->secon);
        }
    }
#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 222 223 224 225 226 227 228 229 230 231 232 233 234
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++) {
            (void)snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1,
                "%d ", service->fds[i]);
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
        (void)snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s", service->name);
        if (setenv(envName, fdBuffer, 1) < 0) {
            INIT_LOGE("Failed to set env %s", envName);
        }
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
235 236
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
static int SetAffinityBetweenProcAndCore(pid_t pid, int cpuIndex)
{
    cpu_set_t setMask;
    CPU_ZERO(&setMask);
    CPU_SET(cpuIndex, &setMask);
    int ret = sched_setaffinity(pid, sizeof(cpu_set_t), &setMask);
    if (ret != 0) {
        INIT_LOGI("Set affinity between process(pid=%d) with CPU's core %d failed", pid, cpuIndex);
        return SERVICE_FAILURE;
    } else {
        INIT_LOGE("Set affinity between process(pid=%d) with CPU's core %d successfully", pid, cpuIndex);
    }
    return SERVICE_SUCCESS;
}

static int BindCpuCore(Service *service)
{
    if (service == NULL || service->cpuInfo.cpuNum <= 0) {
        return SERVICE_SUCCESS;
    }
    long cpuNum = sysconf(_SC_NPROCESSORS_CONF);
    INIT_ERROR_CHECK(service->cpuInfo.cpuNum <= cpuNum, return SERVICE_FAILURE,
        "%s cpus cores exceeds total number of device cores", service->name);
    int index = 0;
    for (int i = 0; i < service->cpuInfo.cpuNum; i++) {
        index = (int)service->cpuInfo.cpus[i];
        if ((int)cpuNum <= index) {
            INIT_LOGW("%s core number %d of CPU cores does not exist", service->name, index);
            continue;
        }
        (void)SetAffinityBetweenProcAndCore(getpid(), index);
    }
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
272 273 274 275 276 277 278 279 280 281
static void ClearEnvironment(void)
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    sigaddset(&mask, SIGTERM);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
    return;
}

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

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

309
        ClearEnvironment();
X
xionglei6 已提交
310

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

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

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

    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
    }
X
add ut  
xionglei6 已提交
365 366
    INIT_ERROR_CHECK(kill(service->pid, SIGKILL) == 0, return SERVICE_FAILURE,
        "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
367
    NotifyServiceChange(service->name, "stopping");
Z
zhong_ning 已提交
368
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
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
{
S
sun_fan 已提交
374 375 376 377 378 379
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0, return 0,
        "Service name=%s, input params error.", service->name);
    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 395 396
}

static int ExecRestartCmd(const Service *service)
{
397 398
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
    INIT_ERROR_CHECK(service->restartArg != NULL, return SERVICE_FAILURE, "restartArg is null");
Z
zhong_ning 已提交
399

400 401 402
    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 已提交
403
    }
404
    free(service->restartArg);
Z
zhong_ning 已提交
405 406 407
    return SERVICE_SUCCESS;
}

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

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

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

438 439 440
    // If the service set timer
    // which means the timer handler will start the service
    // Init should not start it automatically.
X
xionglei6 已提交
441
    INIT_CHECK(IsServiceWithTimerEnabled(service) == 0, return);
442

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

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

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

X
xionglei6 已提交
482
    int ret;
483 484
    if (service->restartArg != NULL) {
        ret = ExecRestartCmd(service);
X
add ut  
xionglei6 已提交
485
        INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);
486 487
    }
    ret = ServiceStart(service);
X
xionglei6 已提交
488
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
W
wenjun 已提交
489 490
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
491 492 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

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;
}
552 553 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 584 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

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) {
        INIT_LOGE("Start service \' %s \' in timer failed");
    }
}

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