WMS和AMS

 WMS

Android WMS-窗口管理

WMS(WindowManagerService)是系统核心服务,它职责主要包含如下几个部分:

WMS作用

  • WMS管理窗口的创建、添加、删除、大小、层级等等。
  • Surface管理 ---SurfaceFlinger
    窗口不具备有绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制。为每个窗口分配Surface是由WMS来完成的。
    Surface就像画布,然后通过Canvas或OpenGL绘制。
    SurfaceFlinger的作用主要是merge Surface,它接受多个来源的Surface图形显示数据,然后将他们合并(根据特定顺序Z-order),然后发送到显示设备。如最常见的界面是3层,顶部的statusbar,底部的导航栏,应用界面。 

  • 输入中转-IMS(InputManagerService)
    触摸窗口产生触摸事件,IMS对触摸事件进行处理,最后寻找一个最合适窗口进行反馈处理
  • 窗口动画 ---WindowAnimator
    窗口间进行切换时,使用窗口动画可以实现更好的效果,窗口动画主要由WindowAnimator管理。可以在开发者模式菜单找到相应设置。

一、捋清几个关系

关系0: WMS和WM关系

关系1:Activity 、Window、View,Surface

这部分牵扯到的是窗口视图架构。

Activity:是系统可视化交互组件,四大组件都由AMS统管理生命周期,事实上它的职责只是生命周期的管理. 一个Activity包含一个Window,如果Activity没有Window,那就相当于Service

window:由设计模式的单职责的原则,那势必需要将Activity和其上的视图View进行解耦.
那么就引入Window的概念,它是个抽象类,对于Activity来说,它的具体实现类是PhoneWindow.
Window类代表着一个视图的顶层窗口,它管理着这个视图中最顶层的View,提供了一些背景、标题栏、默认按键等标准的UI处理策略。
同时,它拥有唯一一个用以绘制自己的内容的Surface,当app通过WindowManager创建一个Window时,WindowManager会为每一个Window创建一个Surface,并把该Surface传递给app以便应用在上面绘制内容。Window与Surface之前存在着一对一的关系。
View:在Activity执行attach的时候,会创建个PhoneWindow对象。PhoneWindow作为装载根视图DecorView的顶级容器,Activity通过setContentView实际上是调用PhoneWindow来创建DecorView并解析xml布局加载到DecorView的contentView部分

关系2:WindowManager、WindowManagerImpl、WindowManagerGlobal

这部分牵扯到的是应用端的窗口管理架构。

WindowManager是个接口类,继承自接口ViewManager,负责窗口的管理(增、删、改)。它的实现类是WindowManagerImpl,而具体操作实际上又会交给WindowManagerGlobal来处理,它是个单例,进程唯。WindowManagerGlobal执行addView的方法中会传入DecorView, 还会初始化个ViewRootImpl。WindowManagerGlobal因为是单例的,它内部会有两个List来分别保存这两个对象,来统管理。

关系3:ViewRootImpl、WindowManagerService

这份部分牵扯到的是具体窗口操作的binder IPC。

WindowManagerGlobal负责对DecorView和对应的ViewRootImpl进行统管理,而具体功能是由ViewRootImpl来处理。

以addView为例,具体window是由WMS管理的,所以这里会进行binder IPC。

windows add 源码:android系统_Window的创建和添加流程分析:https://www.jianshu.com/p/6571fbdd1bcb
binder IPC:
IWindowSession: 应用程序通过Session与WMS通信,并且每个应用程序进程都会对应个Session.
IWindow: 作为WMS主动与应用程序通信的client端,因为不同的Window是不同的client,因此它也被作为识别window的key。

具体可以参考之前图形系统系列文章:
Android图形系统()-Window加载视图过程
Android图形系统(二)-DecorView布局加载流程
Android图形系统(三)-View绘制流程
Android图形系统(四)-Activity、Window、View关系总结

二、Activity与Window关联分析

Activity windows创建过程

这里写图片描述

Activity与Window联系是非常紧密,很多显示相关操作需要两者密切配合,那么如何保证他们的致性呢?Android通过token来保证两者的致性校验

token流向简单归纳如下:

