init_common_service.c 24.2 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
<feat>  
xiacong 已提交
36
#include "init_cmdexecutor.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"
X
xionglei6 已提交
43
#include "loop_event.h"
Z
zhong_ning 已提交
44
#include "securec.h"
X
xionglei6 已提交
45
#include "service_control.h"
W
wenjun 已提交
46

M
Mupceet 已提交
47 48 49 50 51
#ifndef OHOS_LITE
#include "hookmgr.h"
#include "bootstage.h"
#endif

Q
Qin Fandong 已提交
52
#ifdef WITH_SELINUX
X
xionglei6 已提交
53 54
#include "init_selinux_param.h"
#include <selinux/selinux.h>
Q
Qin Fandong 已提交
55 56
#endif // WITH_SELINUX

X
<feat>  
xiacong 已提交
57 58 59 60 61
#ifdef WITH_SECCOMP
#define APPSPAWN_NAME ("appspawn")
#define NWEBSPAWN_NAME ("nwebspawn")
#endif

Z
zhong_ning 已提交
62 63 64
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
Z
zhong_ning 已提交
65

S
sun_fan 已提交
66
static int SetAllAmbientCapability(void)
M
mamingshuai 已提交
67 68 69 70 71 72 73 74 75
{
    for (int i = 0; i <= CAP_LAST_CAP; ++i) {
        if (SetAmbientCapability(i) != 0) {
            return SERVICE_FAILURE;
        }
    }
    return SERVICE_SUCCESS;
}

X
<feat>  
xiacong 已提交
76
static void SetSystemSeccompPolicy(const Service *service)
X
<feat>  
xiacong 已提交
77
{
X
<feat>  
xiacong 已提交
78
#ifdef WITH_SECCOMP
X
<feat>  
xiacong 已提交
79 80
    if (strncmp(APPSPAWN_NAME, service->name, strlen(APPSPAWN_NAME)) \
        && strncmp(NWEBSPAWN_NAME, service->name, strlen(NWEBSPAWN_NAME))) {
X
<feat>  
xiacong 已提交
81
        PluginExecCmdByName("SetSeccompPolicy", "start");
X
<feat>  
xiacong 已提交
82 83
    }
#endif
X
<feat>  
xiacong 已提交
84
}
X
<feat>  
xiacong 已提交
85

M
Mupceet 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
#ifndef OHOS_LITE
/**
 * service Hooking
 */
static int ServiceHookWrapper(const HOOK_INFO *hookInfo, void *executionContext)
{
    SERVICE_INFO_CTX *serviceContext = (SERVICE_INFO_CTX *)executionContext;
    ServiceHook realHook = (ServiceHook)hookInfo->hookCookie;

    realHook(serviceContext);
    return 0;
};

int InitAddServiceHook(ServiceHook hook, int hookState)
{
    HOOK_INFO info;

    info.stage = hookState;
    info.prio = 0;
    info.hook = ServiceHookWrapper;
    info.hookCookie = (void *)hook;

    return HookMgrAddEx(GetBootStageHookMgr(), &info);
}

/**
 * service hooking execute
 */
static void ServiceHookExecute(const char *serviceName, const char *info, int stage)
{
    SERVICE_INFO_CTX context;

    context.serviceName = serviceName;
    context.reserved = info;

    (void)HookMgrExecute(GetBootStageHookMgr(), stage, (void *)(&context), NULL);
}
#endif

W
wenjun 已提交
125 126
static int SetPerms(const Service *service)
{
Z
zhong_ning 已提交
127
    INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
128 129 130 131 132 133

    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 已提交
134
    if (service->servPerm.gIDCnt > 0) {
Z
zhong_ning 已提交
135 136
        INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
            "SetPerms, setgid for %s failed. %d", service->name, errno);
Z
zhong_ning 已提交
137 138
    }
    if (service->servPerm.gIDCnt > 1) {
X
xionglei6 已提交
139 140
        INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
            return SERVICE_FAILURE,
Z
zhong_ning 已提交
141
            "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
W
wenjun 已提交
142
    }
