• 【系统之音】Window篇(一)WindowManager工作机制详解


    前言

           转载请声明,转自【https://www.cnblogs.com/andy-songwei/p/9965714.html】,多谢!

           目光所及,皆有Window!Window,顾名思义,窗口,它是应用与用户交互的一个窗口,我们所见到视图,都对应着一个Window。比如屏幕上方的状态栏、下方的导航栏、按音量键调出来音量控制栏、充电时的充电界面、屏幕中间的应用显示区域(Activity)、Dialog、Toast、PopWindow、菜单等,都依附于对应的Window。可以认为Window是View的实际直接管理者,所以理解Window相关的知识,对理解Android的视图机制有很大的帮助。

          本文将介绍Window相关的基础知识,以及从源码的角度分析WindowManager是如何将View呈现在界面的。本文主要包含如下内容:

     

    一、一个悬浮按钮的demo

            本demo实现了在屏幕上显示一个悬浮的Button,并可以跟随手指的移动而移动。代码如下:

     1 public void drawFloatButton() {
     2     requestWindowPermission();
     3     final WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
     4     final Button button = new Button(this);
     5     button.setText("button");
     6     final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
     7             WindowManager.LayoutParams.WRAP_CONTENT,
     8             WindowManager.LayoutParams.WRAP_CONTENT,
     9             0,
    10             0,
    11             PixelFormat.TRANSPARENT);
    12     params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
    13             | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    14             | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
    15     params.gravity = Gravity.LEFT | Gravity.TOP;
    16     params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    17     params.x = 500;
    18     params.y = 500;
    19     windowManager.addView(button, params);
    20     button.setOnTouchListener(new View.OnTouchListener() {
    21         @Override
    22         public boolean onTouch(View v, MotionEvent event) {
    23             int rawX = (int) event.getRawX();
    24             int rawY = (int) event.getRawY();
    25             switch (event.getAction()) {
    26                 case MotionEvent.ACTION_MOVE:
    27                     params.x = rawX;
    28                     params.y = rawY;
    29                     windowManager.updateViewLayout(button, params);
    30                     break;
    31                 default:
    32                     break;
    33             }
    34             return false;
    35         }
    36     });
    37 }

    如果是在Android6.0及以上,需要处理权限问题,在AndroidManifest.xml中声明权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    并在代码中动态申请

     1 private void requestWindowPermission() {
     2         //android 6.0或者之后的版本需要发一个intent让用户授权
     3         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
     4             if (!Settings.canDrawOverlays(getApplicationContext())) {
     5                 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
     6                         Uri.parse("package:" + getPackageName()));
     7                 startActivityForResult(intent, 100);
     8             }
     9         }
    10     }

    由于该权限是一个敏感权限,所以启动时系统还会弹出一个界面让用户手动开启该权限:

     

    演示效果如下所示:

           该Button是个悬浮按钮,它并不是通过在xml布局文件中加入,然后通过Activity的setContentView方法将其显示在界面中的,而是通过第19行的WindowManager.addView方法实现的。gif中可以看到,该Button可以显示到Title区域,也可以在app退出后(不杀死进程)独立显示在桌面上。手指滑动过程中,通过第29行WindowManager.updateViewLayout更新Button的LayoutParams的坐标参数,不断更新该Button的位置。后续我们会对这两个方法做详细分析。

    二、Window相关特性

           通过上述的demo,我们可以看到设置了LayoutParams的flags、type变量值,它们都是用来定义Window的特性的。

      1、flag

          flag变量用于设置window的属性,控制其显示特性,比如设置为不获取焦点、不接受触屏事件、显示在锁屏之上等。在WindowManager.LayoutParams类中定义了很多的flag常量,来丰富Window的功能及属性。

      2、type

           type变量用于表示Window的类型。系统规定了Window有三种类型,按取值由小到大依次为:

        (1)应用Window:对应着一个Activity,要创建应用窗口就必须在Activity中完成。层级范围:1~99

        (2)子Window:不能独立存在,需要依附于特定的父Window。比如Dialog,PopWindow,菜单等。层级范围:1000~1999

        (3)系统Window:拥有系统权限才能创建的Window。比如Toast、系统状态栏、导航栏、手机低电量提示、输入法Window、搜索条、来电显示等。系统Window是独立于应用程序的,理论上讲应用程序没有权限创建系统Window,只有系统进程才有。层级范围:2000~2999

          type的值越大,在Window体系中显示的层级就越高。为了理解这一点,我们了解一下窗口的Z-Order管理。

          手机上采用的是层叠式的布局,它是一个三维空间,将手机水平方向作为X轴,竖直方向作为Y轴,垂直于屏幕由里向外的方向为Z轴,所有窗口就按照type值的顺序排列在Z轴上,type值越大Z值也就越大。如下图所示,所以系统Window往往会在上层显示:

    三、WindowManager关系网

      1、WindowManager在系统架构中的位置   

            这里咱们先通过系统架构图来直观看看WindowManager在系统架构中的位置:

    WindowManager在系统架构中的位置

           上图中红色边框的“Window Manager”和“Surface Manager”都和Window直接相关,“Surface Manager”不在本文的讨论范围内,这里只关注“Window Manager”,从上图可以看出,它位于Framework层。

      2、WindowManager实例的获取

           在前面的demo中的第三行,通过如下的方式来获取WindowManager实例:

           WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

           这种方式在获取系统服务的时候非常常见,所以这里顺便看看其代码实现:

     1 //=============Activity.java============
     2 private WindowManager mWindowManager;
     3 private Window mWindow;
     4 @Override
     5 public Object getSystemService(@ServiceName @NonNull String name) {
     6     if (getBaseContext() == null) {
     7         throw new IllegalStateException(
     8                 "System services not available to Activities before onCreate()");
     9     }
    10     if (WINDOW_SERVICE.equals(name)) {
    11         return mWindowManager;
    12     } else if (SEARCH_SERVICE.equals(name)) {
    13         ensureSearchManager();
    14         return mSearchManager;
    15     }
    16     return super.getSystemService(name);
    17 }
    18 
    19 final void attach(...){
    20     mWindowManager = mWindow.getWindowManager();
    21 }
    22 
    23 //==========Context.java==========
    24 public static final String WINDOW_SERVICE = "window";
    25 
    26 //===========Window.java==========
    27 private WindowManager mWindowManager;
    28 
    29 public WindowManager getWindowManager() {
    30     return mWindowManager;
    31 }
    32 
    33 public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
    34         boolean hardwareAccelerated) {
    35     ......
    36     mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    37 }
    38 
    39 public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    40     return new WindowManagerImpl(mContext, parentWindow);
    41 }

    理解上面的逻辑,需要先知道一个继承关系:Activity extends ContextThemeWrapper extends ContextWrapper extends Context。通过上述代码可以明确了,这里获得的WindowManager的实例,实际上是WindowManagerImpl实例。这种面向接口编程(在接口中定义方法,在实现类中实现)的方式很普遍,这里就不赘述了。

      3、WindowManager与ViewManager、WindowManager、WindowManagerImpl、WindowManagerGlobal之间的关系

           在分析源码前一定要捋清楚ViewManager、WindowManager、WindowManagerImpl、WindowManagerGlobal之间的关系。下面先把关键代码摆出来:

     1  public interface ViewManager
     2  {
     3      public void addView(View view, ViewGroup.LayoutParams params);
     4      public void updateViewLayout(View view, ViewGroup.LayoutParams params);
     5      public void removeView(View view);
     6  }
     7  
     8  public interface WindowManager extends ViewManager{
     9       ......
    10  }
    11  
    12  public final class WindowManagerImpl implements WindowManager {
    13      private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    14      @override
    15      public void addView(view,params){
    16          mGlobal.addView(...);
    17      }
    18      public void updateViewLayout(view,params){
    19          mGlobal.updateViewLayout(...);
    20      }
    21      public void remove(view){
    22          mGlobal.remove(...);
    23      }
    24  }
    25  
    26  public final class WindowManagerGlobal {
    27      public void addView(...){
    28          ......
    29      }
    30      public void updateViewLayout(...) {
    31          ......
    32      }
    33      public void removeView(...) {
    34          ......
    35      }
    36  }

           看到上述这段代码,相信你一定已经清楚了它们之间的关系了。ViewManager是个接口,其中定义了三个方法,在Window体系中添加、更新、移除View的过程看起来比较复杂,但其实都是围绕着这三个方法展开的。WindowManager是个接口,继承了ViewManager,扩展了功能。WindowManagerImpl是个实现类,其中包含了WindowManagerGlobal实例。WindowManagerGlobal则真正完成了addView、updateViewLayout、removeView过程。所以,在demo中我们在使用WindowManager的实例调用addView,updateViewLayout方法时,实际上都是WindowManagerGlobal来完成的。这种方式称为桥接模式,这在系统源码种很常见,Context机制中也是这种方式,桥接模式这里就不展开讲了。

        第13行中通过WindowManagerGlobal.getInstance()来获取的实例,这里看看其实现:

     1 //=========WindowManagerGlobal.java========
     2 private static WindowManagerGlobal sDefaultWindowManager;
     3 public static WindowManagerGlobal getInstance() {
     4     synchronized (WindowManagerGlobal.class) {
     5         if (sDefaultWindowManager == null) {
     6             sDefaultWindowManager = new WindowManagerGlobal();
     7         }
     8         return sDefaultWindowManager;
     9     }
    10 }

           可见,它是通过单例模式的方式对外提供的实例。如果对单例模式比较了解的话,就能看出这种实现方式是有问题的(对比DCL方式),但不明白系统源码为什么要这样实现,可能是系统中调用该实例方法的场景比较简单吧,咱们自己在设计单例模式的时候可不能这样做。

           在WindowMangerGlobal.java中维护着四个非常重要的list,这四个list在addView、updateViewLayout、removeView的过程中都会频频出现,理清楚这四个list和这三个方法,理解WindowManager工作机制时会清晰很多,它们在下面的源码中会详细讲到。

    1 //=========WindowManagerGlobal.java=========
    2 //所有Window对应的View
    3 private final ArrayList<View> mViews = new ArrayList<View>();
    4 //所有Window对应的ViewRootImpl
    5 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    6 //所有Window对应的LayoutParams
    7 private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>;
    8 //正在被删除的View,或者已经执行了removeView方法但还没有完成删除操作的View
    9 private final ArraySet<View> mDyingViews = new ArraySet<View>;

    四、addView机制
     1 //=========WindowManagerGlobal=========
     2 public void addView(View view, ViewGroup.LayoutParams params,
     3         Display display, Window parentWindow) {
     4    ......
     5     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
     6     ......
     7     ViewRootImpl root;
     8     View panelParentView = null;
     9     synchronized (mLock) {
    10        ......
    11          //view不能重复添加,如果要添加需要先removeView,否则抛异常
    12          int index = findViewLocked(view, false);
    13          if (index >= 0) {
    14              if (mDyingViews.contains(view)) {
    15                  // Don't wait for MSG_DIE to make it's way through root's queue.
    16                  mRoots.get(index).doDie();
    17              } else {
    18                  throw new IllegalStateException("View " + view
    19                          + " has already been added to the window manager.");
    20              }
    21              // The previous removeView() had not completed executing. Now it has.
    22          }
    23          //子window
    24          // If this is a panel window, then find the window it is being
    25          // attached to for future reference.
    26          if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
    27                  wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
    28              final int count = mViews.size();
    29              for (int i = 0; i < count; i++) {
    30                  if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
    31                      panelParentView = mViews.get(i);
    32                  }
    33              }
    34          }
    35          root = new ViewRootImpl(view.getContext(), display);
    36          view.setLayoutParams(wparams);
    37          mViews.add(view);
    38          mRoots.add(root);8
    39          mParams.add(wparams);
    40          // do this last because it fires off messages to start doing things
    41          try {
    42              root.setView(view, wparams, panelParentView);
    43          } catch (RuntimeException e) {
    44              // BadTokenException or InvalidDisplayException, clean up.
    45              if (index >= 0) {
    46                  removeViewLocked(index, true);
    47              }
    48              throw e;
    49          }
    50      }
    51  }

    上述代码中除了关键方法外,注意留意mViews、mRoots、mParams集合的操作。

     1 //=========ViewRootImpl.java========== 
     2 /**
     3 * We have one child
     4 */
     5 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     6    synchronized (this) {
     7        if (mView == null) {
     8            mView = view;
     9            ......
    10            mAdded = true;
    11             int res; /* = WindowManagerImpl.ADD_OKAY; */
    12             // Schedule the first layout -before- adding to the window
    13             // manager, to make sure we do the relayout before receiving
    14             // any other events from the system.
    15             requestLayout();
    16             ......
    17             try {
    18                 ......
    19                 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
    20                         getHostVisibility(), mDisplay.getDisplayId(),
    21                         mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
    22                         mAttachInfo.mOutsets, mInputChannel);
    23             } catch (RemoteException e) {
    24                 mAdded = false;
    25                 mView = null;
    26                 ......
    27                 throw new RuntimeException("Adding window failed", e);
    28             } finally {
    29                 ......
    30             }
    31             ......
    32         }
    33     }
    34 }

           第15行requestLayout()方法会执行View的绘制流程,在我之前的博文【朝花夕拾】Android自定义View篇之(一)View绘制流程中第三节有相关介绍。这里简单截取了一段UML图,读者明白其作用就可以了,想深入研究的可以去这篇文章看看。

     

     第19行的mWindowSession.addToDisplay(...)方法,addView的实际逻辑处理就在这里面。我们继续分析mWindowSession和addToDisplay(...)的逻辑:

     1 //========ViewRootImpl.java=========
     2 public final class ViewRootImpl{
     3     final IWindowSession mWindowSession;
     4     public ViewRootImpl(...){
     5         ......
     6         mWindowSession = WindowManagerGlobal.getWindowSession();
     7         ......
     8     }
     9 }
    10 
    11 //=======WindowManagerGlobal.java==========
    12 public static IWindowSession getWindowSession() {
    13     synchronized (WindowManagerGlobal.class) {
    14         if (sWindowSession == null) {
    15             try {
    16                 ......
    17                 IWindowManager windowManager = getWindowManagerService();
    18                 sWindowSession = windowManager.openSession(
    19                         new IWindowSessionCallback.Stub() {
    20                             @Override
    21                             public void onAnimatorScaleChanged(float scale) {
    22                                 ValueAnimator.setDurationScale(scale);
    23                             }
    24                         },
    25                         ......
    26             } catch (RemoteException e) {
    27                 throw e.rethrowFromSystemServer();
    28             }
    29         }
    30         return sWindowSession;
    31     }
    32 }
    33 
    34 public static IWindowManager getWindowManagerService() {
    35     synchronized (WindowManagerGlobal.class) {
    36         if (sWindowManagerService == null) {
    37             sWindowManagerService = IWindowManager.Stub.asInterface(
    38                     ServiceManager.getService("window"));
    39             ......
    40         }
    41         return sWindowManagerService;
    42     }
    43 }
    44 
    45 //============WindowManagerService.java=======
    46 @Override
    47 public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
    48         IInputContext inputContext) {
    49     if (client == null) throw new IllegalArgumentException("null client");
    50     if (inputContext == null) throw new IllegalArgumentException("null inputContext");
    51     Session session = new Session(this, callback, client, inputContext);
    52     return session;
    53 }
    54 
    55 public int addWindow(Session session, IWindow client, int seq,
    56             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
    57             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
    58             InputChannel outInputChannel) {
    59       //在wms中真正实现
    60       ......
    61 }
    62 
    63 //===========Session.java=========
    64 final WindowManagerService mService;
    65 public Session(WindowManagerService service, ......) {
    66       mService = service;
    67       ......
    68 }
    69 
    70 @Override
    71 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
    72         int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
    73         Rect outOutsets, InputChannel outInputChannel) {
    74     return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
    75             outContentInsets, outStableInsets, outOutsets, outInputChannel);
    76 }

    这里面的代码逻辑很容易理解,最后是把addView的工作交给了WMS的addWindow方法,所以真正添加view的逻辑是在WMS中完成的。这里面逻辑比较复杂繁琐,就不继续深入了,当目前为止就已经清楚整个流程了。

     五、updateViewLayout更新机制

     1 //============WindowManagerGlobal.java==========
     2 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
     3     ......
     4     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
     5     view.setLayoutParams(wparams);
     6     synchronized (mLock) {
     7         int index = findViewLocked(view, true);
     8         ViewRootImpl root = mRoots.get(index);
     9         mParams.remove(index);
    10         mParams.add(index, wparams);
    11         root.setLayoutParams(wparams, false);
    12      }
    13  }

    这里面对mParams进行了操作,将旧有的LayoutParams进行了替换。第11行执行了更新逻辑:

    1 //=============ViewRootImpl.java==========
    2  void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
    3       ...... //对新的LayoutParams参数做一些操作
    4       scheduleTraversals(); //调用绘制流程
    5  }

    从上述过程可以发现更新过程相对比较简单,更新view的过程简单来说就是,将新的LayoutParams替换掉旧的,并启用绘制流程。

    六、removeView移除机制

    1 //============WindowManagerImpl.java==========
    2  @Override
    3  public void removeView(View view) {
    4      mGlobal.removeView(view, false);
    5  }
    6  @Override
    7  public void removeViewImmediate(View view) {
    8      mGlobal.removeView(view, true);
    9 }

    WindowManagerImpl类中提供了两个方法用于移除view,从方法名称可以推测其差别在于Immediate,也就是是否立即移除的意思。

     1 //==========WindowManagerGlobal.java=========
     2 public void removeView(View view, boolean immediate) {
     3    ......
     4     synchronized (mLock) {
     5         int index = findViewLocked(view, true);
     6         View curView = mRoots.get(index).getView();
     7         removeViewLocked(index, immediate);
     8         ......
     9     }
    10 }
    11 
    12 private void removeViewLocked(int index, boolean immediate) {
    13     ViewRootImpl root = mRoots.get(index);
    14     View view = root.getView();
    15     ......
    16     boolean deferred = root.die(immediate);
    17     if (view != null) {
    18         view.assignParent(null);
    19         if (deferred) {
    20             mDyingViews.add(view);
    21         }
    22     }
    23 }
    24 
    25 //========ViewRootImpl.java=========
    26 private final static int MSG_DIE = 3;
    27 final ViewRootHandler mHandler = new ViewRootHandler();
    28 /**
    29  * @param immediate True, do now if not in traversal. False, put on queue and do later.
    30  * @return True, request has been queued. False, request has been completed.
    31  */
    32 boolean die(boolean immediate) {
    33     // Make sure we do execute immediately if we are in the middle of a traversal or the damage
    34     // done by dispatchDetachedFromWindow will cause havoc on return.
    35     if (immediate && !mIsInTraversal) {
    36         doDie();
    37         return false;
    38     }
    39     ......
    40     mHandler.sendEmptyMessage(MSG_DIE);
    41     return true;
    42 }
    43 
    44 final class ViewRootHandler extends Handler {
    45        ......
    46       @Override
    47         public void handleMessage(Message msg) {
    48             switch (msg.what) {
    49                  case MSG_DIE:
    50                        doDie();
    51                         break;
    52                   ......
    53             }
    54         }
    55 }

     如上代码验证了之前的猜想,removeView(View)和removeViewImmediate(View)的区别确实就在于是否立即移除。如果调用removeView,会通过handler来调用doDie(),而我们知道handler对应了一个MessageQueue的,需要排队等待执行的,这样就实现了延后执行。而如果调用removeViewImmediate,如果当前没有执行view的遍历,那就直接调用doDie()了。

     1 //==========ViewRootImpl.java========
     2 void doDie() {
     3     ......
     4     synchronized (this) {
     5         if (mRemoved) {
     6             return;
     7         }
     8         mRemoved = true;
     9         if (mAdded) {
    10             dispatchDetachedFromWindow();
    11         }
    12         ......
    13         mAdded = false;
    14     }
    15     WindowManagerGlobal.getInstance().doRemoveView(this);
    16 }
    17 //移除的主要逻辑都在该方法内完成
    18 void dispatchDetachedFromWindow() {
    19      mView.dispatchDetachedFromWindow();
    20      ......
    21      try {
    22            mWindowSession.remove(mWindow);
    23         } catch (RemoteException e) {
    24         }
    25      ......
    26      unscheduleTraversals();//停止绘制View
    27 }
    28 
    29 //======View.java======
    30 void dispatchDetachedFromWindow() {
    31       ......
    32       onDetachedFromWindow();
    33       ......
    34 }
    35 
    36 @CallSuper
    37 protected void onDetachedFromWindow() {
    38     //在view从window移除后会回调该方法,可以在其中做一些资源回收的操作,如终止动画、停止线程等。
    39 }
    40 
    41 //========WindowManagerGlobal.java=======
    42 //该方法主要用于刷新数据
    43 void doRemoveView(ViewRootImpl root) {
    44     synchronized (mLock) {
    45         final int index = mRoots.indexOf(root);
    46         if (index >= 0) {
    47             mRoots.remove(index);
    48             mParams.remove(index);
    49             final View view = mViews.remove(index);
    50             mDyingViews.remove(view);
    51         }
    52     }
    53     ......
    54 }
    55 
    56 //==========Session.java=======
    57 @Override
    58 public void remove(IWindow window) {
    59     mService.removeWindow(this, window);
    60 }
    61 
    62 //==========WindowManagerService.java=======
    63 void removeWindow(Session session, IWindow client) {
    64     synchronized(mWindowMap) {
    65         WindowState win = windowForClientLocked(session, client, false);
    66         if (win == null) {
    67             return;
    68         }
    69         win.removeIfPossible();
    70     }
    71 }

           上述doDie()过程比较容易理解,第22行,参考addView中的逻辑分析可知,这里也是IPC方式,流程最终进入到了WMS中的removeWindow方法,同样到这里咱们不继续往下深入了。上述流程中,mRoots、mParams、mViews、mDyingViews四个集合也做了相应的操作。

           上面讲到的三个主要方法中,可以看到它们都对mRoots、mParams、mViews、mDyingViews进行了刷新。

    七、WMS简介

          在前面的addView和removeView机制中,我们会发现具体的处理逻辑都交给了WMS(即WindowManagerService的简写)中,那WMS是什么呢?

          WMS是一个非常重要的系统服务。它支撑着视图相关的各项业务,这非常符合软件设计的单一职责原则,其业务和ActivityManagerService(简称AMS)一起几乎占据了framework业务的半壁江山,可见其重要性。关于WMS的内容实在太多了,这里只简单介绍其大致功能以及启动流程。

      1、WMS功能介绍

            WMS的大概功能如下图所示:

     

           这里先简单描述一下各项功能:

           窗口管理:WMS是窗口管理者,结合WindowManager实现窗口的启动、添加、删除,以及管理窗口的大小、层级等。

           窗口动画:在窗口切换时,使用窗口动画可以使这个过程看起来更炫更生动,这个窗口动画就是由WMS的动画子系统来负责的,动画子系统的管理者便是WindowAnimator。

           输入系统的中转站: 触摸设备屏幕上的窗口时会产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,找到最合适的窗口来反馈事件。而WMS是这些窗口的管理者,那自然而然就成为了输入系统的中转站了。

           Surface管理:窗口并不具备绘制功能,所以每个窗口都需要一个Surface来供自己绘制,WMS就是这个Surface的管理者。

           该部分参考:Android解析WindowManagerService(一)WMS的诞生

       2、WMS的启动流程

           在我之前的文章:【系统之音】Android系统启动篇 中有介绍过系统的启动过程,其中提到过WMS的启动时机,这里从源码入手再稍微详细阐述一下:

     1 //===========SystemServer.java==========
     2 /**
     3  * The main entry point from zygote.
     4  */
     5 public static void main(String[] args) {
     6     new SystemServer().run();
     7 }
     8 
     9 private void run() {
    10      ......
    11      startBootstrapServices();
    12      startCoreServices();
    13      startOtherServices();
    14      ......
    15 }
    16 
    17 private void startOtherServices() {
    18      ......
    19      WindowManagerService wm = null;
    20      ......
    21      wm = WindowManagerService.main(context, inputManager,
    22      mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
    23         !mFirstBoot, mOnlyCore, new PhoneWindowManager());
    24      ServiceManager.addService(Context.WINDOW_SERVICE, wm);
    25      ......
    26 }

    在第21行中得到了WMS的实例:

     1 //=========WindowManagerService.java=======
     2 private static WindowManagerService sInstance;
     3 ......
     4 public static WindowManagerService main(final Context context, final InputManagerService im,
     5         final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
     6         WindowManagerPolicy policy) {
     7     DisplayThread.getHandler().runWithScissors(() ->
     8             sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
     9                     onlyCore, policy), 0);
    10     return sInstance;
    11 }

    第7行调用了Handler的runWithScissors方法,该方法的作用是执行一个同步的task,即执行完第8行后才会执行第10行,所以main方法返回的是一个WMS实例。

    第24行就是一个将WMS加入到系统服务的过程:

     1 //============ServiceManager.java=========
     2 /**
     3  * Place a new @a service called @a name into the service
     4  * manager.
     5  *
     6  * @param name the name of the new service
     7  * @param service the service object
     8  */
     9 public static void addService(String name, IBinder service) {
    10     try {
    11         getIServiceManager().addService(name, service, false);
    12     } catch (RemoteException e) {
    13         Log.e(TAG, "error in addService", e);
    14     }
    15 }
    16 
    17 private static IServiceManager sServiceManager;
    18 private static IServiceManager getIServiceManager() {
    19     if (sServiceManager != null) {
    20         return sServiceManager;
    21     }
    22     // Find the service manager
    23     sServiceManager = ServiceManagerNative
    24             .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    25     return sServiceManager;
    26 }

           这里调用的addService就是一个IPC过程,如果有阅读过AIDL实现Binder时编译生成的代码,看到ServiceManagerNative类后就会非常眼熟,它就是实现Binder的中间类。至于提供addService功能实现的Server是谁,笔者目前还未找到,所以先研究到这里,后续研究透彻了再补上。

           到这里我们就清楚了,在SystemServer进程启动过程中,WMS启动,并通过ServiceManager中的addServie方法添加到系统中,供其它进程调用。

    结语

           关于Window、WindowManager、WMS等的内容非常多,这里只写了一些笔者在学习过程中做的一些研究。 由于笔者水平有限,如果有些地方描述不妥或者不准确的地方,请读者不吝赐教。

          本文参考资料有:

           【朝花夕拾】Android自定义View篇之(一)View绘制流程

           Android解析WindowManagerService(一)WMS的诞生

           【系统之音】Android系统启动篇 

           【系统之音】Android系统启动篇

          《Android开发艺术探索》

            

  • 相关阅读:
    JSP显示新闻
    servlet应用
    J2EE_第二次作业_登陆页面
    J2EE第一次作业
    软工最后一次作业
    第三次作业(赵清和李靖)
    第二次作业
    第一次作业
    分布式系统架构之构建你的任务调度中心
    【原创】新零售の从单体系统向微服务演变历程(一)
  • 原文地址:https://www.cnblogs.com/andy-songwei/p/13442221.html
Copyright © 2020-2023  润新知