1)new ActivityRecord的时候会new个token与之对应。
2)ApplicationThread scheduleLaunchActivity的时候,ActivityClientRecord 接收这个token。
3)activity.attach传入该token。
4)setWindowManager的时候传入该token,最终由Window的AppToken接收。
5)在WindowManagerGlobal的addView方法中,执行adjustLayoutParamsForSubWindow,将WindowManager.LayoutParams wp,wp.token赋值appToken,并在之后的流程中,WindowManager.LayoutParams wp作为参数传入WMS的addWindow方法对应attrs.token。
6)WMS中通过WindowToken与之对应。
那么其实,Activity的token,Window中的token,连传入addWindow的attrs.token,都是同个token,都是ActivityRecord构造函数中创建的Token对象.这样做保证了致性,主要体现在如下两点:

  • 将AMS中创建的ActivityRecord和Window挂钩,当前的window明确知道自己是哪个Activity创建的。
  • Window和AMS有联系,同时又和WMS有关系,appToken则保证了这种同步机制。

三、窗口属性与类型

WindowManagerGlobal的addView函数有个重要参数:WindowManager.LayoutParams,它对应有两个重要的值:flag与type(1-2999)。

notes 将创建的窗口成功添加到WMS(addview). 创建窗口的过程是settitle,seticon,setlogo etc

四、窗口组织方式(分组与分层)

Android采用的是层叠式的布局

这个部分逻辑主要在WMS.addWindow中,这个方法非常非常重要!

分组:子窗口与其依附的父窗口属于同组,共用相同的token。

分层:WindowState在WMS中对应个具体的窗口。它有两个重要属性:

  • mBaseLayer:它按窗口类型来决定z-order顺序。
  • mSubLayer:它按值的大小与正负关系来决定多个子窗口在父窗口中的前后关系,以及相互之间的顺序.

然后,按如下流程来调整窗口的层级关系:

wms:计算z轴

WindowManagerService服务计算窗口Z轴位置的过程就分析完成了,这个过程如下所示:
1. WindowManagerService服务将窗口排列在一个窗口堆栈中;
2. WindowManagerService服务根据窗口类型以及窗口在窗口堆栈的位置来计算得窗口的Z轴位置.
3. WindowManagerService服务通过Java层的Surface类的成员函数setLayer来将窗口的Z轴位置设置到SurfaceFlinger服务中去;
4. Java层的Surface类的成员函数setLayer又是通过调用C++层的SurfaceControl类的成员函数setLayer来将窗口的Z轴位置设置到SurfaceFlinger服务中去的;

 wms z轴计算          

   

最终SurfaceFlinger会根据z-order顺序来决定视图的合成。

Android WMS()-Surface管理

一、捋清View、WindowState、Surface的关系

这部分牵扯到的是视图绘制渲染架构。

这里主要分三部分:

1)添加Window(WMS与应用层通信)
ViewRootImpl.setView()方法会向WMS请求添加一个Window,mWindowSession.addToDisplay()跨进程最终调用到了WMS.addWindow,这里会创建WindowState,它是WMS中描述App窗口的对象.

windows使用实例:https://www.cnblogs.com/meizixiong/p/3546397.html

2)与SurfaceFlinger建立连接(WMS与SurfaceFlinger通信)
WMS.addWindow()中WindowState通过attach方法建立一个SurfaceSession走windowAddedLocked()流程与SurfaceFlinger进行连接:
ComPoserService作为client 与 SurfaceFlinger server进行binder IPC , 获取到SurfaceFlinger创建的Client对象,它相当于是SurfaceFlinger内部对应用程序客户端的封装对象.而Client与SurfaceComposerClient又互为binder ipc两端,SurfaceComposerClient为client端,Client为server端.

3)创建Surface(WMS分别与应用程序和SurfaceFlinger通信)

创建完window之后,立刻需要创建surface.Surface是真正UI视图的载体和处理者
ViewRootImpl内会new一个Surface,ViewRootImpl 、WindowState与Surface是一一对应关系。
创建Surface主要走的是ViewRootImpl setView操作的requestLayout流程中的relayoutWindow部分:
这个过程实际上就是在SurfaceFlinger创建Layer,对应在客户端通过SurfaceControl在native层创建Surface并copyForm返回给ViewRootImpl内java层的Surface
,为什么这么麻烦?因为Surface主要负责调用绘制引擎执行渲染视图的操作,这部分工作在native效果更高。并且Android4.0之后的硬件加速绘制,渲染过程是又native进程RenderThread来负责的。

