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

#include "init_service.h"
17

Z
zhong_ning 已提交
18
#include <bits/ioctl.h>
W
wenjun 已提交
19
#include <errno.h>
Z
zhong_ning 已提交
20
#include <fcntl.h>
W
wenjun 已提交
21 22
#include <signal.h>
#include <stdio.h>
Z
zhong_ning 已提交
23
#include <stdlib.h>
M
mamingshuai 已提交
24
#include <string.h>
Z
zhong_ning 已提交
25 26 27
#ifdef __MUSL__
#include <stropts.h>
#endif
Z
zhong_ning 已提交
28
#include <sys/param.h>
Z
zhong_ning 已提交
29 30 31
#ifndef OHOS_LITE
#include <sys/resource.h>
#endif
W
wenjun 已提交
32 33 34
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
35

W
wenjun 已提交
36
#include "init_adapter.h"
Z
zhong_ning 已提交
37 38
#include "init_cmds.h"
#include "init_log.h"
Z
zhong_ning 已提交
39 40 41
#ifndef OHOS_LITE
#include "init_param.h"
#endif
W
wenjun 已提交
42
#include "init_perms.h"
Z
zhong_ning 已提交
43
#include "init_service_socket.h"
Z
zhong_ning 已提交
44
#include "init_utils.h"
Z
zhong_ning 已提交
45 46 47 48
#include "securec.h"
#ifndef OHOS_LITE
#include "sys_param.h"
#endif
W
wenjun 已提交
49 50

#define CAP_NUM 2
Z
zhong_ning 已提交
51
#define WAIT_MAX_COUNT 10
W
wenjun 已提交
52

Z
zhong_ning 已提交
53 54 55
#ifndef TIOCSCTTY
#define TIOCSCTTY 0x540E
#endif
W
wenjun 已提交
56 57 58 59 60
// 240 seconds, 4 minutes
static const int CRASH_TIME_LIMIT  = 240;
// maximum number of crashes within time CRASH_TIME_LIMIT for one service
static const int CRASH_COUNT_LIMIT = 4;

Z
zhong_ning 已提交
61 62 63 64 65 66 67
// 240 seconds, 4 minutes
static const int CRITICAL_CRASH_TIME_LIMIT  = 240;
// maximum number of crashes within time CRITICAL_CRASH_TIME_LIMIT for one service
static const int CRITICAL_CRASH_COUNT_LIMIT = 4;
static const int MAX_PID_STRING_LENGTH = 50;


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

W
wenjun 已提交
78 79 80 81 82
static int SetPerms(const Service *service)
{
    if (KeepCapability() != 0) {
        return SERVICE_FAILURE;
    }
Z
zhong_ning 已提交
83 84

    if (setgroups(service->servPerm.gIDCnt, service->servPerm.gIDArray) != 0) {
Z
zhong_ning 已提交
85
        INIT_LOGE("SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
W
wenjun 已提交
86 87 88
        return SERVICE_FAILURE;
    }

Z
zhong_ning 已提交
89 90
    if (service->servPerm.uID != 0) {
        if (setuid(service->servPerm.uID) != 0) {
Z
zhong_ning 已提交
91
            INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
Z
zhong_ning 已提交
92 93
            return SERVICE_FAILURE;
        }
W
wenjun 已提交
94 95 96 97 98 99 100 101 102
    }

    // 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 已提交
103
    struct __user_cap_data_struct capData[CAP_NUM] = {};
W
wenjun 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
        if (service->servPerm.caps[i] == FULL_CAP) {
            for (int i = 0; i < CAP_NUM; ++i) {
                capData[i].effective = FULL_CAP;
                capData[i].permitted = FULL_CAP;
                capData[i].inheritable = FULL_CAP;
            }
            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 已提交
119
        INIT_LOGE("capset faild for service: %s, error: %d", service->name, errno);
W
wenjun 已提交
120 121
        return SERVICE_FAILURE;
    }
M
mamingshuai 已提交
122 123 124 125 126
    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 已提交
127
            INIT_LOGE("SetAmbientCapability faild for service: %s", service->name);
M
mamingshuai 已提交
128 129 130
            return SERVICE_FAILURE;
        }
    }
W
wenjun 已提交
131 132 133
    return SERVICE_SUCCESS;
}

