Android P WMS简介
Android P WMS初始化过程
Android P WMS addwindow流程
Android P WMS removewindow流程
Android P WMS relayoutWindow流程
Android P WMS windowanimator
Android P WMS Surface
Android P WMS 问题种类和debug分析技巧
Android P WMS View System 简介
我们在WMS addWindow添加打印堆栈log
-
//在WMS添加如下堆栈
-
@WindowManagerService.
java
-
public
int
addWindow
(Session session, IWindow client, int seq,
-
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
-
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
-
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
-
-
new Exception(
"William WindowManagerService stack").printStackTrace();
//add log
然后在launcher点击启动settings,log如下。第一次在启动splash screen时执行addWindow,来至于SplashScreenStartingData.createStartingSurface,第二次是启动settings主界面 com.android.settings/com.android.settings.Settings。这一部分可以参考:
Android悬浮窗TYPE_TOAST小结: 源码分析
Android解析WindowManager(三)Window的添加过程
-
-
//发现启动settings时,会先启动Splash Screen(启动画面也叫欢迎页)
-
1077 1148 W System.err: java.lang.Exception: William WindowManagerService stack
-
1077 1148 W System.err: at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java:1157)
-
1077 1148 W System.err: at com.android.server.wm.Session.addToDisplay(Session.java:205)
-
1077 1148 W System.err: at android.view.ViewRootImpl.setView(ViewRootImpl.java:771)
-
1077 1148 W System.err: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
-
1077 1148 W System.err: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
-
1077 1148 W System.err: at com.android.server.policy.PhoneWindowManager.addSplashScreen(PhoneWindowManager.java:3214)
-
1077 1148 W System.err: at com.android.server.wm.SplashScreenStartingData.createStartingSurface(SplashScreenStartingData.java:56)
-
1077 1148 W System.err: at com.android.server.wm.AppWindowContainerController$1.run(AppWindowContainerController.java:170)
-
1077 1148 W System.err: at android.os.Handler.handleCallback(Handler.java:
873)
-
1077
1148 W System.err:
at android.os.Handler.dispatchMessage(Handler.java:
99)
-
1077
1148 W System.err:
at android.os.Looper.loop(Looper.java:
193)
-
1077
1148 W System.err:
at android.os.HandlerThread.run(HandlerThread.java:
65)
-
1077
1148 W System.err:
at com.android.server.ServiceThread.run(ServiceThread.java:
44)
-
1077
1148 V WindowManager: Window Window{e56651a u0 Splash Screen com.android.settings}
client=android.view.ViewRootImpl$W@f2667c5 token=AppWindowToken{
4be29e3 token=Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}} (Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}) params={(
0,
0)(fillxfill) ty=APPLICATION_STARTING wanim=
0x10302f8
-
1077
1148 V WindowManager: Attaching Window{e56651a u0 Splash Screen com.android.settings} token=AppWindowToken{
4be29e3 token=Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}}
-
1077
1148 V WindowManager: addWindow:
New
client android.view.ViewRootImpl$W@f2667c5: window=Window{e56651a u0 Splash Screen com.android.settings} Callers=com.android.server.wm.Session.addToDisplay:
205 android.view.ViewRootImpl.setView:
771 android.view.WindowManagerGlobal.addView:
356 android.view.WindowManagerImpl.addView:
93 com.android.server.policy.PhoneWindowManager.addSplashScreen:
3214
-
-
-
//然后才
add
settings window(com.android.settings/com.android.settings.Settings)
-
1077
1236 W System.err: java.lang.Exception: William WindowManagerService stack
-
1077
1236 W System.err:
at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java:
1157)
-
1077
1236 W System.err:
at com.android.server.wm.Session.addToDisplay(Session.java:
205)
-
1077
1236 W System.err:
at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:
129)
-
1077
1236 W System.err:
at com.android.server.wm.Session.onTransact(Session.java:
164)
-
1077
1236 V WindowManager: Window Window{c70e488 u0 com.android.settings/com.android.settings.Settings}
client=android.os.BinderProxy@d12a82b token=AppWindowToken{
4be29e3 token=Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}} (Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}) params={(
0,
0)(fillxfill) sim={forwardNavigation} ty=BASE_APPLICATION wanim=
0x10302f8
-
1077
1236 V WindowManager: Attaching Window{c70e488 u0 com.android.settings/com.android.settings.Settings} token=AppWindowToken{
4be29e3 token=Token{afc8e12 ActivityRecord{f88399d u0 com.android.settings/.Settings t7}}}
-
1077
1236 V WindowManager:
First window added
to
Session{d84ba9c
3168:
1000}, creating SurfaceSession
-
1077
1236 V WindowManager: addWindow:
New
client android.os.BinderProxy@d12a82b: window=Window{c70e488 u0 com.android.settings/com.android.settings.Settings} Callers=com.android.server.wm.Session.addToDisplay:
205 android.view.IWindowSession$Stub.onTransact:
129 com.android.server.wm.Session.onTransact:
164 android.os.Binder.execTransact:
731
of
call stack>
Android解析WindowManager(三)Window的添加过程
1.0 概述
WindowManager对Window进行管理,说到管理那就离不开对Window的添加、更新和删除的操作,在这里我们把它们统称为Window的操作。对于Window的操作,最终都是交由WMS来进行处理。窗口的操作分为两大部分,一部分是WindowManager处理部分,另一部分是WMS处理部分。我们知道Window分为三大类,分别是:Application Window(应用程序窗口)、Sub Windwow(子窗口)和System Window(系统窗口),对于不同类型的窗口添加过程会有所不同,但是对于WMS处理部分,添加的过程基本上是一样的, WMS对于这三大类的窗口基本是“一视同仁”的。
1.1 Activity的添加过程
-
@frameworks/base/core/java/android/app/ActivityThread.
java
-
final
void
handleResumeActivity
(IBinder token,
-
boolean clearHide,
boolean isForward,
boolean reallyResume,
int seq, String reason) {
-
...
-
r = performResumeActivity(token, clearHide, reason);
//1
-
...
-
if (r.window ==
null && !a.mFinished && willBeVisible) {
-
r.window = r.activity.getWindow();
-
View decor = r.window.getDecorView();
-
decor.setVisibility(View.INVISIBLE);
-
ViewManager wm = a.getWindowManager();
//2
-
WindowManager.LayoutParams l = r.window.getAttributes();
-
a.mDecor = decor;
-
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
l.softInputMode |= forwardBit;
-
if (r.mPreserveWindow) {
-
a.mWindowAdded =
true;
-
r.mPreserveWindow =
false;
-
ViewRootImpl impl = decor.getViewRootImpl();
-
if (impl !=
null) {
-
impl.notifyChildRebuilt();
-
}
-
}
-
if (a.mVisibleFromClient && !a.mWindowAdded) {
-
a.mWindowAdded =
true;
-
wm.addView(decor, l);
//3
-
}
-
-
}
注释1处的performResumeActivity方法最终会调用Activity的onResume方法。在注释2处得到ViewManager类型的wm对象,
在注释3处调用了wm的addView方法,而addView方法的实现则是在WindowManagerImpl中,此后的过程在上面的系统窗口的添加过程已经讲过,
唯一需要注意的是addView的第一个参数是DecorView。
1.2 系统窗口的添加过程
三大类窗口的添加过程会有所不同,这里以系统窗口StatusBar为例,StatusBar是SystemUI的重要组成部分,具体就是指系统状态栏,用于显示时间、电量和信号等信息。我们来查看StatusBar的实现类PhoneStatusBar的addStatusBarWindow方法,这个方法负责为StatusBar添加Window,如下所示。
-
@/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.
java
-
private
void
addStatusBarWindow
() {
-
makeStatusBarView();
-
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
-
mRemoteInputController =
new RemoteInputController(mHeadsUpManager);
-
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
-
}
-
-
@/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.
java
-
public
void
add
(View statusBarView, int barHeight) {
-
-
// Now that the status bar window encompasses the sliding panel and its
-
// translucent backdrop, the entire thing is made TRANSLUCENT and is
-
// hardware-accelerated.
-
mLp =
new WindowManager.LayoutParams(
-
ViewGroup.LayoutParams.MATCH_PARENT,
-
barHeight,
-
WindowManager.LayoutParams.TYPE_STATUS_BAR,
-
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-
PixelFormat.TRANSLUCENT);
-
mLp.token =
new Binder();
-
mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-
mLp.gravity = Gravity.TOP;
-
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-
mLp.setTitle(
"StatusBar");
-
mLp.packageName = mContext.getPackageName();
-
mStatusBarView = statusBarView;
-
mBarHeight = barHeight;
-
mWindowManager.addView(mStatusBarView, mLp);
//mWindowManager
-
mLpChanged =
new WindowManager.LayoutParams();
-
mLpChanged.copyFrom(mLp);
-
}
-
-
//WindowManager继承ViewManager,因此还是在ViewManager
-
@frameworks/base/core/java/android/view/WindowManager.java
-
/**
-
* The interface that apps use to talk to the window manager.
-
*
-
@SystemService(Context.WINDOW_SERVICE)
-
public interface WindowManager extends ViewManager {
-
-
-
//包括addview update remove
-
@/frameworks/base/core/java/android/view/ViewManager.java
-
public interface ViewManager
-
public void addView(View view, ViewGroup.LayoutParams params);
-
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
-
public void removeView(View view);
-
}
-
-
-
//WindowManagerImpl具体实现addView
-
public final class WindowManagerImpl implements WindowManager {
-
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
-
@Override
-
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
-
applyDefaultToken(params);
-
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
-
}
-
-
@frameworks/base/core/java/android/view/WindowManagerGlobal.java
-
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) {
-
...
-
}
-
}
-
-
/**
-
* We have one child
-
*/
-
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
-
synchronized (
this) {
-
try {
-
mOrigWindowType = mWindowAttributes.type;
-
mAttachInfo.mRecomputeGlobalAttributes =
true;
-
collectViewAttributes();
-
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
-
getHostVisibility(), mDisplay.getDisplayId(),
-
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
-
mAttachInfo.mOutsets, mInputChannel);
-
}
-
}
-
-
@/frameworks/base/services/core/java/com/android/server/wm/Session.
java
-
public
int
addToDisplay
(IWindow window, int seq, WindowManager.LayoutParams attrs,
-
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
-
Rect outOutsets, InputChannel outInputChannel) {
-
return mService.addWindow(
this, window, seq, attrs, viewVisibility, displayId,
//就调用到了wms::addWindow
-
outContentInsets, outStableInsets, outOutsets, outInputChannel);
-
}
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
-
public int addWindow(Session session, IWindow client, int seq,
-
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
-
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
-
InputChannel outInputChannel) {
-
-
int[] appOp =
new
int[
1];
-
int res = mPolicy.checkAddPermission(attrs, appOp);
//1
-
if (res != WindowManagerGlobal.ADD_OKAY) {
-
return res;
-
}
-
...
-
synchronized(mWindowMap) {
-
if (!mDisplayReady) {
-
throw
new IllegalStateException(
"Display has not been initialialized");
-
}
-
final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
//2
-
if (displayContent ==
null) {
-
Slog.w(TAG_WM,
"Attempted to add window to a display that does not exist: "
-
+ displayId +
". Aborting.");
-
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
-
}
-
...
-
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
//3
-
parentWindow = windowForClientLocked(
null, attrs.token,
false);
//4
-
if (parentWindow ==
null) {
-
Slog.w(TAG_WM,
"Attempted to add window with token that is not a window: "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
-
}
-
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
-
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
-
Slog.w(TAG_WM,
"Attempted to add window with token that is a sub-window: "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
-
}
-
}
-
...
-
}
-
...
-
}
WMS的addWindow返回的是addWindow的各种状态,比如添加Window成功,无效的display等等,这些状态被定义在WindowManagerGlobal中。
注释1处根据Window的属性,调用WMP的checkAddPermission方法来检查权限,具体的实现在PhoneWindowManager的checkAddPermission方法中,如果没有权限则不会执行后续的代码逻辑。注释2处通过displayId来获得窗口要添加到哪个DisplayContent上,如果没有找到DisplayContent,则返回WindowManagerGlobal.ADD_INVALID_DISPLAY这一状态,其中DisplayContent用来描述一块屏幕。注释3处,type代表一个窗口的类型,它的数值介于FIRST_SUB_WINDOW和LAST_SUB_WINDOW之间(1000~1999),这个数值定义在WindowManager中,说明这个窗口是一个子窗口,不了解窗口类型取值范围的请阅读Android解析WindowManager(二)Window的属性这篇文章。注释4处,attrs.token是IBinder类型的对象,windowForClientLocked方法内部会根据attrs.token作为key值从mWindowMap中得到该子窗口的父窗口。接着对父窗口进行判断,如果父窗口为null或者type的取值范围不正确则会返回错误的状态。
-
...
-
AppWindowToken atoken =
null;
-
final boolean hasParent = parentWindow !=
null;
-
WindowToken token = displayContent.getWindowToken(
-
hasParent ? parentWindow.mAttrs.token : attrs.token);
//1
-
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
//2
-
boolean addToastWindowRequiresToken =
false;
-
-
if (token ==
null) {
-
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
-
Slog.w(TAG_WM,
"Attempted to add application window with unknown token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
if (rootType == TYPE_INPUT_METHOD) {
-
Slog.w(TAG_WM,
"Attempted to add input method window with unknown token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
if (rootType == TYPE_VOICE_INTERACTION) {
-
Slog.w(TAG_WM,
"Attempted to add voice interaction window with unknown token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
if (rootType == TYPE_WALLPAPER) {
-
Slog.w(TAG_WM,
"Attempted to add wallpaper window with unknown token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
...
-
if (type == TYPE_TOAST) {
-
// Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
-
if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
-
parentWindow)) {
-
Slog.w(TAG_WM,
"Attempted to add a toast window with unknown token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
}
-
final IBinder binder = attrs.token !=
null ? attrs.token : client.asBinder();
-
token = new WindowToken(
this, binder, type,
false, displayContent,
-
session.mCanAddInternalSystemWindow);
//3
-
}
else
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
//4
-
atoken = token.asAppWindowToken();
//5
-
if (atoken ==
null) {
-
Slog.w(TAG_WM,
"Attempted to add window with non-application token "
-
+ token +
". Aborting.");
-
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
-
}
else
if (atoken.removed) {
-
Slog.w(TAG_WM,
"Attempted to add window with exiting application token "
-
+ token +
". Aborting.");
-
return WindowManagerGlobal.ADD_APP_EXITING;
-
}
-
}
else
if (rootType == TYPE_INPUT_METHOD) {
-
if (token.windowType != TYPE_INPUT_METHOD) {
-
Slog.w(TAG_WM,
"Attempted to add input method window with bad token "
-
+ attrs.token +
". Aborting.");
-
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-
}
-
}
-
...
addWindow方法总结
addWindow方法分了3个部分来进行讲解,主要就是做了下面4件事:
1. 对所要添加的窗口进行检查,如果窗口不满足一些条件,就不会再执行下面的代码逻辑。
2. WindowToken相关的处理,比如有的窗口类型需要提供WindowToken,没有提供的话就不会执行下面的代码逻辑,有的窗口类型则需要由WMS隐式创建WindowToken。
3. WindowState的创建和相关处理,将WindowToken和WindowState相关联。
4. 创建和配置DisplayContent,完成窗口添加到系统前的准备工作。
参考链接:
Android悬浮窗TYPE_TOAST小结: 源码分析
Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程
Android解析WindowManager系列
http://androidxref.com/9.0.0_r3/
《深入理解Android:卷III》