三者关系是:

View是视图的素材;
WindowState是窗口实体对象,WMS会通过z-order计算来决定窗口的层级关系,为SurfaceFlinger合成Layer提供层级依据。
notes:根据窗口层级计算
Surface是View的载体和处理者。它会调用绘制引擎处理View,然后申请一块buffer,存入绘制素材,传递给SurfaceFlinger。

具体可以参考之前图形系统文章:
Android图形系统(五)-Surface图形系统概览
Android图形系统(六)-app与SurfaceFlinger服务连接过程
Android图形系统(七)-app请求SurfaceFlinger创建Surface过程
Android图形系统(八)-app与SurfaceFlinger共享UI元数据过程
Android图形系统(九)-View、Canvas与Surface的关系
Android图形系统(十)-SurfaceFlinger启动及图层合成送显过程

二、视图绘制的整体流程

梳理ViewRootImpl#scheduleTraversals( )流程,主要参与的有如下几个模块:

HwComposer: 产生vsync信号
周期性唤醒DipsSyncThread产生虚拟化Vsync信号,EventThread负责请求和分发vsync信号分别到app与surfaceFlinger。

UIThread: 绘制
通过Choreographer请求vsync信号,接收信号执行doFrame,走绘制流程,初始化RenderThread并最终draw出DisplayList。

RenderThread: 渲染
同步DisplayList数据;dequeueBuffer;渲染数据并保存到buffer;queueBuffer同时更新Layer并触发invalidate-sf-vsync请求。

SurfaceFlinger: 合成送显
INVALIDATE:接收invalidate-sf-vsync请求,acquireBuffer更新脏区域、发送refresh-sf-vsync请求.
REFRESH:接收refresh-sf-vsync请求,按z-order计算可见区域,合成视图并做栅格化处理,通过FrameBuffer送显。

最后总结一张手绘的整体流程图: 这个图比较好

 视图绘制整体流程图

具体可以参考之前图形系统文章:
Android图形系统(十一)-Choreographer
Android图形系统(十三)-Vsync信号处理
Android9.0 硬件加速(二)-RenderThread线程的启动
Android9.0 硬件加速(三)-绑定Surface到RenderThread
Android9.0 硬件加速(四)-UI Thread绘制过程
Android9.0 硬件加速(五) -RenderThread渲染过程
从systrace看app冷启动过程(三)-首帧的合成与送显

Android WMS(三)- Input管理

input系统中,wms主要参与inputDispatch寻找焦点窗口建立连接通信的过程.

WMS参与的Input中转流程

(建立了一个socketpair,连接了app和ims;ims-wms-app)
app--wms--sf; app-wms-ims
1) 通信
应用层与wms通信是进程间通信,需要binder call.
wms与inputdispatcher都属于system_server进程,属于进程内通信.
2) 在input event trigger之前的UI绘制阶段viewrootimpl已经通过setview(对应的WMSaddWindow)
让WMS创建InputChannel,会创建一对socket pair用于通信,分别注册到Server端(InputDispatch)和client端(app).
两端都通过各自Looper监听了对端的写操作,一旦对端搞事情,马上回调响应。
另外server端会封装一个connection,它描述的是一个连接通道,主要包含:服务端的inputChannel,outboundQueue以及waitQueue.
它属于一个连接之后数据操作的渠道。并且通过mConnectionsByFd以(fd,connection)键值对形式统一管理Connection.
mConnectionsByFd它就像一个电话薄,每次InputDispacher要打电话,先去查对应的connection,如果对方准备好了,你们就开始喂喂喂的打电话。

WMS在input system中扮演的其实是一个中转站的角色   

源码:主要类和对象

  1. Window是一个抽象类,Activity、Toast、Dialog等都是靠Window来呈现。
    PhoneWindow是Window的具体实现类(几乎是唯一实现类)。
  2. WindowManager是个接口,继承接口 ViewManager(ViewManager定义了3个操作:增加、更新、移除)。
    WindowManagerImpl是WindowManager的实现类。
    不过查看WindowManagerImpl中 关于ViewManager的3个操作可以看出,这3个实现 最终是交由WindowManagerGlobal完成的。
  3. WindowState维护着窗口的所有信息.WMS通过WindowState对窗口进行管理、保存状态等。