Z
zhong_ning 已提交
134 135 136 137 138 139 140 141 142 143 144 145
static void OpenConsole()
{
    setsid();
    WaitForFile("/dev/console", WAIT_MAX_COUNT);
    int fd = open("/dev/console", O_RDWR);
    if (fd >= 0) {
        ioctl(fd, TIOCSCTTY, 0);
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    } else {
Z
zhong_ning 已提交
146
        INIT_LOGE("Open /dev/console failed. err = %d", errno);
Z
zhong_ning 已提交
147 148 149 150
    }
    return;
}

W
wenjun 已提交
151 152
int ServiceStart(Service *service)
{
M
mamingshuai 已提交
153
    if (service == NULL) {
Z
zhong_ning 已提交
154
        INIT_LOGE("start service failed! null ptr.");
M
mamingshuai 已提交
155 156
        return SERVICE_FAILURE;
    }
Z
zhong_ning 已提交
157
    if (service->pid > 0) {
Z
zhong_ning 已提交
158
        INIT_LOGI("service : %s had started already.", service->name);
Z
zhong_ning 已提交
159 160
        return SERVICE_SUCCESS;
    }
W
wenjun 已提交
161
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
162
        INIT_LOGE("start service %s invalid.", service->name);
W
wenjun 已提交
163 164
        return SERVICE_FAILURE;
    }
S
sun_fan 已提交
165 166 167 168
    if (service->pathArgs == NULL) {
        INIT_LOGE("start service pathArgs is NULL.");
        return SERVICE_FAILURE;
    }
W
wenjun 已提交
169 170
    struct stat pathStat = {0};
    service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
M
mamingshuai 已提交
171
    if (stat(service->pathArgs[0], &pathStat) != 0) {
W
wenjun 已提交
172
        service->attribute |= SERVICE_ATTR_INVALID;
Z
zhong_ning 已提交
173
        INIT_LOGE("start service %s invalid, please check %s.",\
M
mamingshuai 已提交
174
            service->name, service->pathArgs[0]);
W
wenjun 已提交
175 176
        return SERVICE_FAILURE;
    }
Z
zhong_ning 已提交
177
    int ret = 0;
W
wenjun 已提交
178 179
    int pid = fork();
    if (pid == 0) {
Z
zhong_ning 已提交
180
        if (service->socketCfg != NULL) {    // start socket service
Z
zhong_ning 已提交
181
            INIT_LOGI("Create socket ");
Z
zhong_ning 已提交
182 183
            ret = DoCreateSocket(service->socketCfg);
            if (ret < 0) {
Z
zhong_ning 已提交
184
                INIT_LOGE("DoCreateSocket failed. ");
Z
zhong_ning 已提交
185
                _exit(0x7f); // 0x7f: user specified
Z
zhong_ning 已提交
186 187
            }
        }
Z
zhong_ning 已提交
188 189 190
        if (service->attribute & SERVICE_ATTR_CONSOLE) {
            OpenConsole();
        }
W
wenjun 已提交
191 192
        // permissions
        if (SetPerms(service) != SERVICE_SUCCESS) {
Z
zhong_ning 已提交
193
            INIT_LOGE("service %s exit! set perms failed! err %d.", service->name, errno);
W
wenjun 已提交
194 195
            _exit(0x7f); // 0x7f: user specified
        }
Z
zhong_ning 已提交
196 197
        char pidString[MAX_PID_STRING_LENGTH];          // writepid
        pid_t childPid = getpid();
S
sun_fan 已提交
198
        if (snprintf_s(pidString, MAX_PID_STRING_LENGTH, MAX_PID_STRING_LENGTH - 1, "%d", childPid) < 0) {
Z
zhong_ning 已提交
199
            INIT_LOGE("start service writepid sprintf failed.");
Z
zhong_ning 已提交
200
            _exit(0x7f); // 0x7f: user specified
Z
zhong_ning 已提交
201 202 203 204 205
        }
        for (int i = 0; i < MAX_WRITEPID_FILES; i++) {
            if (service->writepidFiles[i] == NULL) {
                continue;
            }
S
sun_fan 已提交
206 207 208 209 210
            char *realPath = realpath(service->writepidFiles[i], NULL);
            if (realPath == NULL) {
                continue;
            }
            FILE *fd = fopen(realPath, "wb");
Z
zhong_ning 已提交
211
            if (fd == NULL) {
Z
zhong_ning 已提交
212
                INIT_LOGE("start service writepidFiles %s invalid.", service->writepidFiles[i]);
S
sun_fan 已提交
213 214
                free(realPath);
                realPath = NULL;
Z
zhong_ning 已提交
215 216 217
                continue;
            }
            if (fwrite(pidString, 1, strlen(pidString), fd) != strlen(pidString)) {
Z
zhong_ning 已提交
218
                 INIT_LOGE("start service writepid error.file:%s pid:%s", service->writepidFiles[i], pidString);
Z
zhong_ning 已提交
219
            }
S
sun_fan 已提交
220 221
            free(realPath);
            realPath = NULL;
Z
zhong_ning 已提交
222
            fclose(fd);
Z
zhong_ning 已提交
223
            INIT_LOGE("ServiceStart writepid filename=%s, childPid=%s, ok", service->writepidFiles[i],
Z
zhong_ning 已提交
224
                pidString);
Z
zhong_ning 已提交
225
        }
W
wenjun 已提交
226

Z
zhong_ning 已提交
227
        INIT_LOGI("service->name is %s ", service->name);
Z
zhong_ning 已提交
228
#ifndef OHOS_LITE
Z
zhong_ning 已提交
229 230 231 232 233 234 235 236
        if (service->important != 0) {
            if (setpriority(PRIO_PROCESS, 0, service->important) != 0) {
                INIT_LOGE("setpriority failed for %s, important = %d", service->name, service->important);
                _exit(0x7f); // 0x7f: user specified
            }
        }
        // L2 Can not be reset env
        if (execv(service->pathArgs[0], service->pathArgs) != 0) {
Z
zhong_ning 已提交
237
            INIT_LOGE("service %s execve failed! err %d.", service->name, errno);
Z
zhong_ning 已提交
238
        }
Z
zhong_ning 已提交
239
#else
C
changcheng-weng 已提交
240
        char* env[] = {"LD_LIBRARY_PATH=/storage/app/libs", NULL};
M
mamingshuai 已提交
241
        if (execve(service->pathArgs[0], service->pathArgs, env) != 0) {
Z
zhong_ning 已提交
242
            INIT_LOGE("service %s execve failed! err %d.", service->name, errno);
W
wenjun 已提交
243
        }
Z
zhong_ning 已提交
244 245
#endif

W
wenjun 已提交
246 247
        _exit(0x7f); // 0x7f: user specified
    } else if (pid < 0) {
Z
zhong_ning 已提交
248
        INIT_LOGE("start service %s fork failed!", service->name);
W
wenjun 已提交
249 250 251 252
        return SERVICE_FAILURE;
    }

    service->pid = pid;
