图像显示深入学习三:窗口机制分析

上一篇文章图像显示深入学习一:Activity启动过程中介绍了启动一个Activity在整个Android系统中执行的流程,其中可以看到Window的创建,这篇文章就整理一下Window机制的实现过程吧。

吐个槽,今年大部分时间在公司一直在做SDK项目,UI方面的工作涉及的比较少,现在重新开始做UI了,发现自己对于View方面的知识有点模糊了,后悔以前没有写文章记录下来呀,好记性真的不如烂笔头。


重新回顾一下图像显示深入学习一:Activity启动过程文章中的Activity创建过程,应用层通过ApplicationThread.scheduleLaunchActivity(...)接受远程回调,进而调用ActivityThread.handleLaunchActivity(...)方法,从而开始了一系列Activity生命周期的回调,而Window的创建显示过程也包含其中,所以我们还是从.handleLaunchActivity(...)该方法开始看起,只摘取出跟Window有关的内容:

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
     ...
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
         ...
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {
                performPauseActivityIfNeeded(r, reason);
		...
        }
    }

这里调用了WindowManagerGlobal.initialize()方法, WindowManagerGlobal是与WindowManagerService沟通的桥梁,所以这里我们先看下这个方法到底干了什么:

//WindowManagerGlobal.java
public static void initialize() {
        getWindowManagerService();
    }
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;
        }
    }


initialize()方法中使用Binder通信机制初始化了sWindowManagerService对象,比较简单。回到handleLaunchActivity(...)中,继续查看performLaunchActivity(...):

   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
			//新建Activity
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
		...
            if (activity != null) {
               ...
                appContext.setOuterContext(activity);
				//调用attach初始化Activity相关参数
                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);

				...
				//调用onCreate回调
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
             	...
				//调用onStart回调
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
				//调用onRestoreInstanceState回调
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
				//调用onPostCreate回调
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
          ...
        return activity;
    }

该方法设计到的Window操作不多,就一个activity.attach(...),为了方便,下面把源码贴出来一下:

 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, ActivityConfigCallback activityConfigCallback) {
 		...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        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();
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }

attach(...)方法中主要做了两件事情:

  • 初始化Window实现类PhoneWindow
  • 设置关联的WindowManager

mWindow.setWindowManager(....)会去实例化一个WindowManager实现类WindowManagerImpl:

//Window.java
  public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
     ...
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
	
//WindowManagerImpl.java

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

PhoneWindow是Window的继承类,每一个Window行为都由PhoneWindow执行。好的,接着继续往下看handleResumeActivity(...)方法:

 final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
			...
			//回调onResume方法
      		...
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManager.getService().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
				//1.
                r.window = r.activity.getWindow();
				//2.
                View decor = r.window.getDecorView();
				//首先设置DecorView不可见状态
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
				//Window在初始化的时候也会初始化一个LayoutParams,该LayoutParams是一个
				//WindowManager.LayoutParams对象
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
            	...
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
						//3
                        wm.addView(decor, l);
                    }
					...
                }
            } 
			...
					//4
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
                    }
                }

                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
				//5.
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }

      ...
    }

上面桉序列依次解释代码的逻辑:

  1. 获取Window实例,即获取PhoneWindow对象。
  2. 获取DecorView,DecorView是我们在写布局中的顶层根布局View。
  3. WindowManager调用addView(...)添加布局View。
  4. 调用WindowManager.updateViewLayout(...)方法更新View
  5. 设置DecorView可见。

其中需要解释的是DecorView实例,关于Activity中布局的示意图如下:

可以看到DecorView位于布局的最上游,本质上是一个FrameLayout,那么,DecorView是什么时候添加进去的呢?答案就是在setContentView(...)调用的时候,通过在图像显示深入学习二:setContentView(...)过程分析一文中了解到了DecoView会在setContentView(...)时候初始化,也就是在onCreate(...)方法回调之后。

接下来就要着重讲下WindowManager了,WindowManager本身是一个接口类,继承了ViewManager接口,关于ViewManager的定义如下:

public interface ViewManager
{	//向窗口添加VIew
    public void addView(View view, ViewGroup.LayoutParams params);
	//更新窗口中的View
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
	//移除View
    public void removeView(View view);
}

在WindowManager内部中有一个内部静态类LayoutParam,该类实现了Parcelable接口,也就是说提供了序列化的能力,这里先猜测跟Binder通信有关,下面再进行考证。

