Android的个人修炼心经

自从跳出三界奋勇前行三年有余,其间的喜怒哀乐自有体会,收获还是颇丰,但有一点做得不好就是博客停更,虽说任务重时间紧,但或多或少拿它当借口了。言归正传,期间所做的技术工作主要是原生Linux相关的,本以为做Android机会不是很多(做得又不需要太深入),但是最近的工作又需要转回到Android上(要比较深入),于是乎又得捡起回看一下原来做Android所做的笔记,缩短一下热身和起步时间。下面所写的内容是三、四年前的工作学习笔记,主要是基于4.4.2而做。现在看来还是有一些内容总结得不准确或到位,立flag在此方便修订。另外,由于年代久远,有些文字可能是引用它处,如有未说明引用的请指正。


以列表项的形式书写,不针对具体代码,通过简单直观的方式做概念性描述,以建立一个全局的知识树。由于Android所包含的内容很多,涉及的内容没有面面俱到。

 

第一部分 骨骼

 

一、Android体系结构(静态视角)

1、应用层

Google在Android中内置了一些核心应用程序,有主屏幕(Home)、联系人(Contacts)、电话(Phone)、浏览器(Browser)、日历(Calendar)、地图、短消息(SMS)、图库(Gallery)、输入法、闹钟(Alarm)等。开发者还可以使用应用框架层提供的API编写自己的应用程序。应用程序主要用Java语言编写。

2、应用框架层

不仅为应用层提供API,而且是一种重要的机制。这种机制为应用层提供了可以复用的组件,提供了应用层开发的规范,屏蔽了应用层与底层交互的复杂性。应用框架层提供提供的API并不完全对第三方应用程序开放,有一部分API是隐藏的。引入应用框架层后,应用层被浓缩为Activity、Service、content Provider和Broadcast Receiver四大组件。本层主要是使用Java和JNI实现。

3、Android运行环境(Core Libraries、Dalvik Virtual Machine)和系统运行库(Libraries)层

本层相当于中间件层,为应用框架层提供服务,它分成两部分:一部分是系统运行库,包含各种系统库和第三方库;另一部分是Android运行环境,这里主要是使用C++和C实现的。

4、HAL层

为了避开GPL license完全开放源码的规定,保护硬件厂商的驱动程序,Android把控制硬件的操作放到了HAL中,在内核驱动中只有简单的读写寄存器的操作。硬件厂商可以只提供二进制代码,而不需要提供源码。HAL层并没有在官方早期的体系结构图中体现出来。另外,高通的方案有一个所谓的mm-camera用于在用户空间封装camera相关的厂商实现(不开源),这玩意没有用到HAL,也只是非深入但浅出的了解了一下。

5、Linux内核层

从ICS开始基于Linux 3.0内核,Android对标准的Linux内核做了大量裁剪和优化。

 

二、Android的运行空间(动态视角)

1、用户空间

(1) 用户空间分为两个交互的子系统:Native子系统和Java子系统。两个子系统通过JNI技术连接在一起,建立在内核空间之上。

(2) Native子系统主要由NDK开发的App、应用框架层Native部分和标准库C/C++部分组成。

(3) Java子系统主要由SDK开发的App、系统内置App、应用程序框架层Java部分、标准库的Java接口组成。

(4) 运行时,Java应用程序调用应用框架层的接口使用标准库提供的服务。整个系统的运行环境和进程管理便由Dalvik和Linux Kernel负责。

2、内核空间

内核空间分为两部分:Linux内核和Android扩展支持,用于完成操作系统运行支持。其中Android扩展部分包括Binder、Logger、OOM(Out Of Memory)等机制。Android扩展支持是以staging的形式存在,也就是进入不了Linux的主线。


第二部分 经脉

 

根据Android的静态和动态体系结构分析,可以总结出以下几个重要的知识点:

 

一、Android系统三种开发模式

由于Android的开发涉及到方方面面,在日常工作中,根据社会主义分工又合作的方针,是会对不同的部分进行工作分工及人员划分的。当然如果人员不是很充足,那就只好撸起袖子都来干了。

1、Android应用开发

基于Android提供的系统API(第二层java framework)进行应用层面的开发,通常基于Android SDK开发即可

2、Android系统开发

通常涉及用户空间各层的开发:C或C++本地库、JNI层、Java类层、应用层

3、Android移植开发

Linux中相关设备的驱动程序开发,比如LCD、触摸屏、键盘、音频、摄像头、蓝牙等;以及硬件抽象层的开发(硬件抽象层在用户空间,介于驱动和Android系统之间)

 

二、Android的层间交互

1、Application和Application Framework的交互

(1)在同一个Dalvik虚拟机进程中,Application可以直接调用Framework提供的公共类库。

(2)在不同的Dalvik虚拟机进程中,Application通过Binder IPC调用Framework提供的类库。

2、Application Framework和Libraries的交互

本质上就是Dalvik虚拟机和其它Native Library的交互,这里Dalvik虚拟机提供了JNI接口(Java Native Interface)实现这两层的双向通信。

3、Libraries和Linux Kernel的交互

涉及到Linux系统知识,用户空间和内核空间之间的通信。

 

三、Android控制流程(应用->HAL/驱动)

应用如果要控制到到HAL或驱动,涉及到层级传递(Java到Native还会涉及JNI),如果是跨进程还会涉及到Binder或Socket,常用的方法有几种

1、App==>Java Runtime Service==>Lib。典型案例是位置定位服务。

2、App==>Java Runtime Service==>Native Service==>Lib。Service之间通过Binder通信,典型案例是Camera和MediaPlayer。

3、App==>Java Runtime Service==>Native Daemon==>Lib。Service和Daemon之间通过Socket通信,典型案例是Telephony。

4、App==>Java Runtime Service==>Lib。如果为了调试设备驱动(比如GPIO、I2C)方便,可以直接让App经JNI操作驱动。

5、其它(大脑一片空白)

 

四、Android的数据流

1、IPC数据流

(1) IPC实质上是数据流的传递,Android设计者在Linux内核中设计了一个叫做Binder的设备文件,专门用来进行Android的数据交换。所以从数据流来看Java对象从Java的VM空间进入到C++空间进行了一次转换,并利用C++空间的函数将转换过的对象通过driver/binder设备传递到服务进程,从而完成进程间的IPC。

这个数据流有几层转换过程:

(a)从DVM空间传到C++空间,这个是靠JNI使用ENV来完成对象的映射过程。

(b)从C++空间传入内核Binder设备,使用ProcessState类完成工作。

(c)Service从内核中Binder设备读取数据。

(2) 不管DVM的Binder做了多么复杂的操作,最终还是需要利用ProcessState这个C++空间的对象把数据传递给Binder Driver,接收数据也是通过ProcessState这个对象完成,ProcessState是所有Binder IPC必经的通道。

2、GUI管理的用户输入和屏幕输出两大数据流

(1) 用户输入

KeyEvent

TouchEvent

TrackballEvent

(2) 屏幕输出

通过图形系统将文本、线条、位图等概念对象映射到具体的物理设备。一共有三种输出方式,具体参见“android显示系统”

3、自定义的数据流

与具体产品平台(不在Android考虑范畴)相关的,如外围设备操作等。常用的做法就是集成到一个(自实现)中间层统一管理,然后提供接口供应用来调用。


第三部分 心法

 

一、Android的组件化思想(从应用角度分析)

Android应用开发的哲学是把一切都看作是组件。把应用程序组件化的好处是降低模块间的耦合性,同时提高模块的复用性。Android的组件设计思想与传统的组件设计思想最大的区别在于,前者不依赖于进程。也就是说,进程即使由于内存紧张被强行杀掉了,但是运行在里面的组件还是存在的。这样就可以在组件再次需要使用时,原地满血复活,就像什么都没发生过一样。这种设计思想非常适合内存较小的移动设备。具体参见“Android组件设计思想.pptx”

 

