Android 系统启动流程梳理

本文结合网上两篇介绍比较好的文章,梳理Android启动流程,以增加对系统的理解。

Linux启动过程详解:http://blog.csdn.net/caowenbin/article/details/6110751

Android源码学习之八—系统启动过程:http://blog.chinaunix.net/uid-26495963-id-3066282.html

Android源码数量庞大,虽然对它的学习从未停止,但是整理成这样的文字,实在是费时费力的一件事情,不过好在前文已经对其基本机制加以分析,相信以此为基础,其他的内容学习起来就没那么困难了。

今天是2010年的最后一天了,回顾这一年,从手机操作系统的角度来看,我把重点放在了Android上,对Windows Phone和IPhone没有太深入研究,正好以此做一终结,把对Android源码的学习告一段落。从软件工程或项目管理角度来看,今年感触也很多,可能会成为明年的重点吧,希望到时能在软件工程方法、过程、架构设计、项目管理方面也能成些文字以供交流。

做为Android源码学习系列的最后一文,还是应该从大的角度写点东西,想写Parcelable、Binder,也想写WindowsManager、Dialog,或者是系统架构、JNI,最后还是落笔为Android的系统启动过程了,原因是友人问我这方面的问题,于是偷了懒,顺手成文。

 

Android的启动过程可以分为两个阶段,第一阶段是Linux的启动,第二阶段才是Android的启动,下面我们分别来了解一下具体的过程

一、linux启动流程




启动第一步--加载BIOS

当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。

启动第二步--读取MBR
众所周知,硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,别看地方不大,可里面却存放了预启动信息、分区表信息。
系统找到BIOS所指定的硬盘的MBR后,就会将其复制到0×7c00地址所在的物理内存中。其实被复制到物理内存的内容就是Boot Loader,而具体到你的电脑,那就是lilo或者grub了。

启动第三步--Boot Loader
Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备
Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。
我们以Grub为例来讲解吧,毕竟用lilo和spfdisk的人并不多。
系统读取内存中的grub配置信息(一般为menu.lst或grub.lst),并依照此配置信息来启动不同的操作系统。

启动第四步--加载内核
根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。
系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。

启动第五步--用户层init依据inittab文件来设定运行等级
内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。
其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,其设定形式是“:id:5:initdefault:”,这就表明Linux需要运行在等级5上。Linux的运行等级设定如下:
0:关机
1:单用户模式
2:无网络支持的多用户模式
3:有网络支持的多用户模式
4:保留,未使用
5:有网络支持有X-Window支持的多用户模式
6:重新引导系统,即重启
关于/etc/inittab文件的学问,其实还有很多

启动第六步--init进程执行rc.sysinit
在设定了运行等级后,Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。如果你有兴趣,可以到/etc/rc.d中查看一下rc.sysinit文件,里面的脚本够你看几天的

启动第七步--启动内核模块
具体是依据/etc/modules.conf文件或/etc/modules.d目录下的文件来装载内核模块。

启动第八步--执行不同运行级别的脚本程序
根据运行级别的不同,系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。

启动第九步--执行/etc/rc.d/rc.local
你如果打开了此文件,里面有一句话,读过之后,你就会对此命令的作用一目了然:
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don’t
# want to do the full Sys V style init stuff.
rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。你可以把你想设置和启动的东西放到这里。

启动第十步--执行/bin/login程序,进入登录状态
此时,系统已经进入到了等待用户输入username和password的时候了,你已经可以用自己的帐号登入系统了。:)
===
漫长的启动过程结束了,一切都清静了…
其实在这背后,还有着更加复杂的底层函数调用,等待着你去研究…本文就算抛砖引玉了:)
本文参考了如下文章,精炼荟萃而成:
http://bbs.chinaunix.net/thread-835918-1-1.html
http://hi.baidu.com/fembed/blog/item/b9f0881f51145866f624e4be.html
http://baike.baidu.com/view/9485.htm


二、安卓系统的启动

Linux启动,如前所述,Linux的Bootloader,Kernel,Driver之类的,在这里唯一要提到的就是ServiceManager,即服务管理器,这个是做为一个进程在Android加载之前就被启动了,我们可以从init.rc中看到这个配置项:

service servicemanager /system/bin/servicemanager