//attach()
-performLaunchActivity()
--activity.attach()//创建了PhoneWindow(mWindow)。mWindowManager保存的是 从mWindow处获取的 setWindowManager()创建的WindowManagerImpl
---mWindow.setWindowManager()//PhoneWindow内部 创建了WindowManagerImpl(mWindowManager),并保存了appToken、appName。

//onCreate()
-setContentView()
--installDecor()
---generateDecor()//创建了DecorView(mDecor)
---generateLayout()//将activity的布局作为子视图(ViewGroup)添加到mDecor中

//onResume()
-r.activity.makeVisible()//
--wm.addView(mDecor, ...)//wm即mWindowManager(WindowManagerImpl对象)
---WindowManagerGlobal.addView()//创建了ViewRootImpl。addView的view是mDecor,ViewRootImpl中创建了mWindow(这里是一个IBinder,而非attach()中创建的)
----ViewRootImpl.setView()//openSession()创建了Session(IWindowSession的代理类),view也是mDecor。mDecor传入到ViewRootImpl的mView
-----Session.addToDisplay()//通过Session进入system_server进程
------mService.addWindow()//进入WMS,执行addWindow()添加窗口

attach阶段:
一个Activity 创建了一个PhoneWindow对象 ,PhoneWindow通过setWindowManager() 创建了WindowManagerImpl 。
onCreate阶段:
创建了DecorView ,并将 activity的布局添加到DecorView中 。
onResume阶段:
创建了ViewRootImpl,通过setView()最终由Session进入system_server进程。最终执行addWindow添加窗口到WMS。

通过generateDecor()创建了一个DecorView。DecorView实际是一个FrameLayout。
然后通过generateLayout(),最终将activity的布局作为子视图(ViewGroup)添加到DecorView中。

wms_actui_layout

  1. 一个Activity对应了一个PhoneWindow对象。即 每个Activity对应一个Window (具体实现类是PhoneWindow)。
  2. 一个PhoneWindow 持有一个 DecorView 实例, DecorView实际是一个FrameLayout,它是Activity中所有View的根(最顶层的View)。
  3. 一个PhoneWindow有一个WindowManagerImpl。WindowManagerImpl持有一个单例WindowManagerGlobal

mWindowToken,也就是W的IBinder对象,也是WMS与应用通信的接口
最后WMS.addWindow(),这里完成窗口添加

为什么win.attach()是创建与SurfaceFlinger通信的?
源码是创建了SurfaceSession对象,这个创建进入native,最终创建了一个与SurfaceFlinger通信的 SurfaceComposerClient。 因此,可以与SurfaceFlinger进行通信。
ViewRootImpl创建时就创建的mSurface,mSurface是ViewRootImpl的成员变量,此时创建的Surface什么都没有,最后通过relayoutWindow()进入WMS 一步步向SurfaceFlinger发出请求。
 

setContentView方法小结
1、继承Activity这个父类时;调用setContentView方法的,会去拿到PhoneWindow对象,调用这个PhoneWindow对象的setContentView方法,在这个setContentView方法中会去创建DecorView(FrameLayout的子类) 和mContentParent 这两个容器.
mContentParent 容器是一个FrameLayout布局容器,通过findViewById这个方法传入ID_ANDROID_CONTENT这个常量获取到,然后通过布局加载器,将我们传入的布局id,获取到布局文件,加载成视图树. 添加到DecorView这个FrameLayout当中,并且创建ViewRootImpl对象,与这个DecorView关联起来 ;
2、PhoneWindow对象的创建是在attach这个方法中,attach方法是在Activity创建之后调用的,在各种生命周期之前;
3、onCreate方法里面只是做解析xml保存成视图树.onResume生命周期之后,进行视图的测量、布局摆放、绘制。

下图:PhoneWindow、DecorView、mContentRoot、mContentParent的关系借用网络上图片

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

AMS服务

作用: AMS(ActivityManagerService)贯穿了Android系统组件的核心服务,主要负责Android系统中四大组件的启动、切换、调度以及应用进程管理和调度工作。

所有activity创建和销毁都要告之AMS.

