Android 源码 图形系统之窗口添加

《Android 源码 输入系统之窗口关联》 一节着重考虑了窗口怎样和输入系统关联,而这一节的重点在于窗口如何添加到图形系统。

先来看一个整体概览,再来详细分析。

Android 源码 图形系统之窗口添加_第1张图片

先从 setContentView 说起。此函数的作用是:从布局资源设置 Activity 内容。资源将被解析,将所有顶级视图添加到 Activity 中。首先调用 getWindow() 获取 Window 对象(实际为 PhoneWindow 对象),然后调用其 setContentView(…) 方法。

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {
    ......
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        // 初始化 ActionBar
        initWindowDecorActionBar();
    }
    ......
}

getWindow() 直接返回 mWindow 指向的 Window 对象。这可用于直接访问 “Activity/Screen” 无法使用的 Window API 部分。

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {
    ......
    private Window mWindow;
    ......
    public Window getWindow() {
        return mWindow;
    }
    ......
}

mWindow 是在 attach(…) 函数中赋值的。实际指向一个 PhoneWindow 对象。

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {
    ......
    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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        // 创建 PhoneWindow 对象
        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        ......
        // 设置 WindowManager,和 WMS 建立了关联
        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());
        }
        // 获取 WindowManager 对象
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }
    ......
}

tips:

安卓 5.0 中 Activity 和 Fragment 变换是建立在名叫 Transitions 的安卓新特性之上的。这个诞生于 4.4 的 transition 框架为在不同的 UI 状态之间产生动画效果提供了非常方便的 API。该框架主要基于两个概念:场景(scenes)和变换(transitions)。场景(scenes)定义了当前的 UI 状态,变换(transitions)则定义了在不同场景之间动画变化的过程。

当一个场景改变的时候,Transition 主要负责:

一、捕捉每个 View 在开始场景和结束场景时的状态。二、根据两个场景(开始和结束)之间的区别创建一个 Animator。

可以通过如下两种方式来启用:

  1. 代码方式,在 setContentView 之前调用:getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
  2. 主题 xml 配置,true

假设我们没有启用 Window.FEATURE_CONTENT_TRANSITIONS 特性,setContentView(…) 主要完成了三个动作:

  1. 调用 installDecor() 安装 Decor
  2. 清空 mContentParent
  3. 解析 layoutResID

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    @Override
    public void setContentView(int layoutResID) {
        // 注意:当主题属性等明确化时,
        // 可以在安装 Window Decor 的过程中设置 FEATURE_CONTENT_TRANSITIONS。 
        // 在此之前不要检查此特性。
        if (mContentParent == null) {
            // 1. 安装 Decor
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            // 2. 清空 mContentParent
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            // 3. 解析 layoutResID,填充到父容器 mContentParent
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
    ......
}
  1. 调用 generateDecor() 生成 DecorView
  2. 调用 generateLayout(…) 生成“内容父容器” —— mContentParent
  3. 获取 DecorView 父容器,并设置 WindowCallback 和 WindowTitle

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    private void installDecor() {
        if (mDecor == null) {
            // 生成 DecorView
            mDecor = generateDecor();
            // 焦点分发相关
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            ......
        }
        if (mContentParent == null) {
            // 生成 mContentParent
            mContentParent = generateLayout(mDecor);

            // 如果合适,将 UI 的 Decor 部分设置为忽略 fitsSystemWindows。
            mDecor.makeOptionalFitsSystemWindows();
            // 获取 Decor 内容父容器,实际为内容跟容器
            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                    R.id.decor_content_parent);

            if (decorContentParent != null) {
                mDecorContentParent = decorContentParent;
                mDecorContentParent.setWindowCallback(getCallback());
                if (mDecorContentParent.getTitle() == null) {
                    mDecorContentParent.setWindowTitle(mTitle);
                }
                ......
            } else {
                ......
            }
            ......
        }
    }
    ......
}

generateDecor() 方法非常简单,直接调用 DecorView 构造器返回 DecorView 对象。

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }    
    ......
}
  1. mFeatureId 赋值为 -1,这代表面板的功能部件是 DecorView
  2. 动画-显示、隐藏插值器初始化
  3. Bar 进入、退出时间间隔初始化

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {  
        ......
        public DecorView(Context context, int featureId) {
            super(context);
            // 面板的功能部件 ID;如果这是应用程序的 DecorView,则为 -1
            mFeatureId = featureId;
            // 动画-显示插值器初始化
            mShowInterpolator = AnimationUtils.loadInterpolator(context,
                    android.R.interpolator.linear_out_slow_in);
            // 动画-隐藏插值器初始化
            mHideInterpolator = AnimationUtils.loadInterpolator(context,
                    android.R.interpolator.fast_out_linear_in);
            // Bar 进入、退出时间间隔初始化
            mBarEnterExitDuration = context.getResources().getInteger(
                    R.integer.dock_enter_exit_duration);
        }        
        ......
    }
    ......
}

