AMS(ActivityManagerService) 在SystemServer的进程中,是SystemServer中的一个对象;
作用:
管理activity的生命周期
启动activity
-
与PMS进行交互
Activity->AMS:
调用
activity.startActivity()
通过
ActivityManage.getService("activity")
得到AMS的BpBinder;-
通过BpBinder发送请求,调用AMS的
startActivity()
AMS->PMS:
AMS和PMS都在
SystemServer
进程中,都是SystemServer
中一个对象通过包名和PMS里的缓存
mPackage
查询到App对应的Package使用activity的类名通过PMS里的内部类
PackageManagerInternalImpl
查询到activity对应的包装类ResolveInfo; ps:ResolveInfo
这个javabean里有activityInfo、ServiceInfo
等变量,查询啥就给哪个变量赋值,再返回ResolveInfo;
得到
ResolveInfo
里的activityInfo;
将
activityInfo
返回给App进程的ActivityThread;`ActivityThread
中发送事件ActivityThread
中的Handler对象mH收到159事件,处理通过反射创建Activity对象
将Activity对象放到activtes启动记录中
ActivityThread
- 每个应用有一个ActivityThread;是应用的入口;
- 在APP进程中
- 是AMS的缓存中心
- ActivityThread中的List<ActivityRecord> activtes放了activity的启动记录
ActivityThread中重要的对象:
- ApplicationThread:AMS回调给ActivityThread数据的桥梁
- mInstrumentation:管理Application和Activity的生命周期(及创建)
- mH:Handler,处理ApplicationThread里各种回调函数发送的各种消息
点击桌面App图标发生了什么?
- 点击的APP图标是在单独的Luancher进程,是一个系统App进程
- Luancher进程请求SystemServer进程中的AMS去创建应用的根Activity(AndroidMnifest.xml中initen-fifter为Luanche的activity)
- AMS通过包名让PMS查询到相关应用信息,得到应用的Package;
- AMS创建activity栈,根据Package拿到根activity的配置节点信息,放到栈中,此时栈中只有一个根activity的配置节点信息,也就是在栈顶;(此处的栈不是应用层的栈,这个栈只是用来放activity节点信息的)
- AMS请求zygote进程创建App进程;zygote进程比较特殊, 使用Socket通信,而不是binder;zygote是所有应用的孵化器,zygote进程挂掉时,手机会自动重启;
- zygote进程去fork出App进程;
- APP进程中的主线程调用
ActivityThread.main()
静态函数,main中创建ActivityThread
对象 - 接着在
ActivityThread.attch()
中创建了一个ApplicationThread
对象,作为和AMS通信时,返回结果的桥梁; - App进程通过AMS的binder调用
attachApplication(thread)
请求AMS获取应用对应的Applaction和栈顶中activity节点信息(步骤4),此时给AMS传过去了一个thread,这个thread就是ApplicationThread
- AMS将从PMS查到的application节点数据序列化后,调用
thread.bindApplaction
(data数据...)传给ActivityThread;
(此时代码还会继续往下执行,去获取栈顶activity的节点信息) - ActivityThread调用sendMessage发送消息
BIND_APPLICATION(110)
给Handler,Handler调用handleBindApplication(data)
- 通过反射实例化Instrumentation对象:负责application和activity的生命周期的管理
- 通过Instrumentation对象反射实例化
new Applaction
对象app - 调用
Instrumentation.callApplactionOnCreate(app)
- 执行
Applaction.onCreate()
- 步骤10中AMS继续向下执行查找activity,AMS将查到的栈顶根Activity(LaunchActivity )信息封装到一个事务ClientTransaction中,提交事务并执行,在执行中,调用
thread.scheduleTransaction
(事务数据);(thread为ActivityThread中的ApplicationThread
) - 在
ApplicationThread
回调scheduleTransaction
函数中,发送`EXECUTE_TRANSACTION(159)消息 - Handler处理
EXECUTE_TRANSACTION
消息,从事务数据中取出LaunchActivity
信息,并调用hanldeLaunchActivity
(activity数据) - 通过Instrumentation对象反射实例化
newActivity()
出对象activity - 执行
activity.attach()
,在attach中创建WMS的桥接代理类;(绘制流程会用到) - 通过
Instrumentation
调用callActivityOnCreate(activity)
- 执行
Activty.onCreate();
- 至此启动页根Activity启动完成;
下图中4-5中少了上面7-23的步骤:
7-15创建并启动了Application;
16-22创建并启动了Activity;
应用内activity与activity的跳转是跨进程通信,还是同一个进程内通信?
是跨进程通信;
跳转流程参考上面的:省去了application的创建过程;
步骤3 +步骤16-23;
2.Android Framework源码-PMS
SystemServer: Android一切服务的启动者;
- 开机时,板子引导芯片启动引导程序
- 引导程序启动PID为0的linux内核进程
- linux系统启动init脚本,启动PID永远为1的init进程
- init进程启动SystemManager进程;
- SystemManager进程启动完后;
- init进程启动zygote进程(native进程)
- zygote调用
SystemServer.java
的main函数,frok出SystemServer进程(java进程) -
SystemServer.java
的main函数里执行SystemServer的run方法,main函数里只有一句代码:new SystemServer().run();
- run方法中启动服务进程,AMS、PMS等
ps:SystemManager: 是SystemServer的叔叔,SystemServer把所有服务都交给了SystemManager管理;
- AMS、PMS自身创建后,自身对象会添加到
SystemManager
中,addService("key",AMS/PMS)
-
getService()
时,取的是个binder;
PMS(PackageManagerService): 在SystemServer的进程中,是SystemServer中的一个对象;
有一个缓存中心:mPackages;是一个Map,key为应用的包名,value为每个应用的Package;
在手机启动的时候,做了三件事,且只做一次:
- 遍历所有app文件
- 解压每个apk文件
- dom解析
AndroidMnifest.xml
,并缓存;
作用:只解析每个Apk中的AndroidMnifest.xml
中的信息,而不是去解析节点中每个xxxActivity.java
文件;解析到的信息缓存到mPackages中,相当于“注册表”,方便之后AMS快速定位到相应的APP;
-
PackageManagerService.java
中会去两个目录做扫描scanDirTracedLI
:用户安装的所有APP目录sAppInstallDir:data/app/;
和系统应用所有APP的目录systemAppDir:System/app/
- 6.0-8.0都是单线程扫描,9.0和10.0是用线程池进行扫描,扫描到的apk文件信息,
new PackageParse(),
赋值给包解析工具类PackageParse; - 解压Apk文件,9.0和10.0解析时会去判断缓存中是否有,有则用缓存,6.0-8.0没有使用缓存;
- 使用工具类PackageParse解析
AndroidMnifest.xml
,xml解析完会返回Package对象,每个APK对应一个Package对象,得到这个Package对象后,缓存到PackageManagerService的mPackages
这个ArrayMap里;key为应用的包名,value为应用的Package; - Package对象中有解析出的对应App中的四大组件标签、权限标签等等,放入各自的List中,如:activites、services、revicers、providers、权限list等等;activites这些list存的只是一个javabean,而不是存的具体的应用层的Activity;
解析AndroidMnifest.xml
流程:
- 打开
AndroidMnifest.xml
- 获取版本号、版本名称
- 判断
tagname=="applacation"
- 判断
tagname=="activity","reciver","service","provide"
等等 - 走到对应的解析
parseActivity,parseActivity
(reciver和activity的结构一样,就用同样的javabean接收),parseService,parseProvide
- 解析完添加到Package的对应的list中;
3.Android Framework源码-IMS
Linux事件机制:
事件都是储存在文件中;
如触摸屏幕事件:存储在dev/input/event0的文件中,每次触摸都会以 16进制 数据储存;
INotify:监听文件状态,有变化则产生FD值
epoll机制:
epoll_create:注册监听事件类型
epoll_ctl:监听FD值,FD改变则唤醒epoll_wait()
epoll_wait:没事件则阻塞,有事件则分发;
将INotify和epoll封装为一个对象EventHub;
SystemServer进程启动时,创建了InputManagerService
服务,这个IMS在native层创建了InputManager对象;
InputManager里有一个对象EventHub;
同时InputManager里面又开启了两个线程:
InputReaderThread
:不断去读取EventHub里的事件;有事件时把数据封装后添加到队列,立马从队列里读取交给InputDispatcher
进行分发;
InputDispatcherThread:InputDispatcher
里面保存了wms中所有的window信息(wms会将window信息实时更新到InputDispatcher
中),InputDispatcher就可以将事件分发给对应合适的window;
App进程中的ViewRootImpl和SystemServer中的IMS通过socketpair通信,因为事件产生的非常快且非常多使用binder通信不适合
在ViewRootImpl
中setView后new了一个监听FD文件的回调,new WindowInputEventReceiver();
在回调中,底层使用epoll_ctl()
函数监听FD是否变化,有变化则会回调至java层,dispatchInputEvent();
这里就是Activity-》Viewgroup->View的事件分发前置;
底层事件信号传递总结:
- 事件信号都是用物理文件存储数据的,位置在dev/input 文件夹下;touch事件存储在dev/input/event0的文件中;
- Linux有提供相关的文件监控api: inotify()和epoll机制
- android创建了一个封装了
inotify()
和epoll机制的对象EventHub,来监控dev/input文件夹下面的事件信号文件; - android自己启动两个线程来处理dev/input文件夹下面的事件信号文件:InputReaderThread
和
InputDispatherThread;` - 在
InputReaderThread
中开启循环,对EventHub对象进行getEvent();
-
getEvent()
中有epoll_wait;
相当于wait-notif机制;唤醒的触发点时dev/input下的文件被改变; -
InputReaderThread
将dev/input文件夹下面的事件信号文件数据进行 提取、封装,然后交给InputDispatherThread;
-
InputDispatherThread
最终选择到对应的ViewRootImpl(window)
进行分发数据; - 这里App进程和SystemServer两个进程通过Socketpair进行通信;两个进程一边一组socketpair;
- 在
ViewRootImpl
中对于Channel连接的文件进行监控(epoll_ctr),从而是上层接收到touch信号;
4.Android WMS及绘制流程
主角:ViewRootImpl、Choreographer、Surfaceflinfer
WMS扮演了什么角色?
作为协调者,协调view布局,绘制;
- 在ActivityThread中创建Actiivty后,调用
activity.attach()
时,创建一个窗体对象PhoneWindow - PhoneWindow创建了一个WMS的代理桥接类
WindowManagerImpl
对象,作为WMS在app中的代表; -
WindowManagerImpl
对象中的(mGlobal)WindowManagerGlobal
专门和WMS通信,在mGlobal里面获取了到了WMS的Binder:getWindowSession()->WMS::openSession();
setContentView()
- 调用
PhoneWindow.setContentView(resouseID)
- PhoneWindow中:创建mDector:窗体上的整个View:里面有官方的主题布局+用户自己的布局;
- PhoneWindow中:创建
mContentParent
:官方主题布局中提供给用户装载布局的容器:id为content; - 调用
mLayoutInflater.inflater(resouseID,mContentParent)
: - 解析用户的布局xml
- 递归调用:解析根布局,通过反射创建根布局;解析子view,通过反射创建view;
- 最后PhoneWindow中的
mContentParent
加载用户的根布局; - 提交view数据
ps:这里递归调用,若嵌套层级太多,会导致栈溢出;因为递归调用不会释放栈;
ViewRootImpl 单例,管理所有View的绘制策略;
注意onCreate.setContentView
后view数据已解析并实例化了;
- 在状态机为Resume时:
- 调用WindowManagerImpl中的
mGlobal.addView(view)
- addView中创建
ViewRootImpl root=new ViewRootImpl()
: root.setView(view);
- 在setView总调用
requestLayout()
-
requestLayout()
请求绘制,编舞者出场
帧速率: CPU/GPU出图速率;
刷新率: 屏幕刷新速率;
- 帧速率>刷新率时,出现丢帧(出图好多张了,但是只显示了开头和结尾两张,中间的丢了)
- 帧速率<刷新率,出现卡顿(屏幕刷新好多次了,但是还是显示的第一帧)
Vsync: 垂直同步绘制信号; 因可能硬件帧速率和刷新率不一致,用来同步刷新的问题;
Choreographer编舞者: 负责管理帧率节奏;
- 在内部维护了个Haner和Looper,保证绘制发生在UI主线程:
Looper.myLooper==mLooper
判断是否是主线程,是的话去调同步绘制信号,不是的话发送消息,走主线程去调同步绘制信号 - 走native层请求垂直同步信号,实际是找底层驱动要上次绘制的时间
- 请求到垂直同步信号后回调onVsync
- 走doFrame去逻辑管控, 判断当前时间离上次绘制的时间大于了1帧的时间(16.66毫秒) 就跳帧(卡顿优化有用到),若小于16.66毫秒就再次请求垂直同步信号,防止重叠
- 执行callback,让ViewRootImpl去真正绘制,调用
ViewRootImpl.performTraversals()
真正的绘制: ViewRootImpl.performTraversals()
- 调用
relayoutWindow()
: - 创建用户java层的surface:只有用户提供的画面数据;
- 创建native层的surface:包含用户提供的画面数据(java层的surface)+系统的画面数据(状态栏,电池、wifi等等);
- 创建完surface后:依次调用:
performMeasure(对应view的onMeasure)、performLayout(onLayout)、performDraw(onDraw);
在performDraw()
中:
- 将view的数据传至native层的surface
- surface中的canvas记录数据
- 生成bitmap图像数据(此时数据是在surface中)
- 将surface放入队列中;生产者消费者模式;
- 通知surfaceflinfer进程去队列中取surface数据
- surfaceflinfer拿到不同的surface,进行融合,生成bitmap数据
- 将bitmap数据放入framebuffer中,进行展示
简单版总结: Activity.setContentView(R.layout.resId)
:
解析xml并实例化;
- 调用
phoneWindow.setContentView(resId)
- 在setContentView中调用installDector():根据不同的主题,找到系统默认的xml,初始化出mDector和mContentParent(反射实例化出对应的ViewGroup)
- 初始化完成后,调用
mLayoutInflater.inflate(resId,mContentParent)
: - 解析resId的xml文件,将解析的view反射实例化;递归添加到各节点的viewgroup中;最后将自己定义的xml根布局view添加到
mContentParent;
绘制发生时间: 在AMS回调ActivityThread中的handleResumeActivity
时,也就是Resume时,而不是onCreate()
;
- 获取PhoneWindow
- 获取PhoneWindow中的mDector布局视图view
- 将mDector布局视图view传给ViewRootImpl
- ViewRootImpl中调用
requestLayout()
-
requestLayout()
中依次调用:performMeasure()、performLayout()、performDraw()