xref: /base/startup/init/services/init/standard/init.c (revision d9f0492f)
1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "init.h"
16
17#include <errno.h>
18#include <poll.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <signal.h>
22#include <time.h>
23#include <sys/sysmacros.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <linux/major.h>
28
29#include "config_policy_utils.h"
30#include "device.h"
31#include "fd_holder_service.h"
32#include "key_control.h"
33#include "init_control_fd_service.h"
34#include "init_log.h"
35#include "init_mount.h"
36#include "init_group_manager.h"
37#include "init_param.h"
38#include "init_service.h"
39#include "init_service_manager.h"
40#include "init_utils.h"
41#include "securec.h"
42#include "fd_holder_internal.h"
43#include "bootstage.h"
44
45static int FdHolderSockInit(void)
46{
47    int sock = -1;
48    int on = 1;
49    int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
50    sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
51    if (sock < 0) {
52        INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
53        return -1;
54    }
55
56    setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize));
57    setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
58
59    if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) {
60        INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
61        unlink(INIT_HOLDER_SOCKET_PATH);
62    }
63    struct sockaddr_un addr;
64    addr.sun_family = AF_UNIX;
65    if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
66        INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
67        INIT_LOGE("Failed to copy fd hoder socket path");
68        close(sock);
69        return -1;
70    }
71    socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
72    if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
73        INIT_LOGE("Failed to binder fd folder socket %d", errno);
74        close(sock);
75        return -1;
76    }
77
78    // Owned by root
79    if (lchown(addr.sun_path, 0, 0)) {
80        INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
81    }
82    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
83    if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
84        INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
85    }
86    INIT_LOGI("Init fd holder socket done");
87    return sock;
88}
89
90void SystemInit(void)
91{
92    CloseStdio();
93#ifndef STARTUP_INIT_TEST
94    // Set up a session keyring that all processes will have access to.
95    KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
96#endif
97    // umask call always succeeds and return the previous mask value which is not needed here
98    (void)umask(DEFAULT_UMASK_INIT);
99    MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
100    int sock = FdHolderSockInit();
101    if (sock >= 0) {
102        RegisterFdHoldWatcher(sock);
103    }
104    InitControlFd();
105
106    // sysclktz 0
107    struct timezone tz = { 0 };
108    if (settimeofday(NULL, &tz) == -1) {
109        INIT_LOGE("Set time of day failed, err = %d", errno);
110    }
111}
112
113void LogInit(void)
114{
115    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
116        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
117    if (ret == 0) {
118        OpenLogDevice();
119    }
120}
121
122static void WriteUptimeSysParam(const char *param, const char *uptime)
123{
124    char buf[64];
125
126    if (uptime == NULL) {
127        snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
128                   "%lld", GetUptimeInMicroSeconds(NULL));
129        uptime = buf;
130    }
131    SystemWriteParam(param, uptime);
132}
133
134INIT_TIMING_STAT g_bootJob = {{0}, {0}};
135
136static void RecordInitBootEvent(const char *initBootEvent)
137{
138    const char *bootEventArgv[] = {"init", initBootEvent};
139    PluginExecCmd("bootevent", ARRAY_LENGTH(bootEventArgv), bootEventArgv);
140    return;
141}
142
143INIT_STATIC void BootStateChange(int start, const char *content)
144{
145    if (start == 0) {
146        clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
147        RecordInitBootEvent(content);
148        INIT_LOGI("boot job %s start.", content);
149    } else {
150        clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.endTime));
151        RecordInitBootEvent(content);
152        long long diff = InitDiffTime(&g_bootJob);
153        INIT_LOGI("boot job %s finish diff %lld us.", content, diff);
154        if (strcmp(content, "boot") == 0) {
155            WriteUptimeSysParam("ohos.boot.time.init", NULL);
156        }
157    }
158}
159
160static void InitLoadParamFiles(void)
161{
162    if (InUpdaterMode() != 0) {
163        LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
164        LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
165        LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_ONLY_ADD);
166        return;
167    }
168
169    // Load developer mode param
170    LoadDefaultParams("/proc/dsmm/developer", LOAD_PARAM_NORMAL);
171
172    // Load const params, these can't be override!
173    LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
174    CfgFiles *files = GetCfgFiles("etc/param");
175    for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
176        if (files->paths[i]) {
177            LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
178        }
179    }
180    FreeCfgFiles(files);
181}
182
183INIT_STATIC void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
184{
185    INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
186    clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
187}
188
189INIT_STATIC void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
190{
191    INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
192    clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
193    long long diff = InitDiffTime(stat);
194    INIT_LOGI("Executing hook [%d:%d] cost [%lld]us, result %d.",
195        hookInfo->stage, hookInfo->prio, diff, executionRetVal);
196}
197
198static void InitSysAdj(void)
199{
200    const char* path = "/proc/self/oom_score_adj";
201    const char* content = "-1000";
202    int fd = open(path, O_RDWR);
203    if (fd == -1) {
204        return;
205    }
206    if (write(fd, content, strlen(content)) < 0) {
207        close(fd);
208        return;
209    }
210    close(fd);
211    return;
212}
213
214INIT_STATIC void TriggerServices(int startMode)
215{
216    int index = 0;
217    int jobNum = 0;
218    char jobName[64] = {0}; // 64 job name
219    char cmd[64] = {0};  // 64 job name
220    const int maxServiceInJob = 4; // 4 service in job
221    InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
222    while (node != NULL) {
223        Service *service = node->data.service;
224        if (service == NULL || service->startMode != startMode) {
225            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
226            continue;
227        }
228        if (IsOnDemandService(service)) {
229            if (CreateSocketForService(service) != 0) {
230                INIT_LOGE("service %s exit! create socket failed!", service->name);
231            }
232            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
233            continue;
234        }
235        if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
236            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
237            continue;
238        }
239        if (index == 0) {
240            if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
241                node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
242                continue;
243            }
244            jobNum++;
245        }
246        index++;
247        AddCompleteJob(jobName, NULL, cmd);
248        INIT_LOGV("Add %s to job %s", service->name, jobName);
249        if (index == maxServiceInJob) {
250            PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
251            index = 0;
252        }
253        node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
254    }
255    if (index > 0) {
256        PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
257    }
258}
259
260void ParseInitCfgByPriority(void)
261{
262    CfgFiles *files = GetCfgFiles("etc/init");
263    for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
264        if (files->paths[i]) {
265            if (ReadFileInDir(files->paths[i], ".cfg", ParseInitCfg, NULL) < 0) {
266                break;
267            }
268        }
269    }
270    FreeCfgFiles(files);
271}
272
273void SystemConfig(const char *uptime)
274{
275    INIT_TIMING_STAT timingStat;
276
277    InitSysAdj();
278
279    HOOK_EXEC_OPTIONS options;
280
281    options.flags = 0;
282    options.preHook = InitPreHook;
283    options.postHook = InitPostHook;
284    InitServiceSpace();
285    HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
286    RecordInitBootEvent("init.prepare");
287
288    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
289    if (InitParamService() != 0) {
290        INIT_LOGE("[startup_failed]Init param service failed %d", SYS_PARAM_INIT_FAILED);
291        ExecReboot("panic");
292    }
293    InitParseGroupCfg();
294    RegisterBootStateChange(BootStateChange);
295
296    INIT_LOGI("boot stage: init finish.");
297
298    // The cgroupv1 hierarchy may be created asynchronously in the early stage,
299    // so make sure it has been done before loading SELinux.
300    struct stat sourceInfo = {0};
301    if (stat("/dev/cgroup", &sourceInfo) == 0) {
302        WaitForFile("/dev/memcg/procs", WAIT_MAX_SECOND);
303    }
304
305    // load SELinux context and policy
306    // Do not move position!
307    PluginExecCmdByName("loadSelinuxPolicy", "");
308    RecordInitBootEvent("init.prepare");
309
310    // after selinux loaded
311    SignalInit();
312
313    RecordInitBootEvent("init.ParseCfg");
314    LoadSpecialParam();
315
316    // parse parameters
317    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
318    InitLoadParamFiles();
319
320    // Write kernel uptime into system parameter
321    WriteUptimeSysParam("ohos.boot.time.kernel", uptime);
322
323    // read config
324    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
325    ReadConfig();
326    RecordInitBootEvent("init.ParseCfg");
327    INIT_LOGI("boot stage: parse config file finish.");
328    HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
329
330    IsEnableSandbox();
331    // execute init
332    PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
333    PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
334    TriggerServices(START_MODE_BOOT);
335    PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
336    TriggerServices(START_MODE_NORMAL);
337    clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
338}
339
340void SystemRun(void)
341{
342    StartParamService();
343}
344