AMS service到activitythread-->viewimpl->viewgroup->activitythread是主线程
Applicationthread 是对象不是线程,它是一个binder
Applicationthread连接ams和service.
ActivityThread:记录provider, activity, service在客户端的相关信息

Android系统启动-SystemServer篇(二)中有讲到AMS,本文以AMS为主线,讲述system_server进程中AMS服务的启动过程,以startBootstrapServices()方法为起点,紧跟着startCoreServices(), startOtherServices()共3个方法。
该过程:创建AMS内部类的Lifecycle,已经创建AMS对象,并调用AMS.start();

AMS创建

public ActivityManagerService(Context systemContext) {
    mSystemThread = ActivityThread.currentActivityThread();
    //创建名为"ActivityManager"的前台线程,并获取mHandler
    mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());
    //通过UiThread类,创建名为"android.ui"的线程
    mUiHandler = new UiHandler();
    //创建名为"CpuTracker"的线程
    mProcessCpuThread = new Thread("CpuTracker") {
        public void run() {...}
    }
    ...
}

该过程共创建了3个线程,分别为”ActivityManager”,”android.ui”,”CpuTracker”。

总结

  1. 创建AMS实例对象,创建Andoid Runtime,ActivityThread和Context对象;
  2. setSystemProcess:注册AMS、meminfo、cpuinfo等服务到ServiceManager;
  3. installSystemProviderss,加载SettingsProvider;
  4. 启动SystemUIService,再调用一系列服务的systemReady()方法;

AMS.setSystemProcess()过程向servicemanager注册了如下这个binder服务

服务名类名功能
activityActivityManagerServiceAMS
procstatsProcessStatsService进程统计
meminfoMemBinder内存
.......

要查看这些服务的信息,可通过dumpsys<服务名>命令.比如查看CPU信息命令dumpsys cpuinfo。 

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

AMS作用

  • 统一调度所有应用程序的Activity的生命周期
  • 启动或杀死应用程序的进程
  • 启动并调度Service的生命周期
  • 注册BroadcastReceiver,并接收和分发Broadcast
  • 启动并发布ContentProvider
  • 调度task
  • 处理应用程序的Crash
  • 查询系统当前运行状态

AMS与WMS:

  • AMS统一调度所有应用程序的Activity
  • WMS控制所有Window的显示与隐藏以及要显示的位置

Activity与WIndow:

  • Activity只负责生命周期和事件处理
  • Window只控制视图
  • 一个Activity包含一个Window,如果Activity没有Window,那就相当于Service

上述定义和作用引用:thinkChao blog

Window是个抽象概念:每一个Window对应着一个View和ViewRootImpl,Window通过ViewRootImpl来和View建立联系,View是Window存在的实体,只能通过WindowManager来访问Window。

窗体size计算:

从Activity窗口剔除掉状态栏和输入法窗口所占用的区域之后,所得到的区域就称为可见区域(Visible Region)
Activity窗口的内容区域和可见区域的大小是一致的,而状态栏和输入法窗口所占用的区域又称为屏幕装饰区。
理解了这些概念之后,我们就可以推断,WindowManagerService服务实际上就是需要根据屏幕以及可能出现的状态栏和输入法窗口的大小来计算出Activity窗口的整体大小及其内容区域边衬和可见区域边衬的大小。
有了这三个数据之后,Activity窗口就可以对它里面的UI元素进行测量、布局以及绘制等操作了
WindowManagerService服务计算Activity窗口的大小以及内容区域边衬大小和可见区域边衬大小。
计算完毕之后,Activity窗口的大小就会保存在ViewRoot类的成员变量mWinFrame中,而Activity窗口的内容区域边衬大小和可见区域边衬大小分别保存在ViewRoot类的成员变量mPendingContentInsets和mPendingVisibleInsets中。
由于变量frame和ViewRoot类的成员变量mWinFrame引用的是同一个Rect对象,因此,这时候变量frame描述的也是Activity窗口请求WindowManagerService服务计算之后得到的大小。
这段代码分别将计算得到的Activity窗口的左上角坐标保存在变量attachInfo所指向的一个AttachInfo对象的成员变量mWindowLeft和mWindowTop中,并且将计算得到的Activity窗口的宽度和高度保存在ViewRoot类的成员变量mWidth和mHeight中。

