init.c 13.8 KB
Newer Older
1
/*
M
Mupceet 已提交
2
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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.h"

#include <errno.h>
X
xionglei6 已提交
18
#include <poll.h>
C
cheng_jinsong 已提交
19
#include <stdarg.h>
20 21
#include <stdlib.h>
#include <signal.h>
22
#include <time.h>
23 24 25
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include <sys/types.h>
X
xionglei6 已提交
26
#include <sys/socket.h>
4
411148299@qq.com 已提交
27
#include <linux/major.h>
Z
zhr758 已提交
28 29

#include "config_policy_utils.h"
30
#include "device.h"
X
xionglei6 已提交
31
#include "fd_holder_service.h"
32
#include "fs_manager/fs_manager.h"
33
#include "key_control.h"
M
Mupceet 已提交
34
#include "init_control_fd_service.h"
35 36
#include "init_log.h"
#include "init_mount.h"
X
xionglei6 已提交
37
#include "init_group_manager.h"
38
#include "init_param.h"
X
xionglei6 已提交
39 40
#include "init_service.h"
#include "init_service_manager.h"
41 42
#include "init_utils.h"
#include "securec.h"
43 44 45
#include "switch_root.h"
#include "ueventd.h"
#include "ueventd_socket.h"
X
xionglei6 已提交
46
#include "fd_holder_internal.h"
47
#include "bootstage.h"
48

X
xionglei6 已提交
49 50 51 52
static int FdHolderSockInit(void)
{
    int sock = -1;
    int on = 1;
X
xionglei6 已提交
53 54
    int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
    sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
X
xionglei6 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67
    if (sock < 0) {
        INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
        return -1;
    }

    setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize));
    setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));

    if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) {
        INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
        unlink(INIT_HOLDER_SOCKET_PATH);
    }
    struct sockaddr_un addr;
X
xionglei6 已提交
68
    addr.sun_family = AF_UNIX;
X
xionglei6 已提交
69 70
    if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
        INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
71
        INIT_LOGE("Failed to copy fd hoder socket path");
X
xionglei6 已提交
72 73 74 75 76
        close(sock);
        return -1;
    }
    socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
    if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
X
xionglei6 已提交
77
        INIT_LOGE("Failed to binder fd folder socket %d", errno);
X
xionglei6 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        close(sock);
        return -1;
    }

    // Owned by root
    if (lchown(addr.sun_path, 0, 0)) {
        INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
    }
    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
        INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
    }
    INIT_LOGI("Init fd holder socket done");
    return sock;
}

94 95 96
void SystemInit(void)
{
    SignalInit();
97 98 99 100

    // Set up a session keyring that all processes will have access to.
    KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);

X
xionglei6 已提交
101 102
    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);
103
    MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
X
xionglei6 已提交
104 105 106 107
    int sock = FdHolderSockInit();
    if (sock >= 0) {
        RegisterFdHoldWatcher(sock);
    }
M
Mupceet 已提交
108
    InitControlFd();
X
xionglei6 已提交
109 110
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124
static void EnableDevKmsg(void)
{
    /* printk_devkmsg default value is ratelimit, We need to set "on" and remove the restrictions */
    int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (fd < 0) {
        return;
    }
    char *kmsgStatus = "on";
    write(fd, kmsgStatus, strlen(kmsgStatus) + 1);
    close(fd);
    fd = -1;
    return;
}

125 126 127 128 129 130 131 132 133
void LogInit(void)
{
    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
    if (ret == 0) {
        OpenLogDevice();
    }
}

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
static char **GetRequiredDevices(Fstab fstab, int *requiredNum)
{
    int num = 0;
    FstabItem *item = fstab.head;
    while (item != NULL) {
        if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
            num++;
        }
        item = item->next;
    }
    char **devices = (char **)calloc(num, sizeof(char *));
    INIT_ERROR_CHECK(devices != NULL, return NULL, "Failed calloc err=%d", errno);

    int i = 0;
    item = fstab.head;
    while (item != NULL) {
        if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
            devices[i] = strdup(item->deviceName);
            INIT_ERROR_CHECK(devices[i] != NULL, FreeStringVector(devices, num); return NULL,
                "Failed strdup err=%d", errno);
            i++;
        }
        item = item->next;
    }
    *requiredNum = num;
    return devices;
}

static int StartUeventd(char **requiredDevices, int num)
{
    INIT_ERROR_CHECK(requiredDevices != NULL && num > 0, return -1, "Failed parameters");
    int ueventSockFd = UeventdSocketInit();
    if (ueventSockFd < 0) {
        INIT_LOGE("Failed to create uevent socket");
        return -1;
    }
    RetriggerUevent(ueventSockFd, requiredDevices, num);
    close(ueventSockFd);
    return 0;
}

