WindowManagerService是位于Framework层的窗口管理服务,它的职责是管理系统中的所有窗口,也就是Window,关于Window的介绍,我们在文章03Android显示框架:Android应用视图的管理者Window已经 详细分析过,通俗来说,Window就是手机上一块显示区域,也就是Android中的绘制画布Surface,添加一个Window的过程,也就是申请分配一块Surface的过程。而整个流程的管理者正是WindowManagerService。
Window在WindowManagerService的管理下,有序的显示在屏幕上,构成了多姿多彩的用户界面,关于Android的整个窗口系统,可以用下图来表示:
Android窗口管理框架从窗口的创建到UI的绘制主要涉及以下角色:
前面说到窗口的管理服务WindowManagerService运行在System Server进程,所以应用进程与WindowManagerService的交互是一个IPC的过程,具体流程如下所示:
如上图所示,Activity持有一个Window,负责UI的展示与用户交互,里保存了很多重要的信息,如下所示:
ViewRootImpl负责管理DecorView与WindowManagerService的交互,每次调用WindowManager.addView()添加窗口时,都会创建一个ViewRootImpl对象,它内部也保存了一些重要信息,如下所示:
👉 注:每个Activity对应一个Window,每个Window对应一个ViewRootImpl。
理解了以上内容,我们来看看Window的添加、更新和移除流程。
窗口的操作被定义WindowManager中,WindowManager是一个接口,继承于ViewManager,实现类是WindowManagerImpl,实际上我们常用的功能,也是定义在ViewManager里的。
public interface ViewManager{
//添加View
public void addView(View view, ViewGroup.LayoutParams params);
//更新View
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
//删除View
public void removeView(View view);
}
WindowManager可以通过Context来获取,WindowManager也会和其他服务一样在开机时注册到ContextImpl里的map容器里,然后通过他们的key来获取。
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager的实现类是WindowManagerImpl,在WindowManagerImpl内部实际的功能是有WindowManagerGlobal来完成的,我们直接来分析它里面这三个方法的实现。
public final class WindowManagerGlobal {
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//校验参数的合法性
...
//ViewRootImpl封装了View与WindowManager的交互力促
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
//通过上下文构建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//mViews存储着所有Window对应的View对象
mViews.add(view);
//mRoots存储着所有Window对应的ViewRootImpl对象
mRoots.add(root);
//mParams存储着所有Window对应的WindowManager.LayoutParams对象
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
//调用ViewRootImpl.setView()方法完成Window的添加并更新界面
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
}
在这个方法里有三个重要的成员变量:
这里面提到了一个我们不是很熟悉的类ViewRootImpl,它其实就是一个封装类,封装了View与WindowManager的交互方式,它是View与WindowManagerService通信的桥梁。 最后也是调用ViewRootImpl.setView()方法完成Window的添加并更新界面。
我们来看看这个方法的实现。
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//参数校验与预处理
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//1. 调用requestLayout()完成界面异步绘制的请求
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//2. 创建WindowSession并通过WindowSession请求WindowManagerService来完成Window添加的过程
//这是一个IPC的过程。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
}
}
}
这个方法主要做了两件事:
注:在文章02Android显示框架:Android应用视图的载体View中 我们已经详细的分析过performTraversals()方法的实现,这里我们再简单提一下:
既然提到WindowManager与WindowManagerService的跨进程通信,我们再讲一下它们的通信流程。Android的各种服务都是基于C/S结构来设计的,系统层提供服务,应用层使用服务。WindowManager也是一样,它与 WindowManagerService的通信是通过WindowSession来完成的。
基本上所有的Android系统服务都是基于这种方式实现的,它是一种基于AIDL实现的IPC的过程。关于AIDL读者可自行查阅资料。
public final class WindowManagerGlobal {
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
//获取WindowManagerService对象,并将它转换为IWindowManager类型
IWindowManager windowManager = getWindowManagerService();
//调用openSession()方法与WindowManagerService建立一个通信会话,方便后续的
//跨进程通信。
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
//调用ServiceManager.getService("window")获取WindowManagerService,该方法返回的是IBinder对象
//,然后调用IWindowManager.Stub.asInterface()方法将WindowManagerService转换为一个IWindowManager对象
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
}
Window的删除流程也是在WindowManagerGlobal里完成的。
public final class WindowManagerGlobal {
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
//1. 查找待删除View的索引
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
//2. 调用removeViewLocked()完成View的删除, removeViewLocked()方法
//继续调用ViewRootImpl.die()方法来完成View的删除。
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
if (view != null) {
InputMethodManager imm = InputMethodManager.getInstance();
if (imm != null) {
imm.windowDismissed(mViews.get(index).getWindowToken());
}
}
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
mDyingViews.add(view);
}
}
}
}
我们再来看看ViewRootImpl.die()方法的实现。
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
boolean die(boolean immediate) {
// Make sure we do execute immediately if we are in the middle of a traversal or the damage
// done by dispatchDetachedFromWindow will cause havoc on return.
//根据immediate参数来判断是执行异步删除还是同步删除
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
if (!mIsDrawing) {
destroyHardwareRenderer();
} else {
Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
//如果是异步删除,则发送一个删除View的消息MSG_DIE就会直接返回
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
void doDie() {
checkThread();
if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
//调用dispatchDetachedFromWindow()完成View的删除
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
// If layout params have been changed, first give them
// to the window manager to make sure it has the correct
// animation info.
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
mSurface.release();
}
}
mAdded = false;
}
//刷新数据,将当前移除View的相关信息从我们上面说过了三个列表:mRoots、mParms和mViews中移除。
WindowManagerGlobal.getInstance().doRemoveView(this);
}
void dispatchDetachedFromWindow() {
//1. 回调View的dispatchDetachedFromWindow方法,通知该View已从Window中移除
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
setAccessibilityFocus(null, null);
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
mSurface.release();
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
mInputQueue.dispose();
mInputQueueCallback = null;
mInputQueue = null;
}
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
//调用WindowSession.remove()方法,这同样是一个IPC过程,最终调用的是
//WindowManagerService.removeWindow()方法来移除Window。
try {
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
// Dispose the input channel after removing the window so the Window Manager
// doesn't interpret the input channel being closed as an abnormal termination.
if (mInputChannel != null) {
mInputChannel.dispose();
mInputChannel = null;
}
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
}
我们再来总结一下Window的删除流程:
public final class WindowManagerGlobal {
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
//更新View的LayoutParams参数
view.setLayoutParams(wparams);
synchronized (mLock) {
//查找Viewd的索引,更新mParams里的参数
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams);
//调用ViewRootImpl.setLayoutParams()完成重新布局的工作。
root.setLayoutParams(wparams, false);
}
}
}
我们再来看看ViewRootImpl.setLayoutParams()方法的实现。
public final class ViewRootImpl implements ViewParent,
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
//参数预处理
...
//如果是新View,调用requestLayout()进行重新绘制
if (newView) {
mSoftInputMode = attrs.softInputMode;
requestLayout();
}
// Don't lose the mode we last auto-computed.
if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
== WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
& ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
| (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
}
mWindowAttributesChanged = true;
//如果不是新View,调用requestLayout()进行重新绘制
scheduleTraversals();
}
}
}
Window的更新流程也和其他流程相似:
通过上面分析,我们了解了Window的添加、删除和更新流程。那么我们来思考一个问题:既然说是Window的添加、删除和更新,那为什么方法名是addView、updateViewLayout、removeView,Window的本质是什么?🤔
事实上Window是一个抽象的概念,也就是说它并不是实际存在的,它以View的形式存在,每个Window都对应着一个View和一个ViewRootImpl,Window与View通过ViewRootImpl来建立联系。推而广之,我们可以理解 WindowManagerService实际管理的也不是Window,而是View,管理在当前状态下哪个View应该在最上层显示,SurfaceFlinger绘制也同样是View。
好了本篇文章的内容到这里就讲完了,在这篇文章中我们侧重分析Android窗口服务Client这一侧的实现,事实上更多的内容是在Server这一侧,也就是WindowManagerService。只不过在日常的开发中我们较少 接触到WindowManagerService,它属于系统的内部服务,就暂时不做进一步的展开。总体上来说,本系列文章的目的还是在于更好的服务应用层的开发者,等到关于Android应用层Framework实现原理分析完成以后, 我们再进一步深入,去分析系统层Framework的实现。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8