再来分析 generateLayout(…)。此函数主要解析了根布局文件,获取了内容根容器和内容容器。

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    protected ViewGroup generateLayout(DecorView decor) {
        ......
        // Inflate the window decor.

        int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            ......
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            ......
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            ......
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            ......
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                ......
            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                // 假如使用了 ActionBar
                layoutResource = a.getResourceId(
                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
                        R.layout.screen_action_bar);
            } else {
                ......
            }
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            ......
        } else {
            ......
        }

        mDecor.startChanging();
        // 解析根布局文件
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        // 内容根容器
        mContentRoot = (ViewGroup) in;
        // 内容容器,ID_ANDROID_CONTENT 定义在 Window 类中,
        // ID_ANDROID_CONTENT = com.android.internal.R.id.content
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
        ......
        mDecor.finishChanging();

        return contentParent;
    }    
    ......
}

我们来看 screen_action_bar 这个 layout 文件。根容器 ActionBarOverlayLayout 对应 mContentRoot;第一个 FrameLayout,其 android:id="@android:id/content",这就是 contentParent。

frameworks/base/core/res/res/layout/screen_action_bar.xml



<com.android.internal.widget.ActionBarOverlayLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/decor_content_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:splitMotionEvents="false"
    android:theme="?attr/actionBarTheme">
    <FrameLayout android:id="@android:id/content"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent" />
    ......
com.android.internal.widget.ActionBarOverlayLayout>

接下来继续分析解析 layoutResID,填充到父容器 mContentParent。inflate 方法有很多重载,最后会调用 xml PULL 方式解析布局 layout,将其添加到 mContentParent 代表的 FrameLayout 中,完成内容视图添加。

frameworks/base/core/java/android/view/LayoutInflater.java

public abstract class LayoutInflater {
    ......
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
        return inflate(resource, root, root != null);
    }
    ......
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                    + Integer.toHexString(resource) + ")");
        }

        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
    ......
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {
                // 查找根节点。
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }

                if (type != XmlPullParser.START_TAG) {
                    throw new InflateException(parser.getPositionDescription()
                            + ": No start tag found!");
                }

                final String name = parser.getName();
                ......
                // merge 标签处理
                if (TAG_MERGE.equals(name)) {
                    if (root == null || !attachToRoot) {
                        throw new InflateException(" can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }

                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                    // Temp 是在 xml 中找到的根 View
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // 创建与 root 匹配的布局参数(如果提供)
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            temp.setLayoutParams(params);
                        }
                    }
                    ......
                    // 解析子布局
                    rInflateChildren(parser, temp, attrs, true);
                    ......
                    // 将 temp View 添加到 root。 
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }
                    ......
                }

            } catch (XmlPullParserException e) {
                ......
            } catch (Exception e) {
                ......
            } finally {
                ......
            }

            Trace.traceEnd(Trace.TRACE_TAG_VIEW);

            return result;
        }
    }
    ......
}

在 Activity 启动流程分析中,我们知道启动一个 Activity 当调用了 ActivityThread 中 handleLaunchActivity 方法后,马上就会调用 handleResumeActivity 方法,奥秘就在这里!

  1. 获取 Window 和 DecorView 对象;
  2. 设置 DecorView 为不可见;
  3. 获取 WindowManager 对象;
  4. 将 DecorView 添加到 ViewManager。

frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {
    ......
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ......
        // 会触发 activity 生命周期方法 onResume(...)
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;
            ......
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                // 设置 DecorView 为不可见
                decor.setVisibility(View.INVISIBLE);
                // 获取 WindowManager 对象
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    // 将 DecorView 添加到 ViewManager
                    wm.addView(decor, l);
                }

            } else if (!willBeVisible) {
                ......
            }

            ......

            // 告诉活动管理器(AMS)我们已经恢复。
            if (reallyResume) {
                try {
                    ActivityManagerNative.getDefault().activityResumed(token);
                } catch (RemoteException ex) {
                }
            }

        } else {
            ......
        }
    }
    ......
}

不出所料获取 Window 的 DecorView 就是在 PhoneWindow 类中的全局变量 mDecor 指向的 DecorView。

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ......
    @Override
    public final View getDecorView() {
        if (mDecor == null) {
            installDecor();
        }
        return mDecor;
    }
    ......
}

