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 简介

 

1.APP启动addWindow过程

我们在WMS addWindow添加打印堆栈log

             
  1. //在WMS添加如下堆栈
  2. @WindowManagerService. java
  3. public int addWindow (Session session, IWindow client, int seq,
  4. LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
  5. Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
  6. DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
  7. 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的添加过程

             
  1. //发现启动settings时,会先启动Splash Screen(启动画面也叫欢迎页)
  2. 1077 1148 W System.err: java.lang.Exception: William WindowManagerService stack
  3. 1077 1148 W System.err: at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java:1157)
  4. 1077 1148 W System.err: at com.android.server.wm.Session.addToDisplay(Session.java:205)
  5. 1077 1148 W System.err: at android.view.ViewRootImpl.setView(ViewRootImpl.java:771)
  6. 1077 1148 W System.err: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
  7. 1077 1148 W System.err: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
  8. 1077 1148 W System.err: at com.android.server.policy.PhoneWindowManager.addSplashScreen(PhoneWindowManager.java:3214)
  9. 1077 1148 W System.err: at com.android.server.wm.SplashScreenStartingData.createStartingSurface(SplashScreenStartingData.java:56)
  10. 1077 1148 W System.err: at com.android.server.wm.AppWindowContainerController$1.run(AppWindowContainerController.java:170)
  11. 1077 1148 W System.err: at android.os.Handler.handleCallback(Handler.java: 873)
  12. 1077 1148 W System.err: at android.os.Handler.dispatchMessage(Handler.java: 99)
  13. 1077 1148 W System.err: at android.os.Looper.loop(Looper.java: 193)
  14. 1077 1148 W System.err: at android.os.HandlerThread.run(HandlerThread.java: 65)
  15. 1077 1148 W System.err: at com.android.server.ServiceThread.run(ServiceThread.java: 44)
  16. 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
  17. 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}}}
  18. 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
  19. //然后才 add settings window(com.android.settings/com.android.settings.Settings)
  20. 1077 1236 W System.err: java.lang.Exception: William WindowManagerService stack
  21. 1077 1236 W System.err: at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java: 1157)
  22. 1077 1236 W System.err: at com.android.server.wm.Session.addToDisplay(Session.java: 205)
  23. 1077 1236 W System.err: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java: 129)
  24. 1077 1236 W System.err: at com.android.server.wm.Session.onTransact(Session.java: 164)
  25. 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
  26. 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}}}
  27. 1077 1236 V WindowManager: First window added to Session{d84ba9c 3168: 1000}, creating SurfaceSession
  28. 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对于这三大类的窗口基本是“一视同仁”的。

Android P WMS addwindow流程_第1张图片

 