static void StartInitSecondStage(void)
{
    int requiredNum = 0;
    Fstab* fstab = LoadRequiredFstab();
    INIT_ERROR_CHECK(fstab != NULL, abort(), "Failed to load required fstab");
    char **devices = GetRequiredDevices(*fstab, &requiredNum);
    if (devices != NULL && requiredNum > 0) {
        int ret = StartUeventd(devices, requiredNum);
        if (ret == 0) {
            ret = MountRequriedPartitions(fstab);
        }
        FreeStringVector(devices, requiredNum);
        devices = NULL;
        ReleaseFstab(fstab);
        fstab = NULL;
        if (ret < 0) {
            // If mount required partitions failure.
            // There is no necessary to continue.
            // Just abort
194
            INIT_LOGE("Mount required partitions failed; please check fstab file");
195
            // Execute sh for debugging
C
cheng_jinsong 已提交
196
#ifndef STARTUP_INIT_TEST
197 198
            execv("/bin/sh", NULL);
            abort();
C
cheng_jinsong 已提交
199
#endif
200 201 202 203 204 205 206
        }
    }

    // It will panic if close stdio before execv("/bin/sh", NULL)
    CloseStdio();

#ifndef DISABLE_INIT_TWO_STAGES
C
fix log  
cheng_jinsong 已提交
207
    INIT_LOGI("Start init second stage.");
208 209 210 211 212 213 214 215 216 217 218 219 220 221
    SwitchRoot("/usr");
    // Execute init second stage
    char * const args[] = {
        "/bin/init",
        "--second-stage",
        NULL,
    };
    if (execv("/bin/init", args) != 0) {
        INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
        exit(-1);
    }
#endif
}

222 223
void SystemPrepare(void)
{
224 225 226 227 228
    MountBasicFs();
    CreateDeviceNode();
    LogInit();
    // Make sure init log always output to /dev/kmsg.
    EnableDevKmsg();
C
cheng_jinsong 已提交
229
    INIT_LOGI("Start init first stage.");
230 231
    // Only ohos normal system support
    // two stages of init.
C
cheng_jinsong 已提交
232
    // If we are in updater mode, only one stage of init.
233 234 235
    if (InUpdaterMode() == 0) {
        StartInitSecondStage();
    }
236 237
}

H
handyohos 已提交
238 239 240 241 242
#define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
static HOOK_MGR *bootStageHookMgr = NULL;

HOOK_MGR *GetBootStageHookMgr()
{
243 244 245 246 247 248 249 250 251
    if (bootStageHookMgr != NULL) {
        return bootStageHookMgr;
    }

    /*
     * Create bootstage hook manager for booting only.
     * When boot completed, this manager will be destroyed.
     */
    bootStageHookMgr = HookMgrCreate(INIT_BOOTSTAGE_HOOK_NAME);
H
handyohos 已提交
252 253 254
    return bootStageHookMgr;
}

C
cheng_jinsong 已提交
255
INIT_TIMING_STAT g_bootJob = {{0}, {0}};
C
cheng_jinsong 已提交
256

C
cheng_jinsong 已提交
257 258 259 260 261 262 263
static void RecordInitBootEvent(const char *initBootEvent)
{
    const char *bootEventArgv[] = {"init", initBootEvent};
    PluginExecCmd("bootevent", ARRAY_LENGTH(bootEventArgv), bootEventArgv);
    return;
}

C
cheng_jinsong 已提交
264
INIT_STATIC void BootStateChange(int start, const char *content)
C
cheng_jinsong 已提交
265 266 267
{
    if (start == 0) {
        clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
C
cheng_jinsong 已提交
268
        RecordInitBootEvent(content);
C
cheng_jinsong 已提交
269 270 271
        INIT_LOGI("boot job %s start.", content);
    } else {
        clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.endTime));
C
cheng_jinsong 已提交
272
        RecordInitBootEvent(content);
C
cheng_jinsong 已提交
273 274
        long long diff = InitDiffTime(&g_bootJob);
        INIT_LOGI("boot job %s finish diff %lld us.", content, diff);
X
xionglei6 已提交
275 276 277
    }
}

Z
zhr758 已提交
278 279
static void InitLoadParamFiles(void)
{
Y
yichengzhao 已提交
280 281 282 283 284 285
    if (InUpdaterMode() != 0) {
        LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
        LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
        return;
    }

Z
zhr758 已提交
286 287 288 289 290 291 292 293 294 295 296
    // Load const params, these can't be override!
    LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
    CfgFiles *files = GetCfgFiles("etc/param");
    for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
        if (files->paths[i]) {
            LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
        }
    }
    FreeCfgFiles(files);
}

C
cheng_jinsong 已提交
297
INIT_STATIC void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
298
{
C
fix log  
cheng_jinsong 已提交
299
    INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
300 301 302
    clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
}

