目录
Android系统架构ABC
1) Android的历史
2) Android 系统框架一览
a)应用程序层
b) 应用程序框架层
c)系统库和Android运行时
Dalvik模式的缺点
ART模式(Android Runtime)的优点
d) Linux内核
Android 开源框架
Android 标准库
3) 通信基石 – Binder模式
IPC机制种类
Binder通信机制简介
为啥新发明一个Binider通信机制
Binder通信模型
Binder通信机制原理图
J2EE和Android两种RPC的比较:
4) 消息队列(MessageQueue, Looper, Handler)
5) Framework启动过程: zygote进程和system进程
6) 包管理服务PackageManagerService
7) 第一个应用程序进程的启动过程
8) AMS活动管理, WMS窗口管理, View系统的工作原理
android内核三大核心成员介绍
整个Android生态系统工作原理概述
9) 总结
了解一个事物,往往要从其出身开始,这样才能完整地明白它到底是什么东西。Android的历史渊源要追溯到90年代初,Andriod之父 Andy Rubin还在苹果子公司开发第一代手机OS “MagicCap”开始。
我用一段话简短概述iPhone和Android,苹果和谷歌之间的争端的历史缘由:
IOS产生的历史:
Steve Jobs 于1976年创建了苹果公司, 后于1985年离开苹果,创立了“NeXTComputer”这家公司,创建了一款用Object-C语言编写的叫“NeXTSTEP”的OS,之后在”NeXTSTEP”基础上创造了“Mac OSX”系统,这就是iPhone OS 的基础,简称IOS。后来1996年底,苹果公司又收购NeXT公司,这样Jobs又回到了苹果公司。
Android产生的历史:
1990年,苹果公司的手持设备部门独立,特地成立了”GeneralMagic” 的子公司,研究手机操作系统。”Android之父” ,89年刚进苹果公司的26岁的年轻人——Andy Rubin,认定手机OS发展前景良好,也加入了这个部门, 参与了”MagicCap” OS的开发,后于95年离开了苹果公司。2003年,Andy Rubin创建了Android公司,仅仅22个月之后,2005年被谷歌收购!然后,谷歌Android部门立马投入展开了短信、手机检索等业务,同时基于Linux的通用平台也进入了开发。经过2年的研究,2007年11月5日, Android第一代系统 1.0 beta发布,不过只作为一个面向开发者的软件开发包(SDK)进行发布。之后经过1年的不断优化,于2008年9月23日,发布Android操作系统中的第一个正式版本:Android 1.0,代号为铁臂阿童木(Astro)。仅仅1年之后,便开始了Android打败诺基亚的Symbian,与IPhone两分天下的辉煌时代!
总而言之,无论Android 还是 iPhone, 都是苹果的员工辞职之后,搞出来的。这就是Android和iPhone与苹果公司的渊源!!!这也是苹果一直将安卓列为侵权产品的缘由。苹果方面表示,Android系统创始人Andy Rubin有关Android系统的理念之一诞生于他供职苹果期间。
具体iPhone和Android产生的历史渊源可以查看链接:
http://tech.163.com/14/0426/11/9QOMTFMT00094ODU.html
具体Android各个历史版本可以查看链接:
http://zh.wikipedia.org/zh-cn/Android%E6%AD%B7%E5%8F%B2%E7%89%88%E6%9C%AC
该层提供一些核心应用程序包,例如电子邮件、短信、日历、地图、浏览器和联系人管理等。同时,开发者可以利用Java语言设计和编写属于自己的应用程序,而这些程序与那些核心应用程序彼此平等、友好共处。
该层是Android应用开发的基础,开发人员大部分情况是在和她打交道。应用程序框架层包括活动管理器、窗口管理器、内容提供者、视图系统、包管理器、电话管理器、资源管理器、位置管理器、通知管理器和XMPP服务十个部分。在Android平台上,开发人员可以完全访问核心应用程序所使用的API框架。并且,任何一个应用程序都可以发布自身的功能模块,而其他应用程序则可以使用这些已发布的功能模块。基于这样的重用机制,用户就可以方便地替换平台本身的各种应用程序组件。
系统库包括九个子系统,分别是图层管理、媒体库、SQLite、OpenGLEState、FreeType、WebKit、SGL、SSL和libc。Android运行时包括核心库和Dalvik虚拟机,前者既兼容了大多数Java语言所需要调用的功能函数,又包括了Android的核心库,比如android.os、android.net、android.media等等。后者是一种基于寄存器的java虚拟机,Dalvik虚拟机主要是完成对生命周期的管理、堆栈的管理、线程的管理、安全和异常的管理以及垃圾回收等重要功能。不过,最新的AndroidL 5.0 将彻底抛弃Dalvik虚拟机,改用ART模式。
在Dalvik虚拟机中,因此应用程序每次运行的时候,一部分代码都需要重新进行编译,这过程需要消耗一定的时间和降低应用的执行效率,最明显的便是拖延了应用的启动时间和降低运行速度。
通过在安装应用程序时,自动对程序进行代码预读取编译(可能比较耗时,占用更多ROM内存),让程序直接编译成机器语言,免去了Dalvik模式要时时转换代码,实现高效率、省电、占用更低的系统内存、手机运行流畅。
Android核心系统服务依赖于Linux2.6内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型。Linux内核也是作为硬件与软件栈的抽象层。驱动:显示驱动、摄像头驱动、键盘驱动、WiFi驱动、Audio驱动、flash内存驱动、Binder(IPC)驱动、电源管理等。
在下面的图中,绿色的大部分组件是基于Apache许可证开源,其余基于GPL、LGPL和BSD。
在Linux中,是以进程为单位分配和管理资源的。出于保护机制,一个进程不能直接访问另一个进程的资源,也就是说,进程之间互相封闭
1-采用命名管道(named pipe)
2-消息队列(message queue)
3- 信号(signal)
4-共享内存(share memory)
5 - Socket
在Android终端上的应用软件的通信几乎看不到这些IPC通信方式,取而代之的是Binder方式。
Binder使用Client-Server通信方式:一个进程作为Server提供诸如视频/音频解码,视频捕获,地址本查询,网络连接等服务;多个进程作为Client向Server发起服务请求,获得所需要的服务。要想实现Client-Server通信据必须实现以下两点:
一,是server 必须有确定的访问接入点或者说地址来接受Client的请求,并且Client可以通过某种途径获知Server的地址
二,是制定Command- Reply协议来传输数据。例如在网络通信中Server的访问接入点就是Server主机的IP地址+端口号,传输协议为TCP协议。对Binder而言,Binder可以看成Server提供的实现某个特定服务的访问接入点, Client通过这个‘地址’向Server发送请求来使用该服务;对Client而言,Binder可以看成是通向Server的管道入口,要想和某个 Server通信首先必须建立这个管道并获得管道入口
也可以在这些底层机制上架设一套协议来实现Client-Server通信,但这样增加了系统的复杂性,在手机这种条件复杂,资源稀缺的环境下可靠性也难以保证。
socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。
消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。
共享内存虽然无需拷贝,但控制复杂,难以使用
数据拷贝次数比较图:
IPC进程间通信类型 | 数据拷贝次数 |
共享内存 | 0 |
Binder | 1 |
Socket/管道/消息队列 | 2 |
Android作为一个开放式,拥有众多开发者的的平台,应用程序的来源广泛,确保智能终端的安全是非常重要的。终端用户不希望从网上下载的程序在不知情的情况下偷窥隐私数据,连接无线网络,长期操作底层设备导致电池很快耗尽等等。传统IPC没有任何安全措施,完全依赖上层协议来确保。
首先传统IPC的接收方无法获得对方进程可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。
其次传统IPC访问接入点是开放的,无法建立私有通道。比如命名管道的名称,system V的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接
Binder框架定义了四个角色:Server,Client,ServiceManager(以后简称SMgr)以及驱动。
其中 Server,Client,SMgr运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。
Android进程间通信的底层,都是靠binder驱动传输信息, 如图:
第一步,Server给Binder实体登记
和DNS类似,SMgr的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。注册了名字的Binder叫实名Binder,就象每个网站除了有IP地址外都有自己的网址
。 Server创建了Binder实体,为其取一个字符形式,可读易记的名字,将这个Binder连同名字以数据包的形式通过Binder驱动发送给 SMgr,通知SMgr注册一个名叫张三的Binder,它位于某个Server中。驱动为这个穿过进程边界的Binder创建位于内核中的实体节点以及 SMgr对实体的引用,将名字及新建的引用传递给SMgr。SMgr收数据包后,从中取出名字和引用填入一张查找表中。
第二步,Client获取Binder实体
Server向SMgr注册了Binder实体及其名字后,Client就可以通过名字获得该Binder的引用了。Client也利用保留的0号引用向SMgr请求访问某个Binder:我申请获得名字叫张三的Binder的引用。
SMgr收到这个连接请求,从请求数据包里获得Binder的名字,在查找表里找到该名字对应的条目,从条目中取出Binder的引用,将该引用作为回复发送给发起请求的Client。从面向对象的角度,这个Binder对象现在有了两个引用:一个位于SMgr中,一个位于发起请求的Client中。
如果接下来有更多的Client请求该Binder,系统中就会有更多的引用指向该Binder,就象java里一个对象存在多个引用一样。而且类似的这些指向Binder的引用是强类型,从而确保只要有引用 Binder实体就不会被释放掉。。
处理多线程的时候,Android继承了java的消息队列机制。
Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。
在android中,大部分的应用程序进程都是由zygote来创建的,为什么用大部分,因为还有一些进程比如系统引导进程、init进程等不是有zygote创建的。相反,zygote还是在init进程之后才被创建的。
注:init进程是盘古开天地级别的进程。
zygote在android中主要有两个作用:
建立运行时环境并启动虚拟机,
为应用程序创建DVM进程。
启动SystemServer:
启动应用进程:
Zygote进程运行示意图
1,SystemService的启动是在Zygote进程创建好后进行的,并且由Zygote进程建立好DVM运行环境,加载ZygoteInit的main函数,最终调用Zygote的本地方法forkSystemServer,并执行linux的fork方法创建SystemServer进程。
2,应用程序的进程也是由Zygote创建的,在ActivityManagerService中的startProcessLocked中调用了Process.start()方法。并通过连接调用Zygote的native方法forkAndSpecialize,执行fork任务
ActivityThread启动过程简要序列图
PackagemanagerService主要管理apk,其实就是管理其中的组件等,如Activiey、Service,从apk中解析其中的组件,保存到相关结构中,以使得后面可以通过相关的接口可以查询系统安装组件,apk的安装,卸载,删除都是由PackageManagerService负责的。
简言之:PMS 掌管APK的生死,手里有本生死簿,类于阎王。
(1)WMS:WindowManager Service. Android上发生的事件,例如,触屏,按钮什么的都是由WMS获取的。并且WMS负责了窗口的显示和控制。
(2)AMS:ActivityManager Service. 总共有三部分的功能。
1.activity的管理调度,但是只是在全局负责activity的管理和组织,任何activty的启动,都需要提前通知AMS,并由其进行调度但是不干涉activity内部的东西
2.内存管理,有的时候,activity过多,可能会导致内存不够,AMS会根据内存情况,决定杀死某个 activity。
3.进程管理,AMS会提供API供用户查询当前activity的进程信息。
另外包括了两个消息处理的类KeyQ和InputDispatcherThread,前者是WMS的内部类,当它有一个对象建立的时候,将会监听UI上所有的用户操作,包括触屏,按键等,并且把消息放到队列当中,等待应用的调用。后者的话主要负责从前者放入的消息队列(QueueEvent)当中获取相应的消息并且以一定规则予以消息的过滤,并且发放到相应的应用程序当中,类的作用可以顾名思义。
(3)View
View是什么了,每个人都有自己的理解。在Android的官方文档中是这样描述的:这个类表示了用户界面的基本构建模块。一个View占用了屏幕上的一个矩形区域并且负责界面绘制和事件处理。View是用来构建用户界面组件(Button,Textfields等等)的基类。ViewGroup子类是各种布局的基类,它是个包含其他View(或其他ViewGroups)和定义这些View布局参数的容器。
客户端中的线程
包含有Activity的客户端程序至少包含3个线程,(每个Binder对应一个线程)
1、UI主线程
2、ApplicationThread对象(继承自Binder)(负责AmS的IPC调用)
3、ViewRoot.W对象(继承自Binder) (负责WmS的IPC调用)
Android生态系统工作原理图:
分三步讲解整个过程:
apk程序的运行过程 (一) 前期准备
(看上面大图的中上角,或者看下面的局部截图)
首先,ActivityThread从main()函数开始执行,调用prepareMainLooper()为UI线程创建一个消息队列(MessageQueue)。
然后创建一个ActivityThread对象,在ActivityThread的初始化代码中会创建一个H(Handler)对象和一个ApplicationThread(Binder)对象。其中Binder负责接收远程AmS的IPC调用,接收到调用后,则通过Handler把消息发送到消息队列中,UI主线程会异步的从消息队列中取出消息并执行相应的操作,比如start stop pause等。
接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断的从消息队列中读取并处理消息。
apk程序的运行过程 (二)启动Activity
(看上面大图的中间部分,或者看下面的局部截图)
当ActivityThread接收到AmS发送start某个Activity后,就会创建指定的Activity对象,Activity又会创建PhoneWindow类——>DecorView类——>创建相应的View或者ViewGroup。
创建完成后,Activity需要把创建好的界面显示到屏幕上,于是调用WindowManager类,后者于是创建一个ViewRoot对象,该对象实际上创建了ViewRoot类和W类,创建ViewRoot对象以后,WindowManager再调用WmS提供的远程调用接口完成添加一个窗口并显示到屏幕上。
apk程序的运行过程(三) 响应用户屏幕操作
(看上面大图最左侧,或者看下面的局部截图)
接下来,用户开始在程序界面上操作,KeyQ线程不多把用户消息存储到QueueEvent队列中,InputDispatcherThread线程逐个取出消息,然后调用WmS中的相关函数处理该消息,当WmS发现该消息属于客户端某个窗口时,就会调用相应的窗口W接口。
W类是一个Binder,负责接收WmS的IPC调用,并把调用消息传递给ViewRoot,ViewRoot再把消息传递给UI主线程ActivityThread,ActivityThread解析该消息并作相应的处理,在客户端程序中,首先处理消息的是DecorView,如果DecorView不想处理该消息,则可以把该消息传递给其内部包含的子View或者ViewGroup,如果还没有处理,则传递给PhoneWindow,最后在传递给Activity。
本文仅从总体概念和基本原理上,介绍了Android系统的基本架构、核心功能组件和工作原理,由于篇幅所限,不可能就每章每点都详细讲解,只是蜻蜓点水,一掠而过,只希望能激发初学者的好奇心,通过本文所撕开的Android外衣的一角,让你窥到一点秘密,激起你对Android的兴趣。如果想继续深入了解Android的深层原理,还需要大家一起研究学习讨论。让我们一起,继续向Android的最高殿堂前进!
—— 空谷幽兰 2014-7-7
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。