第一组成员变量是mW和mH,它们分别用来描述当前这轮窗口大小计算过程的屏幕宽度和高度。
第二组成员变量是mCurLeft、mCurTop、mCurRight和mCurBottom,它们组成一个四元组(mCurLeft, mCurTop, mCurRight, mCurBottom),用来描述当前这轮窗口大小计算过程的屏幕装饰区,它对应于前面所提到的Activity窗口的可见区域边衬。
第三组成员变量是mContentLeft、mContentTop、mContentRight和mContentBottom,它们组成一个四元组(mContentLeft, mContentTop, mContentRight, mContentBottom),也是用来描述当前这轮窗口大小计算过程的屏幕装饰区,不过它对应的是前面所提到的Activity窗口的内容区域边衬。
第四组成员变量是mDockLeft、mDockTop、mDockRight、mDockBottom和mDockLayer,其中,前四个成员变量组成一个四元组(mDockLeft, mDockTop, mDockRight, mDockBottom),用来描述当前这轮窗口大小计算过程中的输入法窗口所占据的位置,后一个成员变量mDockLayer用来描述输入法窗品的Z轴位置.
第五组成员变量是mTmpParentFrame、mTmpDisplayFrame、mTmpContentFrame和mTmpVisibleFrame,它们是一组临时Rect区域,用来作为参数传递给具体的窗口计算大小的,避免每次都创建一组新的Rect区域来作来参数传递窗口。
除了这五组成员变量之外,PhoneWindowManager类还有一个成员变量mStatusBar,它的类型为WindowState,用来描述系统的状态栏。
我们就分析完成Activity窗口的大小计算过程了。从这个计算过程中,我们就可以知道一个Activity窗口除了有一个整体大小之外,还有一个内容区域边衬大小和一个可见区域边衬大小。
此外,一个Activity窗口的内容区域边衬大小和可见区域边衬大小是可能会受到与其所关联的输入法窗口的影响的,因为输入法窗口会叠加在该Activity窗口上面,这就涉及到了系统中的窗口的组织方式

1.1 应用程序框架(Application Framework)

ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,
最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的
 1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。
 2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。
 3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程
ZygoteInit:run --mMethod.invoke(null, new Object[] { mArgs }); 这样,android.app.ActivityThread类的main函数就被执行了
zygote进程在内部会先启动Dalvik虚拟机,启动Dalvik虚拟机,startVm(),注册Android内部需要的函数,startReg(),加载ZygoteInit类
loadresource&load 颜色.

在Android应用程序框架层中,是由ActivityManagerService组件负责为Android应用程序创建新的进程的,它本来也是运行在一个独立的进程之中,不过这个进程是在系统启动的过程中创建的。
ActivityManagerService组件一般会在什么情况下会为应用程序创建一个新的进程呢?当系统决定要在一个新的进程中启动一个Activity或者Service时,它就会创建一个新的进程了,然后在这个新的进程中启动这个Activity或者Service

在PKMS中,有一个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息
在AMS中,所谓的“add App”主要是指“添加一个与App进程对应的ProcessRecord节点”。
一旦目标进程启动完毕后,目标进程会attach系统,于是走到AMS的attachApplicationLocked(),在这个函数里,会把目标进程对应的ProcessRecord结点从mPersistentStartingProcesses缓冲列表里删除。
每个ActivityThread中会有一个专门和AMS通信的binder实体——final ApplicationThread mAppThread

Activitythread:

public final class ActivityThread {
    public static final void main(String[] args) {
        ......
        Looper.prepareMainLooper();
        ......
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
 
        if (sMainThreadHandler == null) {    
            sMainThreadHandler = thread.getHandler();
        }
        ......
        Looper.loop();
        ......
    }
}

流程详见:https://blog.csdn.net/luoshengyang/article/details/6677029

详见:https://blog.csdn.net/luoshengyang/article/details/6747696

,,,,,,,,,,,,,,,,,,,,,

AMS

在这里插入图片描述

AMS服务的主要工作

  • 负责四大组件activity,service,broadcast,provider的创建,启动,调度和销毁。
  • 负责进程的创建和调度,销毁等管理工作

