init_common_service.c 23.7 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
#include "init_cmds.h"
C
cheng_jinsong 已提交
35
#include "init_cmdexecutor.h"
Z
zhong_ning 已提交
36
#include "init_log.h"
X
<feat>  
xiacong 已提交
37
#include "init_cmdexecutor.h"
X
xionglei6 已提交
38
#include "init_jobs_internal.h"
X
xionglei6 已提交
39
#include "init_service.h"
X
xionglei6 已提交
40
#include "init_service_manager.h"
Z
zhong_ning 已提交
41
#include "init_service_socket.h"
Z
zhong_ning 已提交
42
#include "init_utils.h"
X
xionglei6 已提交
43
#include "fd_holder_internal.h"
X
xionglei6 已提交
44
#include "loop_event.h"
Z
zhong_ning 已提交
45
#include "securec.h"
X
xionglei6 已提交
46
#include "service_control.h"
W
wenjun 已提交
47

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

X
<feat>  
xiacong 已提交
53 54 55 56 57
#ifdef WITH_SECCOMP
#define APPSPAWN_NAME ("appspawn")
#define NWEBSPAWN_NAME ("nwebspawn")
#endif

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

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

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

M
Mupceet 已提交
82 83 84 85 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
#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 已提交
121 122
static int SetPerms(const Service *service)
{
Z
zhong_ning 已提交
123
    INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
124 125 126 127 128 129

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

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

182
static int WritePid(const Service *service)
S
sun_fan 已提交
183
{
184 185 186
    pid_t childPid = getpid();
    for (int i = 0; i < service->writePidArgs.count; i++) {
        if (service->writePidArgs.argv[i] == NULL) {
S
sun_fan 已提交
187
            continue;
S
sun_fan 已提交
188
        }
189 190 191 192 193 194 195 196
        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) {
C
cheng_jinsong 已提交
197 198
            INIT_CHECK_ONLY_ELOG((int)fprintf(fd, "%d", childPid) > 0,
                "Failed to write %s pid:%d", service->writePidArgs.argv[i], childPid);
199 200
            (void)fclose(fd);
        } else {
C
cheng_jinsong 已提交
201
            INIT_LOGE("Failed to open realPath: %s  %s errno:%d.", realPath, service->writePidArgs.argv[i], errno);
202 203 204 205
        }
        if (realPath != NULL) {
            free(realPath);
        }
C
cheng_jinsong 已提交
206
        INIT_LOGV("ServiceStart writepid filename=%s, childPid=%d, ok", service->writePidArgs.argv[i], childPid);
S
sun_fan 已提交
207
    }
208
    return SERVICE_SUCCESS;
S
sun_fan 已提交
209 210
}

X
xionglei6 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
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 已提交
242 243 244 245 246
            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 已提交
247 248
            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 已提交
249 250 251 252 253
            pos = strlen(fdBuffer);
        }
        fdBuffer[pos - 1] = '\0'; // Remove last ' '
        INIT_LOGI("fd buffer: [%s]", fdBuffer);
        char envName[MAX_BUFFER_LEN] = {};
L
laiguizhong 已提交
254 255 256
        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 已提交
257 258
        INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
    }
259 260
}

261 262
static int BindCpuCore(Service *service)
{
C
cheng_jinsong 已提交
263
    if (service == NULL || service->cpuSet == NULL) {
264 265
        return SERVICE_SUCCESS;
    }
C
cheng_jinsong 已提交
266
    if (CPU_COUNT(service->cpuSet) == 0) {
X
xionglei6 已提交
267 268
        return SERVICE_SUCCESS;
    }
M
Mupceet 已提交
269
#ifndef __LITEOS_A__
X
xlei1030 已提交
270
    int pid = getpid();
C
cheng_jinsong 已提交
271
    INIT_ERROR_CHECK(sched_setaffinity(pid, sizeof(cpu_set_t), service->cpuSet) == 0,
L
laiguizhong 已提交
272
        return SERVICE_FAILURE, "%s set affinity between process(pid=%d) with CPU's core failed", service->name, pid);
X
xlei1030 已提交
273 274
    INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
#endif
275 276 277
    return SERVICE_SUCCESS;
}

X
xlei1030 已提交
278
static void ClearEnvironment(Service *service)
X
xionglei6 已提交
279
{
L
laiguizhong 已提交
280
    if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
X
xlei1030 已提交
281 282 283 284 285 286
        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGTERM);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
    }
X
xionglei6 已提交
287 288 289
    return;
}

C
cheng_jinsong 已提交
290
static int InitServiceProperties(Service *service)
M
Mupceet 已提交
291
{
292
    INIT_ERROR_CHECK(service != NULL, return -1, "Invalid parameter.");
M
Mupceet 已提交
293
    SetServiceEnterSandbox(service->pathArgs.argv[0], service->attribute);
C
fix log  
cheng_jinsong 已提交
294 295
    INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS,
        "Set service %s access token failed", service->name);
