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

歡迎訪問 生活随笔!

生活随笔

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

linux

Android研究-linux内核启动到android系统

發布時間:2025/4/5 linux 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android研究-linux内核启动到android系统 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

很多人閱讀代碼,總喜歡從頭開始,這樣覺得很安全,有依靠,無論如何總是能知道“頭”,有頭就能找到任何需要的部分。

Android生在linux內核基礎上,linux內核啟動的最后一步,一定是啟動的android的進程,下面看收集到的文章。

1. linux內核啟動過程

引用地址:http://blog.csdn.net/ayangke/article/details/6888699

?????? 內核版本:2.6.22? 為什么要采用這樣一個較低的版本進行移植了,因為韋東山大牛說了,低版本的才能學到東西,越是高版本需要移植時做的工作量越少,學的東西越少。

?????? 內核啟動分為三個階段,第一是運行head.S文件和head-common.S,第三個階段是允許第二是運行main.c文件

?????? 對于ARM的處理器,內核第一個啟動的文件是arc/arm/kernel下面的head.S文件。當然arc/arm/boot/compress下面 也有這個文件,這個文件和上面的文件略有不同,當要生成壓縮的內核時zImage時,啟動的是后者,后者與前者不同的時,它前面的代碼是做自解壓的,后面 的代碼都相同。我們這里這分析arc/arm/kernel下面的head.S文件。當head.S所作的工作完成后它會跳到init/目錄下跌的 main.c的start_kernel函數開始執行。

?

第一階段:

?

首先截取部分head.S文件

ENTRY(stext)

?????? msr? cpsr_c,#PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode

????????????????????????????????????????? @ andirqs disabled

?????? mrc? p15,0, r9, c0, c0?????????? @ get processor id

?????? bl??? __lookup_processor_type???????????? @ r5=procinfo r9=cpuid

?????? movs?????? r10,r5???????????????????????? @ invalidprocessor (r5=0)?

?????? beq? __error_p???????????????????? @ yes, error 'p'

?????? bl??? __lookup_machine_type??????? @ r5=machinfo

?????? movs?????? r8,r5?????????????????????????? @ invalidmachine (r5=0)?

?????? beq? __error_a???????????????????? @ yes, error 'a'

?????? bl??? __create_page_tables

?

?????? /*

?????? ?*The following calls CPU specific code in a position independent

?????? ?*manner.? See arch/arm/mm/proc-*.S fordetails.? r10 = base of

?????? ?*xxx_proc_info structure selected by __lookup_machine_type

?????? ?*above.? On return, the CPU will be readyfor the MMU to be

?????? ?*turned on, and r0 will hold the CPU control register value.

?????? ?*/

?????? ldr?? r13,__switch_data??????? @ address to jump toafter

????????????????????????????????????????? @ mmuhas been enabled

?????? adr?? lr,__enable_mmu????????? @ return (PIC)address

?

?

第一步,執行的是__lookup_processor_type,這個函數是檢查處理器型號,它讀取你的電路板的CPU型號與內核支持的處理器進行比較看是否能夠處理。這個我們不關心它的具體實現過程,因為現在主流處理器內核都提供了支持。

?????? 第二步,執行的是__lookup_machine_type,這個函數是來檢查機器型號的,它會讀取你bootloader傳進來的機器ID和他能夠處 理的機器ID進行比較看是否能夠處理。內核的ID號定義在arc/arm/tool/mach_types文件中MACH_TYPE_xxxx宏定義。內 核究竟就如何檢查是否是它支持的機器的呢?實際上每個機器都會在/arc/arm/mach-xxxx/smdk-xxxx.c文件中有個描述特定機器的 數據結構,如下

?

