美文网首页
Android Window 浅析 之二

Android Window 浅析 之二

作者: 瀚海网虫 | 来源:发表于2020-10-07 08:16 被阅读0次

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

相关文章

网友评论

      本文标题:Android Window 浅析 之二

      本文链接:https://www.haomeiwen.com/subject/wqdpwhtx.html