Android Window 浅析 之二

    科技2024-01-02  98

    Window的添加过程的WMS部分,将addWindow方法分为了3个部分来进行讲解,从addWindow方法我们得知WMS有3个重要的类分别是WindowToken、WindowState和DisplayContent

    启动过程

    1.1 WindowManagerService 的诞生 1.1.1 在 SystemServer 中的创建 WMS 是在 SystemServer 进程中启动的,SystemServer 进程是 Android 系统启动的时候初始化的,我们首先来看一下 SystemServer 的入口函数 main()

     

    public final class SystemServer { /** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); } }

    分析run方法

     

    private void run() { ...... mSystemServiceManager = new SystemServiceManager(mSystemContext); // 代码 1 // Start services. try { traceBeginAndSlog("StartServices"); startBootstrapServices(); // 代码 2 startCoreServices(); // 代码 3 startOtherServices(); // 代码 4 SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } }

    代码1处,创建了一个 SystemServiceManager 对象 代码2处,调用 startBootstrapServices() 启动 ActivityManagerService、PackageManagerService 等服务进程 代码3处,调用 startCoreServices() 启动BatteryService、WebViewUpdateService 等服务进程 代码4处,调用 startOtherServices() 启动 WindowManagerService、InputManagerService 等服务进程

    二. WMS 与 WindowManager 的通信

    在上篇文章 初步理解 Window 体系 中,我们最后分析到了 ViewRootImpl,ViewRootImpl 是连接 WindowManager 和 WMS 的桥梁,自然他们之间的通信也是通过 ViewRootImpl 完成的。

    2.1 ViewRootImpl 的成员变量

    在 ViewRootImpl 中有两个个非常重要的成员变量:mWindowSession 和 mWindow,这两个变量都是用于 ViewRootImpl 和 WMS 通信使用的

    public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { ...... final IWindowSession mWindowSession; final W mWindow; ......

     

    public ViewRootImpl(Context context, Display display) { mContext = context; // 代码 1,通过 WindowManagerGlobal.getWindowSession() 方法得到一个 IWindowSession 对象 mWindowSession = WindowManagerGlobal.getWindowSession(); ...... // 代码 2,通过 W 构造方法直接创建一个新的 W 对象 mWindow = new W(this); ...... } ......

    } 2.1.1 IWindowSession IWindowSession 是一个 AIDL 接口,其服务端进程是 WMS,客户端进程是应用进程,IWindowSession 的创建是在 WindowManagerGlobal 中,如下所示:

     

    public final class WindowManagerGlobal { private static IWindowManager sWindowManagerService; private static IWindowSession sWindowSession; ...... public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } } 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; } } ...... }

    从 getWindowSession() 方法中我们可以看出,IWindowSession 对象的创建依赖于 IWindowManager 对象 IWindowManager 也是一个 AIDL 接口,通过 getWindowManagerService() 方法得到其对象,在 getWindowManagerService() 方法中,可以看到是典型的 Android 中 Binder 通信得到服务端在客户端进程中的代理对象的方式,远程端的对象即是 WMS,WMS 实现了 IWindowManager 接口 public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { ...... } 在 getWindowSession() 方法中,我们可以看到是调用了 IWindowManager 的 openSession 方法,其实际的实现是在 WMS 中,WMS 中的 openSession 方法如下所示 public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {

     

    @Override 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 = new Session(this, callback, client, inputContext); return session; }

    } 可以看到,其实 ViewRootImpl 中的 IWindowSession 对象实际对应着 WMS 中的 Session 对象。

    WindowManagerGlobal 和 WMS 实现的是单方向的通信,都是通过如下图所示的 Binder 方式进行进程间通信的

    WindowManagerGlobal.png 2.1.2 W W 类是 ViewRootImpl 的一个内部类,实现了 IWindow 接口,IWindow 也是一个 AIDL 接口,可以猜想到,IWindow 接口是供 WMS 使用的,WSM 通过调用 IWindow 一些方法,通过 Binder 通信的方式,最后执行到了 W 中对应的方法中

    public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

     

    static class W extends IWindow.Stub { private final WeakReference<ViewRootImpl> mViewAncestor; private final IWindowSession mWindowSession; W(ViewRootImpl viewAncestor) { mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); mWindowSession = viewAncestor.mWindowSession; } @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration, backDropFrame, forceLayout, alwaysConsumeNavBar, displayId); } } @Override public void moved(int newX, int newY) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchMoved(newX, newY); } } @Override public void dispatchAppVisibility(boolean visible) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchAppVisibility(visible); } } @Override public void dispatchGetNewSurface() { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchGetNewSurface(); } } @Override public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.windowFocusChanged(hasFocus, inTouchMode); } } private static int checkCallingPermission(String permission) { try { return ActivityManager.getService().checkPermission( permission, Binder.getCallingPid(), Binder.getCallingUid()); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } } ...... }

    } 比如在 ViewRootImpl#setView 方法中,有如下代码,在代码 1 处通过 mWindowSession 调用 addToDisplay 方法时,会将 mWindow 传入,最后传给 WMS,这样 WMS 便得到了一个 W 对象的实例对象。

    public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

     

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { ...... int res; /* = WindowManagerImpl.ADD_OKAY; */ // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); // 代码 1 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { attrs.restore(); } } ...... } } }

    } 从上面代码可以看到,在 ViewRootImpl 中不仅实现了从 ViewRootImpl 向 WMS 的通信,也实现了从 WMS 向 ViewRootImpl 的通信,如下图所示

    image.png

     

    Processed: 0.009, SQL: 8