1.1 Activity的添加过程

             
  1. @frameworks/base/core/java/android/app/ActivityThread. java
  2. final void handleResumeActivity (IBinder token,
  3. boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
  4. ...
  5. r = performResumeActivity(token, clearHide, reason); //1
  6. ...
  7. if (r.window == null && !a.mFinished && willBeVisible) {
  8. r.window = r.activity.getWindow();
  9. View decor = r.window.getDecorView();
  10. decor.setVisibility(View.INVISIBLE);
  11. ViewManager wm = a.getWindowManager(); //2
  12. WindowManager.LayoutParams l = r.window.getAttributes();
  13. a.mDecor = decor;
  14. l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
  15. l.softInputMode |= forwardBit;
  16. if (r.mPreserveWindow) {
  17. a.mWindowAdded = true;
  18. r.mPreserveWindow = false;
  19. ViewRootImpl impl = decor.getViewRootImpl();
  20. if (impl != null) {
  21. impl.notifyChildRebuilt();
  22. }
  23. }
  24. if (a.mVisibleFromClient && !a.mWindowAdded) {
  25. a.mWindowAdded = true;
  26. wm.addView(decor, l); //3
  27. }
  28. }

注释1处的performResumeActivity方法最终会调用Activity的onResume方法。在注释2处得到ViewManager类型的wm对象,
在注释3处调用了wm的addView方法,而addView方法的实现则是在WindowManagerImpl中,此后的过程在上面的系统窗口的添加过程已经讲过,
唯一需要注意的是addView的第一个参数是DecorView。

1.2 系统窗口的添加过程

三大类窗口的添加过程会有所不同,这里以系统窗口StatusBar为例,StatusBar是SystemUI的重要组成部分,具体就是指系统状态栏,用于显示时间、电量和信号等信息。我们来查看StatusBar的实现类PhoneStatusBar的addStatusBarWindow方法,这个方法负责为StatusBar添加Window,如下所示。

             
  1. @/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar. java
  2. private void addStatusBarWindow () {
  3. makeStatusBarView();
  4. mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
  5. mRemoteInputController = new RemoteInputController(mHeadsUpManager);
  6. mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
  7. }
  8. @/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager. java
  9. public void add (View statusBarView, int barHeight) {
  10. // Now that the status bar window encompasses the sliding panel and its
  11. // translucent backdrop, the entire thing is made TRANSLUCENT and is
  12. // hardware-accelerated.
  13. mLp = new WindowManager.LayoutParams(
  14. ViewGroup.LayoutParams.MATCH_PARENT,
  15. barHeight,
  16. WindowManager.LayoutParams.TYPE_STATUS_BAR,
  17. WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  18. | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
  19. | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
  20. | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
  21. | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
  22. PixelFormat.TRANSLUCENT);
  23. mLp.token = new Binder();
  24. mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
  25. mLp.gravity = Gravity.TOP;
  26. mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
  27. mLp.setTitle( "StatusBar");
  28. mLp.packageName = mContext.getPackageName();
  29. mStatusBarView = statusBarView;
  30. mBarHeight = barHeight;
  31. mWindowManager.addView(mStatusBarView, mLp); //mWindowManager
  32. mLpChanged = new WindowManager.LayoutParams();
  33. mLpChanged.copyFrom(mLp);
  34. }
  35. //WindowManager继承ViewManager,因此还是在ViewManager
  36. @frameworks/base/core/java/android/view/WindowManager.java
  37. /**
  38. * The interface that apps use to talk to the window manager.
  39. *

  40. @SystemService(Context.WINDOW_SERVICE)
  41. public interface WindowManager extends ViewManager {
  42. //包括addview update remove
  43. @/frameworks/base/core/java/android/view/ViewManager.java
  44. public interface ViewManager
  45. public void addView(View view, ViewGroup.LayoutParams params);
  46. public void updateViewLayout(View view, ViewGroup.LayoutParams params);
  47. public void removeView(View view);
  48. }
  49. //WindowManagerImpl具体实现addView
  50. public final class WindowManagerImpl implements WindowManager {
  51. private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
  52. @Override
  53. public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
  54. applyDefaultToken(params);
  55. mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
  56. }
  57. @frameworks/base/core/java/android/view/WindowManagerGlobal.java
  58. public void addView(View view, ViewGroup.LayoutParams params,
  59. Display display, Window parentWindow) {
  60. ...//参数检查
  61. final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
  62. if (parentWindow != null) {
  63. parentWindow.adjustLayoutParamsForSubWindow(wparams);//1
  64. } else {
  65. ...
  66. }
  67. ViewRootImpl root;
  68. View panelParentView = null;
  69. ...
  70. root = new ViewRootImpl(view.getContext(), display);//2
  71. view.setLayoutParams(wparams);
  72. mViews.add(view);
  73. mRoots.add(root);//3
  74. mParams.add(wparams);
  75. }
  76. try {
  77. root.setView(view, wparams, panelParentView);//4
  78. } catch (RuntimeException e) {
  79. ...
  80. }
  81. }
  82. /**
  83. * We have one child
  84. */
  85. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  86. synchronized ( this) {
  87. try {
  88. mOrigWindowType = mWindowAttributes.type;
  89. mAttachInfo.mRecomputeGlobalAttributes = true;
  90. collectViewAttributes();
  91. res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
  92. getHostVisibility(), mDisplay.getDisplayId(),
  93. mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
  94. mAttachInfo.mOutsets, mInputChannel);
  95. }
  96. }
  97. @/frameworks/base/services/core/java/com/android/server/wm/Session. java
  98. public int addToDisplay (IWindow window, int seq, WindowManager.LayoutParams attrs,
  99. int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
  100. Rect outOutsets, InputChannel outInputChannel) {
  101. return mService.addWindow( this, window, seq, attrs, viewVisibility, displayId, //就调用到了wms::addWindow
  102. outContentInsets, outStableInsets, outOutsets, outInputChannel);
  103. }

 

