WindowManagerService和应用程序的IPC过程

1、概述

大家都知道我们平时在创建应用程序的Activity时,都需要通过WindowManagerService(后面简称WMS
)为启动的Activity创建对应的窗口,那今天我们就来简单的介绍一下WMS于应用程序的通信。

在介绍其通信之前我们先来了解一下WMS的一些类的关系。

2、源码分析

应用程序想要获取到WindowManager对象,就必须要通过Context.getSystemServer()方法获取,而Context的具体实现是ContextImpl类,如果大家对其不是很清楚,可以看一下我的另外一篇博客Android中的Context源码分析
我们直接进入该类的getSystemServer方法。

public Object getSystemService(String name) {
   ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
   return fetcher == null ? null : fetcher.getService(this);
}

可以看出在SYSTEM_SERVICE_MAP的HashMap中取出ServiceFetcher对象,然后调用该对象的getService方法。

在这里我们先看一下ServiceFetcher这个类。

static class ServiceFetcher {
   int mContextCacheIndex = -1;

    public Object getService(ContextImpl ctx) {
       ArrayList<Object> cache = ctx.mServiceCache;
       Object service;
       synchronized (cache) {
           //......
           service = cache.get(mContextCacheIndex);
           if (service != null) {
                return service;
           }
       }
       service = createService(ctx);
       cache.set(mContextCacheIndex, service);
       return service;
   }

    public Object createService(ContextImpl ctx) {
       throw new RuntimeException("Not implemented");
    }
}

可以发现该类有两个方法getService和createService方法,我们接下来只看WMS对应的代码逻辑。

//用于存储注册的服务
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();

//这里注册WMS服务
registerService(WINDOW_SERVICE, new ServiceFetcher() {
   Display mDefaultDisplay;
   public Object getService(ContextImpl ctx) {
      Display display = ctx.mDisplay;
      if (display == null) {
          if (mDefaultDisplay == null) {
              DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                                    getSystemService(Context.DISPLAY_SERVICE);
              mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
          }
          display = mDefaultDisplay;
      }
      //重写getService方法返回WindowManagerImpl对象
      return new WindowManagerImpl(display);
 }});

//用于注册服务的方法,将结果存入SYSTEM_SERVICE_MAP的Map中
private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }

好啦,以上就是获取WindowManagerImpl代理对象的方法,我们接下来进入WindowManagerImpl的源码。

我们要知道,Window是一个抽象概念,每个Window都对应着一个View和ViewRootImpl,Window和View是通过ViewRootImpl建立联系,因此Window是以View的形式存在的。在实际中我们无法直接访问Window,对Window的访问必须通过WindowManager,为了分析Window,我们这里来了解操作Window的三个方法。

public interface ViewManager{

    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

这个类是WindowManager的父类,我们进入WindowManager类。

public interface WindowManager extends ViewManager {
    //......
}

WindowManager没有直接重写ViewManager的三个抽象方法,而是留给其子类实现,我们进入其子类WindowManagerImpl。

public final class WindowManagerImpl implements WindowManager {

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    //获得WindowManagerGlobal对象
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //调用mGlobal对象的addView方法
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

     public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //调用mGlobal对象的updateViewLayout方法
        mGlobal.updateViewLayout(view, params);
    }

    public void removeView(View view) {
        //调用mGlobal对象的removeView方法
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }
}

可以看到WindowManagerImpl对View的操作直接交给了WindowManagerGlobal对象了,另外我们说一下这里的removeView方法,这里的removeView方法有两个removeView和removeViewImmediate,它们分别表示异步删除和同步删除,平时我们主要使用的是异步删除,接下来我们进入WindowManagerGlobal类。

public static WindowManagerGlobal getInstance() {
   synchronized (WindowManagerGlobal.class) {
       if (sDefaultWindowManager == null) {
           sDefaultWindowManager = new WindowManagerGlobal();
       }
       return sDefaultWindowManager;
   }
}

首先通过getInstance获取到WindowManagerGlobal对象,这是一个单例模式,在这里我们就不详细的分析操作View的三个方法,我们会在后面的文章中详细阐述,这里我们主要就分析两处:

(1)获取WindowManagerService对象

public static IWindowManager getWindowManagerService() {
   synchronized (WindowManagerGlobal.class) {
       if (sWindowManagerService == null) {
           //调用IWindowManager.Stub对象的asInterface方法
           sWindowManagerService = IWindowManager.Stub.asInterface(
//从ServiceManager中获取WMS对象
ServiceManager.getService("window"));
           sWindowManagerService = getWindowManagerService();
       }
   }
   //返回IWindowManager对象
   return sWindowManagerService;
}

从以上代码可以看出,首先我们获取WMS对象,通过ServiceManager.getService(“window”)获取,大家还记得我们之前文章分析SystemServer的启动流程吗?如果不是很清楚的可以去看一下SystemServer启动流程之Zygote启动(一),这里我也将代码贴一下。

 wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);

//此处的Context.WINDOW_SERVICE值就是window
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

我们回到getWindowManagerService方法中,然后调用IWindowManager.Stub对象的asInterface方法并将WMS作为参数传递进去,我们进入asInterface方法源码。

public static android.view.IWindowManager asInterface(android.os.IBinder obj)
{
    if ((obj==null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    //这里分为两种情况
    if (((iin!=null)&&(iin instanceof android.view.IWindowManager))) {
        //直接返回
        return ((android.view.IWindowManager)iin);
    }
    //这里创建IWindowManager.Stub的代理对象Proxy并返回
    return new android.view.IWindowManager.Stub.Proxy(obj);
}

好啦,到此我们就可以通过getWindowManagerService方法获取到WMS对象或者其代理对象,接下来我们在分析如何获取WindowSession对象。

(2)获取WindowSession对象

public static IWindowSession getWindowSession() {
   synchronized (WindowManagerGlobal.class) {
       if (sWindowSession == null) {
           try {
               InputMethodManager imm = InputMethodManager.getInstance();
               //通过getWindowManagerService获取得到WMS对象即其代理对象Proxy
               IWindowManager windowManager = getWindowManagerService();
               //调用WMS的Proxy对象的openSession方法
               sWindowSession = windowManager.openSession(
                     new IWindowSessionCallback.Stub() {
                          //...... 
                     },
                }
            }
            return sWindowSession;
        }
    }

这里我们主要分析调用WMS的Proxy对象的openSession方法,进入该方法的源码可以发现,其调用的是其子类WindowManagerService的openSession方法,我们进入该源码。

public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        //创建Session本地对象
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }

这里直接构造一个Session对象,并将该对象返回给应用程序进程,这样在应用程序这边就可以得到Session的代理对象IWindowSession.Proxy,并保存在ViewRootImpl对象的成员变量mWindowSession中。

下面我们用一张时序图来表示Session的获取方法。

《WindowManagerService和应用程序的IPC过程》

以上就是ViewRootImpl通过getWindowSession来获取WindowSession的代理对象。

好啦,分析到这里相信大家对WMS的获取等都有一定的了解了吧,接下来我们我们用一张图来表示ViewRootImpl和WMS的关系。

《WindowManagerService和应用程序的IPC过程》

到此本篇博客就分析完毕啦,关于Window和WindowManager之间的详细关系请参考另外一篇文章理解Window和WindowManager(一),大家不妨也去阅读一下吧。

    原文作者:雪舞飞影
    原文地址: https://blog.csdn.net/dongxianfei/article/details/52926456
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