记录自己学习android系统启动以及 recovery过程(2)----------kernel
来源:互联网 发布:什么软件可以越狱的 编辑:程序博客网 时间:2024/04/29 02:06
记录自己学习android系统启动以及 recovery过程(1)----------kernel
kernel阶段,代码比较复杂,才看懂基本流程。。。。。
在kernel阶段,会根据传递进来的参数,进行初始化并挂载root
1. uboot->kernel的参数解析模式
解析tag函数流程: start_kernel->setup_arch->parse_tags
以initrc举例,在uboot中,配置函数为:
static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end){/* an ATAG_INITRD node tells the kernel where the compressed * ramdisk can be found. ATAG_RDIMG is a better name, actually. */params->hdr.tag = ATAG_INITRD2;params->hdr.size = tag_size (tag_initrd);params->u.initrd.start = initrd_start;params->u.initrd.size = initrd_end - initrd_start;params = tag_next (params);}
在kernel中,存在相应的解析函数:
static int __init parse_tag_initrd2(const struct tag *tag){phys_initrd_start = tag->u.initrd.start;phys_initrd_size = tag->u.initrd.size;return 0;}__tagtable(ATAG_INITRD2, parse_tag_initrd2);可以看到,这两个函数都使用到了相同的宏ATAG_INITRD2,在kernel中,__tagtable标志使得ATAG_INITRD2, parse_tag_initrd2被注册进了一个结构体tagtable,并在解析tag时,通过比较相应的宏是否一致,调用注册的函数进行解析
在上述函数中:phys_initrd_start,phys_initrd_size是被初始化为0的,因此,当传进来的tag中,不含有ATAG_INITRD2时,这两个变量均等于0。
2. 初始化rootfs文件系统
初始化rootfs文件系统流程:start_kernel->vfs_caches_init->mnt_init
mnt_init函数如下:
void __init mnt_init(void){......init_rwsem(&namespace_sem);......err = sysfs_init();......fs_kobj = kobject_create_and_add("fs", NULL);......init_rootfs(); /*注册rootfs文件系统*/init_mount_tree(); /*这步执行结束后,文件系统中存在目录‘/’,以后的文件系统,会挂载在这个目录下*/}init_rootfs:
int __init init_rootfs(void){int err;err = bdi_init(&ramfs_backing_dev_info);if (err)return err;err = register_filesystem(&rootfs_fs_type); /*rootfs 结构体*/if (err)bdi_destroy(&ramfs_backing_dev_info);return err;}rootfs结构体:
static struct file_system_type rootfs_fs_type = {.name= "rootfs",.get_sb= rootfs_get_sb, /*在mount rootfs时,会用到*/.kill_sb= kill_litter_super,};执行完init_rootfs后,完成了系统中的kobject以及filesystem中rootfs相关的注册
init_mount_tree函数执行流程: init_mount_tree->do_kern_mount->vfs_kern_mount->rootfs_get_sb(type->get_sb)->ramfs_fill_super->d_alloc_root
d_alloc_root函数:
/** * d_alloc_root - allocate root dentry * @root_inode: inode to allocate the root for * * Allocate a root ("/") dentry for the inode given. The inode is * instantiated and returned. %NULL is returned if there is insufficient * memory or the inode passed is %NULL. */ struct dentry * d_alloc_root(struct inode * root_inode){struct dentry *res = NULL;if (root_inode) {static const struct qstr name = { .name = "/", .len = 1 };res = d_alloc(NULL, &name);if (res) {res->d_sb = root_inode->i_sb;res->d_parent = res;d_instantiate(res, root_inode);}}return res;}
这个函数看注释知道干嘛,具体执行过程,暂时不了。。。。
此时,rootfs的初始化,在文件系统中已经存在‘/'目录,并在后续用来mount 需要加载的其他文件系统
3. ramdisk
ramdisk执行流程:start_kernel->rest_init->kernel_init
kernel_init函数:
static int __init kernel_init(void * unused){/* * Wait until kthreadd is all set-up. */wait_for_completion(&kthreadd_done);lock_kernel();/* * init can allocate pages on any node */set_mems_allowed(node_states[N_HIGH_MEMORY]);/* * init can run on any cpu. */set_cpus_allowed_ptr(current, cpu_all_mask);/* * Tell the world that we're going to be the grim * reaper of innocent orphaned children. * * We don't want people to have to make incorrect * assumptions about where in the task array this * can be found. */init_pid_ns.child_reaper = current;cad_pid = task_pid(current);smp_prepare_cpus(setup_max_cpus);do_pre_smp_initcalls(); /*这个函数对注册的initcall进行一次执行,其中包含populate_rootfs*/start_boot_trace();smp_init();sched_init_smp();printk(KERN_INFO "$$$do_basic_setup start\n");do_basic_setup();printk(KERN_INFO "$$$do_basic_setup end\n");/* Open the /dev/console on the rootfs, this should never fail */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);/* * check if there is an early userspace init. If yes, let it do all * the work */ /*查看ramdisk需要执行的函数或者cmd*/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(); /*当当前的目录下,没有/init可以执行,则调用这个函数,cmdline传递进来的(root=/dev/mmcblk0px)就是这一步被正确挂载的*/}/* * 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(); /*执行当前目录下的/init函数*/return 0;}populate_rootfs函数:
static int __init populate_rootfs(void){[1]char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start);if (err)panic(err);/* Failed to decompress INTERNAL initramfs */[2]if (initrd_start) {#ifdef CONFIG_BLK_DEV_RAMint fd;printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start);if (!err) {free_initrd();return 0;} else {clean_rootfs();unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start);}printk(KERN_INFO "rootfs image is not initramfs (%s)""; looks like an initrd\n", err);fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);if (fd >= 0) {sys_write(fd, (char *)initrd_start,initrd_end - initrd_start);sys_close(fd);free_initrd();}#elseprintk(KERN_INFO "Unpacking initramfs...\n");[3]err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start);if (err)printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);free_initrd();#endif}return 0;}
这个函数详细功能:
[1] __initramfs_start, __initramfs_end这个变量是在link script里面定义的,编译进linux内核的ramdisk部分,如果存在,则解压在'/'下
[2] initrd_start是通过tags函数得到的phys_initrd_start,进行PA->VA后的虚拟地址,流程是start_kernel->setup_arch->paging_init->bootmem_init->bootmem_reserve_initrd。因此可知,在uboot传递进initrd tag时,会得到有效地initrd_start,否则无效
[3](什么是CPIO?。。。)同理,解压传递进来的initrd至'/'
在kernel_init函数中,当执行sys_access函数,如果当前目录下没有/init,就执行prepare_namespace函数。
正常boot模式下,挂载的ramdisk是由system.img编译而来,在root目录下,存在/init,但是,当设置为recovery是,由于不存在ramdisk,因此,此时需要执行prepare_namespace函数。
prepare_namespace函数:
/* * Prepare the namespace - decide what/where to mount, load ramdisks, etc. */void __init prepare_namespace(void){int is_floppy;if (root_delay) {printk(KERN_INFO "Waiting %dsec before mounting root device...\n", root_delay);ssleep(root_delay);}/* * wait for the known devices to complete their probing * * Note: this is a potential source of long boot delays. * For example, it is not atypical to wait 5 seconds here * for the touchpad of a laptop to initialize. */wait_for_device_probe();md_run_setup();if (saved_root_name[0]) {[1]root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) || !strncmp(root_device_name, "ubi", 3)) {mount_block_root(root_device_name, root_mountflags);goto out;}[2]ROOT_DEV = name_to_dev_t(root_device_name);[3]if (strncmp(root_device_name, "/dev/", 5) == 0)root_device_name += 5;}[4]if (initrd_load())goto out;/* wait for any asynchronous scanning to complete */if ((ROOT_DEV == 0) && root_wait) {printk(KERN_INFO "Waiting for root device %s...\n",saved_root_name);while (driver_probe_done() != 0 ||(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)msleep(100);async_synchronize_full();}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0))ROOT_DEV = Root_RAM0;[5]mount_root();out:devtmpfs_mount("dev");[6]sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");}[1] 其中的saved_root_name由来:系统注册的commandline函数,解析’root=‘关键字:如下
static int __init root_dev_setup(char *line){strlcpy(saved_root_name, line, sizeof(saved_root_name));return 1;}__setup("root=", root_dev_setup);[2]得到设备号
[3]此时root_device_name就是“mmcblk0px”
[4]initrd_load 后续详细研究,似乎是读取/initrd.image不成功,返回0
[5]mount_root 将ROOT_DEV上的文件mount到/root目录下,mount过程如下:mount_root->mount_block_root->do_mount_root->sys_mount
执行结束后,通过函数
[6]mount当前目录为根目录,替换rootfs,因此,此时目录下,存在/init
4.init_post
init_post函数:
/* 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 noinline int init_post(void)__releases(kernel_lock){/* need to finish all async __init code before freeing the memory */async_synchronize_full();free_initmem();unlock_kernel();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();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. " "See Linux Documentation/init.txt for guidance.");}
[1]执行ramdisk_execute_command,
此时,由于ramdisk_execute_command所指向的/init,在system image和recovery image两种模式下,并不一样
执行结果就是,一个执行system,一个执行recovery
综上:
在kernel启动后
1.会对uboot传递进来的参数进行分析,并对相应的变量初始化
2.挂载root,此处对ramdisk的挂载模式进行区分。
3.执行root目录下的/init
- 记录自己学习android系统启动以及 recovery过程(2)----------kernel
- 记录自己学习android系统启动以及 recovery过程(1)----------uboot
- 记录自己学习android系统启动以及 recovery过程(3)----------factory data reset -> reboot
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程-uBoot+Kernel+Android
- Android系统启动过程---uboot,kernel,android
- 转载:Android系统启动过程uboot--kernel--Android
- Android系统启动过程-uBoot+Kernel+Android
- Android系统启动过程-uBoot+Kernel+Android
- Android系统启动过程学习
- Android源码学习-系统启动过程
- Android系统启动过程(转)
- (转)Android系统启动过程
- Android 5.0内核和源代码学习(2)——源码下载和系统启动过程分析
- Android源码学习—系统启动过程
- 记录自己学习的过程!!!
- tomcat处理session(转载)
- 软件项目开发的文档编写标准化
- java事件机制及自定义事件处理
- Linux kernel logo
- 使用adb push命令返回Read-only file system解决方法
- 记录自己学习android系统启动以及 recovery过程(2)----------kernel
- 如何给access文件加密码
- Lua语言教程2
- 黑马程序员_java入门_函数,重载,重写
- Javascript面向对象编程(二):构造函数的继承
- apktool 打包出错解决办法
- 关于VMware虚拟机的上网
- 2013-2-20 疑问 cs 父窗体中axWindowsMediaPlayer是完整显示模式,单独窗体中是精简显示模式
- Linux下system()函数引发的错误