一:背景
应用启动,在执行完Activity的onCreate/onStart/onResume生命周期函数后,会调用wm.addView来像WMS添加窗口并绘制自己的视图。下面接着wm.addView来看下应用窗口是如何添加的。前置流程可查看应用冷启动流程分析 - AndroidU_notifyactivitylaunching-优快云博客的4.2章节。
二:应用窗口添加
2.1 ViewManager.addView
在ActivityThread的handleResumeActivity函数中,调用完Activity的onResume后,会调用ViewManager的addView函数来触发布局的加载和显示
//frameworks/base/core/java/android/app/ActivityThread.java
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, boolean shouldSendCompatFakeFocus, String reason) {
...
ViewManager wm = a.getWindowManager();
//调用WindowManagerImpl的addView函数
wm.addView(decor, l);
...
}
这里看下wm的赋值流程,通过下面代码可以看到wm是WindowManagerImpl即WindowManager的实现类
//frameworks/base/core/java/android/app/Activity.java
public WindowManager getWindowManager() {
return mWindowManager;
}
//frameworks/base/core/java/android/app/Activity.java
final void attach(...) {
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
mWindowManager = mWindow.getWindowManager();
...
}
//frameworks/base/core/java/android/view/Window.java
public WindowManager getWindowManager() {
return mWindowManager;
}
//frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
...
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
//frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
}
2.2 WindowManagerGlobal.addView
- view重复性判定,不允许view重复添加
- 创建ViewRootImpl对象
- 更新mViews/mRoots/mParams数组
在WindowManagerGlobal中有三个数组非常重要。mViews/mRoots/mParams分别保存View、ViewRootImpl、LayoutParams,相同下标的View、ViewRootImpl、LayoutParams对象是一一对应关系
//frameworks/base/core/java/android/view/WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
//调用WindowManagerGlobal的addView函数。mContext.getDisplayNoVerify()会创建一个默认的Display作为形参传入
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
//参数合法性判断
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
//在mViews列表中查找当前view,如果找到则返回view对应下标
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
...
} else {//view不允许重复添加,抛异常中断addview流程
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
}
...
IWindowSession windowlessSession = null;
...
if (windowlessSession == null) {
//创建ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
} else {
...
}
view.setLayoutParams(wparams);
//更新数组。mViews/mRoots/mParams分别保存View、ViewRootImpl、LayoutParams,相同下标的View、ViewRootImpl、LayoutParams对象是一一对应关系
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
//调用ViewRootImpl的setView函数
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
...
}
}
}
2.3 ViewRootImpl.setView
- 调用requestLayout函数触发重新布局
- 初始化inputChannel,保证view可以收到input事件
- 调用Session的addToDisplayAsUser函数继续窗口添加流程
//frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
...
//把当前view加入到FallbackEventHandler中。FallbackEventHandler Android 系统中一个用于处理未消费的输入事件的备用机制。它主要用于处理那些没有被应用程序的视图层次结构(View Hierarchy)消费的事件。
mFallbackEventHandler.setView(view);
//把attrs赋值给mWindowAttributes
mWindowAttributes.copyFrom(attrs);
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
//把mWindowAttributes赋值给attrs
attrs = mWindowAttributes;
...
//触发重新布局
requestLayout();
//初始化inputChannel,保证view可以收到input事件
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
...
try {
...
//mWindow是IWindow类型的匿名Binder服务,用来让WMS主动和当前窗口通信用的
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
mTempControls, attachedFrame, compatScale);
...
}
...
}
}
}
这里介绍下mWindowSession和mWindow的创建过程
mWindowSession的创建过程:通过WMS的openSession函数new了一个Session对象。每个应用程序进程通过 Session 与 WMS 通信
//frameworks/base/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
}
//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
...
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
//frameworks/base/services/core/java/com/android/internal/wm/WindowManagerService.java
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
mWindow的创建过程:new了一个W对象。mWindow是客户端提供的一个匿名binder,用于WMS和客户端通信
//frameworks/base/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
WindowLayout windowLayout) {
...
mWindow = new W(this);
...
}
//frameworks/base/core/java/android/view/ViewRootImpl.java
static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
...
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
}
2.4 ViewRootImpl.requestLayout
- 检查是否是主线程,只有主线程可以出发requestLayout
- 向Choreographer添加一个Choreographer.CALLBACK_TRAVERSAL类型的回调,当Choreographer收到Vsync信号时,会触发该回调,从而触发mTraversalRunnable线程开始运行
具体流程后续会有专门的文章介绍...
//frameworks/base/core/java/android/view/ViewRootImpl.java
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查线程合法性,判断当前线程是否是创建view的线程即是否是主线程
checkThread();
mLayoutRequested = true;
//触发遍历view树
scheduleTraversals();
}
}
//frameworks/base/core/java/android/view/ViewRootImpl.java
void scheduleTraversals() {
...
if (!mTraversalScheduled) {
mTraversalScheduled = true;
...
//在MessageQueue中插入一个同步屏障,确保Choreographer的vsync信号优先处理。同步屏障会阻塞MessageQueue中的普通消息的的处理,但允许异步消息继续执行
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
...
//通过Choreographer将UI刷新任务和系统的Vsync信号同步,确保UI更新的流畅性和一致性。当Choreographer收到Vsync信号时,会触发CALLBACK_TRAVERSAL回调,启动mTraversalRunnable线程
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
//通知Renderthread Vsync信号即将到来
notifyRendererOfFramePending();
...
}
}
2.5 WindowManagerService.addWindow
- 获取客户端对应的WindowToken
- 创建WindowState对象
- 把新添加的窗口对应的WindowState加入到Session的mAddedWindows数组中
- 把客户端对应的binder和对应的WindowState作为键值对加入到mWindowMap数组中
- 窗口挂载。把WindowState加入到WindowToken中,其实是加入到WindowToken的父类WindowContainer的mChildren中
//frameworks/base/services/core/java/com/android/internal/wm/Session.java
public int addToDisplayAsUser(...) {
return mService.addWindow(...);
}
//frameworks/base/services/core/java/com/android/internal/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
float[] outSizeCompatScale) {
...
synchronized (mGlobalLock) {
if (!mDisplayReady) {//Display没有初始化好,抛异常中断流程
throw new IllegalStateException("Display has not been initialialized");
}
if (session.isClientDead()) {//客户端死亡,例如应用crash了,抛异常中断流程
...
return WindowManagerGlobal.ADD_APP_EXITING;
}
//先获取windowToken对应的DisplayContent,如果获取不到则根据displayId获取对应的DisplayContent
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
...
//限制子窗口必须依赖于父窗口且父窗口不能是子窗口类型
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
...
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
...
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
...
//获取客户端对应的WindowToken。每一个Activity都是一个WindowToken,一个Activity对应一个ActivityRecord,ActivityRecord继承WindowToken
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
//获取Window类型
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
...
if (token == null) {
...
} else if (rootType >= FIRST_APPLICATION_WINDOW
&& rootType <= LAST_APPLICATION_WINDOW) {//应用类型窗口,做合法性检查
activity = token.asActivityRecord();
if (activity == null) {//Activity不存在
...
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
} else if (activity.getParent() == null) {//Activity依附的Application不存在
...
return WindowManagerGlobal.ADD_APP_EXITING;
} else if (type == TYPE_APPLICATION_STARTING) {//startingWindow
...
}
...
} else if (token.asActivityRecord() != null) {
...
}
...
//创建WindowState对象,一个Window对应一个WindowState。this表示WMS本身;session表示WMS提供给窗口使用的IWindowSession;client表示IWindow
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
//获取DisplayContent对应的窗口策略类DisplayPolicy
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
//通过DisplayPolicy调整窗口属性
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
...
//添加窗口权限检查,主要是对系统窗口添加的检查,应用窗口谁都可以添加
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
...
//把新添加的窗口对应的WindowState加入到Session的mAddedWindows数组中
win.mSession.onWindowAdded(win);
//把客户端对应的binder和对应的WindowState作为键值对加入到mWindowMap数组中
mWindowMap.put(client.asBinder(), win);
...
//窗口挂载。把WindowState加入到WindowToken中,其实是加入到WindowToken的父类WindowContainer的mChildren中
win.mToken.addWindow(win);
displayPolicy.addWindowLw(win, attrs);
...
}
...
}
三:总结
3.1 应用程序通过Session请求WMS添加窗口,并创建匿名binder W,供WMS和自己通信
3.2 addWindow其实主要就做了两件事:获取客户端对应的WindowToken;创建WindowState
并挂载到窗口视图树中