android boot 代碼流程 1


之前這篇,從整體展示了 android 的整個啟動流程,為了搞清楚 android 啟動到底在代碼層面上是如何調用的,將從源代碼角度去分析,另所有代碼基於 android 4.0 source tree

   all story begin with the init process startup 
      故事從 init 進程啟動開始

init 運行,代碼:system/core/init ,入口:system/core/init/init.c  main 函數:

 1 int main(int argc, char **argv){
 2     
 3      ...
 4     // 初始化文件系統
 5     mkdir("/dev", 0755);
 6     mkdir("/proc", 0755);
 7     mkdir("/sys", 0755);
 8 
 9     mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
10     mkdir("/dev/pts", 0755);
11     mkdir("/dev/socket", 0755);
12     mount("devpts", "/dev/pts", "devpts", 0, NULL);
13     mount("proc", "/proc", "proc", 0, NULL);
14     mount("sysfs", "/sys", "sysfs", 0, NULL);
15 
16     ...
17 // 解析 /init.rc 和 /init.$hardware.rc 腳本,其中 $hardware 參數從 /proc/cpuinfo 中讀取,模擬器默認是 goldfish 18 INFO("reading config file\n"); 19 init_parse_config_file("/init.rc"); 20 21 /* pull the kernel commandline and ramdisk properties file in */ 22 import_kernel_cmdline(0, import_kernel_nv); 23 /* don't expose the raw commandline to nonpriv processes */ 24 chmod("/proc/cmdline", 0440); 25 get_hardware_name(hardware, &revision); 26 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); 27 init_parse_config_file(tmp); 28 29 ... 30 }

解析 init.rc 文件,主要是由 /system/core/init/init_parser.c 來完成,截取 init.rc 的部分內容如下:(具體 init.rc 文件規范,可參考:/system/core/init/readme.txt)

on early-init
    start ueventd

# create mountpoints
    mkdir /mnt 0775 root system

# setup the global environment
    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin

# Create cgroup mount points for process groups
    mkdir /dev/cpuctl
    mount cgroup none /dev/cpuctl cpu
    chown system system /dev/cpuctl
    chown system system /dev/cpuctl/tasks
    chmod 0777 /dev/cpuctl/tasks
    write /dev/cpuctl/cpu.shares 1024

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

 init.rc 使用的是 android init language 規范,它支持4種語句,Actions,Commands,Services,Options:

  •  Action 定義方式:
on <trigger>                        #以 on 開頭,后面是觸發器名字,觸發器有3種方式:
<command> #1.只是一個名字,如: on early-init; 
  <command>                #2.name=value 對,如:on property:vold.decrypt=trigger_reset_main;
<command> #3.系統自帶的,如:device-added-<path>,device-removed-<path>,service-exited-<name>
<command> #在觸發器下一行就是在觸發器觸發的時候需要執行的命令,如:start...,mkdir,...
  •  Command 就是系統支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是 linux 命令,還有一些是 android 添加的,如:class_start <serviceclass>: 啟動服務,
     class_stop <serviceclass>:關閉服務,等等。 
  •  Service 定義方式: 
service <name> <pathname> [ <argument> ]*
   <option>
   <option>
   ...

#如:啟動 android 最重要的服務 zygote 
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
  •  Option 是針對 Service 的選項,如: 
setenv <name> <value>                           在啟動服務時設置環境變量
user <username>                                 運行服務之前切換用戶
oneshot                                         如果服務已經存在,將不再啟動
class <classname>                               為服務設置名字,具有相同名字的服務將一起啟動或者關閉
socket <name> <type> <perm> [ <user> [ <group> ] ]      創建以<name>命名的 socket,並將該 socket 的文件描述符返回給啟動的服務
onrestart <command>                        在服務重新啟動的時候執行<command>

 在對 init.rc 和 init.$hardware.rc 2個文件按照 android init language 規范進行解析完成以后,會將所有將要執行的命令放到一個大的 action_list 當中,然后緊跟上面解析 init 文件下面:

  // 尋找 early-init 觸發器,加到 action_queue 中
action_for_each_trigger("early-init", action_add_queue_tail);
// 添加系統的一些觸發器    queue_builtin_action(wait_for_coldboot_done_action,
"wait_for_coldboot_done"); queue_builtin_action(property_init_action, "property_init"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); queue_builtin_action(set_init_properties_action, "set_init_properties"); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); /* skip mounting filesystems in charger mode */ if (strcmp(bootmode, "charger") != 0) { action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail); } queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); if (!strcmp(bootmode, "charger")) { action_for_each_trigger("charger", action_add_queue_tail); } else { action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); } /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");      ...
  
  // 按順序執行 action_queue 中的命令 for(;;) { int nr, i, timeout = -1; execute_one_command(); restart_processes(); ... }

 從 action_list 中找到制定觸發器,將觸發器需要執行的命令添加到 action_queue 中,最后按順序執行 action_queue 中的命令來完成初始化,初始化除了設置一些環境變量和創建文件夾以外,

 更多的是關心 Service 的啟動,init 文件里面的服務有2種,1種是 class core,還有1種是 class main,對 init.rc 的 service 按照 class <name> 分類如下:

class core:

service ueventd /sbin/ueventd
service console /system/bin/sh
service adbd /sbin/adbd
service servicemanager /system/bin/servicemanager
service vold /system/bin/vold


class main:

service netd /system/bin/netd
service debuggerd /system/bin/debuggerd
service ril-daemon /system/bin/rild
service surfaceflinger /system/bin/surfaceflinger
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
service drm /system/bin/drmserver
service media /system/bin/mediaserver
service bootanim /system/bin/bootanimation
service dbus /system/bin/dbus-daemon --system --nofork
service bluetoothd /system/bin/bluetoothd -n
service installd /system/bin/installd
service flash_recovery /system/etc/install-recovery.sh
service racoon /system/bin/racoon
service mtpd /system/bin/mtpd
service keystore /system/bin/keystore /data/misc/keystore
service dumpstate /system/bin/dumpstate -s

 service ueventd:會讀取 /ueventd.rc 和 /ueventd.$hadrware.rc 文件,解析跟 init.rc 解析類似,主要是對文件系統的權限和用戶進行設置:(代碼:system/core/init/ueventd.c)

#目錄 權限 user group

/dev/null 0666 root root /dev/zero 0666 root root

 在 class core 服務啟動以后, class main 開始啟動,service zygote 是標志進入 android 最重要的一個服務,服務名字 zygote,實際上啟動的是 app_process,(代碼:frameworks/base/cmds/app_process/app_main.cpp) 

int main(int argc, const char* const argv[])
{
    // These are global variables in ProcessState.cpp
    mArgC = argc;
    mArgV = argv;

    mArgLen = 0;

//讀取參數,傳遞的參數就是 init.rc 中啟動時傳入的: -Xzygote /system/bin --zygote --start-system-server
for (int i=0; i<argc; i++) { mArgLen += strlen(argv[i]) + 1; } mArgLen--; AppRuntime runtime; const char* argv0 = argv[0]; //-Xzygote // Process command line arguments // ignore argv[0] argc--; //之前是 4, 現在是 3 argv++; //argv 指向 argv[1] // Everything up to '--' or first non '-' arg goes to the vm   
   // i = 0,代碼:frameworks/base/core/jni/AndroidRuntime.cpp int i = runtime.addVmArguments(argc, argv); // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; while (i < argc) { const char* arg = argv[i++]; if (!parentDir) { parentDir = arg;               //parentDir = /system/bin } else if (strcmp(arg, "--zygote") == 0) { //當 i = 2,arg = argv[1] 時,即:--zygote zygote = true;                 niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName = arg + 12; } else { className = arg; break; } } if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName); } runtime.mParentDir = parentDir; if (zygote) {
     // zygote = true,啟動 com.android.internal.os.ZygoteInit,參數:startSystemServer runtime.start(
"com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" : ""); } else if (className) { // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } }

檢測傳入參數,將調用 : 

 runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" : "");

 runtime 的代碼:frameworks/base/core/jni/AndroidRuntime.cpp,start 函數會啟動虛擬機, 執行 com.android.internal.os.ZygoteInit 該類的 main 函數,並傳入參數: start-system-server:

void AndroidRuntime::start(const char* className, const char* options)
{
    LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
            className != NULL ? className : "(unknown)");

...
/* start the virtual machine */
//設置 dalvik 虛擬機參數,創建並啟動虛擬機
JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) { return; } onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { LOGE("Unable to register all android natives\n"); return; } ...
/* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */
//將類名 com.xxx.xxx 轉換成 com/xxx/xxx char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { LOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else {
     // jni 調用 java 方法,獲取對應類名的 class,然后調用靜態 main 方法 jmethodID startMeth
= env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { LOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); } } free(slashClassName); LOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) LOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) LOGW("Warning: VM did not shut down cleanly\n"); }

 ZygoteInit 類 main 函數:

 public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
       
//注冊 socket server registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis());

//預加載資源,有 preloadClasses() 和 preloadResources(),加載的開始和結束會被記錄在 /system/etc/event-log-tags 文件中 preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());        
 
// Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); }    if (argv[1].equals("start-system-server")) {
          //在調用 Zygote 的 main 函數時,已經傳入 start-system-server,調用 startSystemServer() startSystemServer(); }
else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); if (ZYGOTE_FORK_MODE) { runForkMode(); } else {
         //上面通過 registerZygoteSocket() 函數調用注冊的 server scocket,會啟動,開始監聽 Zygote 連接 runSelectLoopMode(); }          closeServerSocket(); }
catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }

 

那 startSystemServer 到底又做了什么東東呢,以及最后系統如何發出 ACTION_BOOT_COMPLETED 廣播的呢,且聽下回分解。 -):

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM