【Android底层学习总结】2. 安卓系统内核的Bring Up

1 前言

上节我们学习了驱动开发基础,这节我们继续学习,这节我们主要来了解安卓系统是怎么启动的,以及内核的初始化工作。

2 简介

Android采用分层的架构设计,从高到低分别是应用层,Java API 框架层,系统运行层(包括Android Runtime和原生态的C/C++库)、硬件抽象层、Linux内核层。而我们这篇文章将从上电讲到Kernel的启动,大致流程如下。

Boot Rom Boot Loader Kernel 上电加载 初始化启动 Boot Rom Boot Loader Kernel

3 启动流程

3.1 上电

首先,得要给板子上电才会有后面的事情,一般的个人电脑上电后会加载BIOS进行初始化然后跳入到系统,具体过程就是将非易失性存储器中的系统内核拷贝到RAM执行init代码从而启动内核。安卓作为ARM架构的一个操作系统和个人电脑有所不同,但总体原理一致。
在安卓中,上电后在PC(程序计数器)中取得的第一个地址指向的是Boot Rom(比如Flash)中的第一段程序Bootloader(Boot Loader有很多种,这里不展开讲),然后由Bootloader将内核镜像拷贝至运存,然后启动内核的第一行代码。

3.2 Boot Loader

Boot Loader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序,其作用类似于 PC 机上的 BIOS。 不同的处理器上电或复位后执行的第一条指令地址并不相同,对于 ARM 处理器来说,该地址为 0x00000000。对于一般的嵌入式系统,通常把 Flash 等非易失性存储器映射到这个地址处,而 Boot loader就位于该存储器的最前端,所以系统上电或复位后执行的第一段程序便是Bootloader.

Boot Loader启动后接下来要做的事主要分下面几个步骤:

  1. 初始化 RAM
    因为 Linux 内核一般都会在 RAM 中运行,所以在调用 Linux 内核之前 boot loader 必须设置和初始化 RAM,为调用 Linux内核做好准备。初始化 RAM 的任务包括设置CPU 的控制寄存器参数,以便能正常使用 RAM以及检测RAM大小等。
  2. 初始化串口
    串口在 Linux 的启动过程中有着非常重要的作用,它是 Linux内核和用户交互的方式之一。Linux 在启动过程中可以将信息通过串口输出,这样便可清楚的了解 Linux 的启动过程。虽然它并不是 Bootloader 必须要完成的工作,但是通过串口输出信息是调试Bootloader 和Linux内核的强有力的工具,所以一般的 Bootloader 都会在执行过程中初始化一个串口做为调试端口。
  3. 检测处理器类型
    Bootloader在调用 Linux内核前必须检测系统的处理器类型,并将其保存到某个常量中提供给 Linux 内核。Linux 内核在启动过程中会根据该处理器类型调用相应的初始化程序
  4. 设置linux启动参数
  5. 调用linux内核映像
    Bootloader完成的最后一项工作便是调用 Linux内核。如果 Linux 内核存放在 Flash 中,并且可直接在上面运行(这里的 Flash 指 Nor Flash),那么可直接跳转到内核中去执行。但由于在 Flash 中执行代码会有种种限制,而且速度也远不及 RAM 快,所以一般的嵌入式系统都是将 Linux内核拷贝到 RAM 中,然后跳转到 RAM 中去执行。

以上步骤是bootloader的一般动作(上述BootLoader功能的内容转自此链接),实际上由于芯片厂商的不同,Bootloader的具体工作也是不同的,有些会在启动Kernel前执行安全固件的程序进行安全检查,然后启动little kernel,最后再由little kernel启动Kernel.

3.3 Kernel的初始化

内核的启动主要分为以下几个步骤:

  1. 检查硬件和CPU类型
  2. 初始化堆栈、MMU(Memory Management Unit的缩写,中文名是内存管理单元,它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件)等程序.
  3. 初始化各种模块
  4. 挂接根文件系统
  5. 执行init程序,启动关键服务Zygote
    注:在Android系统中,zygote所有应用进程的父进程,app的进程都是由这个zygote分裂出来的。zygote则是由Linux系统用户空间的第一个进程init进程,通过fork的方式创建的。
    以上过程的代码可以在kernel的init文件夹中main.c文件中进行了解,以下贴出不完全的start_kernel函数。注kernel版本:4.9