M
Mupceet 已提交
296 297 298 299 300 301 302 303 304 305 306
    // 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);
C
cheng_jinsong 已提交
307
    if ((service->attribute & SERVICE_ATTR_CONSOLE)) {
C
cheng_jinsong 已提交
308
        OpenConsole();
M
Mupceet 已提交
309 310 311 312 313
    }

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

X
<feat>  
xiacong 已提交
315
    SetSystemSeccompPolicy(service);
C
cheng_jinsong 已提交
316

M
Mupceet 已提交
317
    // permissions
M
Mupceet 已提交
318
    INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, return -1,
M
Mupceet 已提交
319
        "service %s exit! set perms failed! err %d.", service->name, errno);
C
fix log  
cheng_jinsong 已提交
320

M
Mupceet 已提交
321
    // write pid
M
Mupceet 已提交
322
    INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, return -1,
M
Mupceet 已提交
323
        "service %s exit! write pid failed!", service->name);
C
cheng_jinsong 已提交
324
    PluginExecCmdByName("setServiceContent", service->name);
M
Mupceet 已提交
325 326 327 328 329
    return 0;
}

void EnterServiceSandbox(Service *service)
{
C
cheng_jinsong 已提交
330
    INIT_ERROR_CHECK(InitServiceProperties(service) == 0, return, "Failed init service property");
M
Mupceet 已提交
331 332 333 334 335 336 337
    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 已提交
338
#ifndef STARTUP_INIT_TEST
M
Mupceet 已提交
339 340 341 342
    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 已提交
343
#endif
M
Mupceet 已提交
344 345
}

W
wenjun 已提交
346 347
int ServiceStart(Service *service)
{
S
sun_fan 已提交
348
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
C
fix log  
cheng_jinsong 已提交
349
    INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "Service %s already started", service->name);
350 351
    INIT_ERROR_CHECK(service->pathArgs.count > 0,
        return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name);
X
xionglei6 已提交
352

W
wenjun 已提交
353
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
354
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
355 356
        return SERVICE_FAILURE;
    }
357
    struct stat pathStat = { 0 };
W
wenjun 已提交
358
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
359 360 361 362 363
    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 已提交
364 365 366 367 368 369
#ifndef OHOS_LITE
    /*
     * before service fork hooks
     */
    ServiceHookExecute(service->name, NULL, INIT_SERVICE_FORK_BEFORE);
#endif
370
    int pid = fork();
W
wenjun 已提交
371
    if (pid == 0) {
M
Mupceet 已提交
372
        // fail must exit sub process
C
cheng_jinsong 已提交
373
        INIT_ERROR_CHECK(InitServiceProperties(service) == 0,
M
Mupceet 已提交
374
            _exit(PROCESS_EXIT_CODE), "Failed init service property");
375 376
        ServiceExec(service);
        _exit(PROCESS_EXIT_CODE);
W
wenjun 已提交
377
    } else if (pid < 0) {
Z
zhong_ning 已提交
378
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
379 380
        return SERVICE_FAILURE;
    }
C
fix log  
cheng_jinsong 已提交
381
    INIT_LOGI("Service %s(pid %d) started", service->name, pid);
W
wenjun 已提交
382
    service->pid = pid;
X
xionglei6 已提交
383
    NotifyServiceChange(service, SERVICE_STARTED);
384 385 386 387 388 389
#ifndef OHOS_LITE
    /*
     * after service fork hooks
     */
    ServiceHookExecute(service->name, (const char *)&pid, INIT_SERVICE_FORK_AFTER);
#endif
W
wenjun 已提交
390 391 392 393 394
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
395
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
X
xionglei6 已提交
396 397 398
    if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
        DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
    }
W
wenjun 已提交
399 400 401 402 403
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }
X
xionglei6 已提交
404
    CloseServiceSocket(service);
X
xionglei6 已提交
405
    CloseServiceFile(service->fileCfg);
X
xionglei6 已提交
406 407 408 409 410
    // 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 已提交
411 412 413 414

    if (IsServiceWithTimerEnabled(service)) {
        ServiceStopTimer(service);
    }
C
cheng_jinsong 已提交
415
    INIT_ERROR_CHECK(kill(service->pid, GetKillServiceSig(service->name)) == 0, return SERVICE_FAILURE,
X
add ut  
xionglei6 已提交
416
        "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
X
xionglei6 已提交
417
    NotifyServiceChange(service, SERVICE_STOPPING);
Z
zhong_ning 已提交
418
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
C
cheng_jinsong 已提交
419 420
    service->pid = -1;
    NotifyServiceChange(service, SERVICE_STOPPED);
W
wenjun 已提交
421 422 423
    return SERVICE_SUCCESS;
}

S
sun_fan 已提交
424
static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
Z
zhong_ning 已提交
425
{
X
xionglei6 已提交
426 427
    INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
        return false, "input params error.");
