美文网首页
View篇_01WindowManagerService、Win

View篇_01WindowManagerService、Win

作者: 冉桓彬 | 来源:发表于2019-04-14 10:23 被阅读0次

    前言:
      Android系统中的窗口是屏幕上的一块用于绘制各种UI元素并可以响应用户输入的一个矩形区域, 从原理上来讲, 窗口的概念是独自占有一个Surface实例的显示区域, 例如Dialog、Activity的界面、壁纸、状态栏以及Toast等都是窗口;
      Surface是一块画布, 应用可以随心所欲地通过Canvas或者OpenGL在其上作画, 然后通过SurfaceFlinger将多块Surface的内容按照特定的顺序进行混合并输出到FrameBuffer, 从而将Android界面显示给用户;
      既然每个窗口都有一块Surface供自己涂鸦, 必然需要一个角色对所有窗口的Surface进行协调管理. 于是WMS应运而生, WMS为所有窗口分配Surface, 掌管Surface的显示顺序以及位置尺寸, 控制窗口动画, 并且还是输入系统的重要的中转站;

    一、WindowManagerService实例的创建

    1. WindowManagerService运行在system_server进程中, system_server进程在创建时会初始化WindowManagerService的实例;
    2. 窗口管理服务, 复杂窗口的启动, 添加, 删除等;
    3. 这篇笔记希望分析一下Activity的展示与AMS到底有怎样的关系?
    1.1 SystemServer.main

    system_server进程被创建以后, 会调用SystemServer.main方法

    public final class SystemServer {
        public static void main(String[] args) {
            new SystemServer().run();
        }
        private void run() {
            //**
             * 核心是这三个方法, AMS在第一个方法中被初始化;
             */
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        }
        private void startBootstrapServices() {
            //**
             * 通过SSM拿到AMS的实例;
             */
            mActivityManagerService = mSystemServiceManager.startService(
                    ActivityManagerService.Lifecycle.class).getService();
        }
    }
    

    二、Activity端


    Activity启动的流程比较复杂, 目前结合Activity的生命周期只列出Activity启动时的方法调用链

    ActivityMain.main--->
    ActivityThread.handleLaunchActivity--->
    ActivityThread.performLaunchActivity--->
    ActivityThread.handleResumeActivity--->
    ActivityThread.performResumeActivity--->
    
    2.1 ActivityThread.handleLaunchActivity
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // 获取AMS的实例;
        WindowManagerGlobal.initialize();
        Activity a = performLaunchActivity(r, customIntent);
    }
    
    2.2 WindowManagerGlobal.initialize
    public static void initialize() {
        getWindowManagerService();
    }
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                // 进程间通信获取WindowManagerService实例;
                sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
            }
            // WindowManagerGlobal持有sWindowManagerService的引用;
            return sWindowManagerService;
        }
    }
    
    2.3 ActivityThread.performLaunchActivity
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // 通过Activity.attach将Activity, Window, WindowManager, WMS进行绑定;
        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, r.configCallback);
    }
    
    2.4 Activity.attach
    先理一下各个变量之间的继承关系:
    public class Activity {
        Window mWindow = new PhoneWindow();
        WindowManager mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(PhoneWindow);
    }
    public class WindowManagerImpl extends WindowManager {
        private final Window mParentWindow = new PhoneWindow();
    }
    public class Activity {
        final void attach(...) {
            mWindow = new PhoneWindow(this, window, activityConfigCallback);
            ...
            mWindow.setWindowManager(
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
            ...
            mWindowManager = mWindow.getWindowManager();
        }
    }
    

    三、ActivityThread.handleResumeActivity

    在handleLauncherActivity里面会执行onCreate方法, 然后触发对布局的解析, 根节点为DecorView, resume方法里面对View树进行遍历测量, 布局, 绘制;

    3.1 ActivityThread.handleResumeActivity
    final void handleResumeActivity(...) {
        // 其他几个地方看到了再进行分析吧, 目前先分析这个方法;
        r.activity.makeVisible();
    }
    
    3.2 Activity.makeVisible
    void makeVisible() {
        if (!mWindowAdded) {
            // 由前面的关系可知, 这里的wm指向的是ViewManagerImpl;
            // ViewManagerImpl与DecorView之间有什么关系?
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
    
    3.3 WindowManagerImpl.addView
    // mGlobal持有WMS;
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        // 1. mParentWindow指向的是PhoneWindow;
        // 2. view指向的是DecorView;
        // 3. setContentView时, 已经将PhoneWindow与DecorView进行了关联;
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    
    3.4 WindowManagerGlobal.addView
    public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        }
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
            int index = findViewLocked(view, false);
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            // WindowManagerGlobal持有两个容器: mViews用于存储DecorView, mRoots用于存储ViewRootImpl;
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            // 这里以及后续的View都默认为DecorView, ViewRootImpl通过setView将DecorView与自己进行绑定;
            root.setView(view, wparams, panelParentView);
        }
    }
    
    3.5 ViewRootImpl.setView
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        // 现在只看这三行代码:
        // 1. 将DecorView赋值给View mView;
        // 2. 重新布局时会调用这个requestLayout, 如果在子线程中操作UI会报错, 报错原因就在这个requestLayout中;
        // 3. 将ViewRootImpl赋值给DecorView, 将两者进行相互绑定, DecorView为每一个视图的根节点, 其内部维护ViewRootImpl
        //    实例从而实现了每次View通过ViewRootImpl的渲染;
        mView = view;
        requestLayout();
        view.assignParent(this);
    }
    
    @Override
    public void requestLayout() {
        // 通常所说的不能在非UI线程中操作UI就是在这里进行判断的;
        checkThread();
        mLayoutRequested = true;
        // 这个方法会触发View的测量, 绘制, 布局操作;
        scheduleTraversals();
    }
    void checkThread() {
        // 在初始化ViewRootImpl时会在当前线程生成一个常量mThread, 操作View时判断当前线程是否与ViewRootImpl
        // 初始化时的线程是同一个线程, 如果不是就会报错;
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                        "Only the original thread that created a view hierarchy can touch its views.");
        }
    }
    final Thread mThread;
    public ViewRootImpl(Context context, Display display) {
        mThread = Thread.currentThread();
    }
    

    相关文章

      网友评论

          本文标题:View篇_01WindowManagerService、Win

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