详解Android系统启动过程

计算机是如何启动的

计算机的硬件包括:CPU,内存,硬盘,显卡,显示器,键盘鼠标等输入输出设备。所有的软件都是存放在硬盘中,程序执行时,需要将程序从硬盘上读取到内存中,然后加载到CPU中来运行。当按下开机键时,内存中什么都没有,因此需要借助某种方式,将操作系统加载到内存中,而完成这项任务的就是BIOS。

引导阶段

BIOS:BIOS是主板芯片上的一个程序,计算机通电后,第一件事情就是读取BIOS。

BIOS首先进行硬件检测,检查计算机硬件能否满足运行的基本条件。如果硬件出现问题,主板发出不同的蜂鸣声,启动停止。如果没有问题,屏幕会显示CPU,内存,硬盘等信息。

硬件自检完成后,BIOS将控制权交给下一个阶段的启动程序。这时候BIOS需要知道下一个启动程序存放在哪个设备中。也就是BIOS需要一个外部存储设备的排序。优先交给排在前面的设备。这就是我们在BIOS中设置的启动排序。

当第一个存储设备被激活后,设备读取设备的第一个扇区,也就是前512字节。如果这512个字节的最后两个字节是0x55和0xAA,表明设备是可以用作系统启动的。如果不是,那么就会顺序启动下一个设备。

这前512个字节,就叫做“主引导记录”(缩写MBR)。它负责磁盘操作系统对硬盘进行读写时分区合法型判断、分区引导信息定位。MBR不属于任何一个CIA做系统,它先于操作系统而被调入内存,并发挥作用。然后才将控制权交给主分区内的操作系统,并用主分区信息来管理硬盘。

MBR主要作用是告诉计算机到硬盘的哪个位置去找操作系统。计算机从MBR中读取前446字节的机器码后,不再转交控制权,而是运行实现安装的“启动管理器”(boot loader),由用户选择启动哪个操作系统。

加载内核阶段

选择完操作系统以后,控制权交给操作系统,操作系统内核被载入内存。

以Linux为例,先载入/boot下面的kernel。内核加载完成后,运行第一个程序 /sbin/init。它根据配置文件产生init进程。它是Linux启动后的第一个进程,pid为1.其他进程都是它的后代。

然后init线程加载系统的各个模块。比如:窗口程序和网络程序,直至执行/bin/login程序执行,跳出登录页面,等待用户输入用户名密码。

至此,系统启动完成。

Android的启动过程

Android是基于Linux系统的。但是 它没有BIOS程序,取而代之的是BootLoader(系统启动加载器)。类似于BIOS,在系统加载前,用于初始化硬件设备,最终调用系统内核准备好环境。在Android中没有硬盘,而是ROM,类似于硬盘存放操作系统,用户程序等。ROM跟硬盘一样也会划分为不同的区域,用于放置不同的程序,在Android中主要划分为以下几个区域:

/boot :存放引导程序,包括内核和内存操作程序
/system:相当于电脑C盘,存放Android系统和系统应用
/recover:回复分区。可以进入该分区进行系统回复
/data:用户数据区,包含了用户的数据:联系人、短信、设置、用户安装的程序
/cache:安卓系统缓存区,保存系统经常访问的数据和应用程序
/misc:杂项内容
/sdcard:用户自己的存储区域。存放照片视频等
Android系统启动跟PC相似。当开机时,首先加载BootLoader,BootLoader会读取ROM找到系统并将内核加载进RAM中。

当内核启动后会初始化各种软硬件环境,加载驱动程序,挂载跟文件系统。最后阶段会启动执行第一个用户空间进程init进程。

init进程

init是用户的第一个进程,pid=1。kernal启动后会调用/system/core/init/init.cpp的main()方法。

int main(int argc,char ** argv){
 ...
 if(is_first_stage){
  //创建和挂在启动所需要的文件目录
  mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755");
  mkdir("/dev/pts",0755);
  //创建和挂在很多...
  ...
 }
 ...
 //对属性服务进行初始化
 property_init();
 ...
 //用于设置子进程信号处理函数(如Zygote),如果子进程异常退出,init进程会调用该函数中设定的信号处理函数来处理
 signal_handler_init();
 ...
 //启动属性服务
 start_property_service();
 ...
 //解析init.rc配置文件
 parser.ParseConfig("/init.rc");
}

首先初始化 Kernel log,创建一块共享的内存空间,加载 /default.prop 文件,解析 init.rc 文件。