S
sun_fan 已提交
428 429 430 431
    time_t curTime = time(NULL);
    if (service->crashCnt == 0) {
        service->firstCrashTime = curTime;
        ++service->crashCnt;
X
xionglei6 已提交
432 433 434
        if (service->crashCnt == crashCountLimit) {
            return false;
        }
S
sun_fan 已提交
435 436 437 438 439
    } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
        service->firstCrashTime = curTime;
        service->crashCnt = 1;
    } else {
        ++service->crashCnt;
X
xionglei6 已提交
440
        if (service->crashCnt >= crashCountLimit) {
S
sun_fan 已提交
441
            return false;
Z
zhong_ning 已提交
442 443
        }
    }
S
sun_fan 已提交
444
    return true;
Z
zhong_ning 已提交
445 446
}

X
xionglei6 已提交
447
static int ExecRestartCmd(Service *service)
Z
zhong_ning 已提交
448
{
449
    INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
X
xionglei6 已提交
450 451 452
    if (service->restartArg == NULL) {
        return SERVICE_SUCCESS;
    }
453 454 455
    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 已提交
456
    }
457
    free(service->restartArg);
X
xionglei6 已提交
458
    service->restartArg = NULL;
Z
zhong_ning 已提交
459 460 461
    return SERVICE_SUCCESS;
}

X
xionglei6 已提交
462
static void CheckServiceSocket(Service *service)
X
xionglei6 已提交
463 464 465 466 467 468
{
    if (service->socketCfg == NULL) {
        return;
    }
    ServiceSocket *tmpSock = service->socketCfg;
    while (tmpSock != NULL) {
X
xionglei6 已提交
469
        if (tmpSock->sockFd <= 0) {
470
            INIT_LOGE("Invalid socket %s for service", service->name);
X
xionglei6 已提交
471 472
            tmpSock = tmpSock->next;
        }
C
cheng_jinsong 已提交
473
        AddSocketWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
474 475 476 477 478
        tmpSock = tmpSock->next;
    }
    return;
}

C
codex  
cheng_jinsong 已提交
479
static void CheckOndemandService(Service *service)
C
codex  
chengjinsong 已提交
480 481 482 483 484 485 486 487 488 489
{
    CheckServiceSocket(service);
    if (strcmp(service->name, "console") == 0) {
        if (WatchConsoleDevice(service) < 0) {
            INIT_LOGE("Failed to watch console service after it exit, mark console service invalid");
            service->attribute |= SERVICE_ATTR_INVALID;
        }
    }
}

W
wenjun 已提交
490 491
void ServiceReap(Service *service)
{
492 493
    INIT_CHECK(service != NULL, return);
    INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
Z
zhong_ning 已提交
494
    service->pid = -1;
X
xionglei6 已提交
495
    NotifyServiceChange(service, SERVICE_STOPPED);
496

Z
zhong_ning 已提交
497
    if (service->attribute & SERVICE_ATTR_INVALID) {
498
        INIT_LOGE("Reap service %s invalid.", service->name);
M
mamingshuai 已提交
499 500
        return;
    }
501

X
xionglei6 已提交
502 503 504 505 506
    // 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 已提交
507
    if (!IsOnDemandService(service)) {
X
xionglei6 已提交
508
        CloseServiceSocket(service);
X
xionglei6 已提交
509
    }
X
xionglei6 已提交
510
    CloseServiceFile(service->fileCfg);
W
wenjun 已提交
511 512 513 514 515 516
    // 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;
    }
517

W
wenjun 已提交
518 519 520 521 522 523 524
    // 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;
        }
525
        // the service could be restart even if it is one-shot service
W
wenjun 已提交
526
    }
527 528

    if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
X
xionglei6 已提交
529
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
S
sun_fan 已提交
530
            INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
X
xionglei6 已提交
531
                service->name, service->crashCount);
532
            ExecReboot("reboot");
S
sun_fan 已提交
533 534
        }
    } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
X
xionglei6 已提交
535
        if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
536
            INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
537
            return;
W
wenjun 已提交
538 539
        }
    }
C
cheng_jinsong 已提交
540
    // service no need to restart if it is an ondemand service.
X
xionglei6 已提交
541
    if (IsOnDemandService(service)) {
C
codex  
chengjinsong 已提交
542
        CheckOndemandService(service);
X
xionglei6 已提交
543 544
        return;
    }
545

X
xionglei6 已提交
546 547 548 549 550
    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]);
551 552
    }
    ret = ServiceStart(service);
X
xionglei6 已提交
553
    INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
W
wenjun 已提交
554 555
    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
X
xionglei6 已提交
556 557 558

int UpdaterServiceFds(Service *service, int *fds, size_t fdCount)
{
C
cheng_jinsong 已提交
559
    if (service == NULL || fds == NULL) {
C
cheng_jinsong 已提交
560
        INIT_LOGE("Invalid service info or fds");
X
xionglei6 已提交
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 612 613 614 615 616
        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 已提交
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646

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 已提交
647
        INIT_LOGE("Start service \' %s \' in timer failed", service->name);
X
xionglei6 已提交
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
    }
}

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