init.c 13.2 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();
X
xionglei6 已提交
97 98
    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);
99
    MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
X
xionglei6 已提交
100 101 102 103
    int sock = FdHolderSockInit();
    if (sock >= 0) {
        RegisterFdHoldWatcher(sock);
    }
M
Mupceet 已提交
104
    InitControlFd();
X
xionglei6 已提交
105 106
}

107 108 109 110 111 112 113 114 115 116 117 118 119 120
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;
}

121 122 123 124 125 126 127 128 129
void LogInit(void)
{
    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
    if (ret == 0) {
        OpenLogDevice();
    }
}

130 131 132 133 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
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
190
            INIT_LOGE("Mount required partitions failed; please check fstab file");
191 192 193 194 195 196 197 198 199
            // Execute sh for debugging
            execv("/bin/sh", NULL);
            abort();
        }
    }

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

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

203
#ifndef DISABLE_INIT_TWO_STAGES
C
fix log  
cheng_jinsong 已提交
204
    INIT_LOGI("Start init second stage.");
205 206 207 208 209 210 211 212 213 214 215 216 217 218
    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
}

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

H
handyohos 已提交
235 236 237 238 239
#define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
static HOOK_MGR *bootStageHookMgr = NULL;

HOOK_MGR *GetBootStageHookMgr()
{
240 241 242 243 244 245 246 247 248
    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 已提交
249 250 251
    return bootStageHookMgr;
}

C
fix log  
cheng_jinsong 已提交
252
INIT_TIMING_STAT g_bootJob = {0};
C
cheng_jinsong 已提交
253

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

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

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

Z
zhr758 已提交
283 284 285 286 287 288 289 290 291 292 293
    // 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);
}

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

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

W
wonghiu45 已提交
309 310
static void InitSysAdj(void)
{
W
wonghiu45 已提交
311
    const char* path = "/proc/self/oom_score_adj";
W
wonghiu45 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324
    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 已提交
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
static void TriggerServices(int startMode)
{
    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;
        }
        if (index == 0) {
            sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum);
            jobNum++;
        }
        index++;
        sprintf_s(cmd, sizeof(cmd), "start %s", service->name);
        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));
362 363 364
    }
}

365 366
void SystemConfig(void)
{
C
fix log  
cheng_jinsong 已提交
367
    INIT_TIMING_STAT timingStat;
W
wonghiu45 已提交
368 369
    
    InitSysAdj();
370
    HOOK_EXEC_OPTIONS options;
371

372 373 374
    options.flags = 0;
    options.preHook = InitPreHook;
    options.postHook = InitPostHook;
X
xionglei6 已提交
375
    InitServiceSpace();
M
Mupceet 已提交
376
    HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
C
cheng_jinsong 已提交
377
    RecordInitBootEvent("init.prepare");
378

H
handyohos 已提交
379
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
380
    InitParamService();
X
xionglei6 已提交
381 382 383
    InitParseGroupCfg();
    RegisterBootStateChange(BootStateChange);

C
cheng_jinsong 已提交
384
    INIT_LOGI("boot init finish.");
R
renwei 已提交
385 386
    // load SELinux context and policy
    // Do not move position!
C
cheng_jinsong 已提交
387
    PluginExecCmdByName("loadSelinuxPolicy", "");
C
cheng_jinsong 已提交
388
    RecordInitBootEvent("init.prepare");
M
Mupceet 已提交
389

C
cheng_jinsong 已提交
390
    RecordInitBootEvent("init.ParseCfg");
M
Mupceet 已提交
391 392
    LoadSpecialParam();

393
    // parse parameters
H
handyohos 已提交
394
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
Z
zhr758 已提交
395
    InitLoadParamFiles();
396
    // read config
H
handyohos 已提交
397
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
398
    ReadConfig();
C
cheng_jinsong 已提交
399
    RecordInitBootEvent("init.ParseCfg");
C
cheng_jinsong 已提交
400
    INIT_LOGI("boot parse config file done.");
H
handyohos 已提交
401
    HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
402

X
xionglei6 已提交
403
    IsEnableSandbox();
404 405 406
    // execute init
    PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
    PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
C
cheng_jinsong 已提交
407
    TriggerServices(START_MODE_BOOT);
408
    PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
C
cheng_jinsong 已提交
409 410
    TriggerServices(START_MODE_NORMAL);
    clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
411 412 413 414 415 416
}

void SystemRun(void)
{
    StartParamService();
}