init.rc 文件

init.rc 文件是 Android 系统的重要配置文件,位于 /system/core/rootdir/ 目录中。 主要功能是定义了系统启动时需要执行的一系列 action 及执行特定动作、设置环境变量和属性和执行特定的 service。

init.rc 脚本文件配置了一些重要的服务,init 进程通过创建子进程启动这些服务,这里创建的 service 都属于 native 服务,运行在 Linux 空间,通过 socket 向上层提供特定的服务,并以守护进程的方式运行在后台。

通过 init.rc 脚本系统启动了以下几个重要的服务:

  • service_manager:启动 binder IPC,管理所有的 Android 系统服务
  • mountd:设备安装 Daemon,负责设备安装及状态通知
  • debuggerd:启动 debug system,处理调试进程的请求
  • rild:启动 radio interface layer daemon 服务,处理电话相关的事件和请求
  • media_server:启动 AudioFlinger,MediaPlayerService 和 CameraService,负责多媒体播放相关的功能,包括音视频解码
  • surface_flinger:启动 SurfaceFlinger 负责显示输出
  • zygote:进程孵化器,启动 Android Java VMRuntime 和启动 systemserver,负责 Android 应用进程的孵化工作 在这个阶段你可以在设备的屏幕上看到 “Android” logo 了。

以上工作执行完,init 进程就会进入 loop 状态。

service_manager 进程

ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder 服务。ServiceManager 进程主要是启动 Binder,提供服务的查询和注册。

surface_flinger 进程

SurfaceFlinger 负责图像绘制,是应用 UI 的和兴,其功能是合成所有 Surface 并渲染到显示设备。SurfaceFlinger 进程主要是启动 FrameBuffer,初始化显示系统。

media_server 进程

MediaServer 进程主要是启动 AudioFlinger 音频服务,CameraService 相机服务。负责处理音频解析播放,相机相关的处理。

Zygote 进程

zygote有两个作用:启动systemService和孵化应用进程。

Zygote 进程孵化了所有的 Android 应用进程,是 Android Framework 的基础,该进程的启动也标志着 Framework 框架初始化启动的开始。

Zygote启动主要调用app_main.cpp的main()中的AppRuntime的start方法来启动Zygote进程

int main(int argc,char* const argv[]){
 while( i < argc ){
  const char* arg=argv[i++];
  if(strcmp(arg,"--zygote")==0){
   //如果当前进程在Zygote中,则设置zygote=true
   zygote=true;
   niceName=ZYGOTE_NICE_NAME;
  }else if(strcmp(arg,"--start-system-server")==0){
   //如果当前进程在SystemServer中,将startSystemServer=true
   startSystemServer=true;
  }
 }
 //承接上面Init进程中的代码
 if(zygote){
  //启动Zygote进程
  runtime.start("com.android.internal.os.ZygoteInit",args,zygote);
 }
}

Zygote 服务进程的主要功能:

  • 注册底层功能的 JNI 函数到虚拟机
  • 预加载 Java 类和资源
  • fork 并启动 system_server 核心进程
  • 作为守护进程监听处理“孵化新进程”的请求

当 Zygote 进程启动后, 便会执行到 frameworks/base/cmds/app_process/App_main.cpp 文件的 main() 方法。

system_server 进程

system_server 进程 由 Zygote 进程 fork 而来。

//首先会调用 ZygoteInit.startSystemServer() 方法
ZygoteInit.startSystemServer()
//fork 子进程 system_server,进入 system_server 进程。
ZygoteInit.handleSystemServerProcess()
//设置当前进程名为“system_server”,创建 PathClassLoader 类加载器。
RuntimeInit.zygoteInit()
//重定向 log 输出,通用的初始化(设置默认异常捕捉方法,时区等),初始化 Zygote -> nativeZygoteInit()。
nativeZygoteInit()
//方法经过层层调用,会进入 app_main.cpp 中的 onZygoteInit() 方法。
app_main::onZygoteInit()// 启动新 Binder 线程。
applicationInit() 

//方法经过层层调用,会抛出异常 ZygoteInit.MethodAndArgsCaller(m, argv), ZygoteInit.main() 会捕捉该异常。
ZygoteInit.main() 

//开启 DDMS 功能,preload() 加载资源,预加载 OpenGL,调用 SystemServer.main() 方法。

