Activity和WMS的双向通信

说双向通信之前,首先了解下WindowManagerGlobalViewRootImpl的创建

WindowManagerGlobal的创建

创建过程如下图

Activity和WMS的双向通信_第1张图片
image.png
  • ActivityManagerService->ActivityThread
    AMS里面的main函数里会创建ActivityThread
public static void main(String[] args) {
//省略...
 ActivityThread thread = new ActivityThread();
//省略...
}

ActivityThread是应用程序的UI线程,它主要负责对Android四大组件的创建和管理,以及控制Activity的生命周期等。

  • ActivityThread-> WindowManagerGlobal

当我们执行startActivity启动一个页面时,最终会执行到ActivityThread
handlerLauncherActivity方法来。在这个方法里,会创建一个WindowManagerGlobal

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 创建Activity之前初始化WindowManagerGlobal
        WindowManagerGlobal.initialize();
       //省略...
    }

ViewRootImpl创建

创建过程如下图

Activity和WMS的双向通信_第2张图片
image.png
  • ActivityThread->Activity

创建Activity也是在AndroidThreadhandleLauncherActivity方法里面,创建完WindowManagerGlobal之后调用

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 创建Activity之前初始化WindowManagerGlobal
        Activity a = performLaunchActivity(r, customIntent);
       //省略...
    }
  • Activity->PhoneWindow
    来到performLaunchActivity方法里面创建Activity,并且会执行Activityattach方法来创建PhoneWindow
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //省略...
    Activity activity = null;
 //省略...
 try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            //省略...
        } catch (Exception e) {
             //省略...
        }
}
if (activity != null) {
     //省略...
     activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
     //省略...

}

- PhoneWindow->WindowManagerImpl

Activity里的attach方法创建完PhoneWindow之后会执行WindowsetWindowManager方法。

 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) {
  //省略...
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
  //省略...
 mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
  //省略...
}

PhoneWindow它是Window的唯一实现类,它会在setContentView方法里面创建DecoView,然后DecoView会添加一个id为content的FrameLayout作为根布局,关系如下图

Activity和WMS的双向通信_第3张图片
PhoneWindow.png

创建好 PhoneWindow后,继续执行 WindowsetWindowManager方法,去创建 WindowManagerImpl对象

 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);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
  • WindowManagerImpl->WindowManagerGlobal

WindowManagerImpl里面会和WindowManagerGlobal进行关联,从而通过addView方法,removeView等方法来做为管理View的桥梁,传递给WindowManagerGlobal

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);
    }
   @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

调用WindowManagerImpladdView的位置主要有两个地方
1.ActivitymakeVisible方法会调用

  void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
  1. ActivityThreadhandleResumeActivity会直接执行addView方法
      final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    //省略...
if (r.window == null && !a.mFinished && willBeVisible) {
//省略...
 if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
    }
}
    
//省略...
  if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
    //省略...
     if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
     }
    //省略...
}
}

在添加DecoView的时候会调用addView方法,添加DecoViewView的时候就直接调用ActivitymakeVisible的方法,然后在makeVisible调用addView方法。

  • WindowManagerGlobal->ViewRootImpl

WindowManagerGlobaladdView方法里面会创建ViewRootImpl

 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
     //省略...
    ViewRootImpl root;
     //省略...
     root = new ViewRootImpl(view.getContext(), display);
}

ViewRootImpl它主要管理Window中所有的View的类,每个Activity中ViewRootImpl的数量取决于调用mWindowManager.addView的调用次数,Activity提供与AMS通信的Token(IBinder对象),创建Window为View提供显示的地方,而具体的View管理任务由ViewRootImpl来完成。

Activity->WMS通信

Activity到WMS通信主要是通过WindowManagerGlobalViewRootImpl来完成的,上面说到WindowManagerGlobalinitialize方法

 public static void initialize() {
        getWindowManagerService();
    }
  public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    //...省略

首先可以知道WindowManagerGlobal是个单例,最终调用的是getWindowManagerService方法。ServiceManager.getService("window")获取一个IBinder对象,来到getService方法

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

然后来到getIServiceManager()方法

  private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

这里可以通过如下图来解释

Activity和WMS的双向通信_第4张图片
图片来源https://blog.csdn.net/luoshengyang/article/details/6642463罗老师博客.png

BinderInternal.getContextObject()其实获取的是BinderProxy这个代理类,然后通过asInterface()方法传给IServiceManager的代理类ServiceManagerProxy,也是ServiceManagerJava远程接口,从而实现Binder通信。

然后回到getService()方法,传入一个name参数,然后通过name获取指定的service,比如这里传入的是window,也就是获取到WindowManagerService对应的IBinder对象。最后调用IWindowManager.Stub.asInterface()方法获取到WindowManagerService的抽象类IWindowManager

获取到WMS之后,然后会在ViewRootImpl初始化的时候调用openSession,获取IWindowSession

 final IWindowSession mWindowSession;
 public ViewRootImpl(Context context, Display display) {
      mWindowSession = WindowManagerGlobal.getWindowSession();
}

getWindowSession方法

public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

通过上面获取到的IWindowManager去调用openSession获取IWindowSession对象。然后通过IWindowSession进行通信。如下图

Activity和WMS的双向通信_第5张图片
image.png

IWindowSessionClient端的代理,而它的 Server端是 SessionSession接收到请求后,就会转交给 WMS进行处理。流程如下图

Activity和WMS的双向通信_第6张图片
时序图.png

这样就实现了ActivityWMS的通信

WMS -> Activity通信

WMSActivity通信,也是使用的代理模式,通过IWindow.Stub接口来实现,而WMS的代理对象就是在ViewRootImpl里面的W内部类,它通过上面获取的IWindowSession来在ViewRootImplsetView方法里面调用addToDisplay方法把W代理传递给WMS

 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  //..省略
 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
 //..省略
}

它传递的第一个参数mWindow就是WmWindow中保存了W类型的Binder本地对象,这样通过函数addToDisplay就可以将W的代理对象传递Session然后给WMS服务。SessionaddToDisplay如下

 @Override
    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,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }

然后来到WindowManagerServiceaddWindow方法,从这里可以看出每次ViewRootImplsetView调用一次,对应一个Session请求。然后来到addWindow方法里面,在里面创建了一个WindowState对象,并且把W保存的Binder对象和Session保存在WindowState中,

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
      //省略...
       WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
      //省略...
    win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
     win.attach();
      win.applyScrollIfNeeded();
    win.applyAdjustForImeIfNeeded();
}

创建WindowState

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
  mWindowId = new IWindowId.Stub() {
            @Override
            public void registerFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.registerFocusObserver(observer);
            }
            @Override
            public void unregisterFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.unregisterFocusObserver(observer);
            }
            @Override
            public boolean isFocused() {
                return WindowState.this.isFocused();
            }
        };
}

创建IWindowId主要是用于标识指定窗口。它会在ViewgetWindowId方法里面获取到。

综上,WMSActivity的通信主要是通过IWindow的代理对象W来进行通信。过程如下

Activity和WMS的双向通信_第7张图片
WMS到Activity.png

Activity到WMS是通过IWindowSession来通信,WMS到Activity是通过IWindow代理w来通信

你可能感兴趣的:(Activity和WMS的双向通信)