編輯:Android開發教程
本文使用的軟件版本
Android:4.2.2
Linux內核:3.1.10
本文及後續幾篇文章將對Android的初始化(init)過程進行詳細地、剝絲抽繭式地分析,並且在其中穿插了大量的知識,希望對讀者了解Android的啟動過程又所幫助。本章主要介紹了與硬件相關初始化文件名的確定以及屬性服務的原理和實現。
Android本質上就是一個基於Linux內核的操作系統。與Ubuntu Linux、Fedora Linux類似。只是Android在應用層專門為移動設備添加了一些特有的支持。既然Android是Linux內核的系統,那麼基本的啟動過程也應符 合Linux的規則。如果研究過其他Linux系統應該了解,一個完整的Linux系統首先會將一個Linux內核裝載到內存,也就是編譯Linux內核 源代碼生成的bzImage文件,對於為Android優化的Linux內核源代碼會生成zImage文件。該文件就是Linux內核的二進制版本。由於 zImage在內核空間運行,而我們平常使用的軟件都是在應用空間運行(關於內核空間和應用空間的詳細描述,可以參考《Android深度探索(卷1):HAL與驅動開發》一書的內容,在後續的各卷中將會對Android的整體體系進行全方位的剖析)。內核空間和應用空間是不能直接通過內存地址級別訪問的,所以就需要建立某種通訊機制。
目前Linux有很多通訊機制可以在用戶空間和內核空間之間交互,例如設備驅動文件(位於/dev目錄中)、內存文件(/proc、/sys目錄等)。了 解Linux的同學都應該知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一個設備通常與一個或多個設備文件對應。這些與內核空間交 互的文件都在用戶空間,所以在Linux內核裝載完,需要首先建立這些文件所在的目錄。而完成這些工作的程序就是本文要介紹的init。Init是一個命 令行程序。其主要工作之一就是建立這些與內核空間交互的文件所在的目錄。當Linux內核加載完後,要做的第一件事就是調用init程序,也就是 說,init是用戶空間執行的第一個程序。
在分析init的核心代碼之前,還需要初步了解init除了建立一些目錄外,還做了如下的工作
1. 初始化屬性
2. 處理配置文件的命令(主要是init.rc文件),包括處理各種Action。
3. 性能分析(使用bootchart工具)。
4. 無限循環執行command(啟動其他的進程)。
盡管init完成的工作不算很多,不過代碼還是非常復雜的。Init程序並不是由一個源代碼文件組成的,而是由一組源代碼文件的目標文件鏈接而成的。這些文件位於如下的目錄。
<Android源代碼本目錄>/system/core/init
其中init.c是init的主文件,現在打開該文件,看看其中的內容。由於init是命令行程序,所以分析init.c首先應從main函數開始,現在好到main函數,代碼如下:
int main(int argc, char **argv)
{
int fd_count = 0;
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
char tmp[32];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
bool is_charger = false;
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
if (!strcmp(basename(argv[0]), "watchdogd"))
return watchdogd_main(argc, argv);
/* clear the umask */
umask(0);
// 下面的代碼開始建立各種用戶空間的目錄,如/dev、/proc、/sys等
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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/.booting文件是否可讀寫和創建*/
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
open_devnull_stdio();
klog_init();
// 初始化屬性
property_init();
get_hardware_name(hardware, &revision);
// 處理內核命令行
process_kernel_cmdline();
… …
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
if (!is_charger)
property_load_boot_defaults();
INFO("reading config file\n");
// 分析/init.rc文件的內容
init_parse_config_file("/init.rc");
… …// 執行初始化文件中的動作
action_for_each_trigger("init", action_add_queue_tail);
// 在charger模式下略過mount文件系統的工作
if (!is_charger) {
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 (is_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_property_triggers");
#if BOOTCHART
queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
// 進入無限循環,建立init的子進程(init是所有進程的父進程)
for(;;) {
int nr, i, timeout = -1;
// 執行命令(子進程對應的命令)
execute_one_command();
restart_processes();
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
if (!signal_fd_init && get_signal_fd() > 0) {
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
}
if (!keychord_fd_init && get_keychord_fd() > 0) {
ufds[fd_count].fd = get_keychord_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
keychord_fd_init = 1;
}
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action)
timeout = 0;
// bootchart是一個性能統計工具,用於搜集硬件和系統的信息,並將其寫入磁盤,以便其
// 他程序使用
#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;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
}
return 0;
}
如何apk反編譯破解Android程序
把apktool-install-windows-r05-ibot文件裡的兩個文件剪切到apktool1.5.1目錄。新建一個文件夾把需要破解的apk應用程序放進去。在此
Android屬性動畫之實現靈動菜單效果
前段時間,我學習了自定義View,基本能夠繪制一些比較好看的控件,那麼今天開始,我將會學習屬性動畫。前面我也簡單的看過屬性動畫的概念,然後也是看了一下效果,了解了一些基本
在Android中實現360手機衛士懸浮窗效果
大家好,今天給大家帶來一個仿360手機衛士懸浮窗效果的教程,在開始之前請允許我說幾句不相干的廢 話。不知不覺我發現自己接觸Android已有近三個年頭了,期間各種的成長少
Android實現微信在線/離線狀態切換
先看效果圖,有圖有效果了才有動力(右邊是關閉wifi/3g之後的Title樣子)首先了解一下網絡狀態的判斷方法,網絡狀態是一個SystemService,可以通過cont