1.Window WindowManager WindowManagerService

启动一个Activity
startActivity
最终会走到ActivityThread的performLaunchActivity
这个函数里面会经过层层深入会调用 Activity 的 OnCreate() 方法,而在 performLaunchActivity() 中调 OnCreate() 方法前会调用 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, IBinder assistToken) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
      //创建PhoneWindow,并设置回调
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(mWindowControllerCallback);
        mWindow.setCallback(this);
        
        //将window跟windowmanager绑定

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
       
        //设置管理window的windowmanager
        mWindowManager = mWindow.getWindowManager();
        

继续看Window源码setWindowManager

/**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

这里没有理解清楚是如何获取wms
该方法里面可以看到如果传入的 wm 为空则将其重新赋值。这里其实是获取了 WindowManagerService 的代理,因为 WindowManagerService 和 Activity 所在的应用不在一个进程里,这里是通过 Binder 通信获取的一个 WindowManagerService 代理。获取完 WindowManagerService 代理后通过它来创建出一个真正要用的 WindowManager 并赋值。即这句代码:

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);


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

这里主要就是获取一个WindowManagerImpl

attatch主要创建出activity的window绑定windowmanager,从而获取管理当前window的windowmanager,但是并没有将activity的view添加到window

  • 继续看setContentView
public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

查看PhoneWindow源码setContentView

public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

主要关注installDecor()

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
       
    }

通过源码得知,如果当前DecorView为空,那么就创建一个,并且跟window进行绑定,DecorView 是 Activity 中的顶级 View,是一个 FrameLayout。
不过现在仍然没有将对应的画面展示到手机屏幕上

Window 加入到 WindowManager 这一过程要在调用完 Acitivy 的 onResume() 方法后来实现,之后会调用 Activity 的 makeVisible():

/**
     * Control whether this activity's main window is visible.  This is intended
     * only for the special case of an activity that is not going to show a
     * UI itself, but can't just finish prior to onResume() because it needs
     * to wait for a service binding or such.  Setting this to false allows
     * you to prevent your UI from being shown during that time.
     *
     * <p>The default value for this is taken from the
     * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
     */
    public void setVisible(boolean visible) {
        if (mVisibleFromClient != visible) {
            mVisibleFromClient = visible;
            if (mVisibleFromServer) {
                if (visible) makeVisible();
                else mDecor.setVisibility(View.INVISIBLE);
            }
        }
    }

void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

这个函数里首先判断 Window 是否已经添加到 WindowManager 中,没有的话取出在刚刚 attach() 方法中创建的 WindowManager,将 DecorView 加入进去,这里的 DecorView 其实就是 Window 所持有那个。然后再将 DecorView 设置为显示状态,来显示我们的布局。

  • 至此,我们需要关心WindowManager是如何进行管理Window
    在实际使用中无法直接访问 Window,对 Window 的访问必须通过 WindowManager。我们已经知道 WindowManager 提供的三个接口方法 addView、updateViewLayout 以及 removeView 都是针对 View 的,而这些 View 都被其对应的 Window 所持有,所以上面这些操作实际上相当于对 Window 的操作,WindowManager 是一个接口,它的真正实现由上文可知是 WindowManagerImpl 类。
 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

可以知道,实际是交给了mGlobal进行处理,也就是WindowManagerGlobal

  • 继续看WindowManagerGlobal源码的几个核心参数
  //存储的是所有 Window 所对应的 View
    private final ArrayList<View> mViews = new ArrayList<View>();
   //mRoots 存储的是所有 Window 所对应的 ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
   //mParams 存储的是所有 Window 所对应的布局参数
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
//mDyingViews 存储了那些正在被删除的 View 对象,或者说是那些已经调用了 removeView 方法但是操作删除还未完成的 Window 对象
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

在 addView () 方法中将这些相关对象添加到对应集合中。最后调用 root.setView() 方法,setView() 中会调用一个很重要的方法 requestLayout(),其主要是用来刷新页面,其中还有一个很重要的方法 addToDisplay

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

@Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
            Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
             outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
             outInsetsState);
    }

mWindowSession 的类型是 IWindowSession,它是一个 Binder 对象,真正的实现类是 Session,这也就是之前提到的 IPC 调用的位置。也就是说在这里,完成了 WindowManager 和 WindowManagerService 的通信,将 Window 信息传给了WindowManagerService。

至此,得出结论setView() 方法里面会通过 mWindowSession 这个 Binder 对象将 Window 传给 WindowManagerService。WindowManagerService 来管理各个 Window 的大小和显示位置,来让 SurfaceFlinger 渲染。


image.png

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容