<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 189,comments - 115,trackbacks - 0
    android移植詳解
    http://blog.chinaunix.net/uid-25838286-id-3014386.html
    主要介紹linux 內(nèi)核啟動過程以及掛載android 根文件系統(tǒng)的過程,以及介紹android 源代碼中文件系統(tǒng)部分的淺析。

          主要源代碼目錄介紹
    Makefile (全局的Makefile)
    bionic (Bionic 含義為仿生,這里面是一些基礎(chǔ)的庫的源代碼)
    bootable (引導加載器)
    build (build 目錄中的內(nèi)容不是目標所用的代碼,而是編譯和配置所需要的腳本和工具)
    dalvik (JAVA 虛擬機)
    development (程序開發(fā)所需要的模板和工 具)                                                                                     external (目標機器使用的一些庫)
    frameworks (應(yīng)用程序的框架層)
    hardware (與硬件相關(guān)的庫)
    packages (Android 的各種應(yīng)用程序)
    prebuilt (Android 在各種平臺下編譯的預(yù)置腳本)
    recovery (與目標的恢復功能相關(guān))
    system (Android 的底層的一些庫)
    out (編譯完成后產(chǎn)生的目錄,也就是我們移植文件系統(tǒng)需要的目錄)

    host 目錄的結(jié)構(gòu)如下所示:
    out/host/
    |-- common
    | `-- obj (JAVA 庫)
    `-- linux-x86
    |-- bin (瞥絳潁?br> |-- framework (JAVA 庫,*.jar 文件)
    |-- lib (共享庫*.so)
    `-- obj (中間生成的目標文件)
    host 目錄是一些在主機上用的工具,有一些是二進制程序,有一些是JAVA 的程序。

    target 目錄的結(jié)構(gòu)如下所示:
    out/target/
    |-- common
    | |-- R (資源文件)
    | |-- docs
    | `-- obj (目標文件)
    `-- product
    `-- generic
    其中common 目錄表示通用的內(nèi)容,product 中則是針對產(chǎn)品的內(nèi)容。
    在common 目錄的obj 中,包含兩個重要的目錄:
    APPS 中包含了JAVA 應(yīng)用程序生成的目標,每個應(yīng)用程序?qū)?yīng)其中一個子目錄,將結(jié)合每個應(yīng)用程序的原始文件生成Android 應(yīng)用程序的APK 包。                                                                                       JAVA_LIBRARIES 中包含了JAVA 的庫,每個庫對應(yīng)其中一個子目錄。

    所以,我們提取文件系統(tǒng)主要是在/out/target/product/generic 目錄下,我們可以看到里面有obj 目錄,進入obj 目錄看看,里面是android 文件系統(tǒng)非常重要的內(nèi)容:

    /obj
    APPS (文件系統(tǒng)下/system/apps 目錄下的各種應(yīng)用程序)
    SHARED_LIBRARIES (存放所有動態(tài)庫)
    STATIC_LIBRARIES(存放所有靜態(tài)庫)
    EXECUTABLES (存放各種可執(zhí)行文件)

    Linux 內(nèi)核啟動掛載android根文件系統(tǒng)過程分析

    順便羅列一下內(nèi)核啟動流程:

    /arch/arm/boot/compressed/head.S:

    Start:
    Decompressed_kernel()             //在/arch/arm/boot/compressed/misc.c 中
    Call_kernel()


    Stext:
    /init/main.c
    Start_kernel()
    Setup_arch()

    Rest_init()
    Init()
    Do_basic_setup()
    Prepare_namespace()

    看到了這里,我已激動得說不出話了,因為來到我與掛載根文件系統(tǒng)最重要的接口函數(shù)。

    /* This is a non __init function. Force it to be noinline otherwise gcc
    * makes it inline to init() and it becomes part of init.text section
    */
    static int noinline init_post(void)
    {
    free_initmem();
    unlock_kernel();
    mark_rodata_ro();
    system_state = SYSTEM_RUNNING;
    numa_default_policy();
    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
    printk(KERN_WARNING "Warning: unable to open an initial console.\n");
    (void) sys_dup(0);
    (void) sys_dup(0);
    current->signal->flags |= SIGNAL_UNKILLABLE;
    if (ramdisk_execute_command) {
    run_init_process(ramdisk_execute_command);
    printk(KERN_WARNING "Failed to execute %s\n",ramdisk_execute_command);
    }
    /*
    * We try each of these until one succeeds. *
    * The Bourne shell can be used instead of init if we are*
    * trying to recover a really broken machine.*/
    if (execute_command) {
    run_init_process(execute_command);
    printk(KERN_WARNING "Failed to execute %s. Attempting ""defaults...\n",
    execute_command);
    }
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/init");
    run_init_process("/bin/sh");
    panic("No init found. Try passing init= option to kernel.");
    }

    其中,我們看到行代碼run_init_process(execute_command);
    execute_command 
    是從UBOOT 傳遞過來的參數(shù),一般為/init,也就是調(diào)用文件系統(tǒng)里的init 初始化進程。如果找不到init 文件就會在
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/init");
    run_init_process("/bin/sh");
    中找,否則報錯。

    在這里由于我們的根文件系統(tǒng)是從/linuxrc 開始的,所以我硬性把它改為
    if (execute_command) {
    run_init_process("/linuxrc");
    printk(KERN_WARNING "Failed to execute %s. Attempting "
    "defaults...\n", execute_command);
    }

    Android 文件系統(tǒng)初始化核心Init.c文件分析

           上面我們說的init 這個文件是由android 源代碼編譯來的,編譯后在/out/target/product/generic/root/

    其源碼在/system/core/init/init.c

    Init.c 主要功能:

    (1)安裝SIGCHLD 信號。(如果父進程不等待子進程結(jié)束,子進程將成為僵尸進程(zombie)從而占用系統(tǒng)資源。因此需要對SIGCHLD 信號做出處理,回收僵尸進程的資源,避免造成不必要的資源浪費。)
    (2)對umask 進行清零。
    何為umask,請看http://www.szstudy.cn/showArticle/53978.shtml
    (3)為rootfs 建立必要的文件夾,并掛載適當?shù)姆謪^(qū)。
    /dev (tmpfs)
    /dev/pts (devpts)
    /dev/socket
    /proc (proc)
    /sys (sysfs)
    (4)創(chuàng)建/dev/null 和/dev/kmsg 節(jié)點。
    (5)解析/init.rc,將所有服務(wù)和操作信息加入鏈表。
    (6)從/proc/cmdline 中提取信息內(nèi)核啟動參數(shù),并保存到全局變量。
    (7)先從上一步獲得的全局變量中獲取信息硬件信息和版本號,如果沒有則從/proc/cpuinfo 中提取,并保存到全局變量。
    (8)根據(jù)硬件信息選擇一個/init.(硬件).rc,并解析,將服務(wù)和操作信息加入鏈表。
    在G1 的ramdisk 根目錄下有兩個/init.(硬件).rc:init.goldfish.rc 和init.trout.rc,init 程序會根據(jù)上一步獲得的硬件信息選擇一個解析。
    (9)執(zhí)行鏈表中帶有“early-init”觸發(fā)的的命令。
    (10)遍歷/sys 文件夾,是內(nèi)核產(chǎn)生設(shè)備添加事件(為了自動產(chǎn)生設(shè)備節(jié)點)。
    (11)初始化屬性系統(tǒng),并導入初始化屬性文件。
    (12)從屬性系統(tǒng)中得到ro.debuggable,若為1,則初始化keychord 監(jiān)聽。
    (13)打開console,如果cmdline 中沒有指定console 則打開默認的 /dev/console
    (14)讀取/initlogo.rle(一張565 rle 壓縮的位圖),如果成功則在
    /dev/graphics/fb0 顯示Logo,如果失敗則將/dev/tty0 設(shè)為TEXT 模式并打開/dev/tty0,輸出文“ANDROID”字樣。
    (15)判斷cmdline 中的參數(shù),并設(shè)置屬性系統(tǒng)中的參數(shù):
    1、 如果 bootmode 為
    - factory,設(shè)置ro.factorytest 值為1
    - factory2,設(shè)置ro.factorytest 值為2
    - 其他的設(shè)ro.factorytest 值為0
    2、如果有serialno 參數(shù),則設(shè)置ro.serialno,否則為""
    3、如果有bootmod 參數(shù),則設(shè)置ro.bootmod,否則為"unknown"
    4、如果有baseband 參數(shù),則設(shè)置ro.baseband,否則為"unknown"
    5、如果有carrier 參數(shù),則設(shè)置ro.carrier,否則為"unknown"
    6、如果有bootloader 參數(shù),則設(shè)置ro.bootloader,否則為"unknown"
    7、通過全局變量(前面從/proc/cpuinfo 中提取的)設(shè)置ro.hardware 和
    ro.version。
    (16)執(zhí)行所有觸發(fā)標識為init 的action。
    (17)開始property 服務(wù),讀取一些property 文件,這一動作必須在前面
    那些ro.foo 設(shè)置后做,以便/data/local.prop 不能干預(yù)到他們。
    - /system/build.prop
    - /system/default.prop
    - /data/local.prop
    - 在讀取默認的 property 后讀取 presistent propertie,在 /data/property 中
    (18)為 sigchld handler 創(chuàng)建信號機制
    (19)確認所有初始化工作完成:
    device_fd(device init 完成)
    property_set_fd(property server start 完成)
    signal_recv_fd (信號機制建立)
    (20) 執(zhí)行所有觸發(fā)標識為early-boot 的action
    (21) 執(zhí)行所有觸發(fā)標識為boot 的action
    (22)基于當前property 狀態(tài),執(zhí)行所有觸發(fā)標識為property 的action
    (23)注冊輪詢事件:
    - device_fd
    - property_set_fd
    -signal_recv_fd
    -如果有keychord,則注冊keychord_fd
    (24)如果支持BOOTCHART,則初始化BOOTCHART
    (25)進入主進程循環(huán):
    - 重置輪詢事件的接受狀態(tài),revents 為0
    - 查詢action 隊列,并執(zhí)行。
    - 重啟需要重啟的服務(wù)
    - 輪詢注冊的事件
    - 如果signal_recv_fd 的revents 為POLLIN,則得到一個信號,獲取并處

    - 如果device_fd 的revents 為POLLIN,調(diào)用handle_device_fd
    - 如果property_fd 的revents 為POLLIN,調(diào)用handle_property_set_fd
    - 如果keychord_fd 的revents 為POLLIN,調(diào)用handle_keychord
    到了這里,整個android 文件系統(tǒng)已經(jīng)起來了。

    初始化核心的核心init.rc文件分析

    在上面紅色那一行(5)解析/init.rc,將所有 服務(wù)和操作信息加入鏈表。

           parse_config_file("/init.rc");//在init.c 中代碼 (有關(guān) /init.rc的腳本我就不貼出來了)

    名詞解 釋:
    Android 初始化語言由四大類聲明組成:行為類(Actions)、命令類(Commands)、服務(wù)類(Services)、選項類(Options)。
    初始化語言以行為單位,由以空格間隔的語言符號組成。C 風格的反斜杠轉(zhuǎn)義符可以用來插入空白到語言符號。雙引號也可以用來防止文本被空格分成多個語言符號。當反斜杠在行末時,作為換行符。

           * 以#開始(前面允許空格)的行為注釋。
    * Actions 和Services 隱含聲明一個新的段落。所有該段落下Commands 或 Options 的聲明屬于該段落。第一段落前的Commands 或Options 被忽略。
    * Actions 和Services 擁有唯一的命名。在他們之后聲明相同命名的類將被當作錯誤并忽略。
    Actions 是一系列命令的命名。Actions 擁有一個觸發(fā)器(trigger)用來決定action 何時執(zhí)行。當一個action 在符合觸發(fā)條件被執(zhí)行時,如果它還沒被加入到待執(zhí)行隊列中的話,則加入到隊列最后。隊列中的action 依次執(zhí)行,action 中的命令也依次執(zhí)行。

               Init 在執(zhí)行命令的中間處理其他活動(設(shè)備創(chuàng)建/銷毀,property 設(shè)置,進程重啟)。

              Actions 的表現(xiàn)形式:
    on <trigger>
    <command>
    <command>
    <command>

              重要的數(shù)據(jù)結(jié)構(gòu)兩個列表,一個隊列。
    static list_declare(service_list);
    static list_declare(action_list);
    static list_declare(action_queue);

             *.rc 腳本中所有 service 關(guān)鍵字定義的服務(wù)將會添加到 service_list 列表中。
    *.rc 腳本中所有 on 關(guān)鍵開頭的項將會被會添加到 action_list 列表中。每個action 列表項都有一個列表,此列表用來保存該段落下的 Commands。

    腳本解 析過程:
    parse_config_file("/init.rc")
    int parse_config_file(const char *fn)
    {
    char *data;
    data = read_file(fn, 0);
    if (!data)                                                                                                                                                     return -1;
    parse_config(fn, data);
    DUMP();
    return 0;
    }
    static void parse_config(const char *fn, char *s)                                                                                          {

    ...
    case T_NEWLINE:
    if (nargs) {
    int kw = lookup_keyword(args[0]);
    if (kw_is(kw, SECTION)) {
    state.parse_line(&state, 0, 0);
    parse_new_section(&state, kw, nargs, args);
    } else {
    state.parse_line(&state, nargs, args);
    }
    nargs = 0;
    }
    ...

    parse_config 會逐行對腳本進行解析,如果關(guān)鍵字類型為 SECTION ,那么將會執(zhí)行parse_new_section();
    類型為 SECTION 的關(guān)鍵字有: on 和 sevice

    關(guān)鍵字 類型定義在 Parser.c (system\core\init) 文件中
    Parser.c (system\core\init)
    #define SECTION 0x01
    #define COMMAND 0x02
    #define OPTION 0x04
    關(guān)鍵字                 屬性
    capability,          OPTION, 0, 0)
    class,                 OPTION, 0, 0)
    class_start,        COMMAND, 1, do_class_start)
    class_stop,       COMMAND, 1, do_class_stop)
    console,             OPTION, 0, 0)
    critical,              OPTION, 0, 0)
    disabled,          OPTION, 0, 0)
    domainname,    COMMAND, 1, do_domainname)
    exec,                 COMMAND, 1, do_exec)
    export,              COMMAND, 2, do_export)
    group,              OPTION, 0, 0)
    hostname,         COMMAND, 1, do_hostname)
    ifup,                   COMMAND, 1, do_ifup)
    insmod,            COMMAND, 1, do_insmod)
    import,               COMMAND, 1, do_import)
    keycodes,         OPTION, 0, 0)
    mkdir,               COMMAND, 1, do_mkdir)
    mount,              COMMAND, 3, do_mount)
    on,                   SECTION, 0, 0)
    oneshot,           OPTION, 0, 0)
    onrestart,         OPTION, 0, 0)
    restart,             COMMAND, 1, do_restart)
    service,           SECTION, 0, 0)
    setenv,             OPTION, 2, 0)
    setkey,             COMMAND, 0, do_setkey)
    setprop,          COMMAND, 2, do_setprop)
    setrlimit,           COMMAND, 3, do_setrlimit)
    socket,           OPTION, 0, 0)
    start,                COMMAND, 1, do_start)
    stop,             COMMAND, 1, do_stop)
    trigger,           COMMAND, 1, do_trigger)
    symlink,           COMMAND, 1, do_symlink)
    sysclktz,         COMMAND, 1, do_sysclktz)
    user,             OPTION, 0, 0)
    write,             COMMAND, 2, do_write)
    chown,             COMMAND, 2, do_chown)
    chmod,            COMMAND, 2, do_chmod)
    loglevel,          COMMAND, 1, do_loglevel)
    device,             COMMAND, 4, do_device)

    parse_new_section() 中再分別對 service 或者 on 關(guān)鍵字開頭的內(nèi)容進行解
    析。
    ...
    case K_service:
    state->context = parse_service(state, nargs, args);
    if (state->context) {
    state->parse_line = parse_line_service;
    return;
    }
    break;
    case K_on:
    state->context = parse_action(state, nargs, args);
    if (state->context) {
    state->parse_line = parse_line_action;
    return;
    }
    break;
    ...

    對 on 關(guān)鍵字開頭的內(nèi)容進行解析
    static void *parse_action(struct parse_state *state, int nargs, char **args)
    {
    ...
    act = calloc(1, sizeof(*act));
    act->name = args[1];
    list_init(&act->commands);
    list_add_tail(&action_list, &act->alist);
    ...
    }

    對 service 關(guān)鍵字開頭的內(nèi)容進行解析
    static void *parse_service(struct parse_state *state, int nargs, char **args)
    {
    struct service *svc;
    if (nargs < 3) {
    parse_error(state, "services must have a name and a program\n");
    return 0;
    }
    if (!valid_name(args[1])) {
    parse_error(state, "invalid service name '%s'\n", args[1]);
    return 0;
    }
    //如果服務(wù)已經(jīng)存在service_list 列表中將會被忽略
    svc = service_find_by_name(args[1]);
    if (svc) {
    parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
    return 0;
    }
    nargs -= 2;
    svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
    if (!svc) {
    parse_error(state, "out of memory\n");
    return 0;
    }
    svc->name = args[1];
    svc->classname = "default";
    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
    svc->args[nargs] = 0;
    svc->nargs = nargs;
    svc->onrestart.name = "onrestart";
    list_init(&svc->onrestart.commands);
    //添加該服務(wù)到 service_list 列表
    list_add_tail(&service_list, &svc->slist);
    return svc;
    }

    服務(wù)的 表現(xiàn)形式:
    service <name> <pathname> [ <argument> ]*
    <option>
    <option>
    ...

           申請一個service 結(jié)構(gòu)體,然后掛接到service_list 鏈表上,name 為服務(wù)的名稱,pathname 為執(zhí)行的命令,argument為命令的參數(shù)。之后的 option 用來控制這個service 結(jié)構(gòu)體的屬性,parse_line_service 會對 service 關(guān)鍵字后的內(nèi)容進行解析并填充到 service 結(jié)構(gòu)中 ,當遇到下一個service 或者on 關(guān)鍵字的時候此service 選項解析結(jié)束。
    例如:
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    服務(wù)名稱為: zygote
    啟動該服務(wù)執(zhí)行的命令: /system/bin/app_process
    命令的參數(shù): -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666: 創(chuàng)建一個名為:/dev/socket/zygote 的 socket ,
    類型為:stream

     

    養(yǎng)成勵志的習慣,一生勵志——文指星終極勵志 

    經(jīng)典英語口語與英語學習資料 

    15本經(jīng)典C、C++、MFC、VC++教程,都是pdf完整版的

    30本經(jīng)典Linux學習和開發(fā)教程和資料,都是pdf完整版的 

    10本經(jīng)典Java教程,都是pdf完整版的 

    15本超級經(jīng)典Android教程,都是pdf完整版的 

    一語驚人英語口語--經(jīng)典口語  

    posted on 2012-02-08 20:45 MEYE 閱讀(926) 評論(0)  編輯  收藏 所屬分類: Android3D
    主站蜘蛛池模板: 亚洲AV无码之国产精品| 亚洲人成网77777色在线播放| 成人免费无码大片a毛片| 国产2021精品视频免费播放| 久久99青青精品免费观看| a级午夜毛片免费一区二区| 永久免费av无码入口国语片| 日韩a级无码免费视频| a级毛片无码免费真人久久| a毛片免费在线观看| 可以免费观看的国产视频| 免费成人在线视频观看| 免费在线观看一级片| 一区二区三区四区免费视频 | 久99久无码精品视频免费播放| a级毛片免费观看在线| 国产成人无码区免费网站| 久久精品免费观看国产| 99ee6热久久免费精品6| 男女做羞羞的事视频免费观看无遮挡| 一二三四免费观看在线视频中文版 | 精品在线视频免费| 产传媒61国产免费| 久久精品国产这里是免费| 日本免费xxxx| 成年女性特黄午夜视频免费看| 国产又粗又猛又爽又黄的免费视频| 亚洲国产成人久久综合区| 亚洲日韩激情无码一区| 精品无码一区二区三区亚洲桃色| 亚洲精品亚洲人成在线播放| 免费国产黄网站在线看| 日本亚洲欧洲免费天堂午夜看片女人员| 中文字幕亚洲免费无线观看日本| 好吊妞在线成人免费| 亚洲日韩涩涩成人午夜私人影院 | 成人最新午夜免费视频| 亚洲综合久久夜AV | 亚洲视频在线一区二区三区| 亚洲男人的天堂网站| 中文字幕免费观看视频|