Bugfix: 拆分独立的init_early进程在ramdisk中使用

1)增加init_early完成第一阶段初始化:完成初始文件系统挂载,完成基础的dev节点创建,完成required fs的挂载
2)second stage过程的init去掉第一阶段相关代码,解除仅能静态链接的限制。
3)把init_early打包到ramdisk镜像中,并软链接为init
4)去掉early阶段读取系统参数的无效代码

Signed-off-by: handyohos <zhangxiaotian@huawei.com>
Change-Id: I2225f15ade5004441f2acfc6754c29cf5b201f78

#I81HSS
This commit is contained in:
handyohos 2023-09-20 20:54:43 +08:00
parent 77c8dc9e6a
commit 8b13fa5918
14 changed files with 266 additions and 190 deletions

View File

@ -295,16 +295,6 @@ static int Mount(const char *source, const char *target, const char *fsType,
return rc;
}
static int GetSlotInfoFromParameter(const char *slotInfoName)
{
char name[PARAM_NAME_LEN_MAX] = {0};
BEGET_ERROR_CHECK(sprintf_s(name, sizeof(name), "ohos.boot.%s", slotInfoName) > 0,
return -1, "Failed to format slot parameter name");
char value[PARAM_VALUE_LEN_MAX] = {0};
uint32_t valueLen = PARAM_VALUE_LEN_MAX;
return SystemGetParameter(name, value, &valueLen) == 0 ? atoi(value) : -1;
}
static int GetSlotInfoFromCmdLine(const char *slotInfoName)
{
char value[MAX_BUFFER_LEN] = {0};
@ -334,21 +324,13 @@ static int GetSlotInfoFromBootctrl(off_t offset, off_t size)
int GetBootSlots(void)
{
int bootSlots = GetSlotInfoFromParameter("bootslots");
BEGET_CHECK_RETURN_VALUE(bootSlots <= 0, bootSlots);
BEGET_LOGI("No valid slot value found from parameter, try to get it from cmdline");
return GetSlotInfoFromCmdLine("bootslots");
}
int GetCurrentSlot(void)
{
// get current slot from parameter
int currentSlot = GetSlotInfoFromParameter("currentslot");
BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
BEGET_LOGI("No valid slot value found from parameter, try to get it from cmdline");
// get current slot from cmdline
currentSlot = GetSlotInfoFromCmdLine("currentslot");
int currentSlot = GetSlotInfoFromCmdLine("currentslot");
BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
BEGET_LOGI("No valid slot value found from cmdline, try to get it from bootctrl");
@ -468,6 +450,7 @@ int MountAllWithFstab(const Fstab *fstab, bool required)
}
}
#endif
for (item = fstab->head; item != NULL; item = item->next) {
rc = CheckRequiredAndMount(item, required);
if (required && (rc < 0)) { // Init fail to mount in the first stage and exit directly.

View File

@ -32,6 +32,7 @@ group("startup_init") {
deps = [
"etc:etc_files",
"init/standard:init",
"init/standard:init_early",
"//third_party/e2fsprogs:e2fsprogs",
]

View File

@ -27,8 +27,7 @@ extern "C" {
#define DEV_RANDOM_MINOR 8
#define DEV_URANDOM_MINOR 9
void MountBasicFs(void);
void CreateDeviceNode(void);
void CreateFsAndDeviceNode(void);
#ifdef __cplusplus
#if __cplusplus

View File

@ -42,7 +42,6 @@ extern "C" {
void SystemInit(void);
void LogInit(void);
void SystemPrepare(long long uptime);
void SystemConfig(const char *uptime);
void SystemRun(void);
void SystemExecuteRcs(void);

View File

@ -46,16 +46,16 @@ void LogInit(void)
return;
}
void SystemPrepare(long long uptime)
{
}
void ParseInitCfgByPriority(void)
{
ReadFileInDir(OTHER_CFG_PATH, ".cfg", ParseInitCfg, NULL);
ReadFileInDir("/vendor/etc/init", ".cfg", ParseInitCfg, NULL);
}
void CreateFsAndDeviceNode(void)
{
}
void SystemConfig(const char *uptime)
{
InitServiceSpace();

View File

@ -16,13 +16,13 @@
#include "init.h"
#include "init_log.h"
#include "init_utils.h"
#include "device.h"
static const pid_t INIT_PROCESS_PID = 1;
int main(int argc, char * const argv[])
{
const char *uptime = NULL;
long long upTimeInMicroSecs = 0;
int isSecondStage = 0;
(void)signal(SIGPIPE, SIG_IGN);
// Number of command line parameters is 2
@ -31,19 +31,20 @@ int main(int argc, char * const argv[])
if (argc > 2) {
uptime = argv[2];
}
} else {
upTimeInMicroSecs = GetUptimeInMicroSeconds(NULL);
}
if (getpid() != INIT_PROCESS_PID) {
INIT_LOGE("Process id error %d!", getpid());
return 0;
}
EnableInitLog(INIT_INFO);
// Updater mode
if (isSecondStage == 0) {
SystemPrepare(upTimeInMicroSecs);
} else {
LogInit();
CreateFsAndDeviceNode();
}
LogInit();
SystemInit();
SystemExecuteRcs();
SystemConfig(uptime);

View File

@ -30,6 +30,37 @@ FSCRYPT_PATH =
import("//build/ohos.gni")
import("//build/ohos/native_stub/native_stub.gni")
ohos_executable("init_early") {
sources = [
"//base/startup/init/interfaces/innerkits/hookmgr/hookmgr.c",
"//base/startup/init/services/log/init_commlog.c",
"bootstagehooker.c",
"device.c",
"init_mount.c",
"main_early.c",
"switch_root.c",
]
include_dirs = [
"//third_party/cJSON",
"//base/startup/init/services/include",
"//base/startup/init/services/init/include",
"//base/startup/init/interfaces/innerkits/init_module_engine/include",
]
configs = [ "//build/config/gcc:symbol_visibility_hidden" ]
deps = [
"//base/startup/init/interfaces/innerkits/fs_manager:libfsmanager_static",
"//base/startup/init/services/log:init_log",
"//base/startup/init/ueventd:libueventd_ramdisk_static",
"//third_party/bounds_checking_function:libsec_static",
]
if (startup_init_extra_static_modules != "") {
deps += [ startup_init_extra_static_modules ]
}
install_images = [ "ramdisk" ]
install_enable = true
part_name = "init"
}
ohos_executable("init") {
sources = [
"../adapter/init_adapter.c",
@ -40,11 +71,10 @@ ohos_executable("init") {
"../standard/init_cmds.c",
"../standard/init_control_fd_service.c",
"../standard/init_jobs.c",
"../standard/init_mount.c",
"../standard/init_reboot.c",
"../standard/init_service.c",
"../standard/init_signal_handler.c",
"../standard/switch_root.c",
"bootstagehooker.c",
]
modulemgr_sources = [
@ -66,6 +96,7 @@ ohos_executable("init") {
"//base/startup/init/interfaces/innerkits/control_fd:libcontrolfd",
"//base/startup/init/interfaces/innerkits/fd_holder:fdholder",
"//base/startup/init/interfaces/innerkits/fs_manager:libfsmanager_static",
"//base/startup/init/services/log:init_log",
"//base/startup/init/services/loopevent:loopevent",
"//base/startup/init/services/param/linux:param_init",
"//base/startup/init/services/sandbox:sandbox",
@ -74,7 +105,6 @@ ohos_executable("init") {
deps += [ "//base/startup/init/services/param/base:param_base" ]
deps += [
"//base/startup/init/ueventd:libueventd_ramdisk_static",
"//third_party/bounds_checking_function:libsec_static",
"//third_party/cJSON:cjson_static",
]
@ -152,7 +182,6 @@ ohos_executable("init") {
install_images = [
"system",
"updater",
"ramdisk",
]
install_enable = true
part_name = "init"

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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 "bootstage.h"
#define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
static HOOK_MGR *bootStageHookMgr = NULL;
HOOK_MGR *GetBootStageHookMgr()
{
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);
return bootStageHookMgr;
}

View File

@ -26,7 +26,7 @@
#define DEFAULT_RW_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#define DEFAULT_NO_AUTHORITY_MODE (S_IWUSR | S_IRUSR)
void MountBasicFs(void)
static void MountBasicFs(void)
{
if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755") != 0) {
INIT_LOGE("Mount tmpfs failed. %s", strerror(errno));
@ -66,7 +66,7 @@ void MountBasicFs(void)
}
}
void CreateDeviceNode(void)
static void CreateDeviceNode(void)
{
if (mknod("/dev/null", S_IFCHR | DEFAULT_RW_MODE, makedev(MEM_MAJOR, DEV_NULL_MINOR)) != 0) {
INIT_LOGE("Create /dev/null device node failed. %s", strerror(errno));
@ -80,3 +80,23 @@ void CreateDeviceNode(void)
}
}
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;
}
void CreateFsAndDeviceNode(void)
{
MountBasicFs();
CreateDeviceNode();
EnableDevKmsg();
}

View File

@ -29,7 +29,6 @@
#include "config_policy_utils.h"
#include "device.h"
#include "fd_holder_service.h"
#include "fs_manager/fs_manager.h"
#include "key_control.h"
#include "init_control_fd_service.h"
#include "init_log.h"
@ -40,9 +39,6 @@
#include "init_service_manager.h"
#include "init_utils.h"
#include "securec.h"
#include "switch_root.h"
#include "ueventd.h"
#include "ueventd_socket.h"
#include "fd_holder_internal.h"
#include "bootstage.h"
@ -108,19 +104,6 @@ void SystemInit(void)
InitControlFd();
}
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);
return;
}
void LogInit(void)
{
int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
@ -130,135 +113,6 @@ void LogInit(void)
}
}
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;
}
if (num == 0) {
return NULL;
}
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(long long uptime)
{
int requiredNum = 0;
Fstab *fstab = LoadRequiredFstab();
char **devices = (fstab != NULL) ? GetRequiredDevices(*fstab, &requiredNum) : NULL;
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
INIT_LOGE("Mount required partitions failed; please check fstab file");
// Execute sh for debugging
#ifndef STARTUP_INIT_TEST
execv("/bin/sh", NULL);
abort();
#endif
}
}
if (fstab != NULL) {
ReleaseFstab(fstab);
fstab = NULL;
}
// It will panic if close stdio before execv("/bin/sh", NULL)
CloseStdio();
INIT_LOGI("Start init second stage.");
SwitchRoot("/usr");
char buf[64];
snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%lld", uptime);
// Execute init second stage
char * const args[] = {
"/bin/init",
"--second-stage",
buf,
NULL,
};
if (execv("/bin/init", args) != 0) {
INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
exit(-1);
}
}
void SystemPrepare(long long uptime)
{
MountBasicFs();
CreateDeviceNode();
LogInit();
// Make sure init log always output to /dev/kmsg.
EnableDevKmsg();
INIT_LOGI("Start init first stage.");
HookMgrExecute(GetBootStageHookMgr(), INIT_FIRST_STAGE, NULL, NULL);
// Only ohos normal system support
// two stages of init.
// If we are in updater mode, only one stage of init.
if (InUpdaterMode() == 0) {
StartInitSecondStage(uptime);
}
}
#define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
static HOOK_MGR *bootStageHookMgr = NULL;
HOOK_MGR *GetBootStageHookMgr()
{
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);
return bootStageHookMgr;
}
INIT_TIMING_STAT g_bootJob = {{0}, {0}};
static void RecordInitBootEvent(const char *initBootEvent)