C
cheng_jinsong 已提交
303
INIT_STATIC void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
304
{
C
fix log  
cheng_jinsong 已提交
305
    INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
306
    clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
C
cheng_jinsong 已提交
307
    long long diff = InitDiffTime(stat);
C
codex  
chengjinsong 已提交
308 309
    INIT_LOGI("Executing hook [%d:%d] cost [%lld]us, return %d.",
        hookInfo->stage, hookInfo->prio, diff, executionRetVal);
C
cheng_jinsong 已提交
310
}
311

W
wonghiu45 已提交
312 313
static void InitSysAdj(void)
{
W
wonghiu45 已提交
314
    const char* path = "/proc/self/oom_score_adj";
W
wonghiu45 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327
    const char* content = "-1000";
    int fd = open(path, O_RDWR);
    if (fd == -1) {
        return;
    }
    if (write(fd, content, strlen(content)) < 0) {
        close(fd);
        return;
    }
    close(fd);
    return;
}

C
cheng_jinsong 已提交
328
INIT_STATIC void TriggerServices(int startMode)
C
cheng_jinsong 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
{
    int index = 0;
    int jobNum = 0;
    char jobName[64] = {0}; // 64 job name
    char cmd[64] = {0};  // 64 job name
    const int maxServiceInJob = 4; // 4 service in job
    InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
    while (node != NULL) {
        Service *service = node->data.service;
        if (service == NULL || service->startMode != startMode) {
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
        if (IsOnDemandService(service)) {
            if (CreateServiceSocket(service) != 0) {
                INIT_LOGE("service %s exit! create socket failed!", service->name);
            }
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
C
codex  
chengjinsong 已提交
349 350 351 352
        if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
C
cheng_jinsong 已提交
353
        if (index == 0) {
C
codex  
chengjinsong 已提交
354 355 356 357
            if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
                node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
                continue;
            }
C
cheng_jinsong 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370
            jobNum++;
        }
        index++;
        AddCompleteJob(jobName, NULL, cmd);
        INIT_LOGV("Add %s to job %s", service->name, jobName);
        if (index == maxServiceInJob) {
            PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
            index = 0;
        }
        node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
    }
    if (index > 0) {
        PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
371 372 373
    }
}

C
cheng_jinsong 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386
void ParseInitCfgByPriority(void)
{
    CfgFiles *files = GetCfgFiles("etc/init");
    for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
        if (files->paths[i]) {
            if (ReadFileInDir(files->paths[i], ".cfg", ParseInitCfg, NULL) < 0) {
                break;
            }
        }
    }
    FreeCfgFiles(files);
}

387 388
void SystemConfig(void)
{
C
fix log  
cheng_jinsong 已提交
389
    INIT_TIMING_STAT timingStat;
C
cheng_jinsong 已提交
390

W
wonghiu45 已提交
391
    InitSysAdj();
392
    HOOK_EXEC_OPTIONS options;
393

394 395 396
    options.flags = 0;
    options.preHook = InitPreHook;
    options.postHook = InitPostHook;
X
xionglei6 已提交
397
    InitServiceSpace();
M
Mupceet 已提交
398
    HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
C
cheng_jinsong 已提交
399
    RecordInitBootEvent("init.prepare");
400

H
handyohos 已提交
401
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
402
    InitParamService();
X
xionglei6 已提交
403 404 405
    InitParseGroupCfg();
    RegisterBootStateChange(BootStateChange);

C
cheng_jinsong 已提交
406
    INIT_LOGI("boot init finish.");
R
renwei 已提交
407 408
    // load SELinux context and policy
    // Do not move position!
C
cheng_jinsong 已提交
409
    PluginExecCmdByName("loadSelinuxPolicy", "");
C
cheng_jinsong 已提交
410
    RecordInitBootEvent("init.prepare");
M
Mupceet 已提交
411

C
cheng_jinsong 已提交
412
    RecordInitBootEvent("init.ParseCfg");
M
Mupceet 已提交
413 414
    LoadSpecialParam();

415
    // parse parameters
H
handyohos 已提交
416
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
417
    InitLoadParamFiles();
418
    // read config
H
handyohos 已提交
419
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
420
    ReadConfig();
C
cheng_jinsong 已提交
421
    RecordInitBootEvent("init.ParseCfg");
C
cheng_jinsong 已提交
422
    INIT_LOGI("boot parse config file done.");
H
handyohos 已提交
423
    HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
424

X
xionglei6 已提交
425
    IsEnableSandbox();
426 427 428
    // execute init
    PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
    PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
C
cheng_jinsong 已提交
429
    TriggerServices(START_MODE_BOOT);
430
    PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
C
cheng_jinsong 已提交
431 432
    TriggerServices(START_MODE_NORMAL);
    clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
433 434 435 436 437 438
}

void SystemRun(void)
{
    StartParamService();
}