- 浏览: 1388874 次
- 性别:
- 来自: 陕西.西安
-
文章分类
最新评论
-
dare_:
经过试验 设置之后反而更慢没有调用ensureCapacity ...
ensureCapacity()方法提高ArrayList的初始化速度 -
wangchao9053:
[flash=200,200][url][img][list] ...
Only the original thread that created a view hierarchy can touch its views的相关 -
cyb504:
考虑将rb文件代码隐藏:我先使用命令jrubyc将所有rb文件 ...
Ruby学习十 JRuby中调用java代码 -
4562xse3460:
大哥,您这个写反了,差点误导我,我觉得看着就不对。百度第一条就 ...
portrait表示纵向,landscape表示横向 -
yin138:
portrait是肖像画,即竖屏,landscape是风景画, ...
portrait表示纵向,landscape表示横向
转载 作者:汕头大学—黄珠唐 时间:2009 年10 月29 日
主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析。
主要源代码目录介绍
Makefile (全局的Makefile)
bionic (Bionic 含义为仿生,这里面是一些基础的库的源代码)
bootable (引导加载器)
build (build 目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具)
dalvik (JAVA 虚拟机)
development (程序开发所需要的模板和工具) external (目标机器使用的一些库)
frameworks (应用程序的框架层)
hardware (与硬件相关的库)
packages (Android 的各种应用程序)
prebuilt (Android 在各种平台下编译的预置脚本)
recovery (与目标的恢复功能相关)
system (Android 的底层的一些库)
out (编译完成后产生的目录,也就是我们移植文件系统需要的目录)
host 目录的结构如下所示:
out/host/
|-- common
| `-- obj (JAVA 库)
`-- linux-x86
|-- bin (二进制程序)
|-- framework (JAVA 库,*.jar 文件)
|-- lib (共享库*.so)
`-- obj (中间生成的目标文件)
host 目录是一些在主机上用的工具,有一些是二进制程序,有一些是JAVA 的程序。
target 目录的结构如下所示:
out/target/
|-- common
| |-- R (资源文件)
| |-- docs
| `-- obj (目标文件)
`-- product
`-- generic
其中common 目录表示通用的内容,product 中则是针对产品的内容。
在common 目录的obj 中,包含两个重要的目录:
APPS 中包含了JAVA 应用程序生成的目标,每个应用程序对应其中一个子目录,将结合每个应用程序的原始文件生成Android 应用程序的APK 包。 JAVA_LIBRARIES 中包含了JAVA 的库,每个库对应其中一个子目录。
所以,我们提取文件系统主要是在/out/target/product/generic 目录下,我们可以看到里面有obj 目录,进入obj 目录看看,里面是android 文件系统非常重要的内容:
/obj
APPS (文件系统下/system/apps 目录下的各种应用程序)
SHARED_LIBRARIES (存放所有动态库)
STATIC_LIBRARIES(存放所有静态库)
EXECUTABLES (存放各种可执行文件)
Linux 内核启动挂载android根文件系统过程分析
顺便罗列一下内核启动流程:
/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()
看到了这里,我已激动得说不出话了,因为来到我与挂载根文件系统最重要的接口函数。
/* 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 传递过来的参数,一般为/init,也就是调用文件系统里的init 初始化进程。如果找不到init 文件就会在
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
中找,否则报错。
在这里由于我们的根文件系统是从/linuxrc 开始的,所以我硬性把它改为
if (execute_command) {
run_init_process("/linuxrc");
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
Android 文件系统初始化核心Init.c文件分析
上面我们说的init 这个文件是由android 源代码编译来的,编译后在/out/target/product/generic/root/
其源码在/system/core/init/init.c
Init.c 主要功能:
(1)安装SIGCHLD 信号。(如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。因此需要对SIGCHLD 信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。)
(2)对umask 进行清零。
何为umask,请看http://www.szstudy.cn/showArticle/53978.shtml
(3)为rootfs 建立必要的文件夹,并挂载适当的分区。
/dev (tmpfs)
/dev/pts (devpts)
/dev/socket
/proc (proc)
/sys (sysfs)
(4)创建/dev/null 和/dev/kmsg 节点。
(5)解析/init.rc,将所有服务和操作信息加入链表。
(6)从/proc/cmdline 中提取信息内核启动参数,并保存到全局变量。
(7)先从上一步获得的全局变量中获取信息硬件信息和版本号,如果没有则从/proc/cpuinfo 中提取,并保存到全局变量。
(8)根据硬件信息选择一个/init.(硬件).rc,并解析,将服务和操作信息加入链表。
在G1 的ramdisk 根目录下有两个/init.(硬件).rc:init.goldfish.rc 和init.trout.rc,init 程序会根据上一步获得的硬件信息选择一个解析。
(9)执行链表中带有“early-init”触发的的命令。
(10)遍历/sys 文件夹,是内核产生设备添加事件(为了自动产生设备节点)。
(11)初始化属性系统,并导入初始化属性文件。
(12)从属性系统中得到ro.debuggable,若为1,則初始化keychord 監聽。
(13)打開console,如果cmdline 中沒有指定console 則打開默認的 /dev/console
(14)讀取/initlogo.rle(一張565 rle 壓縮的位圖),如果成功則在
/dev/graphics/fb0 顯示Logo,如果失敗則將/dev/tty0 設為TEXT 模式并打開/dev/tty0,輸出文“ANDROID”字樣。
(15)判斷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。
(16)執行所有触发标识为init 的action。
(17)開始property 服務,讀取一些property 文件,這一動作必須在前面
那些ro.foo 設置后做,以便/data/local.prop 不能干預到他們。
- /system/build.prop
- /system/default.prop
- /data/local.prop
- 在讀取默認的 property 后讀取 presistent propertie,在 /data/property 中
(18)為 sigchld handler 創建信號機制
(19)確認所有初始化工作完成:
device_fd(device init 完成)
property_set_fd(property server start 完成)
signal_recv_fd (信號機制建立)
(20) 執行所有触发标识为early-boot 的action
(21) 執行所有触发标识为boot 的action
(22)基于當前property 狀態,執行所有触发标识为property 的action
(23)注冊輪詢事件:
- device_fd
- property_set_fd
-signal_recv_fd
-如果有keychord,則注冊keychord_fd
(24)如果支持BOOTCHART,則初始化BOOTCHART
(25)進入主進程循環:
- 重置輪詢事件的接受狀態,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
到了这里,整个android 文件系统已经起来了。
初始化核心的核心init.rc文件分析
在上面红色那一行(5)解析/init.rc,将所有服务和操作信息加入链表。
parse_config_file("/init.rc");//在init.c 中代码 (有关 /init.rc的脚本我就不贴出来了)
名词解释:
Android 初始化語言由四大类声明组成:行为类(Actions)、命令类(Commands)、服务类(Services)、选项类(Options)。
初始化语言以行为单位,由以空格间隔的语言符号組成。C 风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为换行符。
* 以#开始(前面允许空格)的行为注释。
* Actions 和Services 隐含声明一个新的段落。所有该段落下Commands 或 Options 的声明属于该段落。第一段落前的Commands 或Options 被忽略。
* Actions 和Services 拥有唯一的命名。在他们之后声明相同命名的类将被当作错误并忽略。
Actions 是一系列命令的命名。Actions 拥有一个触发器(trigger)用来決定action 何時执行。当一个action 在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,則加入到队列最后。队列中的action 依次执行,action 中的命令也依次执行。
Init 在执行命令的中间处理其他活动(设备创建/销毁,property 设置,进程重启)。
Actions 的表现形式:
on <trigger>
<command>
<command>
<command>
重要的数据结构两个列表,一个队列。
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
*.rc 脚本中所有 service 关键字定义的服务将会添加到 service_list 列表中。
*.rc 脚本中所有 on 关键开头的项将会被会添加到 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 会逐行对脚本进行解析,如果关键字类型为 SECTION ,那么将会执行parse_new_section();
类型为 SECTION 的关键字有: on 和 sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c (system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION 0x04
关键字 属性
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 关键字开头的内容进行解
析。
...
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 关键字开头的内容进行解析
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 关键字开头的内容进行解析
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;
}
//如果服务已经存在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);
//添加该服务到 service_list 列表
list_add_tail(&service_list, &svc->slist);
return svc;
}
服务的表现形式:
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
申请一个service 结构体,然后挂接到service_list 链表上,name 为服务的名称,pathname 为执行的命令,argument为命令的参数。之后的 option 用来控制这个service 结构体的属性,parse_line_service 会对 service 关键字后的内容进行解析并填充到 service 结构中 ,当遇到下一个service 或者on 关键字的时候此service 选项解析结束。
例如:
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
服务名称为: zygote
启动该服务执行的命令: /system/bin/app_process
命令的参数: -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666: 创建一个名为:/dev/socket/zygote 的 socket ,
类型为:stream
发表评论
-
Android检查是否已经连接到网络
2012-05-14 15:40 1289http://blog.csdn.net/kerenigma/ ... -
Android Framework系列之IMF(二)
2011-06-02 10:09 2212InputConnection是IMF里面一个重要的接口,他是 ... -
Android Frameworks系列之IMF(一)
2011-06-02 10:03 1891http://www.pin5i.com/showtopic- ... -
Android线程优先级设置方法
2011-05-28 14:15 3556http://blog.sina.com.cn/s/blog_ ... -
如何连接android数据库
2011-05-27 15:18 2325http://zhidao.baidu.com/questio ... -
ensureCapacity()方法提高ArrayList的初始化速度
2011-05-27 14:33 11587http://www.gznc.edu.cn/yxsz/jjg ... -
java的isAlive 和 join
2011-05-27 13:38 1607join()用于停止当前线程而运行别的线程。 isAli ... -
Linux系统下.ko文件是什么文件?.so文件是什么文件?
2011-05-25 18:55 5615.so 文件是动态链接库文件,相当于 win下的 .dll ... -
使用Geocoder
2011-05-11 10:46 62127.6 使用Geocoder 地理编 ... -
Gallery学习总结--Cache缓存及数据处理流程
2011-05-09 14:21 2209http://hi.baidu.com/%D6%C7%B4%E ... -
关注的网站
2011-04-06 14:37 1080http://blog.sina.com.cn/s/blog_ ... -
gallery3d源码学习总结(二)
2011-04-01 10:40 3565http://www.j2megame.com/htm ... -
gallery3d源码学习总结(一)——绘制流程drawFocusItems
2011-04-01 10:14 4954eoe·Android开发者门户 标题: gallery3d ... -
Android 启动过程详解(学习1)
2011-03-31 09:27 2252Android 启动过程详解 http://blog.csd ... -
Android中的WatchDog (2)
2011-03-31 09:11 1103http://wenku.baidu.com/view/09c ... -
Android平台WindowManager运用
2011-03-30 10:00 1823Android平台WindowManager运用 我们A ... -
JPEG Rotation and EXIF Orientation
2011-03-17 14:26 3934http://blog.csdn.net/daisyhd/ar ... -
Android 的动作、广播、类别等标识大全
2011-03-11 10:19 1336Android 的动作、广播、类别等标识大全 Stri ... -
浅析Android MediaProvider之二
2011-03-08 08:27 2691http://www.poemcode.net/2010/01 ... -
Task和Activity相关
2011-02-28 09:21 1574Task和Activity相关 这段时间在做一个项目,发 ...
相关推荐
本篇文章将针对Android文件系统的移植进行详细的总结和探讨。 首先,理解Android文件系统的结构至关重要。Android的根文件系统主要由root和system两个目录构成,data目录则通常在设备启动时自动生成并填充内容。...
在Android操作系统中,ExFAT(Extended File Allocation Table)文件系统的移植是一项重要的技术工作,尤其对于需要支持大容量存储如SDXC(Secure Digital eXtended Capacity)卡的应用场景。ExFAT是一种优化了FAT32...
Android系统移植与平台开发涉及到多个方面,包含对Android系统本身的下载、编译、移植过程,以及对开发人员如何针对特定硬件平台进行开发的指导。本篇文档的内容详细描述了Android系统移植与平台开发的前期准备、...
Android系统移植包括三个主要部分:BOOTLOADER引导程序移植、Linux内核移植和Android文件系统移植。应用程序开发则集中在Android平台的软件开发上,包括手机应用程序的开发,这些应用在实用性、稳定性、安全性和可靠...
总之,将exFAT文件系统移植到Android是一项涉及内核编程、用户空间接口设计、系统级集成以及兼容性测试等多个方面的复杂工程。正确实施后,它将极大地提升Android设备在处理大容量存储设备时的性能和灵活性。
Android系统移植技术是一个复杂而精细的过程,涉及到多个层面的工作,包括环境配置、代码编译、设备驱动移植以及系统服务的定制。以下是对标题和描述中所提及知识点的详细解释: 1. **Android系统开发编译环境配置*...
总结起来,Android系统移植涉及Bootloader、内核、驱动、文件系统、UI框架和应用程序等多个层次的工作。每个环节都需要细致入微的调整和优化,才能让Android系统在新的硬件平台上流畅运行。这个过程既是对技术的挑战...
在"android下的exfat文件系统移植"项目中,我们关注的是将exFAT集成到Android系统中,以便设备能够识别并处理exFAT格式的存储介质。这个过程涉及到多个步骤和技术,包括编译、驱动程序开发和系统集成。 1. **exFAT...
在IT领域,Android系统移植是一项复杂且至关重要的工作,它涉及到将Android操作系统适应不同的硬件平台,使其能够在各种设备上运行。这份"Android系统移植技术详解.pdf"文档将为我们揭示这一过程中的关键步骤和技术...
在Android系统中,蓝牙(Bluetooth)模块的移植是一项重要的工作,尤其对于开发和定制设备固件的工程师来说。本文将详细讲解如何移植REALTAK RTL8723BU蓝牙模块到Android系统,以及在此过程中涉及的关键知识点。 ...
在Android系统移植的过程中,涉及到许多复杂的技术环节和步骤。这里我们根据提供的标题“android系统移植资料集锦”和描述,以及标签“android 移植 系统 文档”,可以提炼出一系列关键知识点。 1. **Android系统...
《Dropbear在Android 9.0系统的移植与应用》 Dropbear是一款轻量级的SSH服务器和客户端软件,尤其适用于资源有限的设备,如嵌入式系统和移动设备,如Android。在Android 9.0(Pie)系统上移植Dropbear,能够为设备...
通过以上步骤,可以在Ubuntu下成功配置Samba服务,实现局域网内跨平台文件共享,使得Windows电脑能够像访问本地文件一样访问Linux文件系统中的内容,极大地提高了文件管理的效率和便利性。 综上所述,无论是Android...
SSH移植到Android系统步骤 SSH(Secure Shell)是一种安全的远程登录协议,常用于Linux系统中。但是,Android系统并不具备SSH功能,这篇文章将讲述如何将OpenSSH移植到Android系统中。 Step 1: 获取OpenSSH源码 ...
总的来说,NTFS-3g在Android上的移植是一个技术性强且具有挑战性的过程,它扩展了Android设备对不同文件系统的支持,提高了用户在移动设备上的数据交互能力。对于开发者而言,这不仅是一个学习Linux驱动开发和...
5. 制作Android文件系统:创建和配置Android运行所需的文件系统环境。 完成这些步骤后,便可以验证Android系统在Devkit8000开发板上的运行情况,并进行后续的测试和调试工作。 文章还探讨了Android应用程序开发...
Android系统移植技术是Android开发中的一个重要环节,它涉及到将Android操作系统适配到不同的硬件平台,以便在各种设备上运行。本文将重点解析Android系统移植的关键步骤和技术要点。 首先,进行Android系统移植...