MTD系列 - android平台上linux启动时init进程解析init.rc文件分析

本文详细介绍了Android系统启动过程中init进程如何解析init.rc配置文件,包括如何加载服务和命令,特别是针对yaffs2文件系统的挂载操作进行了分析,涉及到mount命令的执行流程和相关参数解析。
摘要由CSDN通过智能技术生成

题记:
 前段时间,分析linux中的nand驱动,不知不觉就搞到来MTD层,到了MTD层之后还行往上,却发现往上很难继续,
功夫不复有心人呐,终于有些思路,发现MTD设备存在很多用户,什么char,block,ftl,nftl,jffs,yaffs等比较多,
但是并不是所有的用户都经过了MTD的块设备层,比如jffs和yaffs文件系统就时直接建立在MTD的原始设备层之上的。
好奇心强了就会没完没了,想跟踪一下yaffs2文件系统的挂载过程,心有点大了,不过我还是有勇气去跟踪它。
 我手上的项目使用了android系统,这篇文章就上来讲讲android中的init进程所做的事情。当然它所做的事情多来去来,
 这里只涉及和yaffs2相关的一些东西。同时,本文不会详细分析这部分的代码,只看流程。

 * linux2.6.29
 * android2.0
 * 李枝果/lizgo  2010-11-4  lizhiguo0532@163.com
 * 本人水平有限,难免由不妥之处,烦请指正,谢谢!
 
  
 话说在start_kernel()函数中的vfs_caches_init()中将rootfs建立起来后,根文件系统就一直是内存中的这个rootfs,
 直到在内核线程kernel_init中,通过函数populate_rootfs()函数将initrd或者initramfs释放到内存中的rootfs空间中
 去后,至此,rootfs被initrd代替(initrd是文件系统目录使用命令cpio处理后压缩的镜像),这个时候根目录就会呈现
 出initrd原本的目录结构,其中包含一些初始化系统所必须的文件。
 
 这个制作initrd的原始文件系统从那里的来呢?
 当我们在编译完android系统后,会在目录out/target/product/xxx(xxx为你所建工程名字)中出现一个root目录,
 我们可以使用这个目录来制作initrd,下面是我的root目录内容:
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 08:59 data
 -rw-r--r-- 1 lzg lzg    118 2010-08-23 08:59 default.prop
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 08:59 dev
 -rwxr-xr-x 1 lzg lzg 103104 2010-08-23 11:17 init
 -rw-r--r-- 1 lzg lzg   1677 2010-08-19 14:29 init.goldfish.rc
 -rwxr-xr-x 1 lzg lzg   4211 2010-08-02 15:22 init.pxa930.rc
 -rwxr-xr-x 1 lzg lzg  11275 2010-08-02 15:22 init.rc
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 08:59 proc
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 11:19 sbin
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 08:59 sys
 drwxr-xr-x 2 lzg lzg   4096 2010-08-23 08:59 system 
 其中的init是一个elf格式的可执行文件,该文件会在rootfs被initrd替换后得到执行:
 kernel_init内核线程中的init_post()-->run_init_process(init)-->kernel_execve()来创建进程init。
 下面所分析的部分就是init进程的源码,源码位置: system/core/init
 
 main()                // init.c
 --> parse_config_file("/init.rc")   // parser.c
  --> data = read_file(fn, 0);    // 读取文件
  --> parse_config(fn, data);     // 解析文件    ---    较详细的分解看附录内容 
  在解析文件的过程中是不会实际执行的,android这里实际上使用了服务器来统一执行。函数parse_config()函数会
  首先找到init.rc中类似下面的行:
  service mountd /system/bin/mountd
       socket vold stream 0660 root mount   // mountd的源码在system/core/mountd/

    这种就时描述了需要启动一个服务器来做事情,至于什么时候启动,怎么做,做那些事情,都是由后面跟着的选项所
    决定的。该函数将这些服务器找到后组织成struct service的结构体,并且通过该结构体中的挂钩slist将这些服务器
    挂在全局的链表service_list中,同时每找到一个服务器,都会使用函数
    list_init(&svc>onrestart.commands)来初始化该服务器重启的时候需要执行的命令的链表,以备后续挂接网上挂接
    命令结构体。接着解析分析该init.rc文件,遇到command类型的行,会建立struct command类型的命令结构体,
    然后挂在对应服务器的链表头中,等待执行。
     
    比如,我这里关系的mount命令何时执行,那么从上面可以看出,系统将来会启动mountd服务器来执行init.rc中
    所有mount命令。那么对于mount命令对应需要执行的函数时什么呢?这个很容易看出,从keyword.h中就可以看出
    是do_mount()函数。
  
   这里就不继续深入分析这个服务器是怎么建立起来的了,我想,如果知道这个过程后,我们最关心的还是最后执行命令
   的函数吧!接下来我们来看看do_mount()函数吧
    
   先列举一下init.rc文件中关于挂载nand分区的命令:
   # mount mtd partitions
   
    mount yaffs2 mtd@system /system
  
    mount yaffs2 mtd@opl /opl
   
    mount yaffs2 mtd@userdata /data nosuid nodev
    chown system system /data
    chmod 0771 /data

    mount yaffs2 mtd@local /local nosuid nodev
    chown system system /local
    chmod 0777 /local
   
    mount yaffs2 mtd@cache /cache nosuid nodev
    chown system cache /cache
    chmod 0770 /cache
    ...
   
    可以看出这些分区中存放的全是yaffs2文件系统格式的数据。
   
   do_mount()函数在builtins.c文件中实现:
   
static struct {
    const char *name;
    unsigned flag;
} mount_flags[] = {
    { "noatime",    MS_NOATIME },
    { "nosuid",     MS_NOSUID },
    { "nodev",      MS_NODEV },
    { "nodiratime", MS_NODIRATIME },
    { "ro",         MS_RDONLY },
    { "rw",         0 },
    { "remount",    MS_REMOUNT },
    { "defaults",   0 },
    { 0,            0 },
};

/* mount <type> <device> <path> <flags ...> <options> */
int do_mount(int nargs, char **args)
{
    char tmp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值