frameworks/base/core/java/android/view/ViewManager.java
属于一个接口类,实现了对view的更新,添加,移除,具体代码如下
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
可以看到接收的参数都是view,说明Window管理的都是view,WindowManager继承了该接口,注意是继承并不是实现,后续操作window都靠实现WM
frameworks/base/core/java/android/view/WindowManager.java
实现了ViewManager接口,因为WM本身就是一个接口类,所以并没有重写VM接口里面的方法,后续会通过getSystemService
拿到WM,强制至WindowManagerImpl,因为WMI实现了WM接口,然后在WMI中实现了addView的具体逻辑,可以看看WMI被创建的地方如下
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);//1
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);//2
}
frameworks/base/core/java/android/view/Window.java
Window是一个抽象类,它具体的实现类为PhoneWindow,Window中管理了view,例如我们常知的setContentView
,findViewById
,setTitle
,setBackgroundDrawable
等
一个activity对应了一个Window(也可以称之为PhoneWindow)
frameworks/base/core/java/android/app/Activity.java
一个Activity包含了一个Window(PhoneWindow),也包含了一个WMI,主要的方法是attach方法,就是window创建的开始处,也是activity启动流程的最后一步
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) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window);//1
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
PhoneWindow在Activity#attach中创建,一个activity对应一个PhoneWindow,它继承自抽象类Window,包含了DecorView,也重写了Window的setContentView
方法,当内部的mContentParent(类型是ViewGroup,layout文件中的根view,例如xml中是线性布局开头)
为空的时候,就会开始创建DecorView,然后开始解析activity,分为两部分,第一部分是title,第二部分是content,作为DecorView的内容,然后DecorView的content部分就是mContentParent
,目前还是个空壳,没有实际内容,还没有解析布局文件
frameworks/base/core/java/android/view/WindowManagerGlobal.java
属于一个单例模式,一个进程存在一个此对象,在WMI中的addView中会被调用,WMG中也有个addView,属于WMI中调用过来的,这里面的逻辑才是真正的处理view添加的逻辑,例如处理WindowManager.LayoutParams
,new ViewRootImpl()
,调用ViewRootImpl.setView,接着会调用IWindowSession向WMS中的Session发起窗口添加流程
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...//参数检查
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);//1
} else {
...
}
ViewRootImpl root;
View panelParentView = null;
...
root = new ViewRootImpl(view.getContext(), display);//2
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);//3
mParams.add(wparams);
}
try {
root.setView(view, wparams, panelParentView);//4
} catch (RuntimeException e) {
...
}
}
frameworks/base/core/java/android/view/WindowManagerImpl
在activity#attach中,调用了mWindow.setWindowManager中被创建,是通过getSystemService获取了WM,然后强转为WMI,调用WindowManagerImpl的createLocalWindowManager(this)
,来创建WMI实例,这个this就是activity的PhoneWindow(说Window也行),然后这个this就作为父window(主window)
WMI实现了WM接口,所以WMI调用了addView
,拥有具体实现,会继续调用WindowManagerGlobal进行处理,WMI拥有phonewindow的引用,后续将调用addView对PhoneWindow作为参数进行传递,然后将view绑定到这个PhoneWindow上
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
frameworks/base/service/core/java/com/android/server/wm/WindowState.java
先大概过一下总体逻辑(因为添加view都是通过WM.addView,所以我们目的是分析addView,晚点再分析setContentView):
PhoneWindow.setWindowManager(实际上是Window里面的方法)
,来创建了WindowManagerImpl并和mWindow(PhoneWindow)进行绑定,mWindow在WMI中属于parentWindowmWindowSession.addToDisplayAsUser
方法,mWindowSession是IWindowSession类型的,它是一个Binder对象,用于进行进程间通信,IWindowSession是Client端的代理,它的Server端的实现为Session,此前包含ViewRootImpl在内的代码逻辑都是运行在本地进程的,而Session的addToDisplay方法则运行在WMS所在的进程,每个应用程序进程都会对应一个Session,WMS会用ArrayList来保存这些SessionaddToDisplayAsUser
方法,是从viewRootImpl—>mWindowSession.addToDisplayAsUser跨进程过来的,session又继续调用了WMS的addWindow
方法,所以继续锁定WMS主要分析WMS的public int addWindow()
方法
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility...) {
...
// 父类window
WindowState parentWindow = null;
...
final int type = attrs.type;
synchronized (mGlobalLock) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
// 获取屏幕
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
// 检查屏幕的有效性
if (displayContent == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
+ "not exist: %d. Aborting.", displayId);
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (!displayContent.hasAccess(session.mUid)) {
ProtoLog.w(WM_ERROR,
"Attempted to add window to a display for which the application "
+ "does not have access: %d. Aborting.",
displayContent.getDisplayId());
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
// 检查Window是否以及存在(也就是WindowState),如果存在于集合中则代表重复添加
if (mWindowMap.containsKey(client.asBinder())) {
ProtoLog.w(WM_ERROR, "Window %s is already added", client);
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
// 1000~1999属于sub窗口类型,说明这个窗口是一个子窗口,所以需要找父类窗口
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
// 通过ViewRootImpl.W中的代理对象且从mWindowMap取出WindowState
// LayoutParams中保存了WindowState对应的IBinder代理
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
// 不能在子窗口中添加子窗口,因为父类也是子窗口
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
// 权限检查
if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
ProtoLog.w(WM_ERROR,
"Attempted to add private presentation window to a non-private display. "
+ "Aborting.");
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
}
if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) {
ProtoLog.w(WM_ERROR,
"Attempted to add presentation window to a non-suitable display. "
+ "Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
...
// 检查该window是否存在父类窗口,是否具有ActivityRecord
ActivityRecord activity = null;
final boolean hasParent = parentWindow != null;
// 获取token,有可能为空
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// 如果有父类,则获取父类的窗口type
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
**// 1~99属于应用程序窗口类型**
if (rootType >= FIRST_APPLICATION_WINDOW
&& rootType <= LAST_APPLICATION_WINDOW) {
// 判断当前窗口是否重复添加
...
**// 输入法窗口,也就是:FIRST_SYSTEM_WINDOW(2000)+11**
} else if (rootType == TYPE_INPUT_METHOD) {
// 检查窗口是否可以被添加
if (token.windowType != TYPE_INPUT_METHOD) {
ProtoLog.w(WM_ERROR, "Attempted to add input method window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
**// 壁纸窗口类型,FIRST_SYSTEM_WINDOW(2000)+13**
if (rootType == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_TOAST) { **// toast窗口类型:FIRST_SYSTEM_WINDOW(2000)+5**
// 检查窗口的有效性,是否可以被添加
...
if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
ProtoLog.w(WM_ERROR, "Attempted to add a toast window with bad token "
+ "%s. Aborting.", attrs.token);
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
...
// 创建WindowState对象,client(IBinder/IWindow)都可以代表WindowState对象
// 和父类window(也是WindowState),client,session,WMS,attrs进行绑定
// 它存有窗口的所有的状态信息,在WMS中它代表一个窗口,client就是代表了这个WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
...
// 如果WindowState->WindowToken中找不到屏幕,则直接返回无效屏幕的错误
if (win.getDisplayContent() == null) {
ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
// 调整Toast窗口超时时间等
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
...
...
// 处理Toast超时后隐藏窗口
if (type == TYPE_TOAST) {
if (!displayContent.canAddToastWindowForUid(callingUid)) {
ProtoLog.w(WM_ERROR, "Adding more than one toast window for UID at a time.");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
...
if (addToastWindowRequiresToken
|| (attrs.flags & FLAG_NOT_FOCUSABLE) == 0
|| displayContent.mCurrentFocus == null
|| displayContent.mCurrentFocus.mOwnerUid != callingUid) {
mH.sendMessageDelayed(
mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
win.mAttrs.hideTimeoutMilliseconds);
}
}
...
// WindowState 的绑定方法,实际上就是调用了 mSession.windowAddedLocked();
// 具体作用:创建SessionSurface,然后往WMS.mSessions集合中,把当前session添加到集合中
// 说明一个window对应了一个session,然后mNumWindow++,记录window的个数
win.attach();
// 将WindowState代理对象,保存到mWindowMap中
mWindowMap.put(client.asBinder(), win);
...
// 将当前WindowState添加到WindowToken中
win.mToken.addWindow(win);
// 针对当前window是否属于导航栏窗口还是状态栏窗口,进行处理
displayPolicy.addWindowLw(win, attrs);
...
return res;
}
总结一下以上内容:
mWindowMap
中,Key就是它的IBinder代理,value就是WindowState,可以通过这个Map集合检查窗口是否存在,是否重复添加继续分析一下WindowState
的构造方法
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();
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
mActivityRecord != null
? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
getDisplayId()));
...
// 如果当前window的类型为子窗口
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
// 获取基础layer
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
// 子窗口会依赖基础layer
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
// 父类是否是输入法窗口类型
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
// 父类是否是壁纸窗口类型
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
}
...
// 窗口动画
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mLayer = 0;
mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale(
mAttrs.packageName, s.mUid);
// 如果是子窗口类型,将当前WindowState添加到父类窗口中
if (mIsChildWindow) {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
}
}
以上内容就是将session,WMS,client,WindowToken,LayoutParams,以及父类WindowState进行绑定关联,client(IBinder/IWindow)都可以代表WindowState对象,然后判断当前窗口是否是子窗口,是否具有父类窗口,然后将当前窗口添加到父类窗口中:
parentWindow.addChild(this, sWindowSubLayerComparator);