日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android系统启动系列----init进程

發布時間:2023/11/29 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android系统启动系列----init进程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android系統啟動系列

  • Android系統啟動系列----init進程
  • Android系統啟動系列----Zygote進程
  • 引言

    在開發app的過程中,是不是會有疑問:

    • java程序的運行不是從main方法開始么,怎么app入口是Application的onCreate方法?
    • 那java的運行環境虛擬機Dalvik VM和ART又是什么時候創建的?又是由誰創建的?
    • 安卓是Linux內核,那內核創建后系統又做了什么初始化了整個安卓環境?
    • 當我們的手機或者安卓系統設備按下電源按鍵的時候,系統都做什么?

    當按下電源的那一刻都發生了啥:

    今天的分析都是基于Android 6.0系統的分析。


    第一步:啟動電源

    當電源按下,引導芯片代碼開始從預定義的地方(固化在ROM)開始執行。加載引導程序到RAM,然后執行。

    第二步:執行引導程序(Boot Loader)

    通常在運行Android系統之前會先執行Boot Loader引導程序,它不屬于Android系統,常見的引導程序有:redboot、uboot、qi bootloader等等。或者自行開發引導程序,它是針對特定主板和芯片的,OEM制造廠商或者運營商在加鎖的時候就對這個引導程序做修改,比如魅族就是修改了引導程序,所以刷不了機。

    第三步:內核

    Android內核與桌面linux內核啟動的方式差不多。內核啟動時,設置緩存、被保護存儲器、計劃列表,加載驅動。當內核完成系統設置,它首先在系統文件中尋找”init”文件,然后啟動root進程或者系統的第一個進程。

    第四步:執行init進程

    init進程是Android系統啟動的第一個用戶空間進程,init進程主要做兩個事情。第一:掛載目錄,如:掛載了/sys /dev /proc 等目錄。第二:解析執行init.rc腳本文件。

    系統編譯,刷入手機后,init的進程保存在/system/core/bin目錄中,對應程序的源代碼入口是/system/core/init/init.cpp。

    int main(int argc, char** argv) {if (!is_first_stage) {// 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.process_kernel_dt();process_kernel_cmdline();// Propogate the kernel variables to internal variables// used by init as well as the current required properties.export_kernel_boot_props();}........// 開始屬性服務start_property_service();// 初始化“init.rc”配置文件解析器init_parse_config_file("/init.rc");action_for_each_trigger("early-init", action_add_queue_tail);........ } 復制代碼

    主要看init.rc腳本文件的解析,在說解析前,先來了解下配置腳本的內容,這是一個內建的腳本語言也叫Android初始化語言,有自己的語法結構,大概介紹下: Android初始化語言由四大類型的聲明組成,即Actions(動作)、Commands(命令)、Services(服務)、以及Options(選項)。 Action(動作):動作是以命令流程命名的,有一個觸發器決定動作是否發生。

    on early-init# Set init and its forked children's oom_adj.write /proc/1/oom_score_adj -1000# Set the security context of /adb_keys if present.restorecon /adb_keysstart ueventdon initsysclktz 0# Backward compatibility.symlink /system/etc /etcsymlink /sys/kernel/debug /d# Link /vendor to /system/vendor for devices without a vendor partition.symlink /system/vendor /vendor# Create cgroup mount point for cpu accountingmkdir /acctmount cgroup none /acct cpuacctmkdir /acct/uid 復制代碼

    以上腳本中,on early-init、on init就是 Action類型的語句,語法格式為:

    on <trigger> [&& <trigger>]* //設置觸發器 <command> <command> //動作觸發之后要執行的命令 復制代碼

    Service(服務):服務是init進程啟動的程序、當服務退出時init進程會視情況重啟服務,語法格式為:

    service <name> <pathname> [ <argument> ]* //<service的名字><執行程序路徑><傳遞參數> <option> //option是service的修飾詞,影響什么時候、如何啟動services <option> ... 復制代碼

    下面是默認的init.rc文件,主要的事件及其服務。

    Action/Service描述
    on early-init設置init進程以及它創建的子進程的優先級,設置init進程的安全環境
    on init設置全局環境,為cpu accounting創建cgroup(資源控制)掛載點
    on fs掛載mtd分區
    on post-fs改變系統目錄的訪問權限
    on post-fs-data改變/data目錄以及它的子目錄的訪問權限
    on-boot基本網絡的初始化,內存管理等等
    service servicemanager啟動系統管理器管理所有的本地服務,比如位置、音頻、Shared preference等等…
    service zygote啟動zygote進程

    通常在這個階段,我們可以在屏幕上看到“Android logo”字樣或者圖標。

    我們重點來看看zygote進程相關的屬性配置,它是獨立的一個rc文件在/system/core/rootdir/init.zygote32.rc

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass mainsocket zygote stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart mediaonrestart restart netdwritepid /dev/cpuset/foreground/tasks 復制代碼

    執行zygote程序,其實是通過執行app_process程序,然后傳入xzygote等等參數實現的。先找到app_process程序的源碼所在地:/frameworks/base/cmds/app_process/app_main.cpp 直接看程序的main函數:

    int main(int argc, char* const argv[]) {if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {// Older kernels don't understand PR_SET_NO_NEW_PRIVS and return// EINVAL. Don't die on such kernels.if (errno != EINVAL) {LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));return 12;}}AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;int i;for (i = 0; i < argc; i++) {if (argv[i][0] != '-') {break;}if (argv[i][1] == '-' && argv[i][2] == 0) {++i; // Skip --.break;}runtime.addOption(strdup(argv[i]));}// Parse runtime arguments. Stop at first unrecognized option.bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;++i; // Skip unused "parent dir" argument.while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;} 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.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}Vector<String8> args;if (!className.isEmpty()) {args.add(application ? String8("application") : String8("tool"));runtime.setClassNameAndArgs(className, argc - i, argv + i);} else {// We're in zygote mode.maybeCreateDalvikCache();if (startSystemServer) {args.add(String8("start-system-server"));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",ABI_LIST_PROPERTY);return 11;}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag);// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i < argc; ++i) {args.add(String8(argv[i]));}}if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string());set_process_name(niceName.string());}// 如果參數是--zygote,那么runtime.start執行zygote進程if (zygote) {runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} 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;} } 復制代碼

    上面就是通過app_process進程,啟動zygote進程的入口,執行啟動zygote的程序的在java層的/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,接下來我們看看:runtime.start("com.android.internal.os.ZygoteInit", args, zygote)都干了啥。 runtime是AppRuntime類的對象,start函數在其父類AndroidRuntime中聲明和實現。AndroidRuntime是不是很熟悉了,Android的運行時,通常app異常的時候這玩意是不是總伴隨你左右。原來這玩意這么早就啟動在監控系統的一舉一動了。

    /** Start the Android runtime. This involves starting the virtual machine* and calling the "static void main(String[] args)" method in the class* named by "className".** Passes the main function two arguments, the class name and the specified* options string.*/ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {....../* start the virtual machine */JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;if (startVm(&mJavaVM, &env, zygote) != 0) { // 1return;}onVmCreated(env); // 2/** Register android functions.*/if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}/** We want to call main() with a String array with arguments in it.* At present we have two arguments, the class name and an option string.* Create an array to hold them.*/jclass stringClass;jobjectArray strArray;jstring classNameStr;stringClass = env->FindClass("java/lang/String");assert(stringClass != NULL);strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);assert(strArray != NULL);classNameStr = env->NewStringUTF(className);assert(classNameStr != NULL);env->SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i = 0; i < options.size(); ++i) {jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());assert(optionsStr != NULL);env->SetObjectArrayElement(strArray, i + 1, optionsStr);}/** Start VM. This thread becomes the main thread of the VM, and will* not return until the VM exits.*/char* slashClassName = toSlashClassName(className);jclass startClass = env->FindClass(slashClassName); // 3if (startClass == NULL) {ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);/* keep going */} else {jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V"); // 4if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);/* keep going */} else {env->CallStaticVoidMethod(startClass, startMeth, strArray); // 5#if 0if (env->ExceptionCheck())threadExitUncaughtException(env); #endif}}...... } 復制代碼
  • 注釋1:startVm顧名思義啟動虛擬機,在此啟動java虛擬機,當然這個是運行zygote進程的虛擬機,也就回答了文章最開始引言問題,虛擬機由app_process的AndroidRuntime創建。
  • 注釋2:虛擬機創建后的回調處理,主要是創建一些資源。
  • 注釋3:className就是app_process中傳入的參數“com.android.internal.os.ZygoteInit”,因為ZygoteInit是java層的,所以需要使用jni來找到ZygoteInit.class,startClass就是ZygoteInit.class
  • 注釋4:通過jni的GetStaticMethodID函數獲取到ZygoteInit.java的靜態main方法的類似于反射的Mehod對象引用。
  • 注釋5:最后通過JNI的CallStaticVoidMethod函數類似于java反射的invoke方法,調用了4中獲取的main方法的Method引用。 (如果對JNI不熟的可以看看JNI系列入門文章)
  • 如上就是Zygote進程的啟動方式。


    總結

  • 手機按下電源后,加載引導程序到內存中。
  • 執行引導程序
  • 啟動內核,設置緩存、被保護存儲器、計劃列表,加載驅動,查找/system/core/bin中init程序文件。
  • 啟動init程序,掛載/sys /dev /proc等等目錄,加載和解析init.rc腳本。
  • 在加載init.rc腳本的時候,啟動app_process進程。
  • 在app_process進程中,根據init.zygote32.rc腳本配置的參數,啟動zygote進程。
  • 最終zygote進程的執行,即ZygoteInit.java文件main方法的執行,是由AndroidRuntime通過JNI的方式調用main方法執行的。在這之前啟動了Dalvik VM或者ART虛擬機。

  • Android系統啟動系列

  • Android系統啟動系列----init進程
  • Android系統啟動系列----Zygote進程
  • 總結

    以上是生活随笔為你收集整理的Android系统启动系列----init进程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。