本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Android 10原理机制系列_Activity窗口添加到WMS过程
talkchan · 608浏览 · 发布于2020-12-08 +关注

前言

首先看一个Android界面的布局层次结构,最直观的看一下:

ui_hierarchyviewer

我们能清晰看到,这个界面分成了3部分:顶部状态栏(statusbar)、底部导航栏(navigationbar)、应用界面。

题外话:
查看布局的层次结构,工具或途径可以参考下面的。
Android Studio:Tools->Layout Inspector->选择要查看的进程;
SDK Tools:tools/hierarchyviewer.bat。 不过最新推荐用tools/monitor.bat代替单独的hierarchyviewer.bat;hierarchyviewer.bat在工程目录下也存在prebuilts/devtools/tools

该篇主要介绍Activity中窗口的创建过程 以及 添加到WMS的过程。
第二部分 综述总结,先将上述两个过程的内容做了比较简洁的总结。
第三部分 Activity窗口添加过程,跟踪源码详细 讲述了 Activity窗口的创建过程 以及 添加到WMS过程。
由于第三部分 跟踪源码,这个过程比较长,涉及比较多,相对枯燥。所以把总结先放到了第二部分。这样,如果了解过源码或这个过程的,可以只看第二部分。没了解过的,也可以通过第二部分有个大概了解,再查看第三部分,若遇到不太清楚的部分,可以再回到第二部分,对比理解。

该篇也是基于Android10的源码。
若有不对或不足,欢迎指点。

综述总结

前言已经介绍了为什么将总结放在了前面。下面具体看下。

第二部分,主要介绍了下面几个内容:

  • Window类型:窗口类型介绍

  • 几个重要类:窗口创建添加到WMS过程中常见的一些类,了解下他们之间的关系

  • Activity创建窗口添加到WMS综述:简单总结了下 Activity的创建过程 和 添加到WMS过程

  • Activity中的一些结构示意图:整个过程,Activity中关联的一些类/结构的 关系,理解这个个人觉得很有必要

  • Token传递到WMS:Token是很重要的参数,参与整个过程。这里将该篇涉及的过程中的 Token的传递过程单独总结了下

Window类型

//WindowManager.javapublic static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {    public static final int FIRST_APPLICATION_WINDOW = 1;    public static final int LAST_APPLICATION_WINDOW = 99;    
    public static final int FIRST_SUB_WINDOW = 1000;    public static final int LAST_SUB_WINDOW = 1999;    
    public static final int FIRST_SYSTEM_WINDOW = 2000;    public static final int LAST_SYSTEM_WINDOW = 2999;    //状态栏
    public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;    //搜索栏
    public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;    //来电显示
    public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;    //警告窗口,常见如:低电量警告
    public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;    //锁屏
    public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;    //toast
    public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;    public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;//显示在所有窗口之上,覆盖
    //来电优先,即使锁屏状态下
    public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;    //输入法窗口
    public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;    //壁纸
    public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
}

应用窗口(1 ~ 99): FIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW。对应一个Activity,token需设置成Activity的token。 如:Activity。
子窗口(1000 ~ 1999): FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW。必须要有一个父窗口,token需设置成父窗口的token。 如:PopupWindow,依附于Activity。
系统窗口(2000 ~ 2999): FIRST_SYSTEM_WINDOW ~ LAST_SYSTEM_WINDOW。系统级的 不需要对应Activity 也不需要有父窗口,应用进程一般没有权限创建,只有系统进程可以创建。如:上面列出了部分常见的系统窗口,状态栏、来电、toast、输入法等等。

几个重要类

下面几个类是后续经常看到的,这里主要看下他们直接的继承关系,后面看到比较容易理解。

public abstract class Window {}public class PhoneWindow extends Window implements MenuBuilder.Callback {}public interface WindowManagerPolicy extends WindowManagerPolicyConstants {}public class PhoneWindowManager implements WindowManagerPolicy {}public interface ViewManager {    public void addView(View view, ViewGroup.LayoutParams params);    public void updateViewLayout(View view, ViewGroup.LayoutParams params);    public void removeView(View view);
}public interface WindowManager extends ViewManager {}public final class WindowManagerImpl implements WindowManager {}/** A window in the window manager. */class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {}
  1. Window是一个抽象类,Activity、Toast、Dialog等都是靠Window来呈现。
    PhoneWindow是Window的具体实现类(几乎是唯一实现类)。

  2. WindowManager是个接口,继承接口 ViewManager(ViewManager定义了3个操作:增加、更新、移除)。
    WindowManagerImpl是WindowManager的实现类。
    不过查看WindowManagerImpl中 关于ViewManager的3个操作可以看出,这3个实现 最终是交由WindowManagerGlobal完成的。

  3. WindowState维护着窗口的所有信息。WMS通过WindowState对窗口进行管理、保存状态等。

Activity创建窗口添加到WMS综述

这是跟踪的代码过程,这里汇总下 方便后续查看理解。 红色是比较主要的几个节点方法。
wms_activity_window

//attach()-performLaunchActivity()
--activity.attach()//创建了PhoneWindow(mWindow)。mWindowManager保存的是 从mWindow处获取的 setWindowManager()创建的WindowManagerImpl---mWindow.setWindowManager()//PhoneWindow内部 创建了WindowManagerImpl(mWindowManager),并保存了appToken、appName。//onCreate()-setContentView()
--installDecor()
---generateDecor()//创建了DecorView(mDecor)---generateLayout()//将activity的布局作为子视图(ViewGroup)添加到mDecor中//onResume()-r.activity.makeVisible()//--wm.addView(mDecor, ...)//wm即mWindowManager(WindowManagerImpl对象)---WindowManagerGlobal.addView()//创建了ViewRootImpl。addView的view是mDecor,ViewRootImpl中创建了mWindow(这里是一个IBinder,而非attach()中创建的)----ViewRootImpl.setView()//openSession()创建了Session(IWindowSession的代理类),view也是mDecor。mDecor传入到ViewRootImpl的mView-----Session.addToDisplay()//通过Session进入system_server进程------mService.addWindow()//进入WMS,执行addWindow()添加窗口

attach阶段:
一个Activity 创建了一个PhoneWindow对象 ,PhoneWindow通过setWindowManager() 创建了WindowManagerImpl 。
即Activity 对应一个PhoneWindow,并得到了一个WindowManager(WindowManagerImpl,Window创建的)。
onCreate阶段:
创建了DecorView ,并将 activity的布局添加到DecorView中 。
onResume阶段:
创建了ViewRootImpl,通过setView()最终由Session进入system_server进程。最终执行addWindow添加窗口到WMS。

Activity中的一些结构示意图

下面是我学习总结中 根据理解画的,方便自己查看时一眼可得。
(若有什么不对,多谢指点)

wms_actui_layout

public final class WindowManagerImpl implements WindowManager {    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
}public final class WindowManagerGlobal {    private static IWindowManager sWindowManagerService;//WMS客户端,
    private static IWindowSession sWindowSession;//Session
    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>();
}
  1. 一个Activity对应了一个PhoneWindow对象。即 每个Activity对应一个Window (具体实现类是PhoneWindow)。

  2. 一个PhoneWindow 持有一个 DecorView 实例, DecorView实际是一个FrameLayout,它是Activity中所有View的根(最顶层的View)。

  3. 一个PhoneWindow有一个WindowManagerImpl。WindowManagerImpl持有一个单例WindowManagerGlobal。

Token传递到WMS

Activity启动时 AMS会为其创建一个ActivityRecord。可以参考:AMS之应用的第一次启动过程。

下面先看下ActivityRecord中关于token的几处代码:

final class ActivityRecord extends ConfigurationContainer {    final IApplicationToken.Stub appToken; // window manager token
    // TODO: Remove after unification
    AppWindowToken mAppWindowToken;
        
    ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,...) {
        appToken = new Token(this, _intent);
    }    
    void createAppWindowToken() {
        mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken,...);
    }    
    static class Token extends IApplicationToken.Stub {
        Token(ActivityRecord activity, Intent intent) {
            weakActivity = new WeakReference<>(activity);
            name = intent.getComponent().flattenToShortString();
        }
    }
}

ActivityRecord中的成员变量 appToken ,这个很重要,后续很多地方会一直涉及到。

ActivityRecord中有个 appToken ,其是一个IBinder(内部类Token继承了IApplicationToken接口)。Token内部持有Activity的弱引用。
在ActivityRecord中会通过createAppWindow()创建并保存 AppWindowToken对象 到mAppWindowToken。
mAppWindowToken:这个appToken会被封装在其中。路径:ActivityStack.startActivityLocked()->ActivityRecord.createAppWindowToken()。AppWindowToken是WindowToken子类。WindowToken可以标志一个窗口。

这个appToken,会在Activity.attach()中作为参数传递到Activity。
Activity保存到mToken。
然后通过 Activity.attach()->mWindow.setWindowManager() 传入到Window(PhoneWindow)中。
Window保存到mAppToken。
WindowManagerGlobal.addView()->Window.adjustLayoutParamsForSubWindow()保存到WindowManager.LayoutParams中的token变量中。
最后WindowManager.LayoutParams(其中token即ActivityRecord中的appToken)作为参数传入ViewRootImpl.setView()。
ViewRootImpl中mWindowAttributes拷贝了WindowManager.LayoutParams,作为参数通过Session.addToDisplay()传入WMS中,进行后续操作。

这是整个添加窗口(到addWindow())过程 appToken参与的过程及传递过程。
appToken如何参与窗口的添加,这个在 “第三部分的2.8:mService.addWindow()” 注释中能大致看到,比较详细。


Activity窗口添加过程

这里主要介绍 Activity对应Window的创建 以及 Window添加到WMS的过程。

Activity窗口创建

在 AMS之应用的第一次启动过程 中,从点击应用图标到activity创建并执行onCreate()。 下面部分是后面部分的截取,不清楚可以参考下那篇文章。

1.1:handleLaunchActivity()

这里从handleLaunchActivity()开始。

//ActivityThread.java@Overridepublic Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    ...
    WindowManagerGlobal.initialize();    final Activity a = performLaunchActivity(r, customIntent);
    ...
}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
    }    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);        if (activity != null) {
            Window window = null;
            ...            //attach(),注意这个r.token。参考1.2
            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,
                    r.assistToken);            if (r.isPersistable()) {                //callActivityOnCreate() 最终执行到的activity的onCreate()方法。  
                //参考1.4
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
        }
    }
    ...    return activity;
}

WindowManagerGlobal.initialize();是获取WMS的IBinder代理类,用于与WMS通信。这里不列出代码了。
接着要看的是activity.attach()。注意作为参数传入attach()的 r.token 是个IBinder,来自ActivityClientRecord,简单看标识了一个Activity。

1.2:activity.attach()

//Activity.javafinal void attach(Context context, ActivityThread aThread,
       Instrumentation instr, IBinder token, ...) {
    ...    //创建PhoneWindow
    mWindow = new PhoneWindow(this, window, activityConfigCallback);//创建PhoneWindow 
    //设置软键盘
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }    //token保存到mToken。        
    mToken = token;
    ...    //mToken传入到Window,参考1.3
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);    //mWindowManager即setWindowManager()中创建的WindowManagerImpl。
    mWindowManager = mWindow.getWindowManager();
    ...
}

首先创建了Activityd对应的Window,是PhoneWindow-Window的实现类。 接着看mWindow.setWindowManager()。

1.3:mWindow.setWindowManager()

//Window.javapublic void setWindowManager(WindowManager wm, IBinder appToken, String appName,        boolean hardwareAccelerated) {    //ActivityClientRecord.token
    mAppToken = appToken;
    mAppName = appName;
    mHardwareAccelerated = hardwareAccelerated;    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }    //创建了WindowManagerImpl,注意WindowManagerImpl中mParentWindow是this,非空
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

这里创建了WindowManagerImpl对象,即WindowManager的实现类。并保存了appToken、appName、mWindowManager。
通过setWindowManager(),即为Window(或者PhoneWindow)设置创建了WindowManager(WindowManagerImpl)。

1.4:setContentView()

mInstrumentation.callActivityOnCreate()最终有调用到Activity的onCreate()。
自定义Activity,设置布局都执行了setContentView(),下面直接来看下这个方法。

//Activity.javapublic void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);//
    initWindowDecorActionBar();
}public Window getWindow() {    return mWindow;//即PhoneWindow对象}//PhoneWindow.java// This is the top-level view of the window, containing the window decor.private DecorView mDecor;@Overridepublic 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);
    }
    ...
}private void installDecor() {
    mForceDecorInstall = false;    if (mDecor == null) {        //生成DecorView,参考1.5
        mDecor = generateDecor(-1);
        ...
    } else {
        mDecor.setWindow(this);
    }    if (mContentParent == null) {        //布局添加到DecorView,参考1.5
        mContentParent = generateLayout(mDecor);        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
        mDecor.makeOptionalFitsSystemWindows();        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);        if (decorContentParent != null) {
        } else {
            mTitleView = findViewById(R.id.title);
        }
        ...
    }
}

这里主要关注下两个方法:mDecor = generateDecor(-1); 和 mContentParent = generateLayout(mDecor);。
先看下他们的相关代码:

1.5:generateDecor()和generateLayout()

protected DecorView generateDecor(int featureId) {    // System process doesn't have application context and in that case we need to directly use
    // the context we have. Otherwise we want the application context, so we don't cling to the
    // activity.
    Context context;
    ...    return new DecorView(context, featureId, this, getAttributes());//}public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
}protected ViewGroup generateLayout(DecorView decor) {
    ...
    mDecor.startChanging();
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    ...
    mDecor.finishChanging();    return contentParent;
}//DecorView.javavoid onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
    ...
    mDecorCaptionView = createDecorCaptionView(inflater);    final View root = inflater.inflate(layoutResource, null);    if (mDecorCaptionView != null) {        if (mDecorCaptionView.getParent() == null) {
            addView(mDecorCaptionView,                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mDecorCaptionView.addView(root,                new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
    } else {        // Put it below the color views.
        addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }
    mContentRoot = (ViewGroup) root;
    initializeElevation();
}

通过generateDecor()创建了一个DecorView。DecorView实际是一个FrameLayout。
然后通过generateLayout(),最终将activity的布局作为子视图(ViewGroup)添加到DecorView中。

上面可以看到,activity生成到执行onCreate(),这个过程,activity生成了关联的PhoneWindow,然后创建了WindowManagerImpl、DecorView。
下面看下Window添加到WMS的过程,看这些创建的对象之前如何联系 形成的一开始介绍的结构示意图。

Window添加到WMS过程

在 AMS之应用的第一次启动过程 中主要讲到onCreate,其实onResume也在其中在,这里不详细解释了,再次列出相关代码:

//ActivityStackSupervisor.java:boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,        boolean andResume, boolean checkConfig) throws RemoteException {
    ...    try {
        ...        try {            // Create activity launch transaction.
            final ClientTransaction clientTransaction = ClientTransaction.obtain(
                    proc.getThread(), r.appToken);            final DisplayContent dc = r.getDisplay().mDisplayContent;
            clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
            ...            // Set desired final state.
            final ActivityLifecycleItem lifecycleItem;            if (andResume) {
                lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
            } else {
                lifecycleItem = PauseActivityItem.obtain();
            }
            clientTransaction.setLifecycleStateRequest(lifecycleItem);            // Schedule transaction.
            mService.getLifecycleManager().scheduleTransaction(clientTransaction);
            ...
        } 
    }
    ...    return true;
}

通过 LaunchActivityItem 关联 最终执行结果是创建了应用的Activity 并 执行了attach()和onCreate()。 andResume为true(传入的参数为true,可以参考那篇这段代码往前看), 通过 ResumeActivityItem 关联 最终执行到的是 ActivityThread.handleResumeActivity()。

这里从ActivityThread.handleResumeActivity()来看。

2.1:ActivityThread.handleResumeActivity()

//ActivityThread.java@Overridepublic void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    ...    // TODO Push resumeArgs into the activity for consideration
    //执行onStart()->onResume()。参考2.2
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);    final Activity a = r.activity;    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        ...
    } 
    ...    // The window is now visible if it has been added, we are not
    // simply finishing, and we are not starting another activity.
    if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
        ...
        r.activity.mVisibleFromServer = true;
        mNumVisibleActivities++;        if (r.activity.mVisibleFromClient) {            //参考2.3
            r.activity.makeVisible();
        }
    }
    ...
}

注意 View decor = r.window.getDecorView(); 获取了DecorView对象,最后通过 a.mDecor = decor; 将DecorView赋到了Activity中。
这里关注两个:
performResumeActivity()
r.activity.makeVisible();

2.2:performResumeActivity()

//ActivityThread.java@VisibleForTestingpublic ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,        String reason) {
    final ActivityClientRecord r = mActivities.get(token);
    ...    try {
        r.activity.onStateNotSaved();
        r.activity.mFragments.noteStateNotSaved();
        ...
        r.activity.performResume(r.startsNotResumed, reason);

        r.state = null;
        r.persistentState = null;
        r.setState(ON_RESUME);

        reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
    } 
    return r;
}//Activity.javafinal void performResume(boolean followedByPause, String reason) {
    performRestart(true /* start */, reason);
    mInstrumentation.callActivityOnResume(this);
}

final void performRestart(boolean start, String reason) {
    mInstrumentation.callActivityOnRestart(this);
}//Instrumentation.javapublic void callActivityOnRestart(Activity activity) {
    activity.onRestart();
}public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();
    ...
}

performResumeActivity()中 r.activity.performResume()回调Activity的performResume()方法。最终执行了Activity的onResume()方法。
performResume()在执行onResume前,调用了performRestart(),最终调用的是activity的onStart()。这里可以看出 onStart()执行在onResume()之前。

2.3:r.activity.makeVisible()

//Activity.javavoid makeVisible() {    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}//WindowManagerImpl.javapublic final class WindowManagerImpl implements WindowManager {    @UnsupportedAppUsage
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);        //mParentWindow即创建WindowManagerImpl是 传入的。参考2.4
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
}

这里的getWindowManager()获取到的是前面讲到的 attach()时通过setWindowManager()创建的WindowManagerImpl对象。
前面也讲过,addView()等3个操作定义实现 最终在WindowManagerGlobal中,这里就可以看到。

2.4:WindowManagerGlobal.addView()

//WindowManagerGlobal@UnsupportedAppUsageprivate final ArrayList<View> mViews = new ArrayList<View>();@UnsupportedAppUsageprivate final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ...    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;    if (parentWindow != null) {        //调整Window参数,这个过程将token设置其中了
        //参考2.4.1
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } 
    ...
    ViewRootImpl root;
    View panelParentView = null;    synchronized (mLock) {
        ...
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);        try {            //将view及相关参数设置到ViewRootImpl中。ViewRootImpl会向WMS添加新窗口、申请Surface及绘制工作等。
            //参考2.6
            root.setView(view, wparams, panelParentView);
        } 
        ...
    }
}//ViewRootImpl.java@UnsupportedAppUsagefinal IWindowSession mWindowSession;public ViewRootImpl(Context context, Display display) {
    mContext = context;    //创建了Session(),参考2.5
    mWindowSession = WindowManagerGlobal.getWindowSession();
    mDisplay = display;
    mBasePackageName = context.getBasePackageName();
    mThread = Thread.currentThread();
    mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;    //这里的mWindow不是前面Activity中的PhoneWindow,它是W extends IWindow.Stub
    mWindow = new W(this);
    mViewVisibility = View.GONE;    //创建AttachInfo
    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
    ...
}static class W extends IWindow.Stub {...}//ViewRootImpl.javapublic final class ViewRootImpl implements ViewParent,

//View.javafinal static class AttachInfo {
    AttachInfo(IWindowSession session, IWindow window, Display display,
            ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
            Context context) {
        mSession = session;
        mWindow = window;
        mWindowToken = window.asBinder();
        mDisplay = display;
        mViewRootImpl = viewRootImpl;
        mHandler = handler;
        mRootCallbacks = effectPlayer;
        mTreeObserver = new ViewTreeObserver(context);
    }
}

这里主要看到,创建了ViewRootImpl对象。这个类实现了View与WindowManager之间必要的协议。
注意创建中的mWindow = new W(this);,这个W继承IWindow.Stub。

创建ViewRootImpl对象时 创建了一个mAttachInfo = View.AttachInfo(), AttachInfo是一系列绑定信息。mWindowSession、mWindow作为参数传入。AttachInfo创建时注意mWindowToken = window.asBinder();。
mWindowSession在后续2.5/2.6/2.7中讲到,它是Session对象,它是IWindowSession的代理类,通过他可以与WMS通信的binder接口。
mWindow这里是W对象,它是IWindow.Stub,通过new创建,后续能看到会传入WMS,它是WMS回调应用(与应用通信)的binder接口。
mWindowToken,也就是W的IBinder对象,也是WMS与应用通信的接口。

创建ViewRootImpl对象后,WindowManagerGlobal将View、ViewRootImpl、LayoutParams保存到相应的ArrayList中。前面也讲到过,WindowManagerGlobal是单例的,应用进程中只有一个。最后通过root.setView()将View(这里是DecorView)传入到ViewRootImpl中。

2.4.1:adjustLayoutParamsForSubWindow()

前面看到mAppToken是从Activity的传入的。
这里mAppToken被设置到WindowManager.LayoutParams里,后面可以看到最终传入到WMS参与处理。

//Window.javavoid adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
    CharSequence curTitle = wp.getTitle();    //子窗口,该篇中是应用窗口,所以不走这,也了解下。       
    if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
            wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {        if (wp.token == null) {
            View decor = peekDecorView();            if (decor != null) {
                wp.token = decor.getWindowToken();
            }
        }
        ...    //系统窗口,也不走这
    } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
            wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
        ...    //应用窗口,该篇走这
    } else {        if (wp.token == null) {            //设置到了WindowManager.LayoutParams中
            wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
        }
        ...
    }
    ...
}

2.4.2:AttachInfo在其中了解下

ViewRootImpl与各个View。通过下面的过程,AttachInfo绑定信息被设置到各个View中了,即各个View能够获取到各种相关信息。
2.6执行到ViewRootImpl.setView()后,参考过程:setView()->requestLayout()->scheduleTraversals()->mTraversalRunnable->doTraversal()->performTraversals()->host.dispatchAttachedToWindow(mAttachInfo, 0)->View.dispatchAttachedToWindow()->ViewGroup.dispatchAttachedToWindow()。
属同个ViewGroup的 AttachInfo是一样的。

//ViewGroup.java@Override@UnsupportedAppUsagevoid dispatchAttachedToWindow(AttachInfo info, int visibility) {
    mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;    super.dispatchAttachedToWindow(info, visibility);
    mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;    final int count = mChildrenCount;    final View[] children = mChildren;    for (int i = 0; i < count; i++) {        final View child = children[i];
        child.dispatchAttachedToWindow(info,
                combineVisibility(visibility, child.getVisibility()));
    }    final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();    for (int i = 0; i < transientCount; ++i) {
        View view = mTransientViews.get(i);
        view.dispatchAttachedToWindow(info,
                combineVisibility(visibility, view.getVisibility()));
    }
}
}