Z
zhong_ning 已提交
143 144
    if (service->servPerm.uID != 0) {
        if (setuid(service->servPerm.uID) != 0) {
Z
zhong_ning 已提交
145
            INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
Z
zhong_ning 已提交
146 147
            return SERVICE_FAILURE;
        }
W
wenjun 已提交
148 149 150 151 152
    }

    struct __user_cap_header_struct capHeader;
    capHeader.version = _LINUX_CAPABILITY_VERSION_3;
    capHeader.pid = 0;
Z
zhong_ning 已提交
153
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
154 155
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
156 157 158 159
            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 已提交
160 161 162 163 164 165 166 167
            }
            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 已提交
168
    INIT_ERROR_CHECK(capset(&capHeader, capData) == 0, return SERVICE_FAILURE,
169
        "capset failed for service: %s, error: %d", service->name, errno);
M
mamingshuai 已提交
170 171 172 173
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
            return SetAllAmbientCapability();
        }
L
laiguizhong 已提交
174
        INIT_ERROR_CHECK(SetAmbientCapability(service->servPerm.caps[i]) == 0, return SERVICE_FAILURE,
175
            "SetAmbientCapability failed for service: %s", service->name);
M
mamingshuai 已提交
176
    }
M
Mupceet 已提交
177 178 179 180 181 182
#ifndef OHOS_LITE
    /*
     * service set Perms hooks
     */
    ServiceHookExecute(service->name, NULL, INIT_SERVICE_SET_PERMS);
#endif
W
wenjun 已提交
183 184 185
    return SERVICE_SUCCESS;
}

186
static int WritePid(const Service *service)
S
sun_fan 已提交
187
{
188 189 190 191
    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 已提交
192
    INIT_ERROR_CHECK(len > 0, return SERVICE_FAILURE, "Failed to format pid for service %s", service->name);
193 194
    for (int i = 0; i < service->writePidArgs.count; i++) {
        if (service->writePidArgs.argv[i] == NULL) {
S
sun_fan 已提交
195
            continue;
S
sun_fan 已提交
196
        }
197 198 199 200 201 202 203 204
        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 已提交
205 206
            INIT_CHECK_ONLY_ELOG((int)fwrite(pidString, 1, len, fd) == len,
                "Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString);
207 208 209 210 211 212 213
            (void)fclose(fd);
        } else {
            INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]);
        }
        if (realPath != NULL) {
            free(realPath);
        }
X
xionglei6 已提交
214
        INIT_LOGV("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString);
S
sun_fan 已提交
215
    }
216
    return SERVICE_SUCCESS;
S
sun_fan 已提交
217 218
}

X
xionglei6 已提交
219
void SetSecon(Service *service)
Q
Qin Fandong 已提交
220 221
{
#ifdef WITH_SELINUX
M
Mupceet 已提交
222
    if (service->secon != NULL) {
Q
Qin Fandong 已提交
223 224
        if (setexeccon(service->secon) < 0) {
            INIT_LOGE("failed to set service %s's secon (%s).", service->name, service->secon);
R
renwei 已提交
225
            _exit(PROCESS_EXIT_CODE);
Q
Qin Fandong 已提交
226 227 228
        } else {
            INIT_LOGI("service %s secon set to %s.", service->name, service->secon);
        }
R
renwei 已提交
229
    } else {
L
laiguizhong 已提交
230 231
        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");
232
        INIT_LOGE("Please set secon field in service %s's cfg file, limit_domain will be blocked", service->name);
Q
Qin Fandong 已提交
233 234 235 236
    }
#endif // WITH_SELINUX
}

X
xionglei6 已提交
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
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 已提交
268 269 270 271 272
            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 已提交
273 274
            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 已提交