WindowManager的实现类为WindowManagerImpl,WindowManagerImpl内部持有了一个WindowManagerGlobal实例,在上面分析中我们知道WindowManagerGlobal持有了远程WindowManagerService的Binder对象,那么进行Binder通信肯定就通过WindowManagerGlobal进行了,下面看下WindowManagerImpl的主要实现:


 public final class WindowManagerImpl implements WindowManager {
  ...
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

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

这里的mGlobal就是WindowManagerGlobal对象,可以看到其实WindowManagerImpl也就只是一个代理类,调用ViewManager的方法,实际是调用到了WindowManagerGlobal(WMG)中。接下来就要着重挑一个addView(...)的研究,在研究之前,先整理一下上面的逻辑:

  • ApplicationThread.scheduleLaunchActivity(...)被AMS远程回调后,在会去初始化WindowManagerGlobal与WMS进行沟通的Binder对象。
  • 接下来创建Activity,在调用Activity.attach(...)时候会在内部创建一个PhoneWindow作为Window的实现类。然后回调Activity的onCreate(...)onStart(...)等方法,在onCreate(...)时候会通过setContentView(...)创建DecorView。
  • 接下来回调Activity的onResume(...)方法,然后调用WindowManager的addView(...)以及updateViewLayout(...)方法。

在WMG中有三个变量需要注意一下:


//记录所有Windowsd对应的View
    private final ArrayList<View> mViews = new ArrayList<View>();
	//记录mViews中对应的ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
	//记录所有Window对应的Param
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
	//记录正在被删除的Views
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

好的接下来看下WMG的addView(...)方法:


public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
			//判空
		...
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
      ...
        ViewRootImpl root;
        View panelParentView = null;

        ...
		//新建ViewRootImpl类
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
			//1
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
				//2
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

上面代码首先在三个变量做添加对应DecorView变量的信息,然后调用第2步代码(root是一个ViewRootImpl对象,该类掌管着View的测量,布局以及绘图的主要逻辑):

...
  mWindowSession = WindowManagerGlobal.getWindowSession();
...
  public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
				...//1
				requestLayout();
               ...
				//2
                 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 {
                  ...
    }

上面省略了大部分的代码,步骤1首先看调用了requestLayout()方法,我们在日常中使用的requestLayout()方法其实到最后就是调用ViewRootImpl的requestLayout()方法:


 @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
 void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

这里涉及到Choreographer(编舞者)类,简单来就是使用Handler进行post(...)操作,由于Handler以及消息队列机制的原因,该post(...)需要在我们执行完ActivityThread.handleLaunchActivity(....)才能执行,也就是说窗口添加完毕了,post(...)才会调用,所以等我们下面分析完再回过头了分析这个。

步骤2主要工作就是在于跟WMS进行通信,通过调用mWindowSession.addToDisplay(...)方法,mWindowSession是一个IWindowSession,一般出现I字开头的在系统层代码中都代表着有Binder支持的进程通讯能力,我们看下该类怎么获得到的:

//WindowManagerGlobal.java
    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;
        }
    }

通过WMS对象打开一个Session,每个Session是一个Window的Native的代理类,WMS通过掌管不同的Session与应用层的Window进行通信:

//WindowManagerService.java
    @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;
    }

接下来继续看mWindowSession.addToDisplay(...)方法在Native层的调用的:

//Session.java

@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);
    }

Seesion中重新调回WMS在addWindow(...)方法:

   public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
        int[] appOp = new int[1];
		//检察权限
        int res = mPolicy.checkAddPermission(attrs, appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }
		 ...
		 final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
			...
			//判断Window合法性
			 ...
        ...
            res = WindowManagerGlobal.ADD_OKAY;
         ...
        return res;
    }

改代码中创建一个DisplayContent以及WindowState(真正表示一个Native Window与应用层对应),这些主要跟Surface有关,这里就先不分析了,到时候写一篇关于Surface的文章再做记录。最终返回WindowManagerGlobal.ADD_OKAY。

ok到此Window在Native的添加已经完毕,那我们接着返回查看ViewRootImpl.setView(...)方法中的requestLayout(...)方法。上面讲到该方法最终调用到mTraversalRunnable实例中,那么看下该Runnable对象干了什么东东:

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

这里调用doTraversal()方法,该方法最终又调用performTraversals()方法,该方法就是最终管理View的测量,布局,绘图的最顶层方法:

private void performTraversals() {
        // cache mView since it is used so much below...
        final View host = mView;
		...
		//赋值系统Window的宽高
        int desiredWindowWidth;
        int desiredWindowHeight;
				...
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
				...
					//测量
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
			//布局
            performLayout(lp, mWidth, mHeight);
...
			//绘图
            performDraw();
       ...
    }

首先这里有relayoutWindow(params, viewVisibility, insetsPending)操作,该方法内部会创建一个Surface对象与ViewRootImpl关联起来,这里做个笔记,下次对Surface分析的时候有用。下面方法主要就是测量,布局,绘图过程了,这里不对测量,布局,绘图过程进行细究了,他们最终依次回调onMeasure(...)onLayout(...)onDraw(...)方法。

猜你喜欢

转载自my.oschina.net/u/3863980/blog/2245710