上述过程 performTraversals() 大致了解下:从上而下遍历视图树,每个View绘制自己,ViewGroup通知子View进行绘制。测量performMeasure() 执行布局performLayout() 绘制performDraw()。
Android绘制 重要的部分就在这里,需要了解的可以仔细研究下这个方法(performTraversals()),这里不作关注。

2.5:WindowManagerGlobal.getWindowSession()

// WindowManagerGlobal.java   @UnsupportedAppUsagepublic static IWindowSession getWindowSession() {    synchronized (WindowManagerGlobal.class) {        if (sWindowSession == null) {            try {
                InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                IWindowManager windowManager = getWindowManagerService();                //创建Session对象
                sWindowSession = windowManager.openSession(                        new IWindowSessionCallback.Stub() {                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        });
            } catch (RemoteException e) {                throw e.rethrowFromSystemServer();
            }
        }        return sWindowSession;
    }
}//WindowManagerService.java@Overridepublic IWindowSession openSession(IWindowSessionCallback callback) {    return new Session(this, callback);
}

获取Sessiond对象,如果没有则通过 windowManager.openSession() 创建。Session是IWindowSession的代理类,然后返回给ViewRootImpl中的mWindowSession。

2.6:ViewRootImpl.setView()

//ViewRootImpl.javapublic void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {    synchronized (this) {        if (mView == null) {
            mView = view;
            mWindowAttributes.copyFrom(attrs);
            ...            // 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();//TODO
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();                //参考2.7,进入system_server进程
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                        mTempInsets);
                setFrame(mTmpFrame);
            }
            ...
        }
    }
}

res = mWindowSession.addToDisplay():mWindowSession是上面返回的创建的Session,mWindowSession.addToDisplay()即通过binder进入system_server进程,执行的Session.addToDisplay()。
mView即DecorView。
这里的mWindow是2.4中讲到的,是 W 继承IWindow.Stub。这是一个IBinder对象,在应用进程创建ViewRootImpl时被创建。
这里mWindowSession.addToDisplay()往后可以看到被传入到WMS。

2.7:Session.addToDisplay()

//Session.javaclass Session extends IWindowSession.Stub implements IBinder.DeathRecipient {    final WindowManagerService mService;    public Session(WindowManagerService service, IWindowSessionCallback callback) {
        mService = service;
        ...
    }    @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) {        //参考2.8
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
                outInsetsState);
    }
}

进入WMS,添加Window。

2.8:mService.addWindow()

终于到最后WMS.addWindow(),这里完成窗口添加。可以仔细看下下面源码及注释,这个方法即使缩减了很多还是比较长,需要耐心。

//WindowManagerService.javapublic int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState) {    int[] appOp = new int[1];    //检查权限,无权限不能添加窗口
    int res = mPolicy.checkAddPermission(attrs, appOp);    if (res != WindowManagerGlobal.ADD_OKAY) {        return res;
    }    boolean reportNewConfig = false;
    WindowState parentWindow = null;
    ...    final int type = attrs.type;    synchronized (mGlobalLock) {
        ...        //获取窗口要添加到的DisplayContent。即显示在哪个屏幕上
        final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);        
        if (displayContent == null) {
            Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                    + displayId + ".  Aborting.");            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }        if (!displayContent.hasAccess(session.mUid)) {
            Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
                 &n                
                
                        
					
                
                

相关推荐

android下vulkan与opengles纹理互通

talkchan · 1174浏览 · 2020-11-23 10:37:39
Android 使用RecyclerView实现轮播图

奔跑的男人 · 2172浏览 · 2019-05-09 17:11:13
微软发布新命令行工具 Windows Terminal

吴振华 · 867浏览 · 2019-05-09 17:15:04
Facebook 停止屏蔽部分区块链广告

· 753浏览 · 2019-05-09 17:20:08
加载中

0评论

评论
大家好,我是一名专注技术开发的技术屌丝,有什么问题可以互相交流,一起学习进步,谢谢。
分类专栏
小鸟云服务器
扫码进入手机网页