275 276 277 278 279
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
L
laiguizhong 已提交
280 281 282
        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 已提交
283 284
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
285 286
}

287 288
static int BindCpuCore(Service *service)
{
X
xlei1030 已提交
289
    if (service == NULL) {
290 291
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
292 293 294
    if (CPU_COUNT(&service->cpuSet) == 0) {
        return SERVICE_SUCCESS;
    }
M
Mupceet 已提交
295
#ifndef __LITEOS_A__
X
xlei1030 已提交
296
    int pid = getpid();
L
laiguizhong 已提交
297 298
    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 已提交
299 300
    INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
#endif
301 302 303
    return SERVICE_SUCCESS;
}

X
xlei1030 已提交
304
static void ClearEnvironment(Service *service)
X
xionglei6 已提交
305
{
L
laiguizhong 已提交
306
    if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
X
xlei1030 已提交
307 308 309 310 311 312
        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGTERM);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
    }
X
xionglei6 已提交
313 314 315
    return;
}

M
Mupceet 已提交
316 317
static int InitServicePropertys(Service *service)
{
318
    INIT_ERROR_CHECK(service != NULL, return -1, "Invalid parameter.");
M
Mupceet 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    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 已提交
340

X
<feat>  
xiacong 已提交
341
    SetSystemSeccompPolicy(service);
X
<feat>  
xiacong 已提交
342
    
M
Mupceet 已提交
343
    // permissions
M
Mupceet 已提交
344
    INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, return -1,
M
Mupceet 已提交
345
        "service %s exit! set perms failed! err %d.", service->name, errno);
X
<feat>  
xiacong 已提交
346
    
M
Mupceet 已提交
347
    // write pid
M
Mupceet 已提交
348
    INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, return -1,
M
Mupceet 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
        "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 已提交
364
#ifndef STARTUP_INIT_TEST
M
Mupceet 已提交
365 366 367 368
    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 已提交
369
#endif
M
Mupceet 已提交
370 371
}

W
wenjun 已提交
372 373
int ServiceStart(Service *service)
{
S
sun_fan 已提交
374
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
375 376 377
    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 已提交
378

W
wenjun 已提交
379
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
380
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
381 382
        return SERVICE_FAILURE;
    }
383
    struct stat pathStat = { 0 };
W
wenjun 已提交
384
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
385 386 387 388 389
    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;
    }
M
Mupceet 已提交
390 391 392 393 394 395
#ifndef OHOS_LITE
    /*
     * before service fork hooks
     */
    ServiceHookExecute(service->name, NULL, INIT_SERVICE_FORK_BEFORE);
#endif
396
    int pid = fork();
W
wenjun 已提交
397
    if (pid == 0) {
M
Mupceet 已提交
398 399 400
        // fail must exit sub process
        INIT_ERROR_CHECK(InitServicePropertys(service) == 0,
            _exit(PROCESS_EXIT_CODE), "Failed init service property");
401 402
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
403
    } else if (pid < 0) {
Z
zhong_ning 已提交
404
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
405 406
        return SERVICE_FAILURE;
    }
407
    INIT_LOGI("service %s starting pid %d", service->name, pid);
W
wenjun 已提交
408
    service->pid = pid;
X
xionglei6 已提交
409
    NotifyServiceChange(service, SERVICE_STARTED);
W
wenjun 已提交
410 411 412 413 414
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
415
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
X
xionglei6 已提交
416 417 418
    if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
    }
W
wenjun 已提交
419 420 421 422 423
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
424
    CloseServiceSocket(service);
X
xionglei6 已提交
425
    CloseServiceFile(service->fileCfg);
X
xionglei6 已提交
426 427 428 429 430
    // 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 已提交
431 432 433 434

    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
    }
X
add ut  
xionglei6 已提交
435 436
    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 已提交
437
    NotifyServiceChange(service, SERVICE_STOPPING);