1、应用的四大组件

(1) Android应用的四大组件,Activity就是前台的交互面对用户的一些逻辑,Service是负责后台计算,Broadcast Recviver就是在组件建立一通信和连接,Content Provider是数据的封装。

(2) Android应用的不同组件可以位于不同的进程中,例如:一个Activity启动其他Activity;Activity与Service交互;Activity通过Content Provider访问其它应用程序的数据;一个组件发送广播给其它组件处理。这四种情况下都需要用到Binder通信。Android四大组件能够进行Binder通信的基础是应用框架层提供的系统服务,即SystemServer在init2阶段启动的Java系统服务。Binder在Java框架层的应用并不仅限于四大组件的交互,在四大组件中也可以通过应用框架层提供的getSystemService接口直接使用Java系统服务(应该是调用流程一)。

(3) 组件之间是通过Intent进行通信的,在底层的通信基于Binder机制实现,Binder为组件间通信提供进程间和进程内的支持。

(4) 见下图“四大组件的关系”

Android的个人修炼心经_第1张图片

 

2、应用的本质

(1) Android的应用不等于进程,他们各自有自己的生命周期,一个应用相当于一个user,非常便于权限管理。从以下官方的描述来看,应用更象是一种组件(代码+数据)集合,这些组件依附于应用中,应用并不会一开始就建立起来,而是在这些组件建立起来后,需要运行时,才开始建立应用对象。而进程则是应用运行的承载平台。官方描述如下:

摘自Application Fundamentals(http://developer.android.com/guide/components/fundamentals.html)

The Android operating system is a multi-user Linux system in which each application is a different user.

Android系统是一个多用户的Linux系统,不同来源的应用都由不同的Linux用户来运行。

By default, the system assigns each application a unique Linux user ID (the ID is used only by the system and is unknown to the application). The system sets permissions for all the files in an application so that only the user ID assigned to that application can access them.

默认情况下,系统给每个应用分配一个唯一的Linux用户ID(这个ID只由系统使用并对应用保持透明)。系统给每个应用中的文件设置了用户访问权限,只有分配了对应用户ID的应用才能访问它们。

Each process has its own virtual machine (VM), so an application's code runs in isolation from other applications.

每个虚拟机实例都是一个独立的进程空间,因此(运行在虚拟机实例里的)应用处于不同的进程空间内。

By default, every application runs in its own Linux process. Android starts the process when any of the application's components need to be executed, then shuts down the process when it's no longer needed or when the system must recover memory for other applications.

默认情况下,每个应用运行在其所归属的Linux进程中。当任意一个应用的组件需要被执行时,Android启动它所归属的进程,进程会在所属应用不再使用或系统为其它应用回收内存时结束。

(2) 应用主要由四大组件构成,分别是Activitiy、Service、Content Provider、Broadcast Intent Receiver。应用组件里除了Contentproviders之外都可以用intent对象激活。Activity是Android应用的核心概念,简而言之Activity为用户交互管理者,有一个可视界面呈现,而Service跟Activity的区别是他在后台运行,没有界面呈现。而Intent的意义是意图,他在Android的概念空间中代表消息,这个消息代表了请求的意图。

(3) Activity可以无处不在,提供服务,消除空间差别,Activity是一个独立的个体,更能表面面向对象的实质。这个个体需要接受另外的个体的消息,可以随时发起对另外一个个体的请求。个体是自由的,Android中你可以开始一个Activity,但是没有权利消灭一个Activity,这是个体权利的体现,个体的消灭是由系统决定的,这个就是Android中Activity蕴含的人文意义。

 

3、线程、进程、任务(从应用角度分析)

(1) Android中的每个应用在底层都会对应一个Dalvik实例,即一个进程。

(2) Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器。它通过init进程来启动,首先会孵化出SystemServer,这是Android绝大多数系统服务(Java Service)的守护进程,之后所有应用的进程也都是由它孵化而来。

(3) 与JVM不同的时,DVM的线程是对应于操作系统线程的,而且DVM中的进程对应于操作系统中的进程。

(4) Zygote几乎是所有进程的父进程。因为Linux创建进程时,会共享.text正文段,并且对静态数据采用“写时复制”(copy-on-write)的方式操作,所以fork出来的子进程就继承了父进程的运行时环境。

(5) Dalvik使用信号方式来完成进程间通信,也就是说通过sendSignal函数发送特定的信号。

(6) 关于任务(Task),从官方的Application Fundamentals描述来看,任务就相当于应用的概念。从静态角度看,应用是由组件组成的,从动态角度看,任务是组件组合到一起执行的过程。在开发人员眼中,开发一个Android应用是做一个个独立的组件,但是对于用户而言,他们所感知的只是一个运行起来的整体应用,这个整体背后就是任务。任务简单的说就是一组以栈的模式聚集在一起的Activity集合,它们有潜在的前后驱动关联,新加入的Activity位于栈顶,并仅有在栈顶的Activity才会有机会与用户进行交互,而当栈顶的Activity完成使命退出的时候,任务会将其退栈,并让下一个将跑到栈顶的Activity来与用户面对面,直至栈中再无更多Activity,任务结束。

(7) 线程间的消息机制要素,Looper、MessageQueue、Handler

 

二、GWES

这个缩略词其实最早是在做WINCE的时候遇到的,GWES的意思是“图形(Graphic)窗口(Window)事件(Event)系统”,Android做为移动终端设备系统,GWES也具备普世价值(否则要它何用)。各部分所承担的工作职责从抽象上大体是:

1、事件管理器(Event)

收集系统消息,转换并分发系统消息和用户消息给各个窗口对象

消息队列管理

实现:InputManager System

2、窗口管理器(View)

管理窗口的创建、销毁

窗口的绘制

活动窗口、输入焦点的切换

窗口音关系的管理

控制、菜单实现

实现:Window and View Manager System、Activity Manager System

3、图形(绘制与图形逻辑对象管理)

设备上下文管理

设备上下文对象管理:字体、画笔等

图形绘制:点、线、填充等

图象操作:位传送、位图操作

实现:SurfaceFlinger

4、见下图“GWES各元素关系图”

Android的个人修炼心经_第2张图片

 

、RPC

Android的组件化思想虽然不是原创,但个人看来也算是齐大成者。而各组件之间要如何协调工作是离不开互相商量的,老生常谈的不外乎是IPC和RPC。Android选用的RPC方案是Binder,为什么会选用Binder,从Android诞生所面向的产品市场---移动消费设备--来看,能耗应该是一个很重要的因素:相比要基于其它几种IPC实现RPC,Binder在CPU状态切换、运行开销上还是有优势的。关于Binder的实现网上有大量介绍这方面的文章,由于工作的原因对这一块的内容是很感兴起的,因此除了借鉴别人的成果、阅读相关实现代码,还做了一些不走寻常路的跨平台移植,通过在工作中的运用和实践进一步领会了精髓,这也从一个侧面说明Binder的设计还是足够优秀的---基于客观的抽象才能解决具体问题。

 

四、资源体系

Android如何适配差异化很大的终端设备,资源体系是关键,由于不是关注重点不做展开。

 

五、其它GEM(大脑一片空白)

 

六、和window系统的横向比较(还有必要吗)


第四部分 秘籍

 

1、Android核心分析 之一--------分析方法论探讨之设计意图

http://blog.csdn.net/maxleng/article/details/5471557

 

2、Android架构纵横谈之——软件自愈能力 (1)

http://blog.csdn.net/21cnbao/article/details/7686907

 

你可能感兴趣的:(linux)