[html] view plaincopy
  • MACHINE_START(S3C2440,"SMDK2440")??
  • ???????/*?Maintainer:?Ben?Dooks<ben@fluff.org>?*/??
  • ???????.phys_io??=S3C2410_PA_UART,??
  • ???????.io_pg_offst????=?(((u32)S3C24XX_VA_UART)?>>?18)?&?0xfffc,??
  • ???????.boot_params??=?S3C2410_SDRAM_PA?+?0x100,??
  • ???
  • ???????.init_irq???=s3c24xx_init_irq,??
  • ???????.map_io??????????=smdk2440_map_io,??
  • ???????.init_machine??=?smdk2440_machine_init,??
  • ???????.timer?????????????=&s3c24xx_timer,??
  • MACHINE_END??
  • ???

  • MACHINE_START和 MACHINE_END實際上被展開成一個結構體

    [html] view plaincopy
  • #defineMACHINE_START(_type,_name)?????????????????\??
  • staticconst?struct?machine_desc?__mach_desc_##_type???????\??
  • ?__used?????????????????????????????????????????????\??
  • ?__attribute__((__section__(".arch.info.init")))=?{????\??
  • ???????.nr??????????=MACH_TYPE_##_type,???????????\??
  • ???????.name?????????????=_name,??
  • ????????
  • #defineMACHINE_END??????????????????????????\??
  • };??

  • ?

    于是上面的數據結構就被展開為

    [html] view plaincopy
  • staticconst?struct?machine_desc?__mach_desc_S3C2440?????\??
  • ?__used?????????????????????????????????????????????\??
  • ?__attribute__((__section__(".arch.info.init")))=?{????\??
  • ???????.nr??????????=MACH_TYPE_S3C2440,??????????\??
  • ???????.name?????????????=”SMDK2440”,};??
  • .phys_io??=?S3C2410_PA_UART,??
  • ???????.io_pg_offst????=?(((u32)S3C24XX_VA_UART)?>>?18)?&?0xfffc,??
  • ???????.boot_params??=?S3C2410_SDRAM_PA?+?0x100,??
  • ???
  • ???????.init_irq???=s3c24xx_init_irq,??
  • ???????.map_io??????????=smdk2440_map_io,??
  • ???????.init_machine??=?smdk2440_machine_init,??
  • ???????.timer?????????????=&s3c24xx_timer,??
  • ???
  • }??

  • 每個機器都會有一個machine_desc__mach_desc結構,內核通過檢查每個machine_desc__mach_desc的nr 號和bootloader傳上來的ID進行比較,如果相同,內核就認為支持該機器,而且內核在后面的工作中會調用該機器的 machine_desc__mach_desc_結構中的方法進行一些初始化工作。

    ?????? 第三步,創建一級頁表。

    ?????? 第四步,在R13中保存__switch_data 這個函數的地址,在第四步使能mmu完成后會跳到該函數執行。

    第五步,執行的是__enable_mmu,它是使能MMU,這個函數調用了__turn_mmu_on函數,讓后在_turn_mmu_on在最后將第三步賦給R13的值傳給了PC指針 (mov??? pc, r13),于是內核開始跳到__switch_data這個函數開始執行。

    ?

    我們再來看arch/arm/kenel/head-common.S這個文件中的__switch_data函數

    ?

    [html] view plaincopy
  • __switch_data:??
  • ???????.long???????__mmap_switched??
  • ???????.long???????__data_loc????????????????????@?r4??
  • ???????.long???????__data_start??????????????????@?r5??
  • ???????.long???????__bss_start????????????????????@?r6??
  • ???????.long???????_end????????????????????????????@?r7??
  • ???????.long???????processor_id?????????????????@?r4??
  • ???????.long???????__machine_arch_type???????????@?r5??
  • ???????.long???????cr_alignment?????????????????@?r6??
  • ???????.long???????init_thread_union+?THREAD_START_SP?@?sp??
  • ???
  • /*??
  • ?*?The?following?fragment?of?code?is?executedwith?the?MMU?on?in?MMU?mode,??
  • ?*?and?uses?absolute?addresses;?this?is?notposition?independent.??
  • ?*??
  • ?*??r0??=cp#15?control?register??
  • ?*?r1??=?machine?ID??
  • ?*?r9??=?processor?ID??
  • ?*/??
  • ???????.type???????__mmap_switched,%function??
  • __mmap_switched:??
  • ???????adr???r3,__switch_data?+?4??
  • ???
  • ???????ldmia??????r3!,{r4,?r5,?r6,?r7}??
  • ???????cmp?r4,r5???????????????????????????@?Copy?datasegment?if?needed??
  • 1:????cmpne?????r5,r6??
  • ???????ldrne???????fp,[r4],?#4??
  • ???????strne???????fp,[r5],?#4??
  • ???????bne??1b??
  • ???
  • ???????mov?fp,#0???????????????????????????@?Clear?BSS(and?zero?fp)??
  • 1:????cmp?r6,r7??
  • ???????strcc?fp,[r6],#4??
  • ???????bcc??1b??
  • ???
  • ???????ldmia??????r3,{r4,?r5,?r6,?sp}??
  • ???????str????r9,?[r4]??????????????????@?Save?processor?ID??
  • ???????str????r1,?[r5]??????????????????@?Save?machine?type??
  • ???????bic???r4,r0,?#CR_A???????????????@?Clear?'A'?bit??
  • ???????stmia???????r6,{r0,?r4}???????????????????@?Save?controlregister?values??
  • ???????b?????start_kernel??

  • ?

    這個函數做的工作是,復制數據段清楚BBS段,設置堆在指針,然后保存處理器內核和機器內核等工作,最后跳到start_kernel函數。于是內核開始執行第二階段。

    ?

    第二階段:

    ?

    ?????? 我們再來看init/目錄下的main.c的start_kernel函數,這里我只截圖了部分。

    [html] view plaincopy
  • asmlinkage?void?__init?start_kernel(void)??
  • {??
  • ???????…………………….??
  • ???????……………………..??
  • ???????printk(KERN_NOTICE);??
  • ???????printk(linux_banner);??
  • ???????setup_arch(&command_line);??
  • ???????setup_command_line(command_line);??
  • ????????
  • ????????
  • ???????parse_early_param();??
  • ???????parse_args("Booting?kernel",static_command_line,?__start___param,??
  • ????????????????__stop___param?-?__start___param,??
  • ????????????????&unknown_bootoption);??
  • ……………………??
  • …………………………????????
  • ???????init_IRQ();??
  • ???????pidhash_init();??
  • ???????init_timers();??
  • ???????hrtimers_init();??
  • ???????softirq_init();??
  • ???????timekeeping_init();??
  • ???????time_init();??
  • ???????profile_init();??
  • …………………………??
  • ……………………………??
  • ???????console_init();??
  • ………………………………??
  • ………………………………??
  • ???????rest_init();??
  • }??

  • 從上面可以看出start_kernel首先是打印內核信息,然后對bootloader傳進來的一些參數進行處理,再接著執行各種各樣的初始化,在這其中會初始化控制臺。最后會調用rest_init();

    我們再來看rest_init()函數

    [html] view plaincopy
  • static?void?noinline?__init_refok?rest_init(void)??
  • ????__releases(kernel_lock)??
  • {??
  • ????int?pid;??
  • ??
  • ????kernel_thread(kernel_init,?NULL,?CLONE_FS?|?CLONE_SIGHAND);??
  • ????............??????
  • }???
  • ?他啟動了kernel_init這個函數,再來看kerne_init函數

    [html] view plaincopy
  • static?int?__init?kernel_init(void?*?unused)??
  • {??
  • ????..............................??
  • ??
  • ????if?(!ramdisk_execute_command)??
  • ????????ramdisk_execute_command?=?"/init";??
  • ??
  • ????if?(sys_access((const?char?__user?*)?ramdisk_execute_command,?0)?!=?0)?{??
  • ????????ramdisk_execute_command?=?NULL;??
  • ????????prepare_namespace();??
  • ????}??
  • ??
  • ????/*??
  • ?????*?Ok,?we?have?completed?the?initial?bootup,?and??
  • ?????*?we're?essentially?up?and?running.?Get?rid?of?the??
  • ?????*?initmem?segments?and?start?the?user-mode?stuff..??
  • ?????*/??
  • ????init_post();??
  • ????return?0;??
  • }??
  • kernel_init先調用了prepare_namespace();然后調用了init_post函數

    [html] view plaincopy
  • void?__init?prepare_namespace(void)??
  • {??
  • ????..........................??
  • ????mount_root();??
  • ????.....................??
  • }??
  • 可以看出prepare_namespace調用了mount_root掛接根文件系統。接著kernel_init再執行init_post

    [html] view plaincopy
  • static?int?noinline?init_post(void)??
  • {??
  • ????.......................................??
  • ????/*打開dev/console控制臺,并設置為標準輸入、輸出*/??
  • ??????????
  • ????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);??
  • ??
  • ????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.??
  • ?????*/??
  • ??
  • ????//如果bootloader指定了init參數,則啟動init參數指定的進程??
  • ????if?(execute_command)?{??
  • ????????run_init_process(execute_command);??
  • ????????printk(KERN_WARNING?"Failed?to?execute?%s.??Attempting?"??
  • ????????????????????"defaults...\n",?execute_command);??
  • ????}??
  • ??
  • ????//如果沒有指定init參數,則分別帶sbin、etc、bin目錄下啟動init進程??
  • ????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的會等待init進程返回才往后面執行,所有它一旦找到一個init可執行的文件它將一去不復返。

    綜上,內核啟動的過程大致為以下幾步:

    1.檢查CPU和機器類型

    2.進行堆棧、MMU等其他程序運行關鍵的東西進行初始化

    3.打印內核信息

    4.執行各種模塊的初始化

    5.掛接根文件系統

    6.啟動第一個init進程

    2. android啟動

    引用地址:http://monner.iteye.com/blog/728334

    Android 系統啟動分析(轉)

    init進程是Android啟動后系統執行的第一個名稱為init的可執行程序。這個程序以一個守護進程的方式運行,它提供了以下功能:
    • 設備管理
    • 解析啟動腳本
    • 執行啟動腳本中的基本功能
    • 執行啟動腳本中的各種功能

    1、init可執行程序

    init 可執行文件是系統運行的第一個用戶空間程序,它以守護進程的方式運行。因此這個程序的init.c文件包含main函數的入口,基本分析如下: int main(int argc,char**argv){ ? ?(省略若干。。。) ? ?umask(0); ?/*對umask進行清零。*/ ? ? mkdir("/dev",0755);/*為rootfs建立必要的文件夾,并掛載適當的分區。 */ ? ? mkdir("/proc",0755); ? ? mkdir("/sys",0755);? ? mount("tmpfs","/dev","tmpfs",0,"mode=0755"); ? ? mkdir("/dev/pts",0755); ? ? mkdir("/dev/socket",0755); ? ? mount("devpts","/dev/pts","devpts",0, NULL); ? ? mount("proc","/proc","proc",0, NULL); ? ? mount("sysfs","/sys","sysfs",0, NULL);? ? /*創建/dev/null和/dev/kmsg節點*/ ? ? open_devnull_stdio(); ? ? log_init(); ? ?/*解析/init.rc,將所有服務和操作信息加入鏈表。*/ ? ? INFO("reading config file\n"); ? ? parse_config_file("/init.rc");? ? /*獲取內核命令行參數*/ ? ? qemu_init(); ? ? import_kernel_cmdline(0); ? ? /*先從上一步獲得的全局變量中獲取信息硬件信息和版本號,如果沒有則從/proc/cpuinfo中提取,*并保存到全局變量。根據硬件信息選擇一個/init.(硬件).rc,并解析,將服務和操作信息加入鏈表。*/ ? ? get_hardware_name(); ? ? snprintf(tmp,sizeof(tmp),"/init.%s.rc", hardware); ? ? parse_config_file(tmp); ? ? /*執行鏈表中帶有“early-init”觸發的的命令。*/ ? ? action_for_each_trigger("early-init", action_add_queue_tail); ? ? drain_action_queue(); ? ? /*遍歷/sys文件夾,是內核產生設備添加事件(為了自動產生設備節點)。*初始化屬性系統,并導入初始化屬性文件。用于在系統運行過程中動態創建設備節點、刪除設備節點等操作*/ ? ? INFO("device init\n"); ? ? device_fd = device_init();? ? property_init(); ? ? // 從屬性系統中得到ro.debuggable,若為1,則初始化keychord監聽。 ? ? debuggable = property_get("ro.debuggable"); ? ? if(debuggable &&!strcmp(debuggable,"1")){ ? ? ? ? keychord_fd = open_keychord(); ? ? } ? ? /*打開console,如果cmdline中沒有指定的console則打開默認的/dev/console*/ ? ? if(console[0]){ ? ? ? ? snprintf(tmp,sizeof(tmp),"/dev/%s", console); ? ? ? ? console_name = strdup(tmp); ? ? }? ? fd = open(console_name, O_RDWR); ? ? if(fd >=0) ? ? ? ? have_console =1; ? ? close(fd); ? ? /*讀取/initlogo.rle(一張位圖),如果成功則在/dev/graphics/fb0 顯示Logo,如果失敗則將/dev/tty0*設為TEXT模式并打開/dev/tty0,輸出文本ANDROID(本人修改為Zhao Rui Jia做為啟動項目的修改)。*/ ? ? if( load_565rle_image(INIT_IMAGE_FILE)){ ? ? fd = open("/dev/tty0", O_WRONLY); ? ? if(fd >=0){ ? ? ? ? constchar*msg; ? ? ? ? ? ? msg ="\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ?// console is 40 cols x 30 lines ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? ? "\n" ? ? ? /*" ? ? ? ? ? ? A N D R O I D ";*/ ? ? ? ? " ? ? ? ? ?z h a o R u i J i a"; ? ? ? ? write(fd, msg, strlen(msg)); ? ? ? ? close(fd); ? ? } ? ? } ? ?/* 判斷cmdline 中的參數,并設置屬性系統中的參數:* ?1、 如果 bootmode為* ? ? - factory,設置ro.factorytest值為1* ? ? - factory2,設置ro.factorytest值為2* ? ? - 其他的設ro.factorytest值為0* ?2、如果有serialno參數,則設置ro.serialno,否則為""* ?3、如果有bootmod參數,則設置ro.bootmod,否則為"unknown"* ?4、如果有baseband參數,則設置ro.baseband,否則為"unknown"* ?5、如果有carrier參數,則設置ro.carrier,否則為"unknown"* ?6、如果有bootloader參數,則設置ro.bootloader,否則為"unknown"* ?7、通過全局變量(前面從/proc/cpuinfo中提取的)設置ro.hardware和ro.version。*/ ? ? if(qemu[0]) ? ? ? ? import_kernel_cmdline(1); if(!strcmp(bootmode,"factory")) ? ? ? ? property_set("ro.factorytest","1"); ? ? elseif(!strcmp(bootmode,"factory2")) ? ? ? ? property_set("ro.factorytest","2"); ? ? else ? ? ? ? property_set("ro.factorytest","0");? ? property_set("ro.serialno", serialno[0]? serialno :""); ? ? property_set("ro.bootmode", bootmode[0]? bootmode :"unknown"); ? ? property_set("ro.baseband", baseband[0]? baseband :"unknown"); ? ? property_set("ro.carrier", carrier[0]? carrier :"unknown"); ? ? property_set("ro.bootloader", bootloader[0]? bootloader :"unknown");? ? property_set("ro.hardware", hardware); ? ? snprintf(tmp, PROP_VALUE_MAX,"%d", revision); ? ? property_set("ro.revision", tmp);? ? /*執行所有觸發標識為init的action。*/ ? ? action_for_each_trigger("init", action_add_queue_tail); ? ? drain_action_queue(); ? ? property_set_fd = start_property_service();? ? ?/* 為sigchld handler創建信號機制*/ ? ? if(socketpair(AF_UNIX, SOCK_STREAM,0, s)==0){ ? ? ? ? signal_fd = s[0]; ? ? ? ? signal_recv_fd = s[1]; ? ? ? ? fcntl(s[0], F_SETFD, FD_CLOEXEC); ? ? ? ? fcntl(s[0], F_SETFL, O_NONBLOCK); ? ? ? ? fcntl(s[1], F_SETFD, FD_CLOEXEC); ? ? ? ? fcntl(s[1], F_SETFL, O_NONBLOCK); ? ? }? ? /* 確認所有初始化工作完成* device_fd(device init 完成)* property_set_fd(property server start 完成)* signal_recv_fd (信號機制建立) */ ? ? if((device_fd <0)|| ? ? ? ? (property_set_fd <0)|| ? ? ? ? (signal_recv_fd <0)){ ? ? ? ? ERROR("init startup failure\n"); ? ? ? ? return1; ? ? }? ? /* execute all the boot actions to get us started */ ? ? action_for_each_trigger("early-boot", action_add_queue_tail); ? ? action_for_each_trigger("boot", action_add_queue_tail); ? ? drain_action_queue();? ? /* run all property triggers based on current state of the properties */ ? ? queue_all_property_triggers(); ? ? drain_action_queue();? ? /* enable property triggers */ ? property_triggers_enabled =1; ? ? /** ? ?注冊輪詢事件:* ? - device_fd* ? - property_set_fd* ? -signal_recv_fd* ? -如果有keychord,則注冊keychord_fd*/ ? ? ufds[0].fd = device_fd; ? ? ufds[0].events = POLLIN; ? ? ufds[1].fd = property_set_fd; ? ? ufds[1].events = POLLIN; ? ? ufds[2].fd = signal_recv_fd; ? ? ufds[2].events = POLLIN; ? ? fd_count =3;? ? if(keychord_fd >0){ ? ? ? ? ufds[3].fd = keychord_fd; ? ? ? ? ufds[3].events = POLLIN; ? ? ? ? fd_count++; ? ? }else{ ? ? ? ? ufds[3].events =0; ? ? ? ? ufds[3].revents =0; ? ? }/*如果支持BOOTCHART,則初始化BOOTCHART*/#if BOOTCHART ? ? bootchart_count = bootchart_init(); ? ? if(bootchart_count <0){ ? ? ? ? ERROR("bootcharting init failure\n"); ? ? }elseif(bootchart_count >0){ ? ? ? ? NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS); ? ? }else{ ? ? ? ? NOTICE("bootcharting ignored\n"); ? ? }#endif ? /* ?*進入主進程循環:* ?- 重置輪詢事件的接受狀態,revents為0* ?- 查詢action隊列并執行。* ?- 重啟需要重啟的服務* ?- 輪詢注冊的事件* ? ? ? - 如果signal_recv_fd的revents為POLLIN,則得到一個信號,獲取并處理* ? ? ? - 如果device_fd的revents為POLLIN,調用handle_device_fd* ? ? ? - 如果property_fd的revents為POLLIN,調用handle_property_set_fd* ? ? ? - 如果keychord_fd的revents為POLLIN,調用handle_keychord*/ for(;;){ ? ? ? ? int nr, i, timeout =-1;? ? ? ? for(i =0; i < fd_count; i++) ? ? ? ? ? ? ufds[i].revents =0;? ? ? ? drain_action_queue(); ? ? ? ? restart_processes();? ? ? ? if(process_needs_restart){ ? ? ? ? ? ? timeout =(process_needs_restart - gettime())*1000; ? ? ? ? ? ? if(timeout <0) ? ? ? ? ? ? ? ? timeout =0; ? ? ? ? }#if BOOTCHART ? ? ? ? if(bootchart_count >0){ ? ? ? ? ? ? if(timeout <0|| timeout > BOOTCHART_POLLING_MS) ? ? ? ? ? ? ? ? timeout = BOOTCHART_POLLING_MS; ? ? ? ? ? ? if(bootchart_step()<0||--bootchart_count ==0){ ? ? ? ? ? ? ? ? bootchart_finish(); ? ? ? ? ? ? ? ? bootchart_count =0; ? ? ? ? ? ? } ? ? ? ? }#endif ? ? ? ? nr = poll(ufds, fd_count, timeout); ? ? ? ? if(nr <=0) ? ? ? ? ? ? continue;? ? ? ? if(ufds[2].revents == POLLIN){ ? ? ? ? ? ? /* we got a SIGCHLD - reap and restart as needed */ ? ? ? ? ? ? read(signal_recv_fd, tmp,sizeof(tmp)); ? ? ? ? ? ? while(!wait_for_one_process(0)) ? ? ? ? ? ? ? ? ; ? ? ? ? ? ? continue; ? ? ? ? }? ? ? ? if(ufds[0].revents == POLLIN) ? ? ? ? ? ? handle_device_fd(device_fd);? ? ? ? if(ufds[1].revents == POLLIN) ? ? ? ? ? ? handle_property_set_fd(property_set_fd); ? ? ? ? if(ufds[3].revents == POLLIN) ? ? ? ? ? ? handle_keychord(keychord_fd); ? ? }? ? return0;}

    2、啟動腳本init.rc

    在 Android中使用啟動腳本init.rc,可以在系統的初始化過程中進行一些簡單的初始化操作。這個腳本被直接安裝到目標系統的根文件系統中,被 init可執行程序解析。 init.rc是在init啟動后被執行的啟動腳本,其余發主要包含了以下內容:

    • Commands:命令
    • Actions:動作
    • Triggers:觸發條件
    • Services:服務
    • Options:選項
    • Propertise:屬性

    Commands是一些基本的操作,例如:

    ? ? mkdir /sdcard 0000 system systemmkdir /systemmkdir /data 0771 system systemmkdir /cache 0770 system cachemkdir /config 0500 root rootmkdir /sqlite_stmt_journals 01777 root rootmount tmpfs tmpfs /sqlite_stmt_journals size=4m

    這些命令在init可執行程序中被解析,然后調用相關的函數來實現。 Actions(動作)表示一系列的命令,通常在Triggers(觸發條件)中調用,動作和觸發條件例如:

    ? ? on initexport PATH /sbin:/system/sbin:/system/bin:/system/xbin

    init表示一個觸發條件,這個觸發事件發生后,進行設置環境變量和建立目錄的操作稱為一個“動作” Services(服務)通常表示啟動一個可執行程序,Options(選項)是服務的附加內容,用于配合服務使用。

    service vold /system/bin/voldsocket vold stream 0660 root mountservice bootsound /system/bin/playmp3user mediagroup audiooneshot

    vold和bootsound分別是兩個服務的名稱,/system/bin /vold和/system /bin/playmp3分別是他們所對應的可執行程序。socket、user、group、oneshot就是配合服務使用的選項。 Properties(屬性)是系統中使用的一些值,可以進行設置和讀取。

    ? ? setprop ro.FOREGROUND_APP_MEM 1536 ? ? setprop ro.VISIBLE_APP_MEM 2048 ? ? start adbd

    setprop 用于設置屬性,on property可以用于判斷屬性,這里的屬性在整個Android系統運行中都是一致的。

    綜上如果想要修改啟動過程只需要修改init.c或者init.rc里的內容即可.


    3. 總結:

    (1)內核的init_post類似接口,會去文件系統中啟動init類似的用戶進程

    (2)android實現了這樣的init,這就是android框架啟動的地方,當然linux內核也可說是android系統的一部分

    (3)init進程無限分裂,啟動框架,演變成android系統

    (4)android的init進程的代碼在system/core/init/init.c中,從main函數開始.

    ?

    本文完~

    總結

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

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