前言
前段时间分析了 Window 的添加、更新和删除流程,也知晓了 Activity 、Dialog 和 Toast 中 Window 的创建过程,今天就接着上篇文章,看一下 WMS 的创建 以及WindowManager 添加 WIndow 后 WMS 是怎样进行操作的。上篇文章点这里直达;
WindowManagerService 简称 WMS ,是系统的核心服务,主要分为四大部分,风别是 窗口管理,窗口动画,输入系统中转站,Surface 管理 。
了解 WMS
WMS 的职责很多,主要的就是下面这几点:
窗口管理:WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也时有 WMS 管理的,管理窗口的核心成员有DisplayContent,WindowToken 和 WindowState
窗口动画:窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由 WMS 动画子系统来负责,动画的管理系统为 WindowAnimator
输入系统的中转站:通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS) 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,因此理所当然的就成为了输入系统的中转站。
Surface 管理:窗口并不具备绘制的功能,因此每个窗口都需要有一个块 Surface 来供自己绘制,为每个窗口分配 Surface 是由 WMS 来完成的。
WMS 的职责可以总结为下图:
WMS 的启动
WMS 是在 SystemServer 内部启动的
Android 系统在启动的时候,会启动两个重要的进程,一个是 Aygote 进程,两一个是由 Zygote 进程 fork 出来的 system_server 进程,SystemServer 会启动我们在系统中所需要的一系列 Service。
//#SystemServer.java private void startOtherServices() { //..... //1 WindowManagerService wm = null; InputManagerService inputManager = null; //2 traceBeginAndSlog("StartInputManagerService"); inputManager = new InputManagerService(context); traceEnd(); traceBeginAndSlog("StartWindowManagerService"); //WMS needs sensor service ready ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); mSensorServiceStart = null; //3 wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager); // WMS 初创建完成后调用,后面会讲到 wm.onInitReady(); //4 ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO); //5 ServiceManager.addService(Context.INPUT_SERVICE, inputManager, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL); traceEnd(); //... try { //6 wm.displayReady(); } catch (Throwable e) { reportWtf("making display ready", e); } traceEnd(); try { //7 wm.systemReady(); } catch (Throwable e) { reportWtf("making Window Manager Service ready", e); } traceEnd(); ///... }
startOtherServer 用于启动其他服务,大概有70多个,上面列出了 WMS 和 IMS 的启动逻辑。
在注释1的地方声明了 WMS 和 IMS, 这里值列出了两个,其实非常多。
注释2处创建了 IMS ,
注释 3 调用了 WMS 的 main 方法,并且传入了 IMS,因为 WMS 是 IMS 的中转站。观察 WindowManagerService.main 方法可以知道他是运行在 SystemServer 的 run 方法中,换句话说就是运行在 system_server 线程中。
注释4和5处将 WMS 和 IMS 注册到 ServerManager 里面,这样客户端想要使用 WMS 就需要先去 ServiceManager 中查询信息,然后与 WMS 所在的进程建立通信,这样客户端就可以使用 WMS 了。
注释 6 用来初始化显示信息,注释 7 处用来通知 WMS 系统初始化工作已经完成,内部调用了 WindowManagerPolicy 的 systemReady 方法。
接着,我们看看 WMS 的 maain 方法:
public static WindowManagerService main(final Context context, final InputManagerService im, final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy, ActivityTaskManagerService atm) { return main(context, im, showBootMsgs, onlyCore, policy, atm, SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new); } public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory, Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) { DisplayThread.getHandler().runWithScissors(() -> sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy, atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0); return sInstance; }
上面通过 DisplayThread 的 getHandler 方法获取到了 DisplayThread 的 Handler 实例。
DisplayThread 是一个单例的前台线程,用来处理需要低延时显示的相关操作,并且只能由 WindowManager,DisplayManager 和 INputManager 试试执行快速操作。
runWithScissors 表达式中创建了 WMS 对象。至于 Handler.runWithScissors 方法,有兴趣的可以看一下这篇文章。
到这里我们就知道 WMS 是从何处启动的了,下面我们来看一下 WMS 的构造方法
WMS构造方法
private WindowManagerService(Context context, InputManagerService inputManager, boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy, ActivityTaskManagerService atm, TransactionFactory transactionFactory) { ... //1 mInputManager = inputManager; // Must be before createDisplayContentLocked. //2 mPolicy = policy; //3 mAnimator = new WindowAnimator(this); //4 mRoot = new RootWindowContainer(this); //5 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); //6 mActivityManager = ActivityManager.getService(); //7 LocalServices.addService(WindowManagerInternal.class, new LocalService()); ... }
保存 IMS ,这样就持有了 IMS 的引用。
初始化 WindowManagerPolicy ,它用来定义一个窗口测量所需要遵循的规范。
创建了 WindowAnimator,它用于管理所有的窗口动画。
创建 RootWindowContainer 对象,根窗口容器
获取 DisplayManager 服务
获取 AMS,并持有他的引用
将 LocalService 添加到 LocalServices 中
在上面 WMS的启动中 WMS 创建完成后会调用 wm.onInitReady 方法,下面我们来看一下这个方法:
public void onInitReady() { initPolicy(); //将 WMS 添加到 Watchdog 中,Watchdog 用来监控一下系统关键服务的运行情况。 //这些被监控的服务都会实现 Watchdog.Monitor 接口,Watchdog 每分钟都会对 //被监控的服务进行检测,如果被监控的服务出现了死锁,则会杀死 Watchdog 所在的进程 Watchdog.getInstance().addMonitor(this); ...... } private void initPolicy() { UiThread.getHandler().runWithScissors(new Runnable() { @Override public void run() { WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper()); mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this); } }, 0); }
上面的和 WMS 的 main 方法类似,WindowManagerPolicy (简称 WMP) 是一个接口,init 的具体实现在 PhoneWindowManager(PWM) 中,并且通过上面代码我们知道,init 方法运行在 android.ui线程中。因此他的线程优先级要高于 android.display 线程,必须等 init 方法执行完成后,android.display线程才会被唤醒从而继续执行下面的代码。
WindowManagerPolicy 用来定义一个窗口策略所要遵循的通用规范,,并提供了 WindowManager 所有的特定 UI 行为
他的具体实现类为 PhoneWindowManager
在上面的文章中,一共提供了三个线程,分别是 system_server,android.display ,android.ui,他们之间的关系如下图所示:
system_server 线程中会调用 main 方法,mian 方法中会创建 WMS,创建的过程实在 android.display 线程中,他的优先级会高一些,创建完成后才会唤醒处于 system_server 线程。
WMS 创建完成后会调用 onInitReady 中的 initPolicy 方法,该方法中会调用 PWM 的 init() 方法,init 方法调用完成之后就会唤醒 system_server 线程。init 方法运行中 android.ui 线程中。
之后就会接着执行 system_server 中的代码,例如 displayReady 等。
WIMS 窗口管理
Window 的操作有两大部分,一部分是 WindowManager 来处理,一部分是 WMS 来处理,如下图所示:
WindowManager 中,通过 WindowManagerGlobal 创建 ViewRootImpl ,也就是 View 的根。在 ViewRootImpl 中完成对 View 的绘制等操作,然后通过 IPC 获取到 Session ,最终通过 WMS 来进行处理。在理解 Window 和 WindowManager 这篇文章中,讲解了 WIndow 的创建,添加和删除部分,有兴趣的可以看一下。
WMS 来处理后面的部分,具体见下文
WindowManager -> WMS
我们都知道 Window 的添加最后是通过 ViewRootImpl.addTodisplay 方法来完成的,我们先来看一下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) { synchronized (this) { if (mView == null) { .... try { res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets, mTempControls); } ... } }
这里调用了 mWindowSession.addToDisplayAsUser 来完成最后的添加,我们先看看 mWindowSession 是个啥东西。
public ViewRootImpl(Context context, Display display) { this(context, display, WindowManagerGlobal.getWindowSession(), false /* useSfChoreographer */); }
//WindowManagerGlobal.java public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { .... IWindowManager windowManager = getWindowManagerService(); //通过 windowManager 创建一个 IWindowSession sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }); } return sWindowSession; } } public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { // 通过 AIDL 获取 IWindowManager sWindowManagerService = IWindowManager.Stub.asInterface( //获取 WindowManagerService 的 IBinder ServiceManager.getService("window")); //... } return sWindowManagerService; } } // WindowManagerService.java @Override public IWindowSession openSession(IWindowSessionCallback callback) { return new Session(this, callback);//传入了 this,将 Session 就会持有 WindowManagerService 的引用 }
mWindowSession 是 IwindowSession 的对象,实现类是 Session。
上面代码中,在 VIewRootImpl 初始化的时候,通过IPC 获取到 IWindowManager,然后通过 IPC 的调用创建了 Session 对象。
接着我们来看一下 mWindowSession.addToDisplayAsUser 方法,也就是在 Session 类中
@Override public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, outInsetsState, outActiveControls, userId); }
可以看到,最终是通过 mService 来完成添加的,
需要注意的是,WMS 并不关系 View 的具体内容,他只关心各个应用显示的界面大小,层级值等,这些数据到包含在 WindowManager.LayoutParams 中。也就是上面的 atrs 属性。
注意 addWindow 的第二个参数是一个 IWindow 类型,这是 App 暴露给 WMS 的抽象实例,在 ViewRootImp 中实例化,与 ViewRootImpl 一一对应,同事也是 WMS 向 App 端发送消息的 Binder 通道。
从 WindowManager 到 WMS 的具体流程如下所示:
WMS 重要成员
final WindowManagerPolicy mPolicy; final IActivityManager mActivityManager; final ActivityManagerInternal mAmInternal; final AppOpsManager mAppOps; final DisplaySettings mDisplaySettings; ... final ArraySet<Session> mSessions = new ArraySet<>(); final WindowHashMap mWindowMap = new WindowHashMap(); final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>(); final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>(); final ArrayList<WindowState> mResizingWindows = new ArrayList<>(); final ArrayList<WindowState> mPendingRemove = new ArrayList<>(); WindowState[] mPendingRemoveTmp = new WindowState[20]; final ArrayList<WindowState> mDestroySurface = new ArrayList<>(); final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>(); ... final H mH = new H(); ... final WindowAnimator mAnimator; ... final InputManagerService mInputManager
WindowManagerPolicy mPolicy
窗口管理策略的接口类,用来定义一个窗口策略所要遵循的通用规范,并提供了 WindowManager 所有的特定 UI 行为
他的具体实现类为 PhoneWindowManager,这个实现类在 WMS 创建时被创建。WMP 允许定制窗口层级和特殊窗口类型以及关键字的调度和布局
ArraySet mSessions
ArraySet 类型的变量,元素类型为 Session,他主要用于进程间的通信。并且每个应用程序都会对应一个 Session,WMS 保存这些 Session 用来记录所有向 WMS 提出窗口管理服务的客户端
WindowHashMap mWindowMap
继承自 HashMap,它限制 key 为 IBinder,value 的值类型为 WindowState,WindowState 用于保存窗口信息,在 WMS 中用来描述一个窗口。所以 mWindowMap 就是用来保存 WMS 中各种窗口的集合。
ArrayList mFinishedStarting
元素类型是 AppWindowToken,他是 WindowToken 的子类,想要了解 mFinishedStarting 的含义,需要先了解 WindowToken 是什么,WindowToken 主要由两个作用:
可以理解为窗口令牌,当应用程序想要向 WMS 申请创建一个窗口,则需要向 WMS 出示有效的 WindowToken。AppWindowToken 作为 WindowToken 的子类,主要用来描述应用程序的 WindowToken 结构。
WindowToken 会将相同组件(例如 Activity)的窗口(WindowState)集合在一起,方便管理。
mFinishedStarting 就是用于存储已经完成启动的应用窗口程序窗口(比如Activity) 的 AppWindowToken 的列表。
除了 mFinishedStarting,还有类似的 mFinishedEarlyAnim和 mWindowReplacementTimeouts
其中 mFinishedEarlyAnim 存储了已经完成窗口绘制并且不需要再展示任何已经保存 surface 的应用程序窗口的 AppWindowToken
mWindowReplacementTimeout 存储了等待更换的应用程序窗口的 AppWindowToken,如果更换不及时,旧窗口就需要被处理
ArrayList mResizingWindow
用来存储正在调整大小的窗口列表。与 mResizingWindows 类似的还有个 mPendingRemove,mDestorySurface 和 mDestoryPreservedSurface 等等。
其中 mPendingRemove 是在内存耗尽时设置的,里面存有需要强制删除的窗口。
mDestorySurface 里面存有需要被 Destory 的 Surface ,mDestoryPreservedSurface 里面存有窗口需要保存的等等销毁的 Surface ,为什么窗口需要保存这些 Surface ?这是因为当窗口经历 Surface 变化时,窗口需要一直保持旧 Surface,直到新 Surface 的第一帧绘制完成。
WindowAnimator mAnimator
WindowAnimator 类型的变量,用于管理窗口的动画以及特效动画
H mH
继承自 Hnadler 类,用于将任务加入到主线程的消息队列中,这样代码逻辑就会在主线程执行
InputManagerService mINputManager
IMS ,输入系统的管理者。IMS 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口管理者,因此 WMS 理所应当的成为了输入系统的中转站,WMS 包含了 IMS 的引用不足为怪。