首先来看看这个统一调度各个应用程序之间的activity,可以把AMS理解成一个管理员,管理着手机里面的所有应用程序.
每当一个应用程序想要启动activity,都要先报告AMS,AMS认为该应用程序可以启动,那么就通知该应用程序去执行启动activity操作,当应用程序启动完毕,也要报告AMS,AMS会记录对应的进程以及对应的activity,以便对activity进行管理和调控,例如内存不足时选择杀死某些优先级的activity。

Activity的启动入口是startActivityForResult,startActivity()其实也是调用了startActivityForResult(),
那么就从这个入口去看看具体的启动流程吧;

activity的启动流程
activity的启动流程大概总结为:

启动Activity B -> 当前有正在显示的activity吗 -> 有就先pause() -> B的进程存在吗 -> 不存在则创建 -> B进程启动指定的Activity

首先来看一下这个过程的具体流程图,其实就是上面流程简介的具体化:

在这里插入图片描述
现在从源码开始,一步一步的去看看具体的startActivity()的执行流程:

一.首先是startActivity的调用流程

从Activity中调用了startActivity()之后,经过一系列跳转,会执行到Instrument的execStartActivity()方法中,这个Instrumentation是什么呢?可以说它是应用进程的管家,监控着应用进程与系统的所有交互,所有的创建、暂停、停止activity,都是通过它去发起的,它可以统计所有的开销。
notes: Instrument是具体实现类

二、运行条件检查以及intent的flag处理
三、AMS根据启动intent去找到或者创建合适的Task

接下来,AMS需要确定是否需要给目标activity创建一个新的Task或者是给它找到一个合适的task,具体的执行过程如下:

总结startActivityForResult()的执行过程

在这里插入图片描述

AMS和客户进程间的交互之Application的创建过程

Android应用程序的启动入口在ActivityThread的main()函数,在main()函数中创建了ActivityThread的实例对象并且调用它的attach()去执行应用程序的启动流程,attach()中的工作就是调用ApplicationThread的attachApplication()去创建application,那么就来看看其中具体的过程:

整个过程大致如图:
在这里插入图片描述

attachApplication过程

当应用程序启动后,就会报告给AMS,自己已经启动完毕可以启动activity了,这个实际上是通过IPC调用AMS的attachApplication()方法完成的,该方法具体如下:

应用进程launch指定的Activity
上面attachApplication()执行完,客户进程已经启动,但是它包含的程序文件只是Framework中的ActivityThread基类,这个过程还没有涉及到应用程序本身的任何文件,这个过程类似于LInux程序的启动过程,即首先由操作系统产生一个空进程,然后再通知它去加载具体的要执行程序文件。

那么现在客户进程(空进程)就要根据AMS提供的ApplicationInfo去加载具体的activity了, 注意了,ApplicationInfo是实现了Parcelable的,所以可以在进程间传递数据。上一步中,客户进程向AMS报告自己已经启动,AMS会执行attachApplication(),在这个方法中调用了ActivityThread.ApplicationThread的bindApplication方法,ApplicationThread本身是一个Binder对象
ActivityThread的H(即handler)收到了“BIND_APPLICATION”时,则调用handleBindApplication()去处理这个消息,先看一下大致的流程图:

在这里插入图片描述

加载Activity的过程

上面完成了创建Application的工作,接下来,就会调用handleLaunchActivity()来加载指定的activity并且运行:

         * 1.根据传入参数生成一个ComponentName对象,它是application四大组件(Activity、
         * Service、BroadcastReceiver、ContentProvider)的标识符,主要包含两个信息:包
         * 名和该组件的类名
          * 2.创建Activity所需的context对象,每一个Activity都包含一个Context对象,     
       3.通过类加载器去生成目标activity的实例对象
      4.获取已经创建好的Application 对象
      5.调用Activity的attach()方法将context对象赋给Activity 的mBase,
                 * 同时实例化PhoneWindow,设置各类监听,给各种成员变量例如mToken、
                 * mApplication、mUiThread等进行赋值
        6.从AndroidManifest.xml中定义的theme中获取主题模式,如果没有的则使
                 * 用默认的主题模式,再调用setTheme()设置给Activity
      7. 判断是否是Persistable模式(5.0之后的一种更强的保存数据模式,例如
                  * power off时)然后这里,终于开始回调Activity的onCreate()生命周期
                  * 了;同时activity中也会调用fragment的生命周期。
        8.这里要将当前启动的Activity放入 Activity Thread的mActivities存储,注
               * 意了,保存的对象是ActivityClientRecord,而不是直接的Activity。
