以下分析基于Android S.
简述
之前分析,Activity在被start时会创建其对应ActivityRecord并保存在对应DisplayContent的mTokenMap中,之后在该Activity被resume时,会通过其对应ViewRootImpl中的setView调用到WMS的addWindow方法,传入参数就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,通过这些信息创建WindowState:
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
| public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { ...... final int type = attrs.type; synchronized (mGlobalLock) { ...... WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); ... 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); ...... ...... }
|
一. WindowState
WindowState,顾名思义是用于保存窗口状态的类,WindowToke是用于标记窗口身份、对应哪个进程的Activity的类。
1.1 WindowState的初始化
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
| WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility, int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) { super(service); mTmpTransaction = service.mTransactionFactory.get(); mSession = s; mClient = c; mAppOp = appOp; mToken = token; mActivityRecord = mToken.asActivityRecord(); mOwnerUid = ownerId; mShowUserId = showUserId; mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; mWindowId = new WindowId(this); mAttrs.copyFrom(a); mLastSurfaceInsets.set(mAttrs.surfaceInsets); mViewVisibility = viewVisibility; mPolicy = mWmService.mPolicy; mContext = mWmService.mContext; DeathRecipient deathRecipient = new DeathRecipient(); ...... mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle( mActivityRecord != null ? mActivityRecord.getInputApplicationHandle(false ) : null, getDisplayId())); ...... c.asBinder().linkToDeath(deathRecipient, 0); ...... if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) { ...... } else { mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mSubLayer = 0; mIsChildWindow = false; mLayoutAttached = false; mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; mIsWallpaper = mAttrs.type == TYPE_WALLPAPER; } mIsFloatingLayer = mIsImWindow || mIsWallpaper;
if (mActivityRecord != null && mActivityRecord.mShowForAllUsers) { mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED; }
mWinAnimator = new WindowStateAnimator(this); ...... mWpcForDisplayAreaConfigChanges = (s.mPid == MY_PID || s.mPid < 0) ? null : service.mAtmService.getProcessController(s.mPid, s.mUid); }
|
初始化WindowState的过程并不复杂:
- 调用SurfaceControl.Transaction::new创建mTmpTransaction
- 保存来自应用ViewRootImpl中的mWindowSession、mWindow等
- 保存该WindowState对应window的ActivityRecord
- 创建WindowId
- 保存该Activity的View对应的窗口属性
- 创建InputApplicationHandle,即将该Window注册进Input系统,以便后续input事件传输
- 建立binder死亡监听,处理该WindowState所属应用进程死亡后资源处理
- 计算mBaseLayer,mBaseLayer = windowLayer(2) * 10000 + 1000;
- 标记mIsChildWindow、mIsImWindow(输入法窗口)、mIsWallpaper(壁纸窗口)
- 创建WindowAnimator,用于实现该窗口的动画
- 获取该pid对应的WindowProcessController
这里关于input相关的流程我们后续分析。
1.2 WindowState.attach
1 2 3 4
| void attach() { if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken); mSession.windowAddedLocked(); }
|
很简单的,直接交给mSession处理。
1.2.1 Session.windowAddedLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void windowAddedLocked() { ...... if (mSurfaceSession == null) { if (DEBUG) { Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession"); } mSurfaceSession = new SurfaceSession(); ProtoLog.i(WM_SHOW_TRANSACTIONS, " NEW SURFACE SESSION %s", mSurfaceSession); mService.mSessions.add(this); if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { mService.dispatchNewAnimatorScaleLocked(this); } } mNumWindow++; }
|
SurfaceSession是用于和SurfaceFlinger通信的,因为Session是单个进程只会持有一个,所以创建SurfaceSession也只会初始化一次。
创建Session的过程:WindowManagerGlobal.getWindowSession
1 2 3 4 5 6 7 8 9 10 11 12 13
| >> >>public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { ...... sWindowSession = windowManager.openSession( ...... } return sWindowSession; } >>}
|
1.2.2 创建SurfaceSession
1 2 3 4 5 6
| private static native long nativeCreate();
public SurfaceSession() { mNativeClient = nativeCreate(); }
|
这里直接通过JNI创建对应native层对象,关于JNI后续单独出文章分析,有一个最简单的法则:
SurfaceSession所处的包是 “android.view”, 所以对应JNI文件就是:android_view_SurfaceSession.cpp
1.2.3 android_view_SurfaceSession.cpp:nativeCreate
1 2 3 4 5 6 7
| static jlong nativeCreate(JNIEnv* env, jclass clazz) { SurfaceComposerClient* client = new SurfaceComposerClient(); client->incStrong((void*)nativeCreate); return reinterpret_cast<jlong>(client); }
|
SurfaceSession对应的native层对象就是SurfaceComposerClient!
1.2.4 创建SurfaceComposerClient
1 2 3 4
| SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) { }
|
标记mStatus为NO_INIT,尚未初始化。
回过头看WindowState.attach,这个方法其实就是创建mSurfaceSession并将其保存在WMS.mSessions集合中。而SurfaceSession其实就是对native层SurfaceComposerClient的包装。
1.3 WindowState所属应用进程死亡
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
| public void binderDied() { try { boolean resetSplitScreenResizing = false; synchronized (mWmService.mGlobalLock) { final WindowState win = mWmService .windowForClientLocked(mSession, mClient, false); Slog.i(TAG, "WIN DEATH: " + win); if (win != null) { final DisplayContent dc = getDisplayContent(); if (win.mActivityRecord != null && win.mActivityRecord.findMainWindow() == win) { mWmService.mTaskSnapshotController.onAppDied(win.mActivityRecord); } win.removeIfPossible(shouldKeepVisibleDeadAppWindow()); } else if (mHasSurface) { Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid."); WindowState.this.removeIfPossible(); } } ....... } catch (IllegalArgumentException ex) { } }
|
1.3.1 WMS.windowForClientLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| final WindowState windowForClientLocked(Session session, IWindow client, boolean throwOnError) { return windowForClientLocked(session, client.asBinder(), throwOnError); }
final WindowState windowForClientLocked(Session session, IBinder client, boolean throwOnError) { WindowState win = mWindowMap.get(client); if (DEBUG) Slog.v(TAG_WM, "Looking up client " + client + ": " + win); if (win == null) { ...... return null; } if (session != null && win.mSession != session) { ...... return null; }
return win; }
|
从WMS的mWindowMap中查找client(ViewRootImpl.W)对应的WindowState, 这个是在addWindow时保存的。
1.3.2 WindowState.removeIfPossible
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
| @Override void removeIfPossible() { super.removeIfPossible(); removeIfPossible(false ); }
private void removeIfPossible(boolean keepVisibleDeadWindow) { mWindowRemovalAllowed = true; final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING; ......
try { disposeInputChannel(); ......
boolean wasVisible = false;
if (mHasSurface && mToken.okToAnimate()) { if (mWillReplaceWindow) { ...... mAnimatingExit = true; mReplacingRemoveRequested = true; return; }
wasVisible = isWinVisibleLw(); ...... if (wasVisible) { final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
if (mWinAnimator.applyAnimationLocked(transit, false)) { mAnimatingExit = true;
setDisplayLayoutNeeded(); mWmService.requestTraversal(); } ...... } ...... } removeImmediately(); if (wasVisible) { final DisplayContent displayContent = getDisplayContent(); if (displayContent.updateOrientation()) { displayContent.sendNewConfiguration(); } } mWmService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, true ); } finally { Binder.restoreCallingIdentity(origId); } }
|
窗口所属进程死亡后,需要清理该窗口的WindowState:
- 标记该WindowState是被移除的,mWindowRemovalAllowed置为true
- 将该WindowState从Input系统中移除
- 确认是否需要运行动画。如果需要,推迟删除窗口,直到动画完成。如果显示被冻结,只需立即移除,因为不会看到动画。
- 如果是可见的,需要创建并执行一个窗口退出动画
- 将此WindowState移除
- 移除一个可见的窗口可能会影响显示方向,比如横屏游戏,此时需要重新计算更新相关参数
- 更新焦点窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Override void removeImmediately() { super.removeImmediately(); ...... final DisplayContent dc = getDisplayContent(); ..... dc.getDisplayPolicy().removeWindowLw(this);
disposeInputChannel(); mWinAnimator.destroySurfaceLocked(mTmpTransaction); mTmpTransaction.apply(); mSession.windowRemovedLocked(); try { mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); } catch (RuntimeException e) { } mWmService.postWindowRemoveCleanupLocked(this); }
|
移除WindowState会执行:
- 对所有mChildren执行清理动作
- 将该WindowState的窗口属性从DisplayContent中移除
- 移除窗口的Surface
- 将此窗口WindowState从Session中移除
- Session中窗口数目减一
- 如果窗口数量大于0或者对应应用进程没有死亡时,不需要移除session,以备后续使用
- 否则将此Session从WMS.mSessions集合中移除
- 如果存在mSurfaceSession,则同步清理,清理时将该SurfaceSession对应的SurfaceComposerClient的引用计数减掉
- 执行清理后操作,从WMS.mWindowMap中移除该WindowState然后更新绘制
1.3.2.2 Session.windowRemovedLocked
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
| void windowRemovedLocked() { mNumWindow--; killSessionLocked(); }
private void killSessionLocked() { if (mNumWindow > 0 || !mClientDead) { return; } mService.mSessions.remove(this); if (mSurfaceSession == null) { return; } ...... try { mSurfaceSession.kill(); } catch (Exception e) { Slog.w(TAG_WM, "Exception thrown when killing surface session " + mSurfaceSession + " in session " + this + ": " + e.toString()); } mSurfaceSession = null; mAlertWindowSurfaces.clear(); mAppOverlaySurfaces.clear(); setHasOverlayUi(false); cancelAlertWindowNotification(); }
|
1.3.2.3 SurfaceSession.kill - 清理SurfaceSession
1 2 3 4 5 6
| public void kill() { if (mNativeClient != 0) { nativeDestroy(mNativeClient); mNativeClient = 0; } }
|
执行native清理动作,将mNativeClient置为0.
1 2 3 4
| static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr); client->decStrong((void*)nativeCreate); }
|
native层的清理动作也很简单,将该SurfaceSession对应的SurfaceComposerClient的引用计数减掉即可。
二. 小结
回顾下本文涉及类的类图:
之前分析,Activity在被start时会创建其对应ActivityRecord并保存在对应DisplayContent的mTokenMap中,之后在该Activity被resume时,会通过其对应ViewRootImpl中的setView调用到WMS的addWindow方法,传入参数就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,通过这些信息创建WindowState:
- 初始化WindowState
- 调用SurfaceControl.Transaction::new创建mTmpTransaction
- 保存来自应用ViewRootImpl中的mWindowSession、mWindow等
- 保存该WindowState对应window的ActivityRecord
- 创建WindowId
- 保存该Activity的View对应的窗口属性
- 创建InputApplicationHandle,即将该Window注册进Input系统,以便后续input事件传输
- 建立binder死亡监听,处理该WindowState所属应用进程死亡后资源处理
- 计算mBaseLayer,mBaseLayer = windowLayer(2) * 10000 + 1000;
- 标记mIsChildWindow、mIsImWindow(输入法窗口)、mIsWallpaper(壁纸窗口)
- 创建WindowAnimator,用于实现该窗口的动画
- 获取该pid对应的WindowProcessController
- WindowState.attach, 创建SurfaceSession
- SurfaceSession是用于和SurfaceFlinger通信的,因为Session是单个进程只会持有一个,所以创建SurfaceSession也只会初始化一次。
- 创建SurfaceSession就是创建其对应native层的对象SurfaceComposerClient, 将其mStatus标记为NO_INIT,尚未初始化
- 保存WindowState至WMS.mTokenMap中, key为ViewRoomImpl.W
- 将该WindowState保存在其mToken(ActivityRecord的mChildren)中
当WindowState对应的进程死亡时,执行相关清理动作:
- 标记该WindowState是被移除的,mWindowRemovalAllowed置为true
- 将该WindowState从Input系统中移除
- 确认是否需要运行动画。如果需要,推迟删除窗口,直到动画完成。如果显示被冻结,只需立即移除,因为不会看到动画。
- 如果是可见的,需要创建并执行一个窗口退出动画
- 将此WindowState移除
- 对其所有mChildren执行清理动作
- 将该WindowState的窗口属性从DisplayContent中移除
- 移除窗口的Surface
- 将此窗口WindowState从Session中移除
- Session中窗口数目减一
- 如果窗口数量大于0或者对应应用进程没有死亡时,不需要移除session,以备后续使用
- 否则将此Session从WMS.mSessions集合中移除
- 如果存在mSurfaceSession,则同步清理,清理时将该SurfaceSession对应的SurfaceComposerClient的引用计数减掉
- 执行清理后操作,从WMS.mWindowMap中移除该WindowState然后更新绘制
- 移除一个可见的窗口可能会影响显示方向,比如横屏游戏,此时需要重新计算更新相关参数
- 更新焦点窗口
这里我们注意到WindowState被销毁时会存在一个窗口动画,那么当WindowState的窗口创建时应该也存在一个窗口动画,对应的应该是我们在WindowState被销毁时的TYPE_APPLICATION_STARTING类型窗口(因为Activity对应窗口尚未创建完毕,那么窗口启动动画应该在另一个准备完毕的窗口执行才行)。
下一篇文章我们就探秘一下应用启动窗口动画。