分析Activity创建到显示的过程,理解Window、WindowManager、WindowManagerService之间的关系

基于android8.0-26分析

涉及到的类以及方法主要有下面这些:

  • ActivityThread:UI线程所在类,处理主线程上相关事务
    • performLaunchActivity:创建Activity并调用attach方法以及onCreate方法
    • performResumeActivity:调用Activity的performResume方法,内部会调用onResume方法,最后显示出来
  • Activity
    • attach:创建PhoneWindow,WindowManager的实现类WindowManagerImpl
    • onCreate:调用setContentView方法将用户布局添加进来
    • setContentView:调用PhoneWindow的setContentView方法
    • onContentChanged:当用户自定义布局添加到DecorView之后回调该方法
    • onResume:在DecorView添加到WindowManager之前调用
    • makeVisible:通过WindowManager的addView方法将DecorView添加并显示出来
  • Window:抽象类,用于定义窗口的一些样式行为规则
    • setWindowManager:通过WindowManager的createLocalWindowManager创建它的实现类WindowManagerImpl
  • PhoneWindow:继承自Window类,Android里唯一的窗口类
    • setContentView:调用installDecor方法,回调Activity的onContentChanged方法
    • installDecor:创建DecorView,将用户自定义布局保存到DecorView中id为R.id.content的ViewGroup下面
  • ViewManager:定义了添加、更新、删除窗口的接口
  • WindowManager:继承自ViewManager的接口,定义了窗口相关的属性LayoutParams
  • WindowManagerImpl:WindowManager的实现类
    • createLocalWindowManager:创建一个WindowManagerImpl实例
    • addView :调用WindowManagerGlobal的addView方法
    • updateViewLayout:调用WindowManagerGlobal的updateViewLayout方法
    • removeView:调用WindowManagerGlobal的removeView方法
  • WindowManagerGlobal
    • getInstance:获取WindowManagerGlobal的单例
    • getWindowSession:跨进程调用WindowManagerService的Session方法返回一个Session对象
    • getWindowManagerService:获取WindowMangerService的远程调用接口IWindowManager
    • addView :创建ViewRootImpl,并调用它的setView方法
    • updateViewLayout:获取ViewRootImpl,并调用它的setLayoutParams方法
    • removeView:调用ViewRootImpl的die方法
  • ViewRootImpl:介于View和WindowManager之间,实现了WindowManagerGlobal大部分功能
    • setView :调用了requestLayout方法,跨进程调用了Session的addToDisplay方法将Window添加
    • requestLayout:开始执行view的测量、布局、绘制流程
  • IWindowSession:AIDL实现的Binder类
  • Session:继承自IWindowSession,一般每个进程都有一个Session,相当于WindowManagerService的代理类
    • addToDisplay:调用WindowManagerService的addWindow方法
    • remove:调用WindowManagerService的removeWindow方法
  • WindowManagerService
    • openSession:返回一个Session对象
    • addWindow:添加窗口
    • removeWindow :移除窗口

Activity的启动是从ActivityThread这个类的handleLaunchActivity方法开始的,先来看看这个类的主要代码:

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 * 
 * {@hide}
 */
public final class ActivityThread {

	Instrumentation mInstrumentation;

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

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);//创建Activity并调用Acttivity各生命周期

        if (a != null) {
            .. ..
            //调用Activity的OnResume方法
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//处理Activity显示
          	.. ..
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            try {
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        .. ..
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);//通过反射创建Activity
            .. ..
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            .. ..
            if (activity != null) {
                .. ..
                //调用Activity的attach方法
                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);

				//调用Activity的onCreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                .. ..
                //调用Activity的OnStart方法
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                //调用Activity的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);
                    }
                }
                //调用Activity的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()");
                    }
                }
            }
            .. ..

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
            ActivityClientRecord r = mActivities.get(token);
            .. .. 
            r = performResumeActivity(token, clearHide, reason);
            .. .. 
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();//调用Activity的makeVisible方法
            }
    }

    public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
            ActivityClientRecord r = mActivities.get(token);
            .. .. 
            r.activity.performResume();
    }

}

This manages the execution of the main thread in an application process, scheduling and executing activities, broadcasts, and other operations on it as the activity manager requests.

根据源码对这个类的解释是:在一个应用程序进程里面管理着主线程里的事务,调度和执行所有的Activity和Broadcast,以及ActivityManager请求的其他操作。

在这个类里,Activity从启动到显示主要分两个步骤:
1、performLaunchActivity:创建Activity,并调用Activity的attach方法,接着调用onCreate方法
2、handleResumeActivity:调用Activity的performResume方法,让界面显示出来

在执行Activity的onCreate方法时,并不是直接调用activity的方法,而是通过Instrumentation的callActivityOnCreate方法间接调用,先来看看Instrumentation类是做什么的?

/**
 * Base class for implementing application instrumentation code.  When running
 * with instrumentation turned on, this class will be instantiated for you
 * before any of the application code, allowing you to monitor all of the
 * interaction the system has with the application.  An Instrumentation
 * implementation is described to the system through an AndroidManifest.xml's
 * <instrumentation> tag.
 */
public class Instrumentation {
	
    /**
     * Perform calling of an activity's {@link Activity#onCreate}
     * method.  The default implementation simply calls through to that method.
     *
     * @param activity The activity being created.
     * @param icicle The previously frozen state (or null) to pass through to onCreate().
     */
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);//调用Activity的performCreate方法,最终调用onCreate方法
        postPerformCreate(activity);
    }
  
}

Instrumentation这个类主要用于控制Activity各个生命周期的调用,可以用于自动化测试模拟系统调用Activity各个生命周期,以及用户操作。

接下来就是来到了Activity的attach方法:

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {

        private Thread mUiThread;//UI线程,也就是主线程
        private Window mWindow;//PhoneWindwo.java
        private WindowManager mWindowManager;//WindowManagerImpl
        ActivityThread mMainThread;//调用Activity的attach方法的那个ActivityThread

        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) {

        	attachBaseContext(context);
        	.. ..
        	mWindow = new PhoneWindow(this, window, activityConfigCallback);//创建PhoneWindow
        	.. ..
	        mWindow.setCallback(this);//指的是Window.Callback
	        
	        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
	            mWindow.setSoftInputMode(info.softInputMode);
	        }
	        if (info.uiOptions != 0) {
	            mWindow.setUiOptions(info.uiOptions);
	        }
	        mUiThread = Thread.currentThread();//主线程
	        mMainThread = aThread;
	        .. ..
	        //Window关联上WindowManager
	        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
	        .. ..
	        mWindowManager = mWindow.getWindowManager();//实际上得到的是WindowManagerImpl类

        }

        /**
	     * Set the activity content from a layout resource.  The resource will be
	     * inflated, adding all top-level views to the activity.
	     *
	     * @param layoutResID Resource ID to be inflated.
	     *
	     * @see #setContentView(android.view.View)
	     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
	     */
	    public void setContentView(@LayoutRes int layoutResID) {
	        getWindow().setContentView(layoutResID);//实际调用的是PhoneWindow的setContentView
	        initWindowDecorActionBar();//创建ActionBar
	    }
		//显示Activity界面
	    void makeVisible() {
	        if (!mWindowAdded) {
	            ViewManager wm = getWindowManager();
	            wm.addView(mDecor, getWindow().getAttributes());
	            mWindowAdded = true;
	        }
	        mDecor.setVisibility(View.VISIBLE);
	    }
}
  • 在Activity的attach方法中为Activity创建了PhoneWindow,然后关联了WindowManager;
  • 接着就是ActivityThread里调用了Activity的onCreate方法,在这个方法里,我们一般通过setContentView来给Activity设置界面布局文件;
  • 而在Activity的setContentView方法里实际上是调用了PhoneWindow的setContentView方法

PhoneWindow.java是继承与Window.java,先来看看Window类是做什么的?

/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */
public abstract class Window{
	/**
     * The ID that the main layout in the XML layout file should have.
     */
     //setContentView传进来的布局就是放在DecorView里这个id的ViewGroup下面
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

    private Callback mCallback;
    private final Context mContext;

    public Window(Context context) {
        mContext = context;
        .. ..
    }

     /**
     * Set the Callback interface for this window, used to intercept key
     * events and other dynamic operations in the window.
     *
     * @param callback The desired Callback interface.
     */
    public void setCallback(Callback callback) {
        mCallback = callback;
    }

	/**
     * Finds a view that was identified by the {@code android:id} XML attribute
     * that was processed in {@link android.app.Activity#onCreate}. This will
     * implicitly call {@link #getDecorView} with all of the associated
     * side-effects.
     * <p>
     * <strong>Note:</strong> In most cases -- depending on compiler support --
     * the resulting view is automatically cast to the target class type. If
     * the target class type is unconstrained, an explicit cast may be
     * necessary.
     *
     * @param id the ID to search for
     * @return a view with given ID if found, or {@code null} otherwise
     * @see View#findViewById(int)
     */
    @Nullable
    public <T extends View> T findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }
    /**
     * Retrieve the top-level window decor view (containing the standard
     * window frame/decorations and the client's content inside of that), which
     * can be added as a window to the window manager.
     *
     * <p><em>Note that calling this function for the first time "locks in"
     * various window characteristics as described in
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
     *
     * @return Returns the top-level window decor view.
     */
    public abstract View getDecorView();

	/**
     * Change the background of this window to a custom Drawable. Setting the
     * background to null will make the window be opaque. To make the window
     * transparent, you can use an empty drawable (for instance a ColorDrawable
     * with the color 0 or the system drawable android:drawable/empty.)
     *
     * @param drawable The new Drawable to use for this window's background.
     */
    public abstract void setBackgroundDrawable(Drawable drawable);

	/**
     * Convenience for
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}
     * to set the screen content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the screen.
     *
     * @param layoutResID Resource ID to be inflated.
     * @see #setContentView(View, android.view.ViewGroup.LayoutParams)
     */
    public abstract void setContentView(@LayoutRes int layoutResID);

	/**
     * 通知Activity窗口属性发生变化
     */
    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }


	/**
     * 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) {
        .. ..
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
	public interface Callback:{
		dispatchKeyEvent//分发键盘按键事件
		dispatchTouchEvent//分发触摸事件
		onAttachedToWindow//当跟Activity关联的Window添加到windowManager后回调
		onContentChanged//显示内容发生改变时回调
		onDetachedFromWindow//当window被移除时回调
		onWindowFocusChanged//当窗体焦点发生改变时回调	
	}
}

根据官方对类的描述可以知道:

  • Window是一个抽象的基类,它为顶层的窗口提供了样式和行为策略
  • 这个类的实例应该被用于顶层的视图添加到WindowManager
  • 它提供了标准的UI策略例如:窗口背景、标题区域、默认的按键处理等等
  • 这个类的唯一实现是PhoneWindo.java,所以要用到窗口的时候,只能实例化PhoneWindow
  • 定义了Window相关的回调接口,从回调的接口可以看到,它主要用于分发键盘、触摸事件以及其他Window相关操作方法的回调

然后再来看看Window的唯一实现类,PhoneWindow.java:

/**
 * Android-specific Window.
 * <p>
 * todo: need to pull the generic functionality out into a base class
 * in android.widget.
 *
 * @hide
 */
public class PhoneWindow extends Window implements MenuBuilder.Callback {
	// This is the top-level view of the window, containing the window decor.
	private DecorView mDecor;//Activity界面的根布局

	// This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    ViewGroup mContentParent;//setContentView方法传进来的布局是放在这个布局下面

    private boolean mUseDecorContext = false;

    /**
     * Constructor for main window of an activity.
     */
    public PhoneWindow(Context context, Window preservedWindow, ActivityConfigCallback activityConfigCallback) {
        this(context);
        // Only main activity windows use decor context, all the other windows depend on whatever
        // context that was given to them.
        mUseDecorContext = true;
    }

	@Override
    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)) {
            view.setLayoutParams(params);
            final Scene newScene = new Scene(mContentParent, view);
            transitionTo(newScene);
        } else {
            mContentParent.addView(view, params);//将setContentView传进来的View添加到R.id.content的布局下面
        }
        .. ..

        final Callback cb = getCallback();//这里的Callback就是Activity
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        .. ..
    }

    private void installDecor() {
    	if (mDecor == null) {
            mDecor = generateDecor(-1);//创建DecorView
            .. ..
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {//用户设置的Activity布局所在父类
            mContentParent = generateLayout(mDecor);
        }
    }

    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;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext().getResources());
                .. ..
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }

    protected ViewGroup generateLayout(DecorView decor) {
    	.. ..
    	ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//com.android.internal.R.id.content
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
        .. ..
        return contentParent;
    }

    @Override
    public final View getDecorView() {
        if (mDecor == null || mForceDecorInstall) {
            installDecor();
        }
        return mDecor;
    }

    @Override
    public final void setBackgroundDrawable(Drawable drawable) {
        if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
            mBackgroundResource = 0;
            mBackgroundDrawable = drawable;
            if (mDecor != null) {
                mDecor.setWindowBackground(drawable);
            }
            .. ..
        }
    }
}
  • PhoneWindow继承了Window.java类,并实现了setContentView方法
  • 在setContentView方法里首先创建了DecorView作为根布局,然后查找id为R.id.content的mContentParent并将传进来的View添加进去

接着就是在performResumeActivity方法中调用Activity的performResume以及makeVisible方法,也就是在Activity的生命周期onResume时Window还没添加到WindowManager

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}
  • 通过Activity的makeVisible方法我们可以看到,最后是通过ViewManager的addView方法将PhoneWindow添加进来;
  • 而getWindowManager()返回的是mWindowManager变量,是WindowManager类型的接口
  • WindowManager接口是继承ViewManager ,ViewManager 也是一个接口,定义了新增、更新、删除window的三个方法
/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager{
	/**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
/**
 * The interface that apps use to talk to the window manager.
 * </p><p>
 * Each window manager instance is bound to a particular {@link Display}.
 * To obtain a {@link WindowManager} for a different display, use
 * {@link Context#createDisplayContext} to obtain a {@link Context} for that
 * display, then use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code>
 * to get the WindowManager.
 * </p><p>
 * The simplest way to show a window on another display is to create a
 * {@link Presentation}.  The presentation will automatically obtain a
 * {@link WindowManager} and {@link Context} for that display.
 * </p>
 */
@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
	public void addView(View view, ViewGroup.LayoutParams params){}
    public void updateViewLayout(View view, ViewGroup.LayoutParams params){}
    public void removeView(View view){}

	public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
	}
}

通过上面Activity的attach方法里我们看到在创建PhoneWindow时调用了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) {
        .. ..
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

从代码可以看出最后得到WindowManager,是调用了WindowManagerImpl的createLocalWindowManager方法:

/**
 * Provides low-level communication with the system window manager for
 * operations that are bound to a particular context, display or parent window.
 * Instances of this object are sensitive to the compatibility info associated
 * with the running application.
 *
 * This object implements the {@link ViewManager} interface,
 * allowing you to add any View subclass as a top-level window on the screen.
 * Additional window manager specific layout parameters are defined for
 * control over how windows are displayed.  It also implements the {@link WindowManager}
 * interface, allowing you to control the displays attached to the device.
 *
 * <p>Applications will not normally use WindowManager directly, instead relying
 * on the higher-level facilities in {@link android.app.Activity} and
 * {@link android.app.Dialog}.
 *
 * <p>Even for low-level window manager access, it is almost never correct to use
 * this class.  For example, {@link android.app.Activity#getWindowManager}
 * provides a window manager for adding windows that are associated with that
 * activity -- the window manager will not normally allow you to add arbitrary
 * windows that are not associated with an activity.
 *
 * @see WindowManager
 * @see WindowManagerGlobal
 * @hide
 */
public final class WindowManagerImpl implements WindowManager {
	private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

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

	public void addView(View view, ViewGroup.LayoutParams params){
		.. ..
		mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
	}
    public void updateViewLayout(View view, ViewGroup.LayoutParams params){
    	.. ..
    	mGlobal.updateViewLayout(view, params);
    }
    public void removeView(View view){
    	.. ..
    	mGlobal.removeView(view, false);
    }
}

从代码上可以看出WindowManager的实现类是WindowManagerImpl,所以Activity中makeVisible方法实际上是调用了WindowManagerImpl 中的addView方法。
接着我们发现WindowManagerImpl的addView方法里啥都没有干,完全把任务交给了WindowManagerGlobal :

/**
 * Provides low-level communication with the system window manager for
 * operations that are not associated with any particular context.
 *
 * This class is only used internally to implement global functions where
 * the caller already knows the display and relevant compatibility information
 * for the operation.  For most purposes, you should use {@link WindowManager} instead
 * since it is bound to a context.
 *
 * @see WindowManagerImpl
 * @hide
 */
public final class WindowManagerGlobal {

 	public static void initialize() {
        getWindowManagerService();
    }

 	public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }
	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;
        }
    }
	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;
        }
    }
    
	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");
        }

       .. ..
        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);

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

Provides low-level communication with the system window manager for operations that are not associated with any particular context.
This class is only used internally to implement global functions where the caller already knows the display and relevant compatibility information for the operation.
For most purposes, you should use {@link WindowManager} instead since it is bound to a context.

从类的注释我们可以了解到:

  • WimdowManagerGlobal是为那些与具体Context无关的操作提供低级别的通讯与系统的WindowManager
  • 这个类只在内部实现全局功能,为那些调用者已经知道显示和相关兼容性信息的操作
  • 对于大多数情况,应该使用WindowManager而不是直接使用当前这个类,因为WindowManager已经绑定了Context

通过分析代码可以看到,在WindowManagerGlobal的addView方法里,先检查个传进来的参数是否合法,然后创建了一个ViewRootImpl对象,接着将View、参数、ViewRootImpl保存起来,最后调用了 ViewRootImpl的setView方法。我们再来看看ViewRootImpl关键代码:

/**
 * The top of a view hierarchy, implementing the needed protocol between View
 * and the WindowManager.  This is for the most part an internal implementation
 * detail of {@link WindowManagerGlobal}.
 *
 * {@hide}
 */
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
		
		final IWindowSession mWindowSession;
		final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
		final W mWindow;

		public ViewRootImpl(Context context, Display display) {
			mWindowSession = WindowManagerGlobal.getWindowSession();
			.. ..
			mWindow = new W(this);
		}

		/**
	     * We have one child
	     */
	    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	    	synchronized (this) {
	            if (mView == null) {
	                mView = view;
	                ... ...
	                // 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();
		            ... ...
		            try { 
		            	res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
		            } catch (RemoteException e) {
	                   	... ...
	                    throw new RuntimeException("Adding window failed", e);
                	}
	            }

	        }
	    }

	    void doDie() {
	    	.. ..
	    	if (mAdded) {
                dispatchDetachedFromWindow();
            }
	    }
	    
	    void dispatchDetachedFromWindow() {
	    	.. .. 
	    	try {
            	mWindowSession.remove(mWindow);
	        } catch (RemoteException e) {
	        }
	    }

	    void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
	    	.. ..
	    	scheduleTraversals();
	    }

	    @Override
		public void requestLayout() {
	        .. ..
	        scheduleTraversals();
		}

		void scheduleTraversals() {
	     	.. ..
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
	    }

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

	    void doTraversal() {
	    	.. ..
	        performTraversals();
	    }

	    private void performTraversals() {
	    	.. ..
	    	performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
	    	.. ..
	    	performLayout(lp, mWidth, mHeight);
	    	.. ..
	    	performDraw();

	    }

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

		    @Override
		    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
		            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
		            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
		            boolean alwaysConsumeNavBar, int displayId) {
		        final ViewRootImpl viewAncestor = mViewAncestor.get();
		        if (viewAncestor != null) {
		            viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
		                    visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
		                    backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
		        }
		    }

		    @Override
		    public void moved(int newX, int newY) {
		        final ViewRootImpl viewAncestor = mViewAncestor.get();
		        if (viewAncestor != null) {
		            viewAncestor.dispatchMoved(newX, newY);
		        }
		    }

		    .. ..

		}
}

The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of {@link WindowManagerGlobal}.

从类的注释可以了解到:

  • 这个类是View层级的最上面,实现了在View和WindowManager之间的所需要的协议
  • 它实现了WindowManagerGlobal内部大部分的功能

从ViewRootImpl的setView方法可以看到,主要有两个步骤:

  • requestLayout :用于通知View进行测量、布局、绘制
  • mWindowSession.addToDisplay:跨进程与WindowManagerService通信添加Window

在addToDisplay我们注意到有传入一个mWindow变量,它的类型是W,从代码上来看它是继承自IWindow.Stub,也是一个Binder,它传给WindowManagerService就是为了方便跨进程回调客户端里的方法通知一些消息,可以看看w里都有哪些方法:
在这里插入图片描述
可以看到里面分发拖拽事件、执行命令、移动、调整大小等方法

接着分析代码可以看到mWindowSession的类型是:IWindowSession,并且是通过WindowManagerGlobal.getWindowSession()初始化的

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

而getWindowSession方法里,则是跨进程调用openSession方法获取,我们来看看WindowManagerService里的openSession方法:

public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
	@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;
    }
}

可以看到这个方法返回的是一个Session对象:

/**
 * This class represents an active client session.  There is generally one
 * Session object per process that is interacting with the window manager.
 */
// Needs to be public and not final so we can mock during tests...sucks I know :(
public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
	final WindowManagerService mService;

	public Session(WindowManagerService service, IWindowSessionCallback callback,
            IInputMethodClient client, IInputContext inputContext) {
        mService = service;
        .. ..
    }
	@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);
    }
    public void remove(IWindow window) {
        mService.removeWindow(this, window);
    }
}

This class represents an active client session. There is generally
one Session object per process that is interacting with the window
manager.

这个Session对象继承的是IWindowSession.Stub,从名字可以看出来它是通过AIDL生成的Binder,而它addToDisplay方法,最终还是调用WindowManagerService的addWindow方法,从这个类的注释可以知道:

  • 这个类代表一次客户端访问WindowManagerService 会话
  • 通常情况下每一个进程都只有一个Session正在与WindowManager通信

最后我们来看看WindowManagerService的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 res = mPolicy.checkAddPermission(attrs, appOp);
        	.. ..
        	// 当为某个窗口添加子窗口时,parentWindow将用来保存父窗口的实例
        	WindowState parentWindow = null;
        	.. .. 
        	final int type = attrs.type;
        	synchronized(mWindowMap) {
        		//①获取窗口要添加到的DisplayContent
           		/* 在添加窗口时,必须通过displayId参数指定添加到哪一个DisplayContent。
	              如果没有指定displayId参数,Session会替SampleWindow选择
	              DEFAULT_DISPLAY,也就是手机屏幕 */
        		final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
        		if (displayContent == null) {
                	return WindowManagerGlobal.ADD_INVALID_DISPLAY;
                }
                .. ..
                AppWindowToken atoken = null;
                final boolean hasParent = parentWindow != null;
            	WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
                if(token == null){
                	//检查窗口有效性
                	.. ..
                	token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
                } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                	atoken = token.asAppWindowToken();
                	.. .. 
                	检查有效性
                }.. .. 
                else if (token.asAppWindowToken() != null) {
	               .. ..
	                attrs.token = null;
	                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
	                        session.mCanAddInternalSystemWindow);
	            }
	            //用于维护窗口的状态
	            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
                .. .. 
                final boolean hasStatusBarServicePermission =
                    mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
                            == PackageManager.PERMISSION_GRANTED;
                //根据窗口类型调整LayoutParams的一些成员的取值
            	mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
            	.. ..
            	//创建SurfaceSession,用于与SurfaceFlinger通信
            	 win.attach();
            	 //然后将WindowState对象加入到mWindowMap中
            	 mWindowMap.put(client.asBinder(), win);
        	}
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值