ServiceManager是Binder的服务管理守护进程,是Binder的核心,由其使用Binder驱动进行IPC管理,关于IPC通讯的机制,此处不再详述。在APP和Framework中,应用程序使用的ServiceManager.Java就是通过Proxy与这个守护进程进行的通讯。

 

然后是Android的启动,接下来要详细描述的部分。我们还是先看一下init.rc中的配置

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

即linux启动以后,启动zygote服务进程,这个进程恰如其名:孵化器,是所有Android应用程序的孵化器。

 

我们来看一下app_process的代码,位置是在:

frameworks/base/cmds/app_process/app_main.cpp

在main()函数中有如下代码:

        if (0 == strcmp("--zygote", arg)) {

            bool startSystemServer = (i < argc) ?

                    strcmp(argv[i], "--start-system-server") == 0 : false;

            setArgv0(argv0, "zygote");

            set_process_name("zygote");

            runtime.start("com.android.internal.os.ZygoteInit",

                startSystemServer);

        }

从中可以追踪到AndroidRuntime,代码位于:

frameworks/base/core/jni/AndroidRuntime.cpp

在start()函数中有如下代码:

    /* start the virtual machine */

    if (startVm(&mJavaVM, &env) != 0)

        goto bail;

         ……

                 env->CallStaticVoidMethod(startClass, startMeth, strArray);

即先启动了虚拟机,然后利用JNI调用了zygoteInit函数。

 

继续追踪到frameworks/base/core/java/com/android/internal/os/ZygoteInit.java的main()函数,代码如下:

            if (argv[1].equals("true")) {

                startSystemServer();

            } else if (!argv[1].equals("false")) {

                throw new RuntimeException(argv[0] + USAGE_STRING);

            }

 

            Log.i(TAG, "Accepting command socket connections");

 

            if (ZYGOTE_FORK_MODE) {

                runForkMode();

            } else {

                runSelectLoopMode();

            }

前一部分是在启动系统服务,后一部分是虽然是一个条件判断,但ZYGOTE_FORK_MODE被赋了false,所以进行else分支的runSelectLoopMode()函数,在该函数中,实际上是在一死循环中利用zygoteConnection类通过socket的方式进行消息处理,用于fork出新的zygote,从而以最轻量级的方式实现每个进程一个虚拟机的机制。

 

继续来看startSystemServer(),代码位于:

frameworks/base/services/java/com/android/server/systemserver.java

在其main()函数中调用了init1(args)这个native函数,利用JNI机制,跟踪至

frameworks/base/services/jni/com_android_server_systemService.cpp,然后到

frameworks/base/cmds/system_server/library/system_init.cpp

在system_init()函数中有如下代码:

    if (strcmp(propBuf, "1") == 0) {

        // Start the SurfaceFlinger

        SurfaceFlinger::instantiate();

    }

    AndroidRuntime* runtime = AndroidRuntime::getRuntime();

 

    LOGI("System server: starting Android services./n");

    runtime->callStatic("com/android/server/SystemServer", "init2");

即完成了SurfaceFlinger的实例化,然后利用运行时的callStatic()函数调用了SystemServer的init2()函数,这个函数位于:

frameworks/base/services/java/com/android/server/SystemServer.java

代码是:

    public static final void init2() {

        Slog.i(TAG, "Entered the Android system server!");

        Thread thr = new ServerThread();

        thr.setName("android.server.ServerThread");

        thr.start();

}

在这个ServerThread线程中,可以看到我们熟悉的Android服务了,比如WallpaperService服务的启动:

            try {

                Slog.i(TAG, "Wallpaper Service");

                wallpaper = new WallpaperManagerService(context);

                ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);

            } catch (Throwable e) {

                Slog.e(TAG, "Failure starting Wallpaper Service", e);

            }

最后,调用各服务的systemReady()函数通知系统就绪。

 

至此,系统的启动过程结束,借用两张图来说明问题:

从这里可以看出,linux的init在启动若干守护进程之后,就启动了Android的runtime和zygote,zygote再启动虚拟机,系统服务,系统服务再启动完本地服务后,又启动了若干Android服务,并完成向ServiceManager的注册工作,最后系统启动完成。系统的进程空间如下图所示:

可见,由zygote孵化器为各进程以写时复制的方式用最小的代价实现了虚拟机。

 

好了,相信经过这一系列的源码跟踪,我们都能对Android的启动过程有更清晰的认识,新年即将到来,在结束本系列文章的同时,祝大家新年快乐。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值