From the perspective of the system startup process, init is after the kernel starts, but before the user program starts. User program, refers to the user can interact with the program (such as Home, Shell, intelligent express cabinet interaction program, etc.), but also refers to the final business program (such as intelligent speaker business program, floor robot work program, etc.).
The init process is the system’s first user-space process, and all system processes and user processes fork(), i.e. are its children.
The init module is responsible for parsing the system boot configuration file and executing the commands init to complete the system boot operation. The boot configuration file of Hongmeng OS uses JSON format. This is where system developers will come into contact with the first configuration file for the Hongmeng system. This point should be borrowed from the Linux operating system. We know that the Android system is also based on the Linux kernel development, and also has its own implementation of init boot program and its own Android Initial language init.rc boot configuration file. All of this follows or borrows from the Linux operating system, which boots by parsing shell scripts from different directories through the init boot program.
Let’s go straight to the code and see the implementation of the Hongmeng Init boot program. (The source part will be a bit boring, operating code + comments form)
Init module source code analysis
Code – 1.0 / base/startup/services/init_lite /
This is the code directory for the init module. This module is very small, the total files in the entire directory only add up to 108KB, only 8 source files. The maximum source file code does not exceed 350 lines.
Init main process
Code – 1.0 / base/startup/services/init_lite/SRC/main. C
int main(int argc, char * const argv[])
{
// 1. print system info
PrintSysInfo();
// 2. signal register
SignalInitModule();
// 3. read configuration file and do jobs
InitReadCfg();
// 4. keep process alive
printf("[Init] main, entering wait.\n");
while (1) {
// pause only returns when a signal was caught and the signal-catching function returned.
// pause only returns -1, no need to process the return value.
(void)pause();
}
return 0;
}
Copy the code
This is the main process for the init process to boot:
- Printing system Information
- Register signal
- Read the system boot configuration file and perform the corresponding tasks
init
The process enters an infinite loop
The process is clear and concise. Those who have seen the Android operating system init module source code should be very impressed, the code is short and concise, easy to read. Perhaps, after all, this is just HarmonyOS 2.0, and I wonder if it will become bloated after a few iterations.
The principles and code implementation of each step are analyzed in detail below.
Printing system Information
This step prints system information to the console, which is a patchwork of fields. This system information is similar to the fingerprint of the Android operating system. It is a long string that contains the manufacturer, brand, and compilation type.
Code – 1.0 / base/startup/services/init_lite/SRC/main. C
static void PrintSysInfo(a)
{
char* sysInfo = GetVersionId();
if(sysInfo ! =NULL) {
printf("[Init] %s\n", sysInfo);
// Release the memory as soon as it is used.
// Hongmon OS memory management is very good, read the system source code, you can see this design creed everywhere
free(sysInfo);
sysInfo = NULL;
return;
}
printf("[Init] main, GetVersionId failed! \n");
}
Copy the code
Code – 1.0 / base/startup/frameworks/syspara_lite/parameter/SRC/parameter_common. C
char* GetVersionId(void)
{
char* value = (char*)malloc(VERSION_ID_LEN);
if (value == NULL) {
return NULL;
}
if (memset_s(value, VERSION_ID_LEN, 0, VERSION_ID_LEN) ! =0) {
free(value);
value = NULL;
return NULL;
}
char* productType = GetProductType();
char* manufacture = GetManufacture();
char* brand = GetBrand();
char* productSerial = GetProductSeries();
char* productModel = GetProductModel();
char* softwareModel = GetSoftwareModel();
if (productType == NULL || manufacture == NULL || brand == NULL ||
productSerial == NULL || productModel == NULL || softwareModel == NULL) {
free(productType);
free(manufacture);
free(brand);
free(productSerial);
free(productModel);
free(softwareModel);
free(value);
value = NULL;
return NULL;
}
int len = sprintf_s(value, VERSION_ID_LEN, "%s/%s/%s/%s/%s/%s/%s/%s/%s/%s",
productType, manufacture, brand, productSerial, g_roBuildOs, productModel,
softwareModel, g_roSdkApiLevel, INCREMENTAL_VERSION, BUILD_TYPE);
free(productType);
free(manufacture);
free(brand);
free(productSerial);
free(productModel);
free(softwareModel);
if (len < 0) {
free(value);
value = NULL;
return NULL;
}
return value;
}
Copy the code
There are 10 parameters involved, including product type, manufacturer, brand, product serial number, product model, software model, operating system name, SDK version number, software version, and compilation type. Separate each field with a slash (/). The string is the printed system information.
The first six parameters are defined by the device manufacturer. The package code is configured in the following file:
Code – 1.0 / vendor/huawei/camera/hals/utils/sys_param hal_sys_param. C
static const char OHOS_PRODUCT_TYPE[] = {"* * * *"};
static const char OHOS_MANUFACTURE[] = {"* * * *"};
static const char OHOS_BRAND[] = {"* * * *"};
static const char OHOS_PRODUCT_SERIES[] = {"* * * *"};
static const char OHOS_PRODUCT_MODEL[] = {"* * * *"};
static const char OHOS_SOFTWARE_MODEL[] = {"* * * *"};
Copy the code
Parameters 7 and 8 are defined in the following file, identifying the operating system name and SDK version:
Code – 1.0 / base/startup/frameworks/syspara_lite/parameter/SRC/parameter_common. C
static char g_roBuildOs[] = {"OpenHarmony"};
static char g_roSdkApiLevel[] = {"3"};
Copy the code
The ninth parameter is configured in the JSON script for the production configuration and then passed to the source code with the compile option:
Code - 1.0 / base/startup/frameworks/syspara_lite/parameter/SRC/BUILD designed.the gn Code - 1.0 / build/lite/product/ipcamera_hi3518ev300 jsonCopy the code
The 10th argument is the one passed in when the system is compiled and then passed to the source code with the compile option:
Code – 1.0 / base/startup/frameworks/syspara_lite/parameter/SRC/BUILD designed.the gn
defines = [
"INCREMENTAL_VERSION=\"${ohos_version}\"",
"BUILD_TYPE=\"${ohos_build_type}\"",
"BUILD_USER=\"${ohos_build_user}\"",
"BUILD_TIME=\"${ohos_build_time}\"",
"BUILD_HOST=\"${ohos_build_host}\"",
"BUILD_ROOTHASH=\"${ohos_build_roothash}\"",
]
Copy the code
There is no development board, no way to run the system, will not stick to the actual output effect map.
Register signal
Code – 1.0 / base/startup/services/init_lite/SRC/init_signal_handler. C
void SignalInitModule(a)
{
struct sigaction act;
act.sa_handler = SigHandler;
act.sa_flags = SA_RESTART;
(void)sigfillset(&act.sa_mask);
sigaction(SIGCHLD, &act, NULL);
sigaction(SIGTERM, &act, NULL);
}
Copy the code
SigHandler() is called when signals SIGCHLD and SIGTERM occur.
static void SigHandler(int sig)
{
switch (sig) {
case SIGCHLD: {
pid_t sigPID;
int procStat = 0;
printf("[Init] SigHandler, SIGCHLD received.\n");
while (1) {
// Wait for any child process to return when it is not blocking
sigPID = waitpid(- 1, &procStat, WNOHANG);
if (sigPID <= 0) {
break;
}
ReapServiceByPID((int)sigPID);
}
break;
}
case SIGTERM: {
printf("[Init] SigHandler, SIGTERM received.\n");
StopAllServices();
break;
}
default:
printf("[Init] SigHandler, unsupported signal %d.\n", sig);
break; }}Copy the code
SIGCHLD: Notifies the parent process when the child process stops or exits.
SIGTERM: Program end signal, which, unlike SIGKILL, can be blocked and processed. Usually used to require the program itself to exit normally.
Kill all services
Code – 1.0 / base/startup/services/init_lite/SRC/init_service_manager. C
void StopAllServices(a)
{
for (size_t i = 0; i < g_servicesCnt; i++) {
if(ServiceStop(&g_services[i]) ! = SERVICE_SUCCESS) {printf("[Init] StopAllServices, service %s stop failed! \n", g_services[i].name); }}}Copy the code
Code – 1.0 / base/startup/services/init_lite/SRC/init_service. C
int ServiceStop(Service *service)
{
service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
service->attribute |= SERVICE_ATTR_NEED_STOP;
if (service->pid <= 0) {
return SERVICE_SUCCESS;
}
// Send SIGKILL signal directly to the server process to kill the process
if(kill(service->pid, SIGKILL) ! =0) {
printf("[Init] stop service %s pid %d failed! err %d.\n", service->name, service->pid, errno);
return SERVICE_FAILURE;
}
printf("[Init] stop service %s, pid %d.\n", service->name, service->pid);
return SERVICE_SUCCESS;
}
Copy the code
If the program end signal SIGTERM is received, the system traverses the service list, which stores the Pids of all services, and kills the process by sending the SIGKILL signal to the PID.
Reap Service
If a signal SIGCHLD is received that the child process has stopped or exited
Code – 1.0 / base/startup/services/init_lite/SRC/init_service_manager. C
void ReapServiceByPID(int pid)
{
for (size_t i = 0; i < g_servicesCnt; i++) {
if (g_services[i].pid == pid) {
if (g_services[i].attribute & SERVICE_ATTR_IMPORTANT) {
// important process exit, need to reboot system
g_services[i].pid = - 1;
StopAllServices();
RebootSystem();
}
ServiceReap(&g_services[i]);
break; }}}Copy the code
There are two cases: if an important process died, you need to kill all server processes and restart the system. Otherwise, service harvesting.
Code – 1.0 / base/startup/services/init_lite/SRC/init_service. C
void ServiceReap(Service *service)
{
// First set the service PID to -1
service->pid = - 1;
// init sets the service property NEED_STOP, so no restart is required
if (service->attribute & SERVICE_ATTR_NEED_STOP) {
service->attribute &= (~SERVICE_ATTR_NEED_STOP);
service->crashCnt = 0;
return;
}
// Services with the ONCE attribute
if (service->attribute & SERVICE_ATTR_ONCE) {
// no need to restart
if(! (service->attribute & SERVICE_ATTR_NEED_RESTART)) { service->attribute &= (~SERVICE_ATTR_NEED_STOP);return;
}
// the service could be restart even if it is one-shot service
}
// the service that does not need to be restarted restarts, indicating that it has crashed
if(! (service->attribute & SERVICE_ATTR_NEED_RESTART)) {// crash time and count check
time_t curTime = time(NULL);
// Record the number and time of crashes
if (service->crashCnt == 0) {
service->firstCrashTime = curTime;
++service->crashCnt;
} else if (difftime(curTime, service->firstCrashTime) > CRASH_TIME_LIMIT) {
service->firstCrashTime = curTime;
service->crashCnt = 1;
} else {
++service->crashCnt;
// Crash more than 4 times, do not try to restart
if (service->crashCnt > CRASH_COUNT_LIMIT) {
printf("[Init] reap service %s, crash too many times! \n", service->name);
return; }}}// Restart the service
int ret = ServiceStart(service);
if(ret ! = SERVICE_SUCCESS) {printf("[Init] reap service %s start failed! \n", service->name);
}
// Clear the NEED_RESTART property of the service
service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
}
Copy the code
The state change of the service attribute seems to be a bit convoluted.
Start the service
Code – 1.0 / base/startup/services/init_lite/SRC/init_service. C
int ServiceStart(Service *service)
{
// Check the service properties first. If they are invalid, do not start the service
if (service->attribute & SERVICE_ATTR_INVALID) {
printf("[Init] start service %s invalid.\n", service->name);
return SERVICE_FAILURE;
}
struct stat pathStat = {0};
service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
// Check the service executable file path, if the file does not exist, do not perform service startup
if(stat(service->path, &pathStat) ! =0) {
service->attribute |= SERVICE_ATTR_INVALID;
printf("[Init] start service %s invalid, please check %s.\n", service->name, service->path);
return SERVICE_FAILURE;
}
// call fork() to create the child process
int pid = fork();
if (pid == 0) {
// permissions
if(SetPerms(service) ! = SERVICE_SUCCESS) {printf("[Init] service %s exit! set perms failed! err %d.\n", service->name, errno);
_exit(0x7f); // 0x7f: user specified
}
char* argv[] = {service->name, NULL};
char* env[] = {NULL};
// Start the executable file of the service, passing in the file name parameter
if(execve(service->path, argv, env) ! =0) {
printf("[Init] service %s execve failed! err %d.\n", service->name, errno);
}
_exit(0x7f); // 0x7f: user specified
} else if (pid < 0) {
// Failed to create the child process
printf("[Init] start service %s fork failed! \n", service->name);
return SERVICE_FAILURE;
}
// Store the resulting PID in the data structure of the service
service->pid = pid;
printf("[Init] start service %s succeed, pid %d.\n", service->name, service->pid);
return SERVICE_SUCCESS;
}
Copy the code
Start the service using fork+execve.
Restart the system
Code – 1.0 / base/startup/services/init_lite/SRC/init_adapter. C
void RebootSystem(a)
{
#ifdef __LINUX__
int ret = reboot(RB_DISABLE_CAD);
#else
int ret = syscall(__NR_shellexec, "reset"."reset");
#endif
if(ret ! =0) {
printf("[Init] reboot failed! syscall ret %d, err %d.\n", ret, errno); }}Copy the code
Read the configuration file and execute the task
This is the focus of the init module.
Code – 1.0 / base/startup/services/init_lite/SRC/init_read_cfg. C
void InitReadCfg(a)
{
// Read the json boot configuration file
char* fileBuf = ReadFileToBuf();
if (fileBuf == NULL) {
printf("[Init] InitReadCfg, read file %s failed! err %d.\n", INIT_CONFIGURATION_FILE, errno);
return;
}
// Parse the JSON file
cJSON* fileRoot = cJSON_Parse(fileBuf);
free(fileBuf);
fileBuf = NULL;
if (fileRoot == NULL) {
printf("[Init] InitReadCfg, parse failed! please check file %s format.\n", INIT_CONFIGURATION_FILE);
return;
}
// Get the service data
ParseAllServices(fileRoot);
// Get the task data
ParseAllJobs(fileRoot);
// Free memory
cJSON_Delete(fileRoot);
// Execute the task
DoJob("pre-init");
DoJob("init");
DoJob("post-init");
// Free the memory occupied by the Jobs data structure
ReleaseAllJobs();
}
Copy the code
Reading configuration Files
#define INIT_CONFIGURATION_FILE "/etc/init.cfg"
static char* ReadFileToBuf(a)
{
char* buffer = NULL;
FILE* fd = NULL;
struct stat fileStat = {0};
/ /??? do... while... 0 don't understand, don't know what to do?
do {
// Check file validity
if(stat(INIT_CONFIGURATION_FILE, &fileStat) ! =0 ||
fileStat.st_size <= 0 || fileStat.st_size > MAX_JSON_FILE_LEN) {
break;
}
// Open the file in read-only mode
fd = fopen(INIT_CONFIGURATION_FILE, "r");
if (fd == NULL) {
break;
}
// Allocate file size+1 space
buffer = (char*)malloc(fileStat.st_size + 1);
if (buffer == NULL) {
break;
}
// Read data from a file to buffer
if (fread(buffer, fileStat.st_size, 1, fd) ! =1) {
free(buffer);
buffer = NULL;
break;
}
// Write a null character to the last byte of buffer
buffer[fileStat.st_size] = '\ 0';
} while (0);
if(fd ! =NULL) {
fclose(fd);
fd = NULL;
}
return buffer;
}
Copy the code
Parsing JSON files
Workspace/code – 1.0 / third_party cJSON/cJSON. C
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
{
return cJSON_ParseWithOpts(value, 0.0);
}
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{
size_t buffer_length;
if (NULL == value)
{
return NULL;
}
/* Adding null character size due to require_null_terminated. */
buffer_length = strlen(value) + sizeof("");
return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
}
Copy the code
The open source cJSON library is used for JSON file parsing.
Get service data
Code – 1.0 / base/startup/services/init_lite/SRC/init_read_cfg. C
static void ParseAllServices(const cJSON* fileRoot)
{
int servArrSize = 0;
cJSON* serviceArr = GetArrItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON);
if (serviceArr == NULL) {
printf("[Init] InitReadCfg, get array %s failed.\n", SERVICES_ARR_NAME_IN_JSON);
return;
}
// The maximum number of restricted configuration services is 100
if (servArrSize > MAX_SERVICES_CNT_IN_FILE) {
printf("[Init] InitReadCfg, too many services[cnt %d] detected, should not exceed %d.\n",\
servArrSize, MAX_SERVICES_CNT_IN_FILE);
return;
}
// Apply for space to store service data
Service* retServices = (Service*)malloc(sizeof(Service) * servArrSize);
if (retServices == NULL) {
printf("[Init] InitReadCfg, malloc for %s arr failed! %d.\n", SERVICES_ARR_NAME_IN_JSON, servArrSize);
return;
}
if (memset_s(retServices, sizeof(Service) * servArrSize, 0.sizeof(Service) * servArrSize) ! = EOK) {free(retServices);
retServices = NULL;
return;
}
// Traverse the service queue and read data into 'retServices'
for (int i = 0; i < servArrSize; ++i) {
// Get the service data in JSON format
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
// Get service name and path
if (GetServiceString(curItem, &retServices[i], "name", MAX_SERVICE_NAME) ! = SERVICE_SUCCESS || GetServiceString(curItem, &retServices[i],"path", MAX_SERVICE_PATH) ! = SERVICE_SUCCESS) { retServices[i].attribute |= SERVICE_ATTR_INVALID;printf("[Init] InitReadCfg, bad string values for service %d.\n", i);
continue;
}
// Get service uid, gid, once, importance,
if(GetServiceNumber(curItem, &retServices[i], UID_STR_IN_CFG) ! = SERVICE_SUCCESS || GetServiceNumber(curItem, &retServices[i], GID_STR_IN_CFG) ! = SERVICE_SUCCESS || GetServiceNumber(curItem, &retServices[i], ONCE_STR_IN_CFG) ! = SERVICE_SUCCESS || GetServiceNumber(curItem, &retServices[i], IMPORTANT_STR_IN_CFG) ! = SERVICE_SUCCESS) { retServices[i].attribute |= SERVICE_ATTR_INVALID;printf("[Init] InitReadCfg, bad number values for service %d.\n", i);
continue;
}
// Get the service CAPS
if(GetServiceCaps(curItem, &retServices[i]) ! = SERVICE_SUCCESS) { retServices[i].attribute |= SERVICE_ATTR_INVALID;printf("[Init] InitReadCfg, bad caps values for service %d.\n", i); }}// Assign to global variable 'g_services'
RegisterServices(retServices, servArrSize);
}
Copy the code
// All serivce processes that init will fork+exec.
static Service* g_services = NULL;
static int g_servicesCnt = 0;
void RegisterServices(Service* services, int servicesCnt)
{
g_services = services;
g_servicesCnt = servicesCnt;
}
Copy the code
Get mission data
Code – 1.0 / base/startup/services/init_lite/SRC/init_jobs. C
void ParseAllJobs(const cJSON* fileRoot)
{
if (fileRoot == NULL) {
printf("[Init] ParseAllJobs, input fileRoot is NULL! \n");
return;
}
// Get 'jobs' queue in JSON format
cJSON* jobArr = cJSON_GetObjectItemCaseSensitive(fileRoot, JOBS_ARR_NAME_IN_JSON);
int jobArrSize = 0;
if (cJSON_IsArray(jobArr)) {
jobArrSize = cJSON_GetArraySize(jobArr);
}
// Support a maximum of 10 tasks (groups)
if (jobArrSize <= 0 || jobArrSize > MAX_JOBS_COUNT) {
printf("[Init] ParseAllJobs, jobs count %d is invalid, should be positive and not exceeding %d.\n",\
jobArrSize, MAX_JOBS_COUNT);
return;
}
// Allocate memory
Job* retJobs = (Job*)malloc(sizeof(Job) * jobArrSize);
if (retJobs == NULL) {
printf("[Init] ParseAllJobs, malloc failed! job arrSize %d.\n", jobArrSize);
return;
}
if (memset_s(retJobs, sizeof(Job) * jobArrSize, 0.sizeof(Job) * jobArrSize) ! = EOK) {printf("[Init] ParseAllJobs, memset_s failed.\n");
free(retJobs);
retJobs = NULL;
return;
}
for (int i = 0; i < jobArrSize; ++i) {
cJSON* jobItem = cJSON_GetArrayItem(jobArr, i);
ParseJob(jobItem, &(retJobs[i]));
}
// Assign the global variable 'g_jobs'
g_jobs = retJobs;
g_jobCnt = jobArrSize;
}
Copy the code
static void ParseJob(const cJSON* jobItem, Job* resJob)
{
// Get the task name.
// The task name is pre-init, init, or post-init
if(! GetJobName(jobItem, resJob)) { (void)memset_s(resJob, sizeof(*resJob), 0.sizeof(*resJob));
return;
}
// Get the JSON data of the CMD corresponding to the task
cJSON* cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON);
if(! cJSON_IsArray(cmdsItem)) {return;
}
// Get the number of CMD
int cmdLinesCnt = cJSON_GetArraySize(cmdsItem);
if (cmdLinesCnt <= 0) { // empty job, no cmd
return;
}
// A task group cannot have more than 30 CMD entries
if (cmdLinesCnt > MAX_CMD_CNT_IN_ONE_JOB) {
printf("[Init] ParseAllJobs, too many cmds[cnt %d] in one job, it should not exceed %d.\n",\
cmdLinesCnt, MAX_CMD_CNT_IN_ONE_JOB);
return;
}
// Allocate memory
resJob->cmdLines = (CmdLine*)malloc(cmdLinesCnt * sizeof(CmdLine));
if (resJob->cmdLines == NULL) {
return;
}
if (memset_s(resJob->cmdLines, cmdLinesCnt * sizeof(CmdLine), 0, cmdLinesCnt * sizeof(CmdLine)) ! = EOK) {free(resJob->cmdLines);
resJob->cmdLines = NULL;
return;
}
resJob->cmdLinesCnt = cmdLinesCnt;
for (int i = 0; i < cmdLinesCnt; ++i) {
char* cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i)); ParseCmdLine(cmdLineStr, &(resJob->cmdLines[i])); }}Copy the code
Code – 1.0 / base/startup/services/init_lite/SRC/init_cmds. C
void ParseCmdLine(const char* cmdStr, CmdLine* resCmd)
{
if (cmdStr == NULL || strlen(cmdStr) == 0 || resCmd == NULL) {
return;
}
// Get the CMD line string length
size_t cmdLineLen = strlen(cmdStr);
// The number of supported commands
size_t supportCmdCnt = sizeof(g_supportedCmds) / sizeof(g_supportedCmds[0]);
// Declare and initialize the flag bit: whether the command was found and parsed successfully
int foundAndSucceed = 0;
// Walk through the list of supported commands and check whether the command is in the list of supported commands
for (size_t i = 0; i < supportCmdCnt; ++i) {
size_t curCmdNameLen = strlen(g_supportedCmds[i]);
// If the CMD line is longer than the command being compared, and the command +max_cmd_content_len is smaller
// And the command in CMD line is the same as this command
if (cmdLineLen > curCmdNameLen && cmdLineLen <= (curCmdNameLen + MAX_CMD_CONTENT_LEN) &&
strncmp(g_supportedCmds[i], cmdStr, curCmdNameLen) == 0) {
// write cmd_name and write the last character to a null character
if(memcpy_s(resCmd->name, MAX_CMD_NAME_LEN, cmdStr, curCmdNameLen) ! = EOK) {break;
}
resCmd->name[curCmdNameLen] = '\ 0';
// write cmd_content and write the last character to a null character
const char* cmdContent = cmdStr + curCmdNameLen;
size_t cmdContentLen = cmdLineLen - curCmdNameLen;
if(memcpy_s(resCmd->cmdContent, MAX_CMD_CONTENT_LEN, cmdContent, cmdContentLen) ! = EOK) {break;
}
resCmd->cmdContent[cmdContentLen] = '\ 0';
// Set flag bit: the command was found and parsed successfully
foundAndSucceed = 1;
break; }}// If not found or parsing fails, write 0 to all of them
if(! foundAndSucceed) { (void)memset_s(resCmd, sizeof(*resCmd), 0.sizeof(*resCmd)); }}Copy the code
Pure string operation, look so comfortable!
Perform a task
The task is executed in three stages, in chronological order: pre-init, init, and post-init.
CFG: init_liteOS_A_3518EV300. CFG
pre-init
In this phase, you need to create directories, set file permissions, and mount partitions.init
Phase mainly starts the service programpost-init
Phase Changes device file permissions
Code – 1.0 \ base \ startup \ services \ init_lite \ SRC \ init_jobs c
void DoJob(const char* jobName)
{
if (jobName == NULL) {
printf("[Init] DoJob, input jobName NULL! \n");
return;
}
for (int i = 0; i < g_jobCnt; ++i) {
if (strncmp(jobName, g_jobs[i].name, strlen(g_jobs[i].name)) == 0) {
CmdLine* cmdLines = g_jobs[i].cmdLines;
for (int j = 0; j < g_jobs[i].cmdLinesCnt; ++j) {
DoCmd(&(cmdLines[j]));
}
break; }}}void DoCmd(const CmdLine* curCmd)
{
if (curCmd == NULL) {
return;
}
if (strncmp(curCmd->name, "start ".strlen("start ")) = =0) {
DoStart(curCmd->cmdContent);
} else if (strncmp(curCmd->name, "mkdir ".strlen("mkdir ")) = =0) {
DoMkDir(curCmd->cmdContent);
} else if (strncmp(curCmd->name, "chmod ".strlen("chmod ")) = =0) {
DoChmod(curCmd->cmdContent);
} else if (strncmp(curCmd->name, "chown ".strlen("chown ")) = =0) {
DoChown(curCmd->cmdContent);
} else if (strncmp(curCmd->name, "mount ".strlen("mount ")) = =0) {
DoMount(curCmd->cmdContent);
} else {
printf("[Init] DoCmd, unknown cmd name %s.\n", curCmd->name); }}Copy the code
Currently, there are very few commands supported (or for the sake of introduction), only five :start, mkdir, chmod, chown, and mount. The start command starts the services configured by “services”. The other four commands are functions of the same name commands in Linux.
DoStart() expands on the other four commands, and you can follow the code yourself if you are interested.
static void DoStart(const char* cmdContent)
{
StartServiceByName(cmdContent);
}
void StartServiceByName(const char* servName)
{
// From the global service data structure, find the service by name
int servIdx = FindServiceByName(servName);
if (servIdx < 0) {
printf("[Init] StartServiceByName, cannot find service %s.\n", servName);
return;
}
// Call ServiceStart() to start the service, as expanded earlier
if(ServiceStart(&g_services[servIdx]) ! = SERVICE_SUCCESS) {printf("[Init] StartServiceByName, service %s start failed! \n", g_services[servIdx].name);
}
/ /??? What does this do?
sleep(SLEEP_DURATION);
return;
}
Copy the code
Service attributes
Code – 1.0 / base/startup/services/init_lite/include/init_service. H
#define SERVICE_ATTR_INVALID 0x001 // option invalid
#define SERVICE_ATTR_ONCE 0x002 // do not restart when it exits
#define SERVICE_ATTR_NEED_RESTART 0x004 // will restart in the near future
#define SERVICE_ATTR_NEED_STOP 0x008 // will stop in reap
#define SERVICE_ATTR_IMPORTANT 0x010 // will reboot if it crash
Copy the code
There are five attributes of a service, each of which occupies a single bit.
- INVALID Service does not exist
- After the ONCE service exits, it does not restart
- NEED_RESTART After the service exits, it needs to be restarted (in the near future)
- NEED_STOP If the service is forcibly killed by the init process, the service bit is set to 1
- IMPORTANT IMPORTANT service. If the service exits (abnormal), the system will restart
Critical data structure
Service
Code – 1.0 \ base \ startup \ services \ init_lite \ include \ init_service h
typedef struct {
uid_t uID;
gid_t gID;
unsigned int *caps;
unsigned int capsCnt;
} Perms;
typedef struct {
char name[MAX_SERVICE_NAME + 1];
char path[MAX_SERVICE_PATH + 1];
int pid;
int crashCnt;
time_t firstCrashTime;
unsigned int attribute;
Perms servPerm;
} Service;
Copy the code
Service data structure, define a structure, and then write each data field of the Service to the structure.
Job
Code – 1.0 \ base \ startup \ services \ init_lite \ include \ init_jobs h
// one job, could have many cmd lines
typedef struct {
char name[MAX_JOB_NAME_LEN + 1];
int cmdLinesCnt;
CmdLine* cmdLines;
} Job;
Copy the code
Code – 1.0 \ base \ startup \ services \ init_lite \ include \ init_cmds h
// one cmd line
typedef struct {
char name[MAX_CMD_NAME_LEN + 1];
char cmdContent[MAX_CMD_CONTENT_LEN + 1];
} CmdLine;
Copy the code
The Job data structure contains three fields: the Job name, CMD quantity, and CMD pointer.
The global variable
Code – 1.0 \ base \ startup \ services \ init_lite \ SRC \ init_service_manager c
static Service* g_services = NULL;
static int g_servicesCnt = 0;
Copy the code
The global variable g_services holds all configured services.
Boot configuration file
Code – 1.0 / vendor/huawei \ camera \ init_configs \ init_liteos_a_3516dv300 CFG
{ "jobs" : [{ "name" : "pre-init", "cmds" : [ "mkdir /sdcard", "chmod 0777 /sdcard", "mount vfat /dev/mmcblk1 /sdcard rw,umask=000" ] }, { "name" : "init", "cmds" : [ "start foundation", "start appspawn" ] }, { "name" : "post-init", "cmds" : [ "chown 0 99 /dev/dev_mgr", "chown 0 99 /dev/hdfwifi" ] } ], "services" : [{ "name" : "foundation", "path" : "/bin/foundation", "uid" : 7, "gid" : 7, "once" : 0, "importance" : 1, "caps" : [10, 11, 12, 13] }, { "name" : "appspawn", "path" : "/bin/appspawn", "uid" : 1, "gid" : 1, "once" : 0, "importance" : 0, "caps" : [2, 6, 7, 8, 23]}Copy the code
Currently, two types of definitions are supported: Services and Jobs. Services Configured services can be started by calling the start command in Jobs.
Services has seven configuration items: Name, PATH, UID, GID, once, Importance, and CAPS. Important are the service name, executable file path, whether to restart after a hang, and importance. The maximum number of configurable services is 100.
- Name: indicates the service name
- Path: indicates the path of the executable file
- Uid: user ID
- Gid: group ID
- Once: Do I need to pull it up again after I hang up
- Importance: The importance of service
- Caps: What does it do for a while
Jobs sets the commands to be executed. Currently, five commands are supported: start, mkdir, chown, chmod, and mount. The start command is used to start a service defined in services.
The JSON configuration file has a number of limitations:
- The file size cannot exceed 100KB
- The number of configured services cannot exceed 100
- The name of the service cannot exceed 32 characters
- The path of the service cannot exceed 64 characters
- The number of configured tasks (task groups) cannot exceed 10
- A task group cannot be configured with more than 30 CMDS
- A CMD line containing cmd_name and cmd_content
- The cmd_name contains a maximum of 10 characters
- Cmd_content Contains a maximum of 128 characters
3518 Development board default configuration boot does what
Create the log folder, the softbus folder, and the sdcard folder, mount the SDcard folder, and start the shell, ApphilogCat, Foundation, BundLE_daemon, MediA_Server, and Appspawn services in sequence. Modify some device permissions.
Follow-up study Plan
Now that you’ve studied the init module, how do you proceed?
In fact, according to the system startup process to learn is a good learning path. The init process is followed by the start of the six services. Each service is studied in order of shell, ApphilogCat, Foundation, BundLE_DAEMON, MediA_server, and Appspawn. This is just a rough plan, the key modules will be very large, and you need to learn them separately when you encounter them.