asmlinkage __visible void __init start_kernel(void)
{
	char *command_line; // 命令行,用来存放 bootloader 传递过来的参数
	char *after_dashes;
	
	/* 函数参数:init_task即手工创建的PCB,0号进程就是最终的idle进程,它是个结构体:struct task_struct init_task = INIT_TASK(init_task);
	INIT_TASK 是一个宏用来设置拼接第一个PCB,Base=0, limit=0x1fffff (=2MB)
	
	函数功能:获取栈边界地址,然后把 STACK_END_MAGIC这个宏设置为栈溢出的标志。
	*/
	set_task_stack_end_magic(&init_task);
	/*针对SMP处理器,用于获取当前CPU的硬件ID ,如果不是多核,函数为空*/
	smp_setup_processor_id();
	/*初始化哈希桶 (hash buckets) 并将 static object 和 pool object 放 入 poll 列表,这样堆栈就可以完全操作了 【这个函数的主要作用就是对调试对象进行早期的初始化,就是HASH锁和静态对象池进行初始化,执行完后,object tracker已经开始完全运作了*/
	debug_objects_early_init();

	/*
	 * 初始化堆栈保护的加纳利值,防止栈溢出攻击的堆栈保护关键字
	 */
	boot_init_stack_canary();

	/*在系统启动时初始化 cgroups ,同时初始化需要 early_init 的子系统 
	【这个函数作用是控制组 (control groups) 早期的初始化,
	控制组就是 定义一组进程具有相同资源的占有程度,
	比如,可以指定一组进程使用 CPU 为 30% ,磁盘 IO 为 40% ,网络带宽为 50%,
	目的就是为了把所有进程分配不同的资源*/
	cgroup_init_early();

	/*关闭当前CPU的所有中断响应,操作CPSR寄存器。对应后面的系统中断关闭标志,当early_init完毕后,会恢复中断设置标志为false 。*/
	local_irq_disable();
	early_boot_irqs_disabled = true;

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
	boot_cpu_init();
	page_address_init();
	pr_notice("%s", linux_banner);

	/*内核架构相关初始化函数,是非常重要的一个初始化步骤。
	其中包含了处理器相关参数的初始化、内核启动参数 (tagged list)的获取
	和前期处理、内存子系统的早期初始化(bootmem 分配器)*/
	setup_arch(&command_line);
	...
	page_alloc_init();
	...

	/*初始化中断向量*/
	trap_init();
	/*内存管理模块初始化*/
	mm_init();
	
	 /*调度模块初始化*/
	sched_init();
	...
	/*剩下的初始化工作*/
	rest_init();
}

对于start_kernel最后一行,对于我们后续研究比较重要
现在我们跟随源码在main.c文件中依次进入以下函数:

rest_init->
	kernel_thread(kernel_init, NULL, CLONE_FS)->
		kernel_init->
			kernel_init_freeable()->
				do_basic_setup():
	/* 到这一步,系统的内核初始化就已经差不多完成了,CPU 的子系统已经启动并运行, 
	且内存和处理器管理系统已经在工作了。但还有些设置未完成,这些
	设置对于驱动工程师比较重要,特别是driver_init和do_initcalls函数
	*/
	static void __init do_basic_setup(void)
	{
		// 针对SMP系统,初始化内核control group的cpuset子系统。如果非SMP,此函数为空。  
		cpuset_init_smp();
		shmem_init();
		// 初始化驱动模型中的各子系统,可见的现象是在/sys中出现的目录和文件 
		driver_init();
		// 在proc文件系统中创建irq目录,并在其中初始化系统中所有中断对应的目录。
		init_irq_proc();
		// 调用链接到内核中的所有构造函数,也就是链接进.ctors段中的所有函数。
		do_ctors();
		// 启用用户态的帮助器
		usermodehelper_enable();
		// 调用所有编译内核的驱动模块中的初始化函数。
		do_initcalls();
	}

至此我们本节的内容基本结束,内核也完成了初始化,至于更多的内容需要对源码进行更深的研究,后期有机会会出几篇特定的源码解析。

4 总结

本节,主要研究了安卓系统内核从上电到启动之后初始化的全过程,并对一些函数进行了解析,但还不够完善,一些比较重要的函数源码还没有进行研究,下节将对driver_init进行深入研究。