2.Window的添加过程(WMS部分)

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

             
  1. public int addWindow(Session session, IWindow client, int seq,
  2. WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
  3. Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
  4. InputChannel outInputChannel) {
  5. int[] appOp = new int[ 1];
  6. int res = mPolicy.checkAddPermission(attrs, appOp); //1
  7. if (res != WindowManagerGlobal.ADD_OKAY) {
  8. return res;
  9. }
  10. ...
  11. synchronized(mWindowMap) {
  12. if (!mDisplayReady) {
  13. throw new IllegalStateException( "Display has not been initialialized");
  14. }
  15. final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId); //2
  16. if (displayContent == null) {
  17. Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
  18. + displayId + ". Aborting.");
  19. return WindowManagerGlobal.ADD_INVALID_DISPLAY;
  20. }
  21. ...
  22. if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { //3
  23. parentWindow = windowForClientLocked( null, attrs.token, false); //4
  24. if (parentWindow == null) {
  25. Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
  26. + attrs.token + ". Aborting.");
  27. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  28. }
  29. if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
  30. && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
  31. Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
  32. + attrs.token + ". Aborting.");
  33. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  34. }
  35. }
  36. ...
  37. }
  38. ...
  39. }

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的取值范围不正确则会返回错误的状态。
 

 

             
  1. ...
  2. AppWindowToken atoken = null;
  3. final boolean hasParent = parentWindow != null;
  4. WindowToken token = displayContent.getWindowToken(
  5. hasParent ? parentWindow.mAttrs.token : attrs.token); //1
  6. final int rootType = hasParent ? parentWindow.mAttrs.type : type; //2
  7. boolean addToastWindowRequiresToken = false;
  8. if (token == null) {
  9. if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
  10. Slog.w(TAG_WM, "Attempted to add application window with unknown token "
  11. + attrs.token + ". Aborting.");
  12. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  13. }
  14. if (rootType == TYPE_INPUT_METHOD) {
  15. Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
  16. + attrs.token + ". Aborting.");
  17. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  18. }
  19. if (rootType == TYPE_VOICE_INTERACTION) {
  20. Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
  21. + attrs.token + ". Aborting.");
  22. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  23. }
  24. if (rootType == TYPE_WALLPAPER) {
  25. Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
  26. + attrs.token + ". Aborting.");
  27. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  28. }
  29. ...
  30. if (type == TYPE_TOAST) {
  31. // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
  32. if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
  33. parentWindow)) {
  34. Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
  35. + attrs.token + ". Aborting.");
  36. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  37. }
  38. }
  39. final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
  40. token = new WindowToken( this, binder, type, false, displayContent,
  41. session.mCanAddInternalSystemWindow); //3
  42. } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { //4
  43. atoken = token.asAppWindowToken(); //5
  44. if (atoken == null) {
  45. Slog.w(TAG_WM, "Attempted to add window with non-application token "
  46. + token + ". Aborting.");
  47. return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
  48. } else if (atoken.removed) {
  49. Slog.w(TAG_WM, "Attempted to add window with exiting application token "
  50. + token + ". Aborting.");
  51. return WindowManagerGlobal.ADD_APP_EXITING;
  52. }
  53. } else if (rootType == TYPE_INPUT_METHOD) {
  54. if (token.windowType != TYPE_INPUT_METHOD) {
  55. Slog.w(TAG_WM, "Attempted to add input method window with bad token "
  56. + attrs.token + ". Aborting.");
  57. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  58. }
  59. }
  60. ...

 

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》 

更多相关文章

  1. Glide使用方法汇总
  2. 【android】对canvas的translate(),save(),restore()方法的理解
  3. 让Activity变成一个窗口
  4. android粗略获得程序运行时间的方法
  5. TextView英文自动换行解决方法
  6. Android实现全屏的方法
  7. [android]布局(容器)简介和使用方法
  8. android 动态控制状态栏显示和隐藏的方法实例
  9. Android文件系统的结构及目录用途、操作方法 整理

随机推荐

  1. Android实战(四)------Myeclipse10搭建an
  2. Android(安卓)-移动数据开发
  3. 安卓工程师 人才缺口日益显现
  4. Android(安卓)上实现水波特效
  5. Android(安卓)Studio 的代码检查功能,使用
  6. Android+Jquery Mobile学习系列(1)-开发
  7. Android(安卓)Push Notification(Android
  8. Android(安卓)Animation总结
  9. Android(安卓)日历开发教程[七] 修正后代
  10. 浅谈Android多进程APP的优势