Z
zhong_ning 已提交
253 254 255
#ifndef OHOS_LITE
    char paramName[PARAM_NAME_LEN_MAX] = {0};
    if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", service->name) < 0) {
Z
zhong_ning 已提交
256
        INIT_LOGE("snprintf_s paramName error %d ", errno);
Z
zhong_ning 已提交
257 258 259
    }
    SystemWriteParam(paramName, "running");
#endif
W
wenjun 已提交
260 261 262 263 264
    return SERVICE_SUCCESS;
}

int ServiceStop(Service *service)
{
M
mamingshuai 已提交
265
    if (service == NULL) {
Z
zhong_ning 已提交
266
        INIT_LOGE("stop service failed! null ptr.");
M
mamingshuai 已提交
267 268 269
        return SERVICE_FAILURE;
    }

W
wenjun 已提交
270 271 272 273 274 275 276
    service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
    service->attribute |= SERVICE_ATTR_NEED_STOP;
    if (service->pid <= 0) {
        return SERVICE_SUCCESS;
    }

    if (kill(service->pid, SIGKILL) != 0) {
Z
zhong_ning 已提交
277
        INIT_LOGE("stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
W
wenjun 已提交
278 279
        return SERVICE_FAILURE;
    }
Z
zhong_ning 已提交
280 281 282
#ifndef OHOS_LITE
    char paramName[PARAM_NAME_LEN_MAX] = {0};
    if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", service->name) < 0) {
Z
zhong_ning 已提交
283
        INIT_LOGE("snprintf_s paramName error %d ", errno);
Z
zhong_ning 已提交
284 285 286
    }
    SystemWriteParam(paramName, "stopping");
#endif
Z
zhong_ning 已提交
287
    INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
W
wenjun 已提交
288 289 290
    return SERVICE_SUCCESS;
}

