天天看點

android 7.1.2程式崩潰,android7.1.2啟動流程分析之init程式

android7.1.2啟動流程分析之init程式

闆子平台ROC_RK3328_CC

安卓源碼樹Android7.1.2–>kernel/init/main.c 檔案

asmlinkage void __init start_kernel(void){

rest_init();//在start_kernel函數最後一行

}

安卓源碼樹Android7.1.2–>kernel/init/main.c 檔案

static noinline void __init_refok rest_init(void)

{

kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

}

安卓源碼樹Android7.1.2–>kernel/init/main.c 檔案

static int __ref kernel_init(void unused)

{

kernel_init_freeable();//有ramdisk_execute_command = “/init”;

/ need to finish all async __init code before freeing the memory */

async_synchronize_full();

free_initmem();

mark_rodata_ro();

system_state = SYSTEM_RUNNING;

numa_default_policy();

flush_delayed_fput();

if (ramdisk_execute_command) {

if (!run_init_process(ramdisk_execute_command))

return 0;

pr_err("Failed to execute %s\n", ramdisk_execute_command);

}

if (execute_command) {

if (!run_init_process(execute_command))

return 0;

pr_err("Failed to execute %s. Attempting defaults...\n",

execute_command);

}

if (!run_init_process("/sbin/init") ||

!run_init_process("/etc/init") ||

!run_init_process("/bin/init") ||

!run_init_process("/bin/sh"))

return 0;

panic("No init found. Try passing init= option to kernel. "

"See Linux Documentation/init.txt for guidance.");

}

安卓系統跟目錄下的init.rc初始化腳本配置檔案預設放置在android源碼樹的system/core/rootdir目錄(類同于傳統linux系統下使用busybox生成的/sbin/init程式去解析/etc/inittab檔案)

android中的/init程式會通過解析/init.rc和init.rc裡面包含的

import /init.${ro.hardware}.rc這兩個檔案中的相關的指令來完成相應的初始化流程,是目前android系統運作時所依賴的相關硬體平台的名字,/proc/cmdline指令行腳本有androidboot.hardware=rk30board,此處的ro.hardware應該就是rk30board

/init.rc初始化腳本配置檔案是提供通用的相關初始化指令,/init..rc腳本配置檔案是提供特定的硬體平台的機器相關的初始化指令

init.rc初始化配置腳本的語言文法規則 有說明文檔android源碼樹system/core/init/readme.txt.

當平台啟動時,kernel中的引導參數将會被設定成init=/init.進而當挂載檔案系統成功後,便會開始執行/init初始化程式。init的入口點在源碼樹的system/core/init/init.cpp的main函數

int main(int argc, char** argv) {

//建立我們需要的基礎檔案系統/dev,/dev/pts,/dev/socket,/proc,/sys到initramdisk中的根目錄,然後由*.rc腳本配置檔案來解決餘下的目錄節點的建立

// Get the basic filesystem setup we need put together in the initramdisk

// on / and then we'll let the rc file figure out the rest.

if (is_first_stage) {

mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");

mkdir("/dev/pts", 0755);

mkdir("/dev/socket", 0755);

mount("devpts", "/dev/pts", "devpts", 0, NULL);

#define MAKE_STR(x) __STRING(x)

mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));

mount("sysfs", "/sys", "sysfs", 0, NULL);

}

NOTICE(“init %s started!\n”, is_first_stage ? “first stage” : “second stage”);

if (!is_first_stage) {

//此處是init: init second stage started!

// Indicate that booting is in progress to background fw loaders, etc.

close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

property_init();

// If arguments are passed both on the command line and in DT,

// properties set in DT always have priority over the command-line ones.

///操作proc/device-tree/firmware/android裡面的裝置樹描述

process_kernel_dt();

//跟蹤進去,發現是操作/proc/cmdline裡面的核心指令行參數資訊的

process_kernel_cmdline();

// Propagate the kernel variables to internal variables

// used by init as well as the current required properties.

export_kernel_boot_props();

//add by xzj to set ro.rk.soc read from /proc/cpuinfo if not set

set_soc_if_need();

}

// If we're in the kernel domain, re-exec init to transition to the init domain now

// that the SELinux policy has been loaded.

if (is_first_stage) {

if (**restorecon("/init")** == -1) {

ERROR("restorecon failed: %s\n", strerror(errno));

security_failure();

}

char* path = argv[0];

char* args[] = { path, const_cast("--second-stage"), nullptr };

if (execv(path, args) == -1) {

ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));

security_failure();

}

}

// These directories were necessarily created before initial policy load

// and therefore need their security context restored to the proper value.

// This must happen before /dev is populated by ueventd.

NOTICE("Running restorecon...\n");

restorecon("/dev");

restorecon("/dev/socket");

restorecon("/dev/__properties__");

restorecon("/property_contexts");

restorecon_recursive("/sys");

epoll_fd = epoll_create1(EPOLL_CLOEXEC);

if (epoll_fd == -1) {

ERROR("epoll_create1 failed: %s\n", strerror(errno));

exit(1);

}

signal_handler_init();

property_load_boot_defaults();

export_oem_lock_status();

start_property_service();

const BuiltinFunctionMap function_map;

Action::set_function_map(&function_map);

Parser& parser = Parser::GetInstance();

parser.AddSectionParser("service",std::make_unique());

parser.AddSectionParser("on", std::make_unique());

parser.AddSectionParser("import", std::make_unique());

//解析/init.rc配置檔案

parser.ParseConfig("/init.rc");

ActionManager& am = ActionManager::GetInstance();

//周遊連結清單并執行所有标志為early-init的活動Action

am.QueueEventTrigger("early-init");

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...

am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");

// ... so that we can start queuing up actions that require stuff from /dev.

am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");

am.QueueBuiltinAction(keychord_init_action, "keychord_init");

am.QueueBuiltinAction(console_init_action, "console_init");

// Trigger all the boot actions to get us started.

am.QueueEventTrigger("init");

// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random

// wasn't ready immediately after wait_for_coldboot_done

am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

// Don't mount filesystems or start core system services in charger mode.

std::string bootmode = property_get("ro.bootmode");

if (bootmode == "charger") {

am.QueueEventTrigger("charger");

} else {

am.QueueEventTrigger("late-init");

}

// Run all property triggers based on current state of the properties.

am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

while (true) {

if (!waiting_for_exec) {

am.ExecuteOneCommand();

restart_processes();

}

return 0;

}

/proc/cmdline 檔案裡資訊如下

earlyprintk=uart8250-32bit,0xff130000 console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=permissive androidboot.hardware=rk30board androidboot.console=ttyFIQ0 init=/init mtdparts=rk29xxnand:[email protected](uboot),[email protected](trust),[email protected](misc),[email protected](baseparamer),[email protected](resource),[email protected](kernel),[email protected](boot),[email protected]