本系列链接传送:
【Android底层学习总结】1. 驱动开发基础
【Android底层学习总结】3. 内核中driver_init函数源码解析

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 《Android底层开发技术实战详解:内核、移植和驱动(第2版)》是一本介绍Android底层开发技术的书籍,该书全面讲解了Android操作系统内核、移植和驱动方面的知识。 首先,该书详细解析了Android底层开发中的内核技术。内核是操作系统的核心部分,负责管理硬件资源、进程调度、内存管理等功能。该书介绍了Android内核的架构和组成,深入解析了Android内核的关键技术,包括进程管理、内存管理、设备驱动等内容,读者可以通过学习这些知识来深入了解Android系统的内部工作原理。 其次,该书还详细讲解了Android系统的移植技术。移植是将一个操作系统或软件从一个平台移植到另一个平台的过程。Android系统可以在不同的硬件平台上运行,这需要进行相应的移植工作。该书介绍了Android系统的移植流程和方法,包括硬件支持、设备树、引导和启动流程等方面的内容,为读者提供了实践移植Android系统的指导。 最后,该书还详细介绍了Android系统中驱动的开发技术。驱动是将硬件与操作系统连接的桥梁,它负责驱动硬件设备,使之能够与操作系统进行交互。该书介绍了Android系统驱动的基本原理和开发方法,包括字符设备驱动、块设备驱动、网络设备驱动等方面的内容,读者可以通过学习这些知识来了解Android系统中驱动的实现原理和开发技巧。 《Android底层开发技术实战详解:内核、移植和驱动(第2版)》是一本深入探讨Android底层开发的专业书籍,读者通过学习这本书可以系统地了解Android底层开发的相关知识,为掌握Android系统的工作原理和进行底层开发提供了重要的参考。 ### 回答2: 《Android底层开发技术实战详解:内核、移植和驱动(第2版)》是一本专注于Android底层开发的技术实战指南。本书主要讲解了Android系统内核、移植和驱动开发相关的知识和实践经验。 首先,本书深入介绍了Android内核的基本原理和开发技术。内核Android系统的核心组件,涉及到系统的运行机制、进程管理、内存管理和设备驱动等重要模块。通过学习内核的原理和开发技术,读者可以更好地理解Android系统的运行机制和优化方法。 其次,本书详细讲解了Android系统的移植技术。移植是将Android系统适配到不同硬件平台上的过程,包括处理器架构、硬件接口、设备驱动和文件系统等方面的适配工作。通过学习本书的内容,读者可以全面了解Android系统的移植原理和实践步骤,提高系统适配的效率和成功率。 最后,本书还介绍了Android设备驱动程序的开发技术。设备驱动是Android系统与硬件设备之间的桥梁,负责控制和管理外设的访问。本书通过实际案例,讲解了Android设备驱动的编写和调试技巧,帮助读者掌握设备驱动开发的方法和技巧。 总之,本书通过深入浅出的方式,详细介绍了Android底层开发的核心知识和实战经验。无论是对于Android系统开发者还是对于对Android底层感兴趣的读者来说,本书都是一本不可多得的参考书籍,可帮助读者更好地理解和应用Android底层开发技术。 ### 回答3: 《Android底层开发技术实战详解:内核、移植和驱动(第2版)》是一本关于Android底层开发技术的实践指南。 这本书首先介绍了Android操作系统的基本架构和内核的相关知识,包括Linux内核Android系统的关系,以及Android的启动过程和内核的工作原理。读者可以了解到Android系统是如何工作的,为之后的实践奠定了基础。 接下来,书中详细介绍了Android的移植过程。移植是将Android系统适配到不同硬件平台的过程,这本书将详细讲解如何进行移植工作,包括硬件支持、设备树和启动流程等内容。读者可以学习到如何将Android系统移植到特定的硬件平台上。 最后,书中还讲解了Android的驱动开发。驱动是连接硬件和操作系统的桥梁,本书将介绍Android系统中不同种类的驱动开发,包括字符设备驱动、块设备驱动和图形设备驱动等。读者可以学习到如何编写驱动程序来支持不同的硬件设备。 整本书的内容结构清晰,循序渐进地介绍了Android底层开发的关键技术。通过实践案例和详细的代码示例,读者可以更深入地理解和掌握Android底层开发的技术和方法。无论是对于想要从事Android底层开发的初学者,还是已经从事相关工作的开发者来说,这本书都是一本不可或缺的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值