View File

@ -18,7 +18,6 @@
#include <errno.h>
#include <stdbool.h>
#include "fs_manager/fs_manager.h"
#include "init_cmds.h"
#include "init_log.h"
#include "init_utils.h"
#include "securec.h"

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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 <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/major.h>
#include "securec.h"
#include "device.h"
#include "init.h"
#include "init_log.h"
#include "init_utils.h"
#include "init_mount.h"
#include "fs_manager/fs_manager.h"
#include "switch_root.h"
#include "ueventd.h"
#include "ueventd_socket.h"
#include "bootstage.h"
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;
}
if (num == 0) {
return NULL;
}
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 MountRequiredPartitions(void)
{
int requiredNum = 0;
Fstab *fstab = LoadRequiredFstab();
char **devices = (fstab != NULL) ? GetRequiredDevices(*fstab, &requiredNum) : NULL;
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
INIT_LOGE("Mount required partitions failed; please check fstab file");
// Execute sh for debugging
#ifndef STARTUP_INIT_TEST
execv("/bin/sh", NULL);
abort();
#endif
}
}
if (fstab != NULL) {
ReleaseFstab(fstab);
fstab = NULL;
}
}
static void StartSecondStageInit(long long uptime)
{
INIT_LOGI("Start init second stage.");
// It will panic if close stdio before execv("/bin/sh", NULL)
CloseStdio();
SwitchRoot("/usr");
char buf[64];
snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%lld", uptime);
// Execute init second stage
char * const args[] = {
"/bin/init",
"--second-stage",
buf,
NULL,
};
if (execv("/bin/init", args) != 0) {
INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
exit(-1);
}
}
static void EarlyLogInit(void)
{
int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
makedev(MEM_MAJOR, DEV_KMSG_MINOR));
if (ret == 0) {
OpenLogDevice();
}
}
int main(int argc, char * const argv[])
{
long long upTimeInMicroSecs = GetUptimeInMicroSeconds(NULL);
(void)signal(SIGPIPE, SIG_IGN);
EnableInitLog(INIT_INFO);
EarlyLogInit();
INIT_LOGI("Start init first stage.");
CreateFsAndDeviceNode();
HookMgrExecute(GetBootStageHookMgr(), INIT_FIRST_STAGE, NULL, NULL);
MountRequiredPartitions();
StartSecondStageInit(upTimeInMicroSecs);
return 0;
}

View File

@ -72,13 +72,11 @@ HWTEST_F(InitUnitTest, TestSystemPrepare, TestSize.Level1)
{
SetStubResult(STUB_MOUNT, -1);
SetStubResult(STUB_MKNODE, -1);
MountBasicFs();
CreateDeviceNode();
CreateFsAndDeviceNode();
SetStubResult(STUB_MOUNT, 0);
SetStubResult(STUB_MKNODE, 0);
MountBasicFs();
CreateDeviceNode();
CreateFsAndDeviceNode();
}
HWTEST_F(InitUnitTest, TestSystemExecRcs, TestSize.Level1)

View File

@ -596,7 +596,6 @@ static __attribute__((constructor(101))) void ParamTestStubInit(void)
#ifndef OHOS_LITE
TestBeforeInit();
#endif
SystemPrepare(0);
#ifndef __LITEOS_A__
SystemInit();
#endif