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