以下分析基于Android S.
简述 之前我们通过Vsync这个Android绘制的脉搏疏通了绘制的流程,在Activity的显示研究过程中,粗略接触了WindowManagerService,也即Android的窗口管理。
接下来我们深入探讨一下Android中的窗口管理设计,以便我们理解View、Activity、Window、Task等之间的关系。
首先还是从WindowManagerService服务的启动开始,在Android开机流程中,我们知道WMS是在引导服务和核心服务启动之后才会开始的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void startOtherServices (@NonNull TimingsTraceAndSlog t) { ... t.traceBegin("StartWindowManagerService" ); ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); mSensorServiceStart = null ; wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, new PhoneWindowManager (), mActivityManagerService.mActivityTaskManager); ServiceManager.addService(Context.WINDOW_SERVICE, wm, false , DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO); ServiceManager.addService(Context.INPUT_SERVICE, inputManager, false , DUMP_FLAG_PRIORITY_CRITICAL); t.traceEnd(); t.traceBegin("SetWindowManagerService" ); mActivityManagerService.setWindowManager(wm); t.traceEnd(); t.traceBegin("WindowManagerServiceOnInitReady" ); wm.onInitReady(); t.traceEnd(); }
这里眼尖的同学发现了,WMS的启动必须等待SensorService的启动完毕,为什么呢,后面给出答案。
一. WMS启动 从上面也看出了,WMS的启动是先调用了其静态方法main, 并传入context, inputManager及ActivityTaskManager等,还有一个WindowManagerPolicy子类PhoneWindowManager的对象.
1.1 WindowManagerService.main 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 ); } @VisibleForTesting 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; }
这里使用的双冒号”::”、Supplier以及Function都是java8引入的函数式编程语法。这里值得注意的是runWithScissors方法。
1.2 DisplayThread.getHandler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public final class DisplayThread extends ServiceThread { private static DisplayThread sInstance; private static Handler sHandler; private DisplayThread () { super ("android.display" , Process.THREAD_PRIORITY_DISPLAY + 1 , false ); } private static void ensureThreadLocked () { if (sInstance == null ) { sInstance = new DisplayThread (); sInstance.start(); sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler (sInstance.getLooper()); } } public static Handler getHandler () { synchronized (DisplayThread.class) { ensureThreadLocked(); return sHandler; } } ... }
由此可以看出DisplayThread其实就是Android里的”android.display”线程,优先级仅仅比THREAD_PRIORITY_DISPLAY低一档。
1.2.1 Handler.runWithScissors 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public final boolean runWithScissors (@NonNull Runnable r, long timeout) { if (r == null ) { throw new IllegalArgumentException ("runnable must not be null" ); } if (timeout < 0 ) { throw new IllegalArgumentException ("timeout must be non-negative" ); } if (Looper.myLooper() == mLooper) { r.run(); return true ; } BlockingRunnable br = new BlockingRunnable (r); return br.postAndWait(this , timeout); }
这里可以看到该方法首先检查了参数合法性,然后判断当前允许的线程是否是Handler处理线程:
如果是Handler处理线程,则执行runnable
如果不是,则创建一个BlockingRunnable,执行其postAndWait方法
从postAndWait名字中可以推测,必定是需要等待指定runnable在Handler处理线程上执行完毕后,调用runWithScissors的线程才能继续运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 private static final class BlockingRunnable implements Runnable { private final Runnable mTask; private boolean mDone; public BlockingRunnable (Runnable task) { mTask = task; } @Override public void run () { try { mTask.run(); } finally { synchronized (this ) { mDone = true ; notifyAll(); } } } public boolean postAndWait (Handler handler, long timeout) { if (!handler.post(this )) { return false ; } synchronized (this ) { if (timeout > 0 ) { final long expirationTime = SystemClock.uptimeMillis() + timeout; while (!mDone) { long delay = expirationTime - SystemClock.uptimeMillis(); if (delay <= 0 ) { return false ; } try { wait(delay); } catch (InterruptedException ex) { } } } else { while (!mDone) { try { wait(); } catch (InterruptedException ex) { } } } } return true ; } }
所以runWithScissors方法为啥会标记为hide呢,明明很好的实现了将某个任务放到指定线程执行并等待该任务执行完毕后继续。
考虑到如果等待超时,postAndWait返回的也是false,但是对应runnable的message仍旧处于Handler的MessageQueue之中,这样该runnable最终还是会被执行的。
可能造成死锁,因为runWithScissors所处线程会一直等待,除非超时。比如任务所处的handler的Looper被调用了quit()退出时。我们知道quit方法是会清理Looper的MessageQueue中所有消息,如果此时timeout的时间设置的是0,那么runWithScissors方法所处的线程会一直等到天荒地老。除非Looper退出时是调用的quitSafely(), 该方法只会清空MessageQueue中当前时间点之后的message,在这之前的message仍会被执行。
而我们知道,DisplayThread代表线程是不会退出的(除非关机), 所以这里调用runWithScissors是安全的。
1.3 WindowManagerService 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 private WindowManagerService (Context context, InputManagerService inputManager, boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy, ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory, Supplier<Surface> surfaceFactory, Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) { installLock(this , INDEX_WINDOW); ... mInTouchMode = context.getResources().getBoolean( com.android.internal.R.bool.config_defaultInTouchMode); inputManager.setInTouchMode(mInTouchMode); ... mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mSurfaceFactory = surfaceFactory; mTransaction = mTransactionFactory.get(); mPolicy = policy; mAnimator = new WindowAnimator (this ); mRoot = new RootWindowContainer (this ); ... mWindowPlacerLocked = new WindowSurfacePlacer (this ); mTaskSnapshotController = new TaskSnapshotController (this ); ... mScreenFrozenLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN" ); mScreenFrozenLock.setReferenceCounted(false ); mDisplayNotificationController = new DisplayWindowListenerController (this ); ... mHoldingScreenWakeLock = mPowerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM); mHoldingScreenWakeLock.setReferenceCounted(false ); mSurfaceAnimationRunner = new SurfaceAnimationRunner (mTransactionFactory, mPowerManagerInternal); ... mTaskPositioningController = new TaskPositioningController ( this , mInputManager, mActivityTaskManager, mH.getLooper()); mDragDropController = new DragDropController (this , mH.getLooper()); mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources()); ... mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( mContext.getResources()); ... setGlobalShadowSettings(); mAnrController = new AnrController (this ); mStartingSurfaceController = new StartingSurfaceController (this ); }
这里省略的很多设置代码,仅贴了一些比较重要或者有趣的类对象初始化。
二. Activity的Window创建 之前我们在*Activity的显示(1)*一文中有分析过,应用的Activity在onCreate方法中setContentView设置了UI布局,之后在该Activity第一次resume时,初始化ViewRootImpl,当该Activity是应用进程第一个被resume的Activity时,建立进程与WMS的通信通道,也就是WindowSession!
最后ViewRootImpl的setView方法中,通过binder调用WindowManager的addToDisplay,之后进入到SystemServer进程调用到WMS.addWindow,在这里创建该Activity对应的WindowState,并保存在mWindowMap中。
如下即是WMS中addWindow的关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public int addWindow (Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { ...... synchronized (mGlobalLock) { ...... final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); ...... ActivityRecord activity = null ; final boolean hasParent = parentWindow != null ; WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); final int rootType = hasParent ? parentWindow.mAttrs.type : type; boolean addToastWindowRequiresToken = false ; final IBinder windowContextToken = attrs.mWindowContextToken; if (token == null ) { if (hasParent) { ...... } else { final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); token = new WindowToken (this , binder, type, false , displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); } } ... final WindowState win = new WindowState (this , session, client, token, parentWindow, appOp[0 ], attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); ...... win.attach(); mWindowMap.put(client.asBinder(), win); ...... win.mToken.addWindow(win); ...... ...... }
如上,我们可以看到WMS中几个关键的类: WindowState,WindowToken,ActivityRecord等。之前我们就绘制过这个类图:
WindowToken: 是在WindowManagerService 中定义的一个基类,顾名思义,它是用来标识某一个窗口。可以把WindowToken看成是一个显示令牌,无论是系统窗口还是应用窗口,添加新的窗口时需要使用这个令牌向WMS表明自己的身份,添加窗口(addWindow)时会创建WindowToken,销毁窗口的时候移除WindowToken(removeWindowToken方法)。
ActivityRecord(原AppWindowToken): 顾名思义,它是用来标识app, 跟准确的说法,是用来标识某个具体的Activity. App每个的Activity对应一個ActivityRecord。其中的appToken為IApplicationToken.Stub类型,有了它就可以找到对应的ActivityRecord.
从上面的关系图也能发现,这个WindowToken中token是关键点,我们尚未理清这个值的含义,接下来我们分析一下这个token的来源:
2.1 PhoneWindow的创建 简单回顾一下 Activity 对应的 PhoneWindow的创建,注意这里仅仅是App进程中的Window.
我们从handleLaunchActivity开始:
1 2 3 4 5 6 public Activity handleLaunchActivity (ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ...... final Activity a = performLaunchActivity(r, customIntent); ...... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private Activity performLaunchActivity (ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; ...... Activity activity = null ; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ...... } try { Application app = r.packageInfo.makeApplication(false , mInstrumentation); ...... if (activity != null ) { ...... activity.attach(appContext, this , getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken, r.shareableActivityToken); ...... synchronized (mResourcesManager) { mActivities.put(r.token, r); } } ...... }
每次调用performLaunchActivity就一定会创建一个新的Activity对象,并保存在mActivities集合中。
2.1.2 Activity.attach 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 final void attach (Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken, IBinder shareableActivityToken) { ...... mWindow = new PhoneWindow (this , window, activityConfigCallback); mWindow.setWindowControllerCallback(mWindowControllerCallback); mWindow.setCallback(this ); mWindow.setOnWindowDismissedCallback(this ); mWindow.getLayoutInflater().setPrivateFactory(this ); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0 ) { mWindow.setUiOptions(info.uiOptions); } ...... mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0 ); if (mParent != null ) { mWindow.setContainer(mParent.getWindow()); } ...... }
可以看到一个Activity对应一个PhoneWindow, 而且PhoneWindow是在Activity launch的时候才创建的。
2.2 WindowToken中token的作用 我们假设添加window的Activity是该应用第一个被resume的activity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();token = new WindowToken (this , binder, type, false , displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) { this (service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, roundedCornerOverlay, false , null ); } WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) { super (service); token = _token; windowType = type; mOptions = options; mPersistOnEmpty = persistOnEmpty; mOwnerCanManageAppTokens = ownerCanManageAppTokens; mRoundedCornerOverlay = roundedCornerOverlay; mFromClientToken = fromClientToken; if (dc != null ) { dc.addWindowToken(token, this ); } }
从WindowToken的构造函数和其初始化的传参中可以看到,WindowToken中的token就是attrs的token,或者是client(IWindow)转换来的。
2.2.1 LayoutParams中的token 溯源addWindow, 在ViewRootImpl.setView时,会将该LayoutParams作为参数传入,注意,有两个LayoutParams,一个是WindowManager.LayoutParams, 一个是其父类ViewGroup.LayoutParams:
而ViewRootImpl.setView也是在 WindowManagerGlobal.addView 时调用的,也就是ActivityThread处理该Activity的Resume状态时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public void handleResumeActivity (ActivityClientRecord r, boolean finalStateRequest, boolean isForward, String reason) { ...... final Activity a = r.activity; ...... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true ; wm.addView(decor, l); ...... ...... ...... }
从上可以看出只有当该Activity的window是尚未被添加且此次resume状态时是需要可见的时候,才会将该Activity对应View添加至WindowManager中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Override public void addView (@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyTokens(params); mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, mContext.getUserId()); } private void applyTokens (@NonNull ViewGroup.LayoutParams params) { if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException ("Params must be WindowManager.LayoutParams" ); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (mDefaultToken != null && mParentWindow == null && wparams.token == null ) { wparams.token = mDefaultToken; } wparams.mWindowContextToken = mWindowContextToken; }
虽然不是在此追踪,但是我们可以发现mGlobal.addView中的LayoutParams仍然是ViewGroup.LayoutParams类型,其并不带有token成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void addView (View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) { ...... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null ) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { ...... synchronized (mLock) { root = new ViewRootImpl (view.getContext(), display); ...... root.setView(view, wparams, panelParentView, userId); ...... } }
注意每个Activity对应一个PhoneWindow, 一个PhoneWindow对应一个WindowManager(即WindowManagerImpl), 而PhoneWindow继承自Window。PhoneWindow在其对应的Activity被调用attach时创建, 然后会创建WindowManagerImpl,保存在PhoneWindow的mWindowManager成员中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public void setWindowManager (WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { mAppToken = appToken; mAppName = appName; mHardwareAccelerated = hardwareAccelerated; if (wm == null ) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this ); } void adjustLayoutParamsForSubWindow (WindowManager.LayoutParams wp) { CharSequence curTitle = wp.getTitle(); if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { ...... } else { if (wp.token == null ) { wp.token = mContainer == null ? mAppToken : mContainer.mAppToken; } ...... ...... }
一般Window的mContainer是null的,所以wp.token就是Window的mAppToken,也即Activity中的mToken, 对应LocalActivityManager.LocalActivityRecord, 通过此变量可以快速找到Activity、ActivityInfo、Window等。所以最后Activity对应的WindowState中对应的WindowToken里的token成员变量就是Activity中的mToken.
2.3 Activity的View与Window的关系 在应用的一个Activity对象即将resume时,会通过WindowManagerImpl将View与该Activity对应的PhoneWindow关联起来。这部分发生WindowManagerGlobal.addView中:
1 2 3 4 5 6 7 8 9 10 11 12 public void addView (View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) { ...... synchronized (mLock) { root = new ViewRootImpl (view.getContext(), display); ...... root.setView(view, wparams, panelParentView, userId); ...... } }
这里传入的View 就是 r.window.getDecorView() 获取的decorView; 而parentWindow就是该Activity首次launch时创建的PhoneWindow(如果没有parent Activity时)
简单回顾下 PhoneWindow 的 DecorView是怎么来的:
在Activity被launch后,会调用其onCreate方法
应用会在这个方法中调用setContentView, 将该Activity对应的View或者layout资源ID传入
然后在调用该Activity对应PhoneWindow的setContentView方法
如果是首次调用,则先调用installDecor方法创建DecorView
之后通过PhoneWindow中的mLayoutInflater将该View实例化
最后将该View保存在PhoneWindow的ViewGroup对象mContentParent中
这部分的流程比如installDecor方法我们之后讨论View的生成时再详细分析。所以简单来说,Activity对应的layout视图作为一个子视图保存在这个Activity对应PhoneWindow的DecorView中。
2.4 IWindowSession - PhoneWindow与WMS的交互 Activity对应的Window和WMS的交互肯定是双向的,那么:
Activity对应的PhoneWindow需要保存WMS的client端
WMS需要保存该PhoneWindow的client端
毫无疑问,PhoneWindow中保存WMS的client端就是对应的IWindowManager, 保存在WindowManagerGlobal中。而PhoneWindow会用在其对应的ViewRootImpl中继承了IWindow.Stub的W类的对象,通过binder传递到WMS中,作为PhoneWindow在WMS中的client端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public ViewRootImpl (Context context, Display display) { this (context, display, WindowManagerGlobal.getWindowSession(), false ); } public ViewRootImpl (@UiContext Context context, Display display, IWindowSession session, boolean useSfChoreographer) { mContext = context; mWindowSession = session; ...... mWindow = new W (this ); ...... } public void setView (View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) { ....... res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets, mTempControls); ...... }
由此可见,ViewRootImpl发挥这至关重要的作用,其不仅包含Activity对应的View, PhoneWindow及该Window的属性LayoutParams, 还保存着作为WMS中该Activity的Window的服务端W类的对象。
之前我们略有分析mWindowSession的创建,这里我们直接给出时序图:
之前我们也说过:
IWindowManager 对应WindowManagerService, 应用进程端通过这个接口即可向WMS传递消息.
IWindowSession 通过这个Session和WMS中的Session交互.暂时还不理解这个作用
W extends IWindow 对应应用进程端的窗口, WMS通过这个向应用进程的Window发送消息.
现在我们分析IWindowSession的方法其实不难理解,IWindowSession是为了方便管理某个应用的某个Window与WMS通信的,虽然最后也是与WMS通信,但是将通信过程也视为一个对象,方便了管理。
三. 小结 本文中分析了Android显示框架中Framework层最重要的WMS服务启动过程,以及复习了Activity窗口的创建过程。
3.1 WMS服务启动
WMS服务是在引导服务和核心服务启动之后启动的,而且必须等待Sensor服务的启动完毕。
WMS服务的启动首先初始化了”android.display”线程,然后将启动过程放在此线程中处理,主线程阻塞等待该启动完毕。
WMS服务的创建过程:
创建了WindowAnimator
创建RootWindowContainer
创建WindowSurfacePlacer,如其名,用於定位窗口及其表面
创建TaskSnapshotController,用於获取相应任务的快照(位图)并将其放入缓存
设置全局阴影等等
WMS服务创建完毕后,通过ServiceManager将其发布,服务名为Context.WINDOW_SERVICE
3.2 Activity、Window与WindowManagerService
Activity在第一次启动后,调用attach方法时,会创建PhoneWindow以及对应的WindowManagerImpl
在Activity第一次resume时,调用该Activity的WindowManagerImpl创建ViewRootImpl
在创建ViewRootImpl之前,会通过adjustLayoutParamsForSubWindow将该Activity的mToken保存在PhoneWindow的LayoutParams中
创建ViewRootImpl过程中,会通过IWindowManager与WMS通信,创建IWindowSession, 用于该Activity的Window和WMS通信
创建ViewRootImpl之后,再通过期间创建的IWindowSession与将该Activity的IWindow、相关Window属性传递给WMS.
接下来我们看看WMS是怎么管理不同应用的Window的。