WindowManagerService 源码
Android 的framework 层主要是由 WindowManagerService 与 ActivityManagerService 以及 View 所构成,这三个模块穿插交互在 framework中。
WMS 和其他很多服务一样, 都是由 SystemServer 启动。
在SystemServer 中,有如下代码:
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
addService中 key 是 window。 那么在其他进程就可以通过 ServiceManager 以key 为 window 来获取到 WMS。
下面是WMS 中的 main 方法。 通过 Handler 的 runWithScissors 方法执行一个特殊的同步 Task. 并构建了 WMS 的实例。
public static WindowManagerService main(final Context context,
final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
//执行同步 task
DisplayThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
//构建实例
holder[0] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
}
Handler 的 runWithScissors
方法中 第一行注释说明这是一个同步 task。如下:
- Runs the specified task synchronously.
WMS 的构造方法中主要是对一些窗口管理将要用到的成员变量 进行初始化:
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
mHaveInputMethods = haveInputMethods;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
mHasPermanentDpad = context.getResources().getBoolean(
com.android.internal.R.bool.config_hasPermanentDpad);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings(context);
// ... 省略几行代码
//获取显示服务
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = mDisplayManager.getDisplays();
//为每一个 Display 分配一个 Content
for (Display display : displays) {
createDisplayContentLocked(display);
}
// ... 省略几行代码
//构建App 事务
mAppTransition = new AppTransition(context, mH);
//获取 IActivityManager 对象
mActivityManager = ActivityManagerNative.getDefault();
// ... 省略几行代码
//构造 Window 动画对象
mAnimator = new WindowAnimator(this);
// 初始化窗口策略
initPolicy();
//开启绘制事务
SurfaceControl.openTransaction();
// ... 省略几行代码
}
WMS 主要功能有两个方面, 一是 对窗口的管理; 二是 对事件的管理和分发。
接口方法定义在 IWindowManager.aidl。 编译后会生成 IWindowManager.java接口文件。 里面定义了 WMS 绝大部分的功能和方法。
WMS 定义了许多各种不同的窗口。
//已经完成启动的应用
final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();
//渐变窗口
final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>();
//尺寸正在改变的窗口
final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();
//动画正在结束的窗口
final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
//即将释放的Surface窗口
final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();
// 失去焦点的Window
ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();
//为了释放内存需要强制关闭的Window
ArrayList<WindowState> mForceRemoves;
//正在打开的应用
final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<AppWindowToken>();
//正在关闭的应用
final ArraySet<AppWindowToken> mClosingApps = new ArraySet<AppWindowToken>();
//得到焦点的应用
AppWindowToken mFocusedApp = null;
... //省略代码 还有很多。
不同的窗口或者同一个窗口在不同的阶段可能会位于不同的表中。
Android 中主要由两种窗口类型:
1.应用窗口。
如 Activity所处的窗口,对话框窗口、弹出的窗口等等。 与应用相关的 Window类的 PhoneWindow。 核心是DecorView, 通过 addView 将一个DecorView 添加到 WindowManager.
2.系统窗口。
如 屏幕顶部的状态栏 、 底部的导航栏、桌面的窗口等。 系统窗口没有针对的封装类, 只需要通过 WindwoManager的 addView方法 添加到WindowManager 即可。
比如PhoneStatusBar 中。 createAndAddWindows() -> StatusBarWindowManager.java -> add()中:
mWindowManager.addView(mStatusBarView, mLp);
客户端添加一个窗口
WindowManager.addView() -> WindowManagerImpl.addView() -> WindowMangerGlobal.addView() -> ViewRootImpl.setView() -> IWindowSession.addToDisplay() -> Session.addToDisplay() -> WMS.addWindow().
Sesson中:
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
ok 。我们来看 WMS 中 addWindow 的实现:
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
...// 省略一堆代码...
}
这里的 mPolicy 实际上是 PhoneWindowManager. Policy 中的实现。
public WindowManagerPolicy makeNewWindowManager() {
return new PhoneWindowManager();
}
PhoneWindowManager 的 checkAddPermission 中会先判断窗口的 type 是否是系统级别。 如果不是 则返回 WindowManagerGlobal.ADD_OKAY
. 如果是,就会进行相关权限等的校验 SYSTEM_ALERT_WINDOW
、INTERNAL_SYSTEM_WINDOW
. 如果没有权限就会 返回 ADD_PERMISSION_DENIED
. 校验完毕权限 会校验窗口的有效性。
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
if (token == null) {
//如果窗口是子窗口
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
//如果是输入法窗口
if (type == TYPE_INPUT_METHOD) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
...// 省略一堆 if else.
检查窗口的有效性完毕,接下来就是为该窗口创建一个 WindowState对象。维护窗口的状态以及更加适当的机制来调整窗口状态。
synchronized(mWindowMap) {
// ...省略代码
//构建WindowState对象
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
//如果客户端已经被销毁
if (win.mDeathRecipient == null) {
return WindowManagerGlobal.ADD_APP_EXITING;
}
//根据窗口类型调整属性
mPolicy.adjustWindowParamsLw(win.mAttrs);
//设置该窗口是否只对自己的 uid 可见
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
//根据窗口类型判定权限
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
//如果输出 Channel 的通道为空
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
//创建通道
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
//向 InputManager 中注册该通道,以便当前窗口可以接受到事件。
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
//...省略一些代码
mPolicy 实质上就是 PhoneWindowManager。 对用它的 adjustWindowParamsLw
方法。里面判断如果是 TYPE_SYSTEM_OVERLAY 和 TYPE_SECURE_SYSTEM_OVERLAY 类型 的窗口,不要获取焦点即可。
addWindow 最后部分的逻辑
... 省略大量代码
res = WindowManagerGlobal.ADD_OKAY;
//重置当前线程 IPC 的 ID
origId = Binder.clearCallingIdentity();
是否需要token
if (addToken) {
mTokenMap.put(attrs.token, token);
}
//将窗口添加至Session
win.attach();
//将窗口添加至 WMS
mWindowMap.put(client.asBinder(), win);
//省略几行代码...
//顺序排列窗口
if (type == TYPE_INPUT_METHOD) {
//如果是输入法窗口
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
//如果是输入法对话框窗口
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
imMayMove = false;
} else {
//如果是其他窗口
addWindowToListInOrderLocked(win, true);
if (type == TYPE_WALLPAPER) {
mLastWallpaperTimeoutTime = 0;
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (mWallpaperTarget != null
&& mWallpaperTarget.mLayer >= win.mBaseLayer) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
win.mWinAnimator.mEnterAnimationPending = true;
//如果displayContent 是默认的显示
if (displayContent.isDefaultDisplay) {
//获取系统窗口区域的inserts
mPolicy.getContentInsetHintLw(attrs, outContentInsets);
} else {
//否则将 outContentInsets 置为空
outContentInsets.setEmpty();
}
if (mInTouchMode) {
//标识用户直接触摸的窗口
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
if (win.mAppToken == null || !win.mAppToken.clientHidden) {
//标识应用窗口
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
mInputMonitor.setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
//如果当前窗口可以接收按键事件
if (win.canReceiveKeys()) {
//那么更新焦点将窗口信息存入 InputDispatcher
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
if (imMayMove) {
moveInputMethodWindowsIfNeededLocked(false);
}
//分配最终层级
assignLayersLocked(displayContent.getWindowList());
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
reportNewConfig = true;
}
}
if (reportNewConfig) {
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
return res;
}
这部分逻辑中,最重要的一步就是通过 WindowState的 attach方法 创建一个关联的 SurfaceSession的对象 用以与 SurfaceFlinger通信。 而 SurfaceSession实际对应的是 native层中的 SurfaceComposerClient对象。 SurfaceComposerClient 主要作用就是在 应用进程与 SurfaceFlinger 服务之间建立连接。(这块不是很明白。很多知识都不理解)。
mSurfaceSession = new SurfaceSession();