Z
zhong_ning 已提交
291 292 293
// the service need to be restarted, if it crashed more than 4 times in 4 minutes
void CheckCritical(Service *service)
{
S
sun_fan 已提交
294 295 296
    if (service == NULL) {
        return;
    }
Z
zhong_ning 已提交
297 298 299 300 301 302 303 304 305 306 307 308
    if (service->attribute & SERVICE_ATTR_CRITICAL) {            // critical
        // crash time and count check
        time_t curTime = time(NULL);
        if (service->criticalCrashCnt == 0) {
            service->firstCriticalCrashTime = curTime;
            ++service->criticalCrashCnt;
        } else if (difftime(curTime, service->firstCriticalCrashTime) > CRITICAL_CRASH_TIME_LIMIT) {
            service->firstCriticalCrashTime = curTime;
            service->criticalCrashCnt = 1;
        } else {
            ++service->criticalCrashCnt;
            if (service->criticalCrashCnt > CRITICAL_CRASH_COUNT_LIMIT) {
Z
zhong_ning 已提交
309
                INIT_LOGE("reap critical service %s, crash too many times! Need reboot!", service->name);
Z
zhong_ning 已提交
310 311 312 313 314 315 316 317
                RebootSystem();
            }
        }
    }
}

static int ExecRestartCmd(const Service *service)
{
Z
zhong_ning 已提交
318
    INIT_LOGI("ExecRestartCmd ");
Z
zhong_ning 已提交
319 320 321 322 323
    if ((service == NULL) || (service->onRestart == NULL) || (service->onRestart->cmdLine == NULL)) {
        return SERVICE_FAILURE;
    }

    for (int i = 0; i < service->onRestart->cmdNum; i++) {
Z
zhong_ning 已提交
324
        INIT_LOGI("SetOnRestart cmdLine->name %s  cmdLine->cmdContent %s ", service->onRestart->cmdLine[i].name,
Z
zhong_ning 已提交
325 326 327 328
            service->onRestart->cmdLine[i].cmdContent);
        DoCmd(&service->onRestart->cmdLine[i]);
    }
    free(service->onRestart->cmdLine);
S
sun_fan 已提交
329
    service->onRestart->cmdLine = NULL;
Z
zhong_ning 已提交
330 331 332 333
    free(service->onRestart);
    return SERVICE_SUCCESS;
}

W
wenjun 已提交
334 335
void ServiceReap(Service *service)
{
M
mamingshuai 已提交
336
    if (service == NULL) {
Z
zhong_ning 已提交
337
        INIT_LOGE("reap service failed! null ptr.");
Z
zhong_ning 已提交
338 339 340
        return;
    }

Z
zhong_ning 已提交
341 342 343 344
    service->pid = -1;
#ifndef OHOS_LITE
    char paramName[PARAM_NAME_LEN_MAX] = {0};
    if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", service->name) < 0) {
Z
zhong_ning 已提交
345
        INIT_LOGE("snprintf_s paramName error %d ", errno);
Z
zhong_ning 已提交
346 347 348
    }
    SystemWriteParam(paramName, "stopped");
#endif
Z
zhong_ning 已提交
349
    if (service->attribute & SERVICE_ATTR_INVALID) {
Z
zhong_ning 已提交
350
        INIT_LOGE("ServiceReap service %s invalid.", service->name);
M
mamingshuai 已提交
351 352 353
        return;
    }

W
wenjun 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
    // 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;
    }

    // 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;
        }
        // the service could be restart even if it is one-shot service
    }

    // the service that does not need to be restarted restarts, indicating that it has crashed
    if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
        // crash time and count check
        time_t curTime = time(NULL);
        if (service->crashCnt == 0) {
            service->firstCrashTime = curTime;
            ++service->crashCnt;
        } else if (difftime(curTime, service->firstCrashTime) > CRASH_TIME_LIMIT) {
            service->firstCrashTime = curTime;
            service->crashCnt = 1;
        } else {
            ++service->crashCnt;
            if (service->crashCnt > CRASH_COUNT_LIMIT) {
Z
zhong_ning 已提交
384
                INIT_LOGE("reap service %s, crash too many times!", service->name);
W
wenjun 已提交
385 386 387 388 389
                return;
            }
        }
    }

Z
zhong_ning 已提交
390 391 392 393 394
    CheckCritical(service);
    int ret = 0;
    if (service->onRestart != NULL) {
        ret = ExecRestartCmd(service);
        if (ret != SERVICE_SUCCESS) {
Z
zhong_ning 已提交
395
            INIT_LOGE("SetOnRestart fail ");
Z
zhong_ning 已提交
396 397 398
        }
    }
    ret = ServiceStart(service);
W
wenjun 已提交
399
    if (ret != SERVICE_SUCCESS) {
Z
zhong_ning 已提交
400
        INIT_LOGE("reap service %s start failed!", service->name);
W
wenjun 已提交
401 402 403 404
    }

    service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
M
mamingshuai 已提交
405