SystemServer.main()
//先初始化 SystemServer 对象,再调用对象的 run() 方法。

SystemServer.run()
//准备主线程 looper,加载 android_servers.so 库,该库包含的源码在 frameworks/base/services/ 目录下。

system_server 进程启动后将初始化系统上下文(设置主题),创建系统服务管理 SystemServiceManager,然后启动各种系统服务

startBootstrapServices(); // 启动引导服务
//该方法主要启动服务 ActivityManagerService,PowerManagerService,LightsService,DisplayManagerService,PackageManagerService,UserManagerService。
//设置 ActivityManagerService,启动传感器服务。

startCoreServices();  // 启动核心服务
//该方法主要
//启动服务 BatteryService 用于统计电池电量,需要 LightService。
//启动服务 UsageStatsService,用于统计应用使用情况。
//启动服务 WebViewUpdateService。

startOtherServices();  // 启动其他服务
//该方法主要启动服务 InputManagerService,WindowManagerService。
//等待 ServiceManager,SurfaceFlinger启动完成,然后显示启动界面。
//启动服务 StatusBarManagerService,
//准备好 window, power, package, display 服务:
//	- WindowManagerService.systemReady()
//	- PowerManagerService.systemReady()
//	- PackageManagerService.systemReady()
//	- DisplayManagerService.systemReady()

所有的服务启动后会注册到ServiceManager。

ActivityManagerService 服务启动完成后,会进入 ActivityManagerService.systemReady(),然后启动 SystemUI,WebViewFactory,Watchdog,最后启动桌面 Launcher App。

最后会进入循环 Looper.loop()。

ActivityManagerService 启动

启动桌面 Launcher App 需要等待 ActivityManagerService 启动完成。我们来看下 ActivityManagerService 启动过程。

ActivityManagerService(Context)
//创建名为“ActivityManager”的前台线程,并获取mHandler。
//通过 UiThread 类,创建名为“android.ui”的线程。
//创建前台广播和后台广播接收器。
//创建目录 /data/system。
//创建服务 BatteryStatsService。

ActivityManagerService.start() //启动电池统计服务,创建 LocalService,并添加到 LocalServices。

ActivityManagerService.startOtherServices() -> installSystemProviders()
//安装所有的系统 Provider。

ActivityManagerService.systemReady()
//恢复最近任务栏的 task。
//启动 WebView,SystemUI,开启 Watchdog,启动桌面 Launcher App。
//发送系统广播。

启动桌面 Launcher App,首先会通过 Zygote 进程 fork 一个新进程作为 App 进程,然后创建 Application,创建启动 Activity,最后用户才会看到桌面。

完整的启动流程图

源码解析项目地址:github.com/kailaisi/an…

以上就是详解Android系统启动过程的详细内容,更多关于Android系统启动过程的资料请关注我们其它相关文章!

时间: 2021-03-28

Android使用 Coroutine + Retrofit打造简单的HTTP请求库