Z
zhong_ning 已提交
438
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
X
xionglei6 已提交
439
    service->pid = -1;
M
Mupceet 已提交
440
    NotifyServiceChange(service, SERVICE_STOPPED);
W
wenjun 已提交
441 442 443
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
444
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
445
{
X
xionglei6 已提交
446 447
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
        return false, "input params error.");
S
sun_fan 已提交
448 449 450 451
    time_t curTime = time(NULL);
    if (service->crashCnt == 0) {
        service->firstCrashTime = curTime;
        ++service->crashCnt;
X
xionglei6 已提交
452 453 454
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
455 456 457 458 459
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
460
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
461
            return false;
Z
zhong_ning 已提交
462 463
        }
    }
S
sun_fan 已提交
464
    return true;
Z
zhong_ning 已提交
465 466
}

X
xionglei6 已提交
467
static int ExecRestartCmd(Service *service)
Z
zhong_ning 已提交
468
{
469
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
X
xionglei6 已提交
470 471 472
    if (service->restartArg == NULL) {
        return SERVICE_SUCCESS;
    }
473 474 475
    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 已提交
476
    }
477
    free(service->restartArg);
X
xionglei6 已提交
478
    service->restartArg = NULL;
Z
zhong_ning 已提交
479 480 481
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
482
static void CheckServiceSocket(Service *service)
X
xionglei6 已提交
483 484 485 486 487 488
{
    if (service->socketCfg == NULL) {
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
X
xionglei6 已提交
489
        if (tmpSock->sockFd <= 0) {
490
            INIT_LOGE("Invalid socket %s for service", service->name);
X
xionglei6 已提交
491 492
            tmpSock = tmpSock->next;
        }
493
        SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
494 495 496 497 498
        tmpSock = tmpSock->next;
    }
    return;
}

W
wenjun 已提交
499 500
void ServiceReap(Service *service)
{
501 502
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
503
    service->pid = -1;
X
xionglei6 已提交
504
    NotifyServiceChange(service, SERVICE_STOPPED);
505

Z
zhong_ning 已提交
506
    if (service->attribute & SERVICE_ATTR_INVALID) {
507
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
508 509
        return;
    }
510

X
xionglei6 已提交
511 512 513 514 515
    // 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 已提交
516
    if (!IsOnDemandService(service)) {
X
xionglei6 已提交
517
        CloseServiceSocket(service);
X
xionglei6 已提交
518
    }
X
xionglei6 已提交
519
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
520 521 522 523 524 525
    // 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;
    }
526

W
wenjun 已提交
527 528 529 530 531 532 533
    // 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;
        }
534
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
535
    }
536 537

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
538
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
S
sun_fan 已提交
539
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
540
                service->name, service->crashCount);
541
            ExecReboot("reboot");
S
sun_fan 已提交
542 543
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
X
xionglei6 已提交
544
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
545
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
546
            return;
W
wenjun 已提交
547 548
        }
    }
X
xionglei6 已提交
549 550
    // service no need to restart which socket managed by init until socket message detected
    if (IsOnDemandService(service)) {
X
xionglei6 已提交
551
        CheckServiceSocket(service);
X
xionglei6 已提交
552 553
        return;
    }
554

X
xionglei6 已提交
555 556 557 558 559
    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]);
560 561
    }
    ret = ServiceStart(service);
X
xionglei6 已提交
562
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
W
wenjun 已提交
563 564
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
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 612 613 614 615 616 617 618 619 620 621 622 623 624 625

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 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655

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 已提交
656
        INIT_LOGE("Start service \' %s \' in timer failed", service->name);
X
xionglei6 已提交
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
    }
}

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 已提交
680 681
    INIT_ERROR_CHECK(status == LE_SUCCESS, return,
        "Start service timer for service \' %s \' failed, status = %d", service->name, status);
X
xionglei6 已提交
682 683
    EnableServiceTimer(service);
}