本文主要是介绍Android FrameWork(AMS,WMS,PMS等)的概念及解析,获取系统服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Framework API: Activity Manager/Window Manager/Content Providers/View System/Notification Manager/Package Manager/Telephony Manager/Resource Manager...
其实所谓的AMS,PMS,以及WMS等都是运行在system_server这个进程中的线程.
Framwork 中的主流服务:ActivityManagerService、PackageManagerService、WindowManagerService、AlarmManagerService、JobSchedulerService、ResourceManagerService、InputManagerService 等。
-- Framework开发
> Android的硬件抽象层,内核驱动
Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。
Android才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android被踢出了Linux内核主线代码树中。大家想想,Android放在内核空间的驱动程序对硬件的支持是不完整的,把Linux内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说Android是开放系统而不是开源系统的原因。
对Android人才需求一类是偏向硬件驱动的Android人才需求,一类是偏向软件应用的Android人才需求。总的来说,对有志于从事Android硬件驱动的开发工程师来说,现在是一个大展拳脚的机会。那么,就让我们一起来看看如何为Android系统编写内核驱动程序吧。Android系统镜像system.img。
为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序。硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中。如何在Linux内核编写驱动程序。如何在硬件抽象层中增加硬件模块来和内核驱动程序交互。
如何为Android系统的硬件编写驱动程序,如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口。Android系统的应用程序是用Java语言编写的,而硬件驱动程序是用C语言来实现的。在Android系统中,Java应用程序通过JNI来调用硬件抽象层接口。
在Linux内核层、硬件抽象层和运行时库层提供的自定义硬件服务接口,这些接口都是通过C或者C++语言来实现的。让应用层的APP能够通过Java接口来访问硬件服务。
> 框架层Log和Linux Kernel Log (logger日志系统)
LOG是广泛使用的用来记录程序执行过程的机制,它既可以用于程序调试,也可以用于产品运营中的事件记录。
1.内核开发时LOG的使用。Android内核是基于Linux Kerne 2.36的,因此,Linux Kernel的LOG机制同样适合于Android内核,它就是有名的printk,与C语言的printf齐名。与printf类似,printk提供格式化输入功能,同时,它也具有所有LOG机制的特点--提供日志级别过虑功能。
2.用户空间程序开发时LOG的使用。Android系统在用户空间中提供了轻量级的logger日志系统,它是在内核中实现的一种设备驱动,与用户空间的logcat工具配合使用能够方便地跟踪调试程序。在Android系统中,分别为C/C++ 和Java语言提供两种不同的logger访问接口。
在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件。
每一条日志记录是由两大部分组成的,一个用于描述这条日志记录的结构体struct logger_entry,另一个是记录体本身,即有效负载。结构体struct logger_entry的长度是固定的,只要知道有效负载的长度,就可以知道整条日志记录的长度了。而有效负载的长度是记录在结构体struct logger_entry的成员变量len中,而len成员变量的地址与struct logger_entry的地址相同,因此,只需要读取记录的开始位置的两个字节就可以了。又由于日志记录缓冲区是循环使用的,这两个节字有可能是第一个字节存放在缓冲区最后一个字节,而第二个字节存放在缓冲区的第一个节,除此之外,这两个字节都是连在一起的。
首先是从应用程序层调用应用程序框架层的Java接口,应用程序框架层的Java接口通过调用本层的JNI方法进入到系统运行库层的C接口,系统运行库层的C接口通过设备文件来访问内核空间层的Logger驱动程序。
> Android通信(OpenBinder,Binder)
Android系统是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通信(IPC)机制。有传统的管道(Pipe)、信号(Signal)和跟踪(Trace),这三项通信手段只能用于父进程与子进程之间,或者兄弟进程之间;后来又增加了命令管道(Named Pipe),使得进程间通信不再局限于父子进程或者兄弟进程之间;为了更好地支持商业应用中的事务处理,在AT&T的Unix系统V中,又增加了三种称为“System V IPC”的进程间通信机制,分别是报文队列(Message)、共享内存(Share Memory)和信号量(Semaphore);后来BSD Unix对“System V IPC”机制进行了重要的扩充,提供了一种称为插口(Socket)的进程间通信机制。
Android系统没有采用上述提到的各种进程间通信机制,而是采用Binder机制。Binder其实也不是Android提出来的一套新的进程间通信机制,它是基于OpenBinder来实现的。OpenBinder最先是由Be Inc.开发的,接着Palm Inc.也跟着使用。现在OpenBinder的作者Dianne Hackborn就是在Google工作,负责Android平台的开发工作。Binder是一种进程间通信机制,它是一种类似于COM和CORBA分布式组件架构,通俗一点,其实是提供远程过程调用(RPC)功能。
在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。Service Manager和Binder驱动已经在Android平台中实现好,开发者只要按照规范实现自己的Client和Server组件就可以了。
-- Client、Server、Service Manager和Binder驱动:
1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中
2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
4. Client和Server之间的进程间通信通过Binder驱动程序间接实现
5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力
组件Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能。
> FD文件描述符?
进程使用的是虚拟地址,不同进程间是地址隔离的。
Navite Looper 除了提供message机制之外,还提供了监听文件描述符的方式。 Android Native Looper机制 - 监听文件描述符。
> fork App,Linux的fork机制,App Runtime, Android,Runtime?
init, Zygote与SystemServer(Java世界加持),zygote和system_server这两个进程分别是Java世界的半边天,任何一个进程的死亡,都会导致Java世界的崩溃。
-- Zygote创建Java世界的步骤:
· 第一天:创建AppRuntime对象,并调用它的start。此后的活动则由AppRuntime来控制。
· 第二天:调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数。
· 第三天:通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了Java世界。然而在这个世界刚开创的时候,什么东西都没有。
· 第四天:调用registerZygoteSocket。通过这个函数,它可以响应子孙后代的请求。同时Zygote调用preloadClasses和preloadResources,为Java世界添砖加瓦。
· 第五天:Zygote觉得自己工作压力太大,便通过调用startSystemServer分裂一个子进程system_server来为Java世界服务。
· 第六天:Zygote完成了Java世界的初创工作,它已经很满足了。下一步该做的就是调用runSelectLoopMode后,便沉沉地睡去了。
· 以后的日子:Zygote随时守护在我们的周围,当接收到子孙后代的请求时,它会随时醒来,为它们工作。
> android framework及服务
Android获取系统服务- https://blog.csdn.net/xjh_shin/article/details/79837384
Android之导入源码到eclipse中以及单模块调试(Launch)- http://blog.csdn.net/way_ping_li/article/details/10494925
Android FrameWork- http://blog.csdn.net/weidi1989/article/category/1612489
Android Framework 记录- http://blog.csdn.net/banketree/article/details/24718899
Android Framework 记录之二- http://blog.csdn.net/banketree/article/details/24982021
Android5.1.1源码 - 在Framework中添加自定义系统服务- http://www.oschina.net/question/2625381_2181457
[android]Framework新增系统服务- http://blog.csdn.net/yiwuxue/article/details/40144155
Android framework之积累- http://blog.csdn.net/u010164190/article/category/6041764
Android framework之积累- http://blog.csdn.net/u010164190?viewmode=contents
Android的系统服务一览- http://blog.csdn.net/freshui/article/details/5993195
android framework Service分析- http://blog.csdn.net/andy_android/article/details/7327888
android framework层服务是android启动时由systemServer init2阶段的第一个java线程ServerThread 初始化的.
Framwork 中的主流服务:ActivityManagerService、PackageManagerService、WindowManagerService、AlarmManagerService、JobSchedulerService、ResourceManagerService、InputManagerService 等等的一些服务,可以结合 Android 的开机流程的每个阶段来看!
-- FrameWork提供的服务有:
第一类服务:
ActivityManagerService ; PowerManagerService ; PackageManagerService ; WindowManagerService
第二类服务:
NetworkManagementService ; NetworkTimeUpdateService ; NetworkPolicyManagerService ; NetWorkStatsService ; WifiService ; WifiP2pService ; ThrottleService ; ConnectivityService ; TelephonyRegistry ; Telephony Manager ; Resource Manager ; NetStat Service
第三类服务:
ContentService ; AccountManagerService ; MountService ; AudioService ; TextServicesManagerService ; SearchManagerService ; LocationManagerService ; AccessibilityManagerService ; UsbService ; DevicePolicyManagerService ; RecognitionManagerService ; UI Mode Manager Service ; Backup Service
第四类服务:
BatteryService ; LightService ; AlarmManagerService ; VibratorService
第五类服务:
EntropyService ; ClipboardService ; DiskStatsService ; DropBoxManagerService ; SamplingProfilerService ; DeviceStorageMonitorService ; Watchdog ; Headset Observer ; Dock Observer ; USB Observer ; DiskStats Service
第六类服务
BluetoothA2dpService ; BluetoothService ;
第七类服务:
AppWidgetService ; InputMethodManagerService ; iModeManagerService ; StatusBarManagerService ; NotificationManagerService ; WallpaperManagerService
---------------------------
Innost的专栏及FrameWork学习- http://blog.csdn.net/innost
> Android壁纸:动态和静态壁纸
> SystemUI(状态栏和导航栏) Notification
> 控件系统(GUI):
在小屏幕设备如手机中,由于屏幕宽度有限,Android采取了状态栏与导航栏分离的布局方案,也就是说导航栏与状态栏占用了更多的垂直空间,使得导航栏的虚拟按键尺寸足够大以及状态栏的信息量足够多。而在大屏幕设备如平板电脑中,由于屏幕宽度比较大,足以在一个屏幕宽度中同时显示足够大的虚拟按键以及足够多的状态栏信息量,此时可以选择将状态栏与导航栏功能集成在一起成为系统栏作为大屏幕下的布局方案,以节省对垂直空间的占用。
ViewRootImpl实现了ViewParent接口,作为整个控件树的根部,它是控件树正常运作的动力所在,控件的测量、布局、绘制以及输入事件的派发处理都由ViewRootImpl触发。另一方面,它是WindowManagerGlobal工作的实际实现者,因此它还需要负责与WMS交互通信以调整窗口的位置大小,以及对来自WMS的事件(如窗口尺寸改变等)作出相应的处理。
INotify是一个Linux内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等。INotify机制有两个基本对象,分别为inotify对象与watch对象,都使用文件描述符表示。
> AudioService
在分析Android音频系统时,习惯将其实现分为两个部分:数据流和策略。数据流描述了音频数据从数据源流向目的地的过程。而策略则是管理及控制数据流的路径与呈现的过程。
在Android手机上有两种改变系统音量的方式。最直接的做法就是通过手机的音量键进行音量调整,还有就是从设置界面中调整某一种类型音频的音量。
phoneWindow描述了一片显示区域,用于显示与管理我们所看到的Activity、对话框等内容。同时,它还是输入事件的派发对象,而且只有显示在最上面的PhoneWindow才会收到事件。
按照Android的输入事件派发策略,Window对象在事件的派发队列中排在Activity的后面(应该说排在队尾比较合适),所以应用程序可以重写自己的onKeyDown()函数,将音量键用作其他的功能。比如说,在一个相机应用中,按下音量键所执行的动作是拍照而不是调节音量。
PhoneWindow的onKeyDown()函数实现如下:[PhoneWindow.java-->PhoneWindow.onKeyDown()]
......//加省略号, 略过一些内容
switch (keyCode) {
caseKeyEvent.KEYCODE_VOLUME_UP:
caseKeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
// 直接调用到AudioManager的handleKeyUp里面去了。是不是很简单而且直接呢
getAudioManager().handleKeyDown(event,mVolumeControlStreamType);
return true;
}
……
}
我们发现它只被用来作为AudioService的几个函数调用的参数。从AudioManager这边看来它没有任何实际意义。其实,这在Android中进程间交互通讯中是一种常见且非常重要的技术。mICallBack这个简单的变量可以充当Bp端在Bn端的一个唯一标识。Bn端,也就是AudioService拿到这个标识后,就可以通过DeathRecipient机制获取到Bp端异常退出的回调。这是AudioService维持静音状态正常变迁的一个基石。
注意服务端把客户端传入的这个Binder对象作为客户端的一个唯一标识,能做的事情不仅仅DeathRecipient这一个。还以这个标识为键创建一个Hashtable,用来保存每个客户端相关信息。这在Android各个系统服务的实现中是一种很常见的用法。
音量控制是AudioService最重要的功能之一。
· AudioService音量管理的核心是VolumeStreamState。它保存了一个流类型所有的音量信息。
· VolumeStreamState保存了运行时的音量信息,而音量的生效则是在底层AudioFlinger完成。所以音量设置需要做两件事情,更新VolumeStreamState存储的音量值。设置音量到Audio底层系统。
· VolumeDeathHandler是VolumeStreamState的一个内部类。它的实例对应了在一个流类型上执行了静音操作的一个客户端,是实现静音功能的核心对象。
> Java Binder和MessageQueue:
· Binder系统在Java世界是如何布局和工作的。
· MessageQueue的新职责。
Binder架构中代表Client的Bp端及代表Server的Bn端感到陌生。Java层中Binder实际上也是一个C/S架构,而且其在类的命名上尽量保持与Native层一致,因此可认为,Java层的Binder架构是Native层Binder架构的一个镜像。
-- Binder、JavaBBinderHolder和JavaBBinder:
· Java层的Binder通过mObject指向一个Native层的JavaBBInderHolder对象。
· Native层的JavaBBinderHolder对象通过mBinder成员变量指向一个Native的JavaBBinder对象。
· Native的JavaBBinder对象又通过mObject变量指向一个Java层的Binder对象。
MessageQueue类封装了与消息队列有关的操作。在一个以消息驱动的系统中,最重要的两部分就是消息队列和消息处理循环。epoll机制提供了Linux平台上最高效的I/O复用机制.从调用方法上看,epoll的用法和select/poll非常类似,其主要作用就是I/O复用,即在一个地方等待多个文件句柄的I/O事件。
epoll内部用于保存事件的数据结构使用的是红黑树,查找速度很快。而select采用数组保存信息,不但一次能等待的句柄个数有限,并且查找起来速度很慢。当然,在只等待少量文件句柄时,select和epoll效率相差不是很多,但还是推荐使用epoll。
-- MessageQueue/Looper/MessageQueue
· Java层提供了Looper类和MessageQueue类,其中Looper类提供循环处理消息的机制,MessageQueue类提供一个消息队列,以及插入、删除和提取消息的函数接口。另外,Handler也是在Java层常用的与消息处理相关的类。
· MessageQueue内部通过mPtr变量保存一个Native层的NativeMessageQueue对象,mMessages保存来自Java层的Message消息。
· NativeMessageQueue保存一个native的Looper对象,该Looper从ALooper派生,提供pollOnce和addFd等函数。
· Java层有Message类和Handler类,而Native层对应也有Message类和MessageHandler抽象类。在编码时,一般使用的是MessageHandler的派生类WeakMessageHandler类。
注意 在include/media/stagfright/foundation目录下也定义了一个ALooper类,它是供stagefright使用的类似Java消息循环的一套基础类。这种同名类的产生,估计是两个事先未做交流的Group的人写的。
-- MessageQueue处理流程总结:
· MessageQueue核心逻辑下移到Native层后,极大地拓展了消息处理的范围,总结一下有以下几点:
· MessageQueue继续支持来自Java层的Message消息,也就是早期的Message加Handler的处理方式。
· MessageQueue在Native层的代表NativeMessageQueue支持来自Native层的Message,是通过Native的Message和MessageHandler来处理的。
· NativeMessageQueue还处理通过addFd添加的Request。在后面分析输入系统时,还会大量碰到这种方式。
· 从处理逻辑上看,先是Native的Message,然后是Native的Request,最后才是Java的Message。
Java层的Binder架构和Native层Binder架构类似,但是Java的Binder在通信上还是依赖Native层的Binder。
> WindowManagerService(WMS):
WmS简介(三)之Activity窗口是如何创建的?基于Android7.0源码 - http://blog.csdn.net/u012702547/article/details/53239925
Android系统中的窗口是屏幕上的一块用于绘制各种UI元素并可以响应应用户输入的一个矩形区域。从原理上来讲,窗口的概念是独自占有一个Surface实例的显示区域。例如Dialog、Activity的界面、壁纸、状态栏以及Toast等都是窗口。
-- 入分析WMS的两个基础子系统的工作原理:
·布局系统(Layout System),计算与管理窗口的位置、层次。
·动画系统(Animation System),根据布局系统计算的窗口位置与层次渲染窗口动画。
-- Android WindowManagerService显示系统的三个层次:
· 第一个层次是UI框架层,其工作为在Surface上绘制UI元素以及响应输入事件。
· 第二个层次为WMS,其主要工作在于管理Surface的分配、层级顺序等。
· 第三层为SurfaceFlinger,负责将多个Surface混合并输出。
-- 用户消息可分为两类,一类是Key消息,另一类是Motion消息。在Android2.3版本的消息系统设计中,对于Motion消息,InputDispatcher会使用pipe直接把消息发往客户窗口,WmS类不能对这些消息进行任何的前置(pre)处理,而对于Key消息,则会首先回调WmS中的Key消息处理函数,在WmS中不处理该消息时,才把消息发往客户窗口中。
Android系统中的窗口是屏幕上的一块用于绘制各种UI元素并可以响应应用户输入的一个矩形区域。从原理上来讲,窗口的概念是独自占有一个Surface实例的显示区域。例如Dialog、Activity的界面、壁纸、状态栏以及Toast等都是窗口。
-- 分析WMS的两个基础子系统的工作原理:
· 布局系统(Layout System),计算与管理窗口的位置、层次。
· 动画系统(Animation System),根据布局系统计算的窗口位置与层次渲染窗口动画。
-- WMS使用Choreographer负责驱动所有的窗口动画、屏幕旋转动画、墙纸动画的渲染。
所谓的应用组件可以是Activity、InputMethod、Wallpaper以及Dream。在WMS对窗口的管理过程中,用WindowToken指代一个应用组件。WindowToken具有令牌的作用,是对应用组件的行为进行规范管理的一个手段。WindowToken由应用组件或其管理者负责向WMS声明并持有。应用组件在需要新的窗口时,必须提供WindowToken以表明自己的身份,并且窗口的类型必须与所持有的WindowToken的类型一致。 对于WMS的客户端来说,Token仅仅是一个Binder对象而已。
-- WallpaperManagerService
WallpaperManagerService使用WindowToken对一个特定的Wallpaper做出了如下限制:
· Wallpaper只能创建TYPE_WALLPAPER类型的窗口。
· Wallpaper显示的生命周期由WallpaperManagerService牢牢地控制着。仅有当前的Wallpaper才能创建窗口并显示内容。其他的Wallpaper由于没有有效的Token,而无法创建窗口。
InputMethod的Token的来源与Wallpaper类似,其声明位于InputMethodManagerService的startInputInnerLocked()函数中,取消声明的位置在InputmethodManagerService的unbindCurrentMethodLocked()函数。InputMethodManagerService通过Token限制着每一个InputMethod的窗口类型以及显示生命周期。
AMS通过ActivityRecord表示一个Activity。而ActivityRecord的appToken在其构造函数中被创建,所以每个ActivityRecord拥有其各自的appToken。而WMS接受AMS对Token的声明,并为appToken创建了唯一的一个AppWindowToken。因此,这个类型为IApplicationToken的Binder对象appToken粘结了AMS的ActivityRecord与WMS的AppWindowToken,只要给定一个ActivityRecord,都可以通过appToken在WMS中找到一个对应的AppWindowToken,从而使得AMS拥有了操纵Activity的窗口绘制的能力。例如,当AMS认为一个Activity需要被隐藏时,以Activity对应的ActivityRecord所拥有的appToken作为参数调用WMS的setAppVisibility()函数。此函数通过appToken找到其对应的AppWindowToken,然后将属于这个Token的所有窗口隐藏。
对比一下mTokenMap和mWindowMap。这两个HashMap维护了WMS中最重要的两类数据:WindowToken及WindowState。它们的键都是IBinder,区别是: mTokenMap的键值可能是IAppWindowToken的Bp端(使用addAppToken()进行声明),或者是其他任意一个Binder的Bp端(使用addWindowToken()进行声明);而mWindowToken的键值一定是IWindow的Bp端。
AppWindowToken在mAppTokens的顺序就是Activity的顺序。
WindowStateAnimator和AppWindowAnimator是动画系统中的两员大将,它们负责渲染窗口动画以及最终的Surface显示次序的修改。WindowStateAnimator/AppWindowAnimator则是动画体系的类,其mAnimLayer的意义偏向于动画,而且由于动画系统维护着窗口的Surface,因此mAnimLayer是Surface的实际显示次序。
窗口根据自己的类型得出其主序及子序,然后addWindowToListInOrderLocked()根据主序、子序以及其所属的Activity的顺序,按照升序排列在DisplayContent的mWindows列表中。然后assignLayersLocked()为mWindows中的所有窗口分配最终的显示次序。之后,WMS的动画系统将最终的显示次序通过Surface.setLayer()设置进SurfaceFlinger。
-- Android源码分析之理解Window和WindowManager- http://blog.csdn.net/u012124438/article/details/77347732
Android中所有的视图都是通过Window来呈现的,无论是Activity,Dialog还是Toast,Window实际上是View的直接管理者。单击时间由Window传递给DecorView,然后DecorView再传递给我们的View,就连Activity设置视图的方法setContentView底层也是通过Window来完成的。
Android源码解析Window系列第(三)篇---WindowManager基本原理-http://blog.csdn.net/u013263323/article/details/53614123
Android关于EditText和WindowManager的一些知识- http://blog.csdn.net/zjutkz/article/details/46610945
Android-WindowManager- http://blog.csdn.net/z82367825/article/details/50899805
WindowManager和WindowManagerService的交互是一个IPC过程。
> ActivityManagerService(AMS)
AMS是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要。
-- 为了帮助读者更好地理解AMS,按五条不同的线来分析它:
·第一条线:同其他服务一样,将分析SystemServer中AMS的调用轨迹。
·第二条线:以am命令启动一个Activity为例,分析应用进程的创建、Activity的启动,以及它们和AMS之间的交互等知识。
·第三条线和第四条线:分别以Broadcast和Service为例,分析AMS中Broadcast和Service的相关处理流程。
·第五条线:以一个Crash的应用进程为出发点,分析AMS如何打理该应用进程的身后事。
-- ActivityManagerService提供的主要功能:(1)统一调度各应用程序的Activity;(2)内存管理;(3)进程管理;
在整个系统中,Activity实际上有两个实体。一个在应用进程中跟应用程序员打交道的Activity,一个是在AMS的中具有管理功能的History Record。应用进程中的Activity都登记ActivityThread实例中的mActivity数组中,而在AM端,HistroytRecord实例放置在mHistroy栈中。mHistory栈是Android管理Activity的场所,放置在栈顶的就是User看到的处于活动状态的Activity。
Activity的内核实体是依靠在ProcessRecord的成员变量中,通过ProcessRecord我们可以访问到所有的属于该Process的Activity。而在ProcessRecord记录了与应用进程之间的联系:IActivtityThread接口。通过该接口,可以访问到所对应的Activity的方法。在Launch Activity时,AMS将对应的HistoryRecord作为token传递到客服端和客服端的Activity建立联系。在AMS中Activity状态变化时,将通过该联系找到客服端的Activity,从而将消息或者动作传递应用程序面对的接口:xxxActivity。
-- ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。应用进程指那些运行APK的进程,它们由Zyote 派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和SystemServer)。
· Instrumentation:Base class for implementingapplication instrumentation code. When running with instrumentation turned on,this class will be instantiated for you before any of the application code,allowing you to monitor all of the interaction the system has with the application.An Instrumentation implementation is described to the system through anAndroidManifest.xml's <instrumentation> tag.大意是:Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递,这样,Instrumentation就能监测系统和这些组件的交互情况了。在实际使用中,我们可以创建Instrumentation的派生类来进行相应的处理。读者可查询Android中Junit的使用来了解Intrstrumentation的作用。
· Application:Base class for those who need tomaintain global application state. You can provide your own implementation byspecifying its name in your AndroidManifest.xml's <application> tag,which will cause that class to be instantiated for you when the process foryour application/package is created.大意是:Application类保存了一个全局的application状态。Application由AndroidManifest.xml中的<application>标签声明。在实际使用时需定义Application的派生类。
· Context:Interface to global informationabout an application environment. This is an abstract class whoseimplementation is provided by the Android system. It allows access toapplication-specific resources and classes, as well as up-calls forapplication-level operations such as launching activities, broadcasting andreceiving intents, etc.大意是:Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。
· 进程:来源于操作系统,是在OS中看到的运行体。我们编写的代码一定要运行在一个进程中。
· Android运行环境:Android努力构筑了一个自己的运行环境。在这个环境中,进程的概念被模糊化了。组件的运行及它们之间的交互均在该环境中实现。
Android运行环境是构建在进程之上的。有Android开发经验的读者可能会发现,在应用程序中,一般只和Android运行环境交互。基于同样的道理,SystemServer希望它内部的那些Service也通过Android运行环境交互,因此也需为它创建一个运行环境。由于SystemServer的特殊性,此处调用了systemMain函数,而普通的应用进程将在主线程中调用ActivityThread的main函数来创建Android运行环境。
另外,ActivityThread虽然本意是代表进程的主线程,但是作为一个Java类,它的实例到底由什么线程创建,恐怕不是ActivityThread自己能做主的,所以在SystemServer中可以发现,ActivityThread对象由其他线程创建,而在应用进程中,ActivityThread将由主线程来创建。
· ContextWrapper比较有意思,其在SDK中的说明为“Proxying implementation ofContext that simply delegates all of its calls to another Context. Can besubclassed to modify behavior without changing the original Context.”大概意思是:ContextWrapper是一个代理类,被代理的对象是另外一个Context。在图6-3中,被代理的类其实是ContextImpl,由ContextWrapper通过mBase成员变量指定。读者可查看ContextWrapper.java,其内部函数功能的实现最终都由mBase完成。这样设计的目的是想把ContextImpl隐藏起来。
· Application从ContextWrapper派生,并实现了ComponentCallbacks2接口。Application中有一个LoadedApk类型的成员变量mLoadedApk。LoadedApk代表一个APK文件。由于一个AndroidManifest.xml文件只能声明一个Application标签,所以一个Application必然会和一个LoadedApk绑定。
· Service从ContextWrapper派生,其中Service内部成员变量mApplication指向Application(在AndroidManifest.xml中,Service只能作为Application的子标签,所以在代码中Service必然会和一个Application绑定)。
· ContextThemeWrapper重载了和Theme(主题)相关的两个函数。这些和界面有关,所以Activity作为Android系统中的UI容器,必然也会从ContextThemeWrapper派生。与Service一样,Activity内部也通过mApplication成员变量指向Application。
-- AMS的main函数的目的有两个:
· 首先也是最容易想到的目的是创建AMS对象。
· 另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。
-- Android希望SystemServer中的服务也通过Android运行环境来交互。这更多是从设计上来考虑的,比如组件之间交互接口的统一及未来系统的可扩展性。
· 关键点一:ActivityThread的installSystemApplicationInfo函数。
· 关键点二:ProcessRecord类,它和AMS对进程的管理有关。
AMS如何与应用进程交互?例如AMS启动一个位于其他进程的Activity,由于该Activity运行在另外一进程中,因此AMS势必要和该进程进行跨进程通信。答案自然是通过Binder进行通信。为此,Android提供了一个IApplicationThread接口,该接口定义了AMS和应用进程之间的交互函数.
· AMS保存ProviderInfo的原因是它要管理ContentProvider。
· ProcessRecord保存ProviderInfo的原因是ContentProvider最终要落实到一个进程中。其实也是为了方便AMS管理,例如该进程一旦退出,AMS需要把其中的ContentProvider信息从系统中去除。
AMS及ProcessRecord均使用了一个新的数据结构ContentProviderRecord来管理ContentProvider信息。
-- ActivityManagerService总结:
· AMS的main函数:创建AMS实例,其中最重要的工作是创建Android运行环境,得到一个ActivityThread和一个Context对象。
· AMS的setSystemProcess函数:该函数注册AMS和meminfo等服务到ServiceManager中。另外,它为SystemServer创建了一个ProcessRecord对象。由于AMS是Java世界的进程管理及调度中心,要做到对Java进程一视同仁,尽管SystemServer贵为系统进程,此时也不得不将其并入AMS的管理范围内。
· AMS的installSystemProviders:为SystemServer加载SettingsProvider。
· AMS的systemReady:做系统启动完毕前最后一些扫尾工作。该函数调用完毕后,HomeActivity将呈现在用户面前。
-- 对多Task的情况来说,系统只支持一个处于前台的Task,即用户当前看到的Activity所属的Task,其余的Task均处于后台,这些后台Task内部的Activity保持顺序不变。用户可以一次将整个Task挪到后台或者置为前台。
· Activity由ActivityRecord表示,Task由TaskRecord表示。ActivityRecord的task成员指向该Activity所在的Task。state变量用于表示该Activity所处的状态(包括INITIALIZING、RESUMED、PAUSED等状态)。
· ActivityStack用mHistory这个ArrayList保存ActivityRecord。令人大跌眼镜的是,该mHistory保存了系统中所有Task的ActivityRecord,而不是针对某个Task进行保存。
· ActivityStack的mMainStack成员比较有意思,它代表此ActivityStack是否为主ActivityStack。有主必然有从,但是目前系统中只有一个ActivityStack,并且它的mMainStack为true。从ActivityStack的命名可推测,Android在开发之初也想用ActivityStack来管理单个Task中的ActivityRecord(在ActivityStack.java的注释中说过,该类为“State and management of asingle stack of activities”),但不知何故,在现在的代码实现将所有Task的ActivityRecord都放到mHistory中了,并且依然保留mMainStack。
· ActivityStack中没有成员用于保存TaskRecord。
由上述内容可知,ActivityStack采用数组的方式保存所有Task的ActivityRecord,并且没有成员保存TaskRecord。这种实现方式有优点亦有缺点:
· 优点是少了TaskRecord一级的管理,直接以ActivityRecord为管理单元。这种做法能降低管理方面的开销。
· 缺点是弱化了Task的概念,结构不够清晰。
-- Launch Mode用于描述Activity的启动模式,目前一共有4种模式,分别是standard、singleTop、singleTask和singleInstance。初看它们,较难理解,实际上不过是Android玩的一个“小把戏“而已。启动模式就是用于控制Activity和Task关系的。
除了启动模式外,Android还有其他一些标志用于控制Activity及Task之间的关系。这里只列举一二,详细信息请参阅SDK文档中Intent的相关说明。
· FLAG_ACTIVITY_NEW_TASK:将目标Activity放到一个新的Task中。
· FLAG_ACTIVITY_CLEAR_TASK:当启动一个Activity时,先把和目标Activity有关联的Task“干掉“,然后启动一个新的Task,并把目标Activity放到新的Task中。该标志必须和FLAG_ACTIVITY_NEW_TASK标志一起使用。
· FLAG_ACTIVITY_CLEAR_TOP:当启动一个不处于栈顶的Activity时候,先把排在它前面的Activity“干掉”。例如Task有A、B、C、D 4个Activity,要要启动B,直接把C、D“干掉”,而不是新建一个B。
AMS提供了两个函数,用于暂时(注意,是暂时)禁止App切换。为什么会有这种需求呢?因为当某些重要(例如设置账号等)Activity处于前台(即用户当前所见的Activity)时,不希望系统因用户操作之外的原因而切换Activity(例如恰好此时收到来电信号而弹出来电界面)。
当前Activity所在进程、AMS所在进程及目标进程。如目标SDK版本大于9,则不允许在主线程使用网络操作(如Socketconnect等),否则抛出NetworkOnMainThreadException,这么做的目的是防止应用程序在主线程中因网络操作执行时间过长而造成用户体验下降。说实话,没有必要进行这种限制,在主线程中是否网络操作是应用的事情。再说,Socket也可作为进程间通信的手段,在这种情况下,网络操作耗时很短。作为系统,不应该设置这种限制。另外,Goolge可以提供一些开发指南或规范来指导开发者,而不应如此蛮横地强加限制。
Service是Android的四大组件之一。和Activity,BroadcastReceiver相比,Service定位于业务层逻辑处理,而Activity定位于前端UI层逻辑处理,BroadcastReceiver定位于通知逻辑的处理。
-- 这两种方式还影响Service对象的生命周期,简单总结如下:
·对于以startService方式启动的Service对象,其生命周期一直延续到stopSelf或stopService被调用为止。
·对于以bindService方式启动的Service对象,其生命周期延续到最后一个客户端调用完unbindService为止。
Android将应用进程分为五大类,分别为Forground类、Visible类、Service类、Background类及Empty类。
AMS在处理应用进程的Crash及死亡的工作上也是不遗余力的。
> PMS(PowerManagerService)
-- systemReady主要工作为:
· PMS创建SensorManager,通过它可与对应的传感器交互。关于Android传感器系统,将放到本书后续章节讨论。PMS仅仅启用或禁止特定的传感器,而来自传感器的数据将通过回调的方式通知PMS,PMS根据接收到的传感器事件做相应处理。
· 通过setPowerState函数设置电源状态为ALL_BRIGHT(不考虑UseSoftwareAutoBrightness的情况)。此时屏幕及键盘灯都会点亮。关于setPowrState函数,后文再做详细分析。
· 调用BatteryStatsService提供的函数,以通知屏幕打开事件,在BatteryStatsService内部将处理该事件。稍后,本章将详细讨论BatteryStatsService的功能。
当系统中的服务都在systemReady中进行处理后,系统会广播一次ACTION_BOOT_COMPLETED消息,而PMS也将处理该广播. WakeLock是Android提供给应用程序获取电力资源的唯一方法。只要还有地方在使用WakeLock,系统就不会进入休眠状态。
PMS用来管理所有的package信息,包括安装、卸载、更新以及解析AndroidManifest.xml以组织相应的数据结构,这些数据结构将会被PMS、
ActivityMangerService等service和application使用到。
-- PackageInstaller安装APK的过程,简单来说就两步:
1. 将APK的信息通过IO流的形式写入到PackageInstaller.Session中。
2. 调用PackageInstaller.Session的commit方法,将APK的信息交由PMS处理
-- WakeLock的一般使用方法如下:
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
//①创建一个WakeLock,注意它的参数
PowerManager.WakeLock wl =pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,"MyTag");
PMS提供了一个函数叫preventScreenOn,该函数(在SDK中未公开)使应用程序可以阻止屏幕点亮。PMS有时需要进行点亮屏幕,打开键盘灯等操作,为此Android提供了Power类及LightService满足PMS的要求。
-- PMS和系统中其他两个服务BatterService及BatteryStatsService均有交互,其中:
· BatteryService提供接口用于获取电池信息,充电状态等。
· BatteryStatsService主要用做用电统计,通过它可知谁是系统中的耗电大户。
· 一共有两大类计量工具,Counter用于计数,Timer用于计时。
· BSImpl实现了StopwatchTimer(即所谓的秒表)、SamplingTimer(抽样计时)、Counter和SamplingCounter(抽样计数)等4个具体的计量工具。
· BSImpl中定义了一个Unpluggable接口。当手机插上USB线充电(不论是由AC还是由USB供电)时,该接口的plug函数被调用。反之,当拔去USB线时,该接口的unplug函数被调用。设置这个接口的目的是为了满足BSImpl对各种情况下系统用电量的统计要求。关于Unpluggable接口的作用,在后续内容中可以能见到。
BatteryService和系统中的供电系统交互,通过它可获取电池状态等信息。而BatteryStatsService用于统计系统用电量的情况。
PMS的初始化流程、WakeLock获取流程、userActivity函数的工作流程及Power按键处理流程。
-- PMS(Package manager Service)负责系统中Package的管理,应用程序的安装、卸载、信息查询等。
PKMS构造函数的主要功能是,扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。抽象地看,PKMS像一个加工厂,它解析实际的物理文件(APK文件)以生成符合自己要求的产品。例如,PKMS将解析APK包中的AndroidManifest.xml,并根据其中声明的Activity标签来创建与此对应的对象并加以保管。
PKMS的工作流程相对简单,复杂的是其中用于保存各种信息的数据结构和它们之间的关系,以及影响最终结果的策略控制(例如前面代码中的onlyCore变量,用于判断是否只扫描系统目录)
-- PKMS构造函数的工作流程大体可分三个阶段:
· 扫描目标文件夹之前的准备工作。
· 扫描目标文件夹。
· 扫描之后的工作。
-- Android系统明确指定的一个Intent可由两方面属性来衡量。
· 主要属性:包括Action和Data。其中Action用于表示该Intent所表达的动作意图、Data用于表示该Action所操作的数据。
· 次要属性:包括Category、Type、Component和Extras。其中Category表示类别,Type表示数据的MIME类型,Component可用于指定特定的Intent响应者(例如指定广播接收者为某Package的某个BroadcastReceiver),Extras用于承载其他的信息。
-- Andorid规定了3项内容.
· Action:求职方支持的Intent动作(和Intent中的Action对应)。
· Category:求职方支持的Intent种类(和Intent的Category对应)。
· Data:求职方支持的Intent 数据(和Intent的Data对应,包括URI和MIME类型)。
-- IntentFilter中的Data可以包括两个内容。
· URI:完整格式为“scheme://host:port/path”,包含4个部分,scheme、host、port和path。其中host和port合起来标示URI authority,用于指明服务器的网络地址(IP加端口号)。由于URI最多可包含,4个部分,因此要根据情况相应部分做匹配检查。
· Date type:指定数据的MIME类型,要特别注意的是,URI中也可以携带数据的类型信息,所以在匹配过程中,还需要考虑URI中指定的数据类型。
-- PKMS:
· 从工作流程上看,PKMS包含几条重要的主线。一条是PKMS自身启动时构造函数的工作流程,另外几条和APK安装、卸载相关。每一条主线的难度都比较大,读者可结合日常工作的需求进行单独研究,例如研究如何加快构造函数的执行时间等。
· 从数据结构上看,PKMS涉及非常多的数据类型。如果对每个数据结构进行孤立分析,很容易陷入不可自拔的状态。笔者建议不妨跳出各种数据结构的具体形态,只从目的及功能角度去考虑。这里需要读者仔细查看前面的重要数据结构及说明示意图。
· APK安装在SD卡,以及APK从内部存储转移到SD卡的流程。
· 和Package相关的内容,例如签名管理、dex优化等。
> 书籍
《Linux内核源代码情景分析》
这篇关于Android FrameWork(AMS,WMS,PMS等)的概念及解析,获取系统服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!