基于 kotlin/coroutine/retrofit/jetpack 打造,100来行代码,用法超级简单舒适 设置默认Retrofit工厂和全局错误处理程序 HttpCall.init(retrofitFactory = { // ... }, errorHandler = { throwable -> // ... }) 基本用法 data class Reault(val data:String) interface TestService { @GET("test")

Android如何实现动态滚动波形图(心电图)功能

一.前言 最近涉及的某个医疗相关的业务,传感器数据传递上来需要实现示波器的效果,心电图的效果,目前交付效果还算理想,于是封装了一下,方便自己以后使用,也给大家分享一下 二.效果图 图一是心电图效果,图二是一个滚动的波形图 三.功能实现 (一)绘制背景网格 为了让他看上去像示波器上的数据,我们先绘制一层网格背景,看上去似乎就有那么点意思了 在onLayout函数中获取控件宽高,然后除以默认网格的宽高,得出需要绘制横线和竖线的数量 /** 根据网格的单位长宽,获取能绘制网格横线和竖线的数量*/ gr

Android LiveData使用需要注意的地方

关于LiveData是什么以及基本使用方式,请参考官方文档:developer.android.com/topic/libra- 简单来说,LiveData是一个可被观察的数据容器类.它将数据包装起来,使得数据成为"被观察者",页面成为"观察者".当ViewModel存放页面所需要的各种数据发生变化时,通过LiveData的方式实现对页面的通知,完成ViewModel与页面组件之间的通信. 那么在使用时发现有以下几个地方需要注意: 1.回调通知 LiveData的观

Android 侧滑抽屉菜单的实现代码

侧滑抽屉菜单 前言正文一.创建项目二.添加滑动菜单三.UI美化四.添加导航视图五.菜单分类六.动态菜单七.源码 运行效果图: 前言   滑动菜单相信都不会陌生,你可能见过很多这样的文章,但我的文章会给你不一样的阅读和操作体验. 正文   写博客,自然是从创建项目开始了,这样你可以更好的知道这个过程中经历了什么. 一.创建项目   项目就命名为DrawerDemo, 绝对的手把手教学,让你清楚每一步怎么做. 然后打开app下的build.gradle,在android{}闭包中添加如下代码: //

Kotlin + Flow 实现Android 应用初始化任务启动库

特性 Kotlin + Flow 实现的 Android 应用初始化任务启动库. 支持模块化,按模块加载任务 可指定工作进程名称,main 表示仅在主进程运行,all 表示在所有进程运行,默认值all 可指定任务仅在工作线程执行 可指定任务仅在调试模式执行 可指定任务在满足合规条件后执行 可指定任务优先级,决定同模块内无依赖同步任务的执行顺序 可指定依赖任务列表,能检测循环依赖 使用 Flow 调度任务 仅200多行代码,简单明了 有耗时统计 引入依赖 项目地址:github.com/czy11

Android 如何获取设备唯一标识

一. 先简单总结一下比较常见的几个解决方案的弊端: 1. IMEI Android 10 中官方明确说明第三方应用无法获取到IMEI码:Android 10 中的隐私权变更, Android 10 以下的版本,需要申请READ_PHONE_STATE权限. 2. Android ID Android ID 不具有真正的唯一性, ROOT.刷机.恢复出厂设置.不同签名的应用等都会导致获取的 Android ID 发生改变, 并且不同厂商定制的系统的BUG会导致不同的设备可能会产生相同的 Andro

Android AMS启动详解

启动 在Android系统启动流程中中我们提到过,AMS是在system_service中启动的, //frameworks/base/services/java/corri/android/server/SystemServer.java //该方法主要启动服务 ActivityManagerService,PowerManagerService,LightsService,DisplayManagerService,PackageManagerService,UserManagerServi

Android nativePollOnce函数解析

nativePollOnce的实现函数是android_os_MessageQueue_nativePollOnce,代码如下: android_os_MessageQueue.cpp static void android_os_MessageQueue_nativePollOnce(JNIEnv*env, jobject obj, jintptr, jint timeoutMillis) NativeMessageQueue*nativeMessageQueue = reinterpret_

从源码角度分析Android的消息机制

前言 说到Android的消息机制,那么主要的就是指的Handler的运行机制.其中包括MessageQueue以及Looper的工作过程. 在开始正文之前,先抛出两个问题: 为什么更新UI的操作要在主线程中进行? Android中为什么主线程不会因为Looper.loop()里的死循环卡死? UI线程的判断是在ViewRootImpl中的checkThread方法中完成的. 对于第一个问题,这里给一个简单的回答: 如果可以在子线程中修改UI,多线程的并发访问可能会导致UI控件的不可预期性,采用

Android如何使用Glide加载清晰长图

最近项目中使用的是Glide加载图片,上线后用户反馈图片模糊,经过测试后发现是用户点击超长图放大的时候,图片变的模糊看不起,这很影响用户的体验,要解决这个问题,我们需要先充分的了解Glide的使用. Glide概述 使用习惯Glide3的朋友总会觉得Glide 4相对于Glide 3改动非常大,其实不然.之所以大家会有这种错觉,是因为你将Glide 3的用法直接搬到Glide 4中去使用,结果IDE全面报错,然后大家可能就觉得Glide 4的用法完全变掉了. 其实Glide 4相对于Glide

Android端代码量非常小的分页加载库

前言 RecyclerView几乎在每个app里面都有被使用,但凡使用了列表就会采用分页加载进行数据请求和加载.android 官方也推出了分页库,但是感觉只有kotlin一起使用才能体会到酸爽.Java 版本的也有很多很强大的第三方库, BaseRecyclerViewAdapterHelper这个库是我用起来最顺手的分页库,里面也包含了各式各样强大的功能:分组.拖动排序.动画,因为功能强大,代码量也相对比较大. 但是很多时候我们想要的就是分页加载,所以参照BaseRecyclerViewAd

微信小程序分页加载的实例代码

整理文档,搜刮出一个微信小程序分页加载的代码,稍微整理精简一下做下分享. 分页加载功能大家遇到的应该会经常遇到,应用场景也很多,例如微博,QQ,微信朋友圈以及新闻类应用,都会有分页加载的功能,这不仅节省了我们用户的流量,还提升了用户体验.那么今天的这篇文章就是介绍微信小程序中如何实现分页加载的功能.照例先上源码及效果图. 源码传送门 要实现这样的功能,一般需要在请求数据时加入当前请求页数,以及页的大小(每页显示的数量)也有一部分接口是通过请求的开始偏移量和结束偏移量请求数据,例如你一页显示10条

Android实现基于滑动的SQLite数据分页加载技术(附demo源码下载)

本文实例讲述了Android实现基于滑动的SQLite数据分页加载技术.分享给大家供大家参考,具体如下: main.xml如下: <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_settings" android:orderInCategory="100" android:showAs

Android之ListView分页加载数据功能实现代码

什么是ListView分页加载数据功能呢?在现在的大数据时代,我们不可能把某些数据全部展示到界面,好比我们经常会看的QQ空间一样,当你看动态的时候,系统不可能会把所有好友的动态都展示在上面,你能看到的一般都是最新好友更新的动态,假如你要看非最新的好友动态,通常你都会手指向上滑动屏幕然后去查看,当界面下滑到一定数量的时候,就会看到一个"查看更多",然后突然停顿一下,系统会通过网络去给你刷新其他动态信息,这样的功能我们一般叫做数据下拉刷新功能,也就是我们的分页加载功能,具体的实现是怎样的呢

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

最近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多. 新浪微博就是使用这种方式的典型. 当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容.这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第N页就好了!!!).通过分

Android基于ListView实现类似Market分页加载效果示例

本文实例讲述了Android基于ListView实现类似Market分页加载效果.分享给大家供大家参考,具体如下: 最近几天研究ListView实现分页加载和滚动加载,发现可以用listView的OnScroll方法来实现,直接上代码 ListViewScroll.java package zy.lucifer.ListViewScroll; import android.app.Activity; import android.os.Bundle; import android.util.Lo

微信小程序实战之上拉(分页加载)效果(2)

上拉加载(分页加载) 当用户打开一个页面时,假设后台数据量庞大时,一次性地返回所有数据给客户端,页面的打开速度就会有所下降,而且用户只看上面的内容而不需要看后面的内容时,也浪费用户流量,基于优化的角度来考虑,后台不要一次性返回所有数据,当用户有需要再往下翻的时候,再加载更加数据出来. 业务需求: 列表滚动到底部时,继续往上拉,加载更多内容 必备参数: (1)pageindex: 1 //第几次加载 (2)callbackcount: 15 //需要返回数据的个数 其他参数: 根据接口的所需参数

android九宫格可分页加载控件使用详解

本文实例为大家分享了android九宫格可分页加载控件的具体实现代码,供大家参考,具体内容如下 github地址 基本思路是viewpager+gridview,每一页viewpager视图有一个gridview,gridview加载九格.所以要保证数据的准确性.数据以List< List < T>>的形式.控件实现了高度自适应,根据控件的个数,计算控件的高度.内部的viewpager和gridview视图都以动态创建,无需新建一个xml文件,整个控件只需要一个item的布局文件.

Android编程实现分页加载ListView功能示例

本文实例讲述了Android编程实现分页加载ListView功能.分享给大家供大家参考,具体如下: package eoe.listview; import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import andr

iOS 高效的分页加载实现示例

今天在review代码的时候发现之前的tableview 和 collectview 的分页加载逻辑还有优化的余地,于是进行了优化. 一.tableview的分页加载的代码对比 没有优化之前的代码如下: [strongSelf.tableView.mj_footer endRefreshing]: [strongSelf.articleArr addObjectsFromArray:feedList]; [strongSelf.tableView reloadData]; 优化之后的代码如下:

Android ListView下拉刷新上拉自动加载更多DEMO示例

代码下载地址已经更新.因为代码很久没更新,已经很落伍了,建议大家使用RecyclerView实现. 参考项目: https://github.com/bingoogolapple/BGARefreshLayout-Android https://github.com/baoyongzhang/android-PullRefreshLayout 下拉刷新,Android中非常普遍的功能.为了方便便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能.设计最初是参考开源中国的And