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