上面的performLaunchActivity()方法返回之后,继续执行handleResumeActivity(),那么再来看看这个方法内部是如何回调activity的onResume()生命周期的;
        * 1.内部调用了performResumeActivity(),这个方法内部就是改变activity的生命周
          * 期状态,并且调用activity的onResume()方法,并改变了ActivityRecord的一些
          * pause、stopped的状态变量
         * 2. 尽管前面所有的步骤中,创建了Application、Activity、并且调用了Activity的
         * onCreate()、onResume()方法,但是都还没有通知到WMS,没有完成真正的显示工作,
         *  这一步就会去获取activity的window对象,且添加给WMS
           3.这一步调用activity的makeVisible(),内部其实是将DecorView设成
                  * 可见,到了这一步,用户终于能够看到了Activity的内容了。
     *  4.添加一个IdleHandler对象,一般情况下,activity执行完上面步骤后,就进入了空闲 * 状态,所以可以进行内存回收。

,,,,,,,,,,,,,,,,,,,,,,,,,,

AMS和APP交互框架

AMS和APP交互框架

Activity启动框图

Activity启动框图

Activity启动流程(从Launcher开始):

第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)
Launcher.startActivitySafely //首先Launcher发起启动Activity的请求
Activity.startActivity
Activity.startActivityForResult
Instrumentation.execStartActivity //交由Instrumentation代为发起请求
ActivityManager.getService().startActivity //通过IActivityManagerSingleton.get()得到一个AMP代理对象
ActivityManagerProxy.startActivity //通过AMP代理通知AMS启动activity

第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后,AMS会通知Launcher程序pause Activity(在AMS所在进程执行)
ActivityManagerService.startActivity
...
ActivityStackSupervisor.startActivityLocked :检查有没有在AndroidManifest中注册
..
ActivityStack.startActivityLocked :判断是否需要创建一个新的任务来启动Activity。
ActivityStack.resumeTopActivityLocked :获取栈顶的activity,并通知Launcher应该pause掉这个Activity以便启动新的activity。
...
ApplicationThreadProxy.schedulePauseActivity

第三阶段: pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)
ApplicationThread.schedulePauseActivity
ActivityThread.queueOrSendMessage
H.handleMessage
ActivityThread.handlePauseActivity
ActivityManagerProxy.activityPaused

第四阶段:检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Process.start创建一个新进程(执行在AMS进程)
ActivityManagerService.activityPaused
ActivityStack.activityPaused
ActivityStack.completePauseLocked
ActivityStack.resumeTopActivityLocked
ActivityStack.startSpecificActivityLocked
ActivityManagerService.startProcessLocked
Process.start //在这里创建了新进程,新的进程会导入ActivityThread类,并执行它的main函数

第五阶段: 创建ActivityThread实例,执行一些初始化操作,并绑定Application。如果Application不存在,会调用LoadedApk.makeApplication创建一个新的Application对象。之后进入Loop循环。(执行在新创建的app进程)
ActivityThread.main
ActivityThread.attach(false) //声明不是系统进程
ActivityManagerProxy.attachApplication

第六阶段:处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序进程启动目标Activity组件(执行在AMS进程)
ActivityManagerService.attachApplication //AMS绑定本地ApplicationThread对象,后续通过ApplicationThreadProxy来通信。
ActivityManagerService.attachApplicationLocked
ActivityStack.realStartActivityLocked //真正要启动Activity了!
ApplicationThreadProxy.scheduleLaunchActivity //AMS通过ATP通知app进程启动Activity

第七阶段: 加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)
ApplicationThread.scheduleLaunchActivity //ApplicationThread发消息给AT
ActivityThread.queueOrSendMessage
H.handleMessage //AT的Handler来处理接收到的LAUNCH_ACTIVITY的消息
ActivityThread.handleLaunchActivity
ActivityThread.performLaunchActivity
Instrumentation.newActivity //调用Instrumentation类来新建一个Activity对象
Instrumentation.callActivityOnCreate
MainActivity.onCreate
ActivityThread.handleResumeActivity
AMS.activityResumed
AMS.activityResumed(AMS进程)



 

APP启动过程(从点击图标—>Activity可见)

一、程序入口——ActivityThread.main()