wm 局部变量实际指向 WindowManagerImpl 对象,所以实际调用了 WindowManagerImpl 类的 addView 方法。此处又调用了 WindowManagerGlobal 单例的 addView 方法。

frameworks/base/core/java/android/view/WindowManagerImpl.java

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ......
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    ......
}
  1. 参数检查
  2. 获取 WindowManager.LayoutParams
  3. mViews 中查找新添加 DecorView,如果已经添加过,抛出 IllegalStateException 异常
  4. 从 mViews 中找到 panelParentView
  5. 创建 ViewRootImpl 对象
  6. DecorView 设置 LayoutParams
  7. 向容器(mViews、mRoots 和 mParams)中添加各种对象
  8. ViewRootImpl 对象设置 DecorView

frameworks/base/core/java/android/view/WindowManagerImpl.java

public final class WindowManagerGlobal {
    ......
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();
    ......
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        // 参数检查
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }
        // 获取 WindowManager.LayoutParams
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            ......
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            ......
            // mViews 中查找新添加 DecorView
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    ......
                } else {
                    // 已经添加过,抛出 IllegalStateException 异常
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // 从 mViews 中找到 panelParentView
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }
            // 创建 ViewRootImpl 对象
            root = new ViewRootImpl(view.getContext(), display);
            // DecorView 设置 LayoutParams
            view.setLayoutParams(wparams);
            // 向容器中添加各种对象
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        try {
            // ViewRootImpl 设置 DecorView
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ......
        }
    }
    ......
}

现在重点关注 ViewRootImpl setView(…) 方法:

  1. 调用 requestLayout() 请求 layout
  2. 远程调用 Session addToDisplay 方法添加 W 对象,W 对象在构造的时候传入了 ViewRootImpl 对象

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ......
    final W mWindow;
    ......
    // Surface 对象创建
    final Surface mSurface = new Surface();
    ......
    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();

        mDisplayAdjustments = display.getDisplayAdjustments();

        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
        mTempRect = new Rect();
        mVisRect = new Rect();
        mWinFrame = new Rect();
        mWindow = new W(this);
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mViewVisibility = View.GONE;
        mTransparentRegion = new Region();
        mPreviousTransparentRegion = new Region();
        mFirst = true; // true for the first time the view is added
        mAdded = false;
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAccessibilityInteractionConnectionManager =
            new AccessibilityInteractionConnectionManager();
        mAccessibilityManager.addAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager);
        mHighContrastTextManager = new HighContrastTextManager();
        mAccessibilityManager.addHighTextContrastStateChangeListener(
                mHighContrastTextManager);
        mViewConfiguration = ViewConfiguration.get(context);
        mDensity = context.getResources().getDisplayMetrics().densityDpi;
        mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
        mChoreographer = Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        loadSystemProperties();
    }
    ......
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ......
                // 安排第一次 layout,在添加到 WMS 之前
                // 确保在从系统接收任何其他事件之前进行重新布局
                requestLayout()
                ......
                try {
                    ......
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    ......
                } finally {
                    ......
                }
                ......
            }
        }
    }
    ......
    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;
        }
        ......
    }
    ......
}

requestLayout() 方法主要调用了 scheduleTraversals() 进一步处理,后续详细分析。

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ......
    boolean mHandlingLayoutInLayoutRequest = false;
    ......
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    ......
}

现在开始关注 Session 类 addToDisplay 方法。

Session 类表示活动的客户端会话。通常,每个与窗口管理器交互的进程都有一个 Session 对象。

addToDisplay 方法实际工作由 WindowManagerService 类 addWindow 方法完成。

frameworks/base/services/core/java/com/android/server/wm/Session.java

final class Session extends IWindowSession.Stub
        implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    ......
    @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);
    }
    ......
}

addWindow 方法首先创建了 WindowState 对象,然后调用了其 attach() 方法进行附着,最后将其添加到了 mWindowMap 中。attach() 以后的流程在接下来的文章中详细分析。

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    ......
    // 从 IWindow IBinder 映射到服务端的 Window 对象(WindowState)。
    final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
    ......
    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 attachedWindow = null;
        ......
        synchronized(mWindowMap) {
            ......
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            ......
            // From now on, no exceptions or errors allowed!
            res = WindowManagerGlobal.ADD_OKAY;
            ......
            win.attach();
            mWindowMap.put(client.asBinder(), win);
            ......
        }
        ......
    }
    ......
}

写在最后画时序图总结一下。

Android 源码 图形系统之窗口添加_第2张图片

你可能感兴趣的:(Android源码)