Android Framework 窗口子系统 (02) 应用进程和WMS之间的关系

系列文章解读&说明:

Android Framework 窗口子系统 的 分析主要分为以下部分:

(01)WindowMangerService基础知识

(02)应用进程和WindowManagerService之间的关系

(03)窗口显示次序

(04)确定窗口尺寸

(05)窗口布局说明

(06)Choreographer机制

(07)窗口动画系统

本模块分享的内容:应用进程和WMS之间的关系

本章关键点总结 & 说明:

该图关注➕思维导图中右下方:应用进程 & WMS部分即可。主要从actvity.attach这一步骤开始分析和WMS之间的关系。

1 以应用启动为契机分析Window和WindowManager
每个Activity中含有2个关键成员变量:mWindow和mWindowManager,这里以Activity启动为契机开始对它们进行分析,

@1 应用中的Window和WindowManager
从handleLaunchActivity->...->performLaunchActivity->...->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.voiceInteractor);

因此这里直接从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) {
        attachBaseContext(context);
        mFragments.attachActivity(this, mContainer, null);
        mWindow = PolicyManager.makeNewWindow(this);//关键点1,利用PolicyManager来创建Window对象
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ...
        //关键点2,创建WindowManager对象
        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());
        }
        //关键点3,将之前创建的WindowManager对象保存在mWindowManager对象中
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

这里开始对attach的3个关键点进行详细分析,分别是创建window对象、创建windowManager对象并将2者保存

1.1 分析mWindow = PolicyManager.makeNewWindow(this);
这里多出个PolicyManager类,Window是由它的makeNewWindow函数所创建,因此必须看PolicyManager实现。代码如下:

public final class PolicyManager {
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";
    private static final IPolicy sPolicy;
    static {
        try {
            //根据POLICY_IMPL_CLASS_NAME获得类Policy
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
            sPolicy = (IPolicy)policyClass.newInstance();//创建Policy类型对象
        } catch (ClassNotFoundException ex) {
            ...
        }
    }
    private PolicyManager() {}
    //通过Policy对象的makeNewWindow创建一个Window
    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }
    ...
}

这里有一个单例的sPolicy对象,它是Policy类型,Policy类型的定义代码如下所示: 

public class Policy implements IPolicy {
    private static final String TAG = "PhonePolicy";
 
    private static final String[] preload_classes = {
        "com.android.internal.policy.impl.PhoneLayoutInflater",
        "com.android.internal.policy.impl.PhoneWindow",
        "com.android.internal.policy.impl.PhoneWindow$1",
        "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
        "com.android.internal.policy.impl.PhoneWindow$DecorView",
        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
    };
 
    static {
        for (String s : preload_classes) { //预加载所有的类
            try {
                Class.forName(s);
            } catch (ClassNotFoundException ex) {
                Log.e(TAG, "Could not preload class for phone policy: " + s);
            }
        }
    }
 
    public Window makeNewWindow(Context context) {//makeNewWindow返回的是PhoneWindow对象
        return new PhoneWindow(context);
    }
    ...
}

分析到这里知道:mWindow = PolicyManager.makeNewWindow(this);//这里返回的Window是一个PhoneWindow对象(定义在PhoneWindow.java中,这里的setWindowManager是在windows中实现的,因为PhoneWindow是继承Window的)

1.2 接下来分析mWindow.setWindowManager的实现,代码如下:

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {//如果wm为空,则创建一个WindowManager对象
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //注意:针对该流程,这里不为空,因为传递时执行了一次
        //mWindowManager是一个LocalWindowManager
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

这里继续分析方法createLocalWindowManager,代码实现如下:

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

继续分析WindowManagerImpl,代码如下:

private WindowManagerImpl(Display display, Window parentWindow) {
    mDisplay = display;
    mParentWindow = parentWindow;//这里简单的保存了传递进来的参数parentWindow
}

注意:这里WindowManagerImpl类中还有一个重要成员变量mGlobal,是通过WindowManagerGlobal的getInstance方法得到,代码如下:

public static WindowManagerGlobal getInstance() {
    synchronized (WindowManagerGlobal.class) {
        if (sDefaultWindowManager == null) {
            sDefaultWindowManager = new WindowManagerGlobal();
        }
        return sDefaultWindowManager;//单例模式,创建整个应用唯一全局对象,最后赋值给mGlobal
    }
}

实际上WindowManagerImpl类中的各种方法最后都是转调WindowManagerGlobal来实现,由此可见,一个应用中所有的Activity都是通过这个进程内唯一的WindowManagerGlobal对象和WMS之间进行通信, WindowManagerGlobal中有3个重要的成员变量,代码如下:

public final class WindowManagerGlobal {
    private static final String TAG = "WindowManager";
    ...
    //保存所有顶层View的对象(DecorView)
    private final ArrayList<View> mViews = new ArrayList<View>();

    //保存和顶层View相关联的ViewRootImpl对象
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();

    //保存创建顶层View的layout参数
    private final ArrayList<WindowManager.LayoutParams> mParams =    
    new ArrayList<WindowManager.LayoutParams>();
    ...
}

1.3 分析mWindowManager = mWindow.getWindowManager();这里看getWindowManager的实现,代码如下:

public WindowManager getWindowManager() {
    return mWindowManager;
}

这里主要是获取mWindowManager,也就是之前设置的WindowManager对象。

1.4 总结

  1. Activity中mWindow是PhoneWindow类型的,PhoneWindow是继承Window的。
  2. Activity中mWindowManager是WindowManagerImpl类型的,WindowManagerImpl实现了WindowManager接口
  3. 到此,WMS的类关系图总结如下:

2 建立应用与WMS之间的关系,WMS与应用之间的关系
@1 ViewRootImpl有很多成员变量,与WMS相关的几个变量如下:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ...
    final IWindowSession mWindowSession;
    final W mWindow;
    final Surface mSurface = new Surface();
    final View.AttachInfo mAttachInfo;
    ...
}

它的构造方法对这几个关键变量进行初始化,代码如下所示:

public ViewRootImpl(Context context, Display display) {
    mContext = context;
    mWindowSession = WindowManagerGlobal.getWindowSession();//关键点1,建立和WindowManagerService的关系
    ...
    mWindow = new W(this);//关键点2,mWindow是一个W类型,注意它不是Window类型,而是IWindow类型
    ...
    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
    ...
}

这里的mWindowSession是IWindowSession类型,它是WMS中某个Binder对象的引用对象,继续分析getWindowsession函数,代码如下:

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager imm = InputMethodManager.getInstance();
                //下面这个函数先得到WindowManagerService的Binder代理
                IWindowManager windowManager = getWindowManagerService();
                //调用代理端的openSession
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        },
                        imm.getClient(), imm.getInputContext());
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to open window session", e);
            }
        }
        return sWindowSession;
    }
}

继续分析openSession,代码实现如下:

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属于远程Binder调用,返回给用户进程的是Session对象引用对象(注意:一个应用中所有的ViewRootImpl对象中的mWindowSession都引用相同的对象,这就是应用与WMS之间建立的一条Binder通信通道)。
@2 Activity的创建流程后面有一个handleResumeActivity方法,方法实现如下:

final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume) {
    unscheduleGcIdler();
   ...
   r.activity.makeVisible();//这里仅关注此方法
   ...
}

继续分析makeVisible,代码如下:

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());//关键是这句代码
        mWindowAdded = true;
    }
    /// M: BMW @{
    MultiWindowProxy mMultiWindowProxy = MultiWindowProxy.getInstance();            
    if (MultiWindowProxy.isFeatureSupport() && mMultiWindowProxy != null) {   
        mMultiWindowProxy.setFloatDecorVisibility(mToken, View.VISIBLE);
    } 
    /// @}
    mDecor.setVisibility(View.VISIBLE);
}

这里又调用了WM的addView方法,参数是mDecor,这里实际上调用的是WindowManagerGlobal(WM->WMImpl->WMG流程),代码如下:

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ...//参数检查
    ViewRootImpl root;
    View panelParentView = null;
    synchronized (mLock) {
        ...
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        //加入View、ViewRootImpl、LayoutParams 3个对象到列表
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    ...
    root.setView(view, wparams, panelParentView);
    ...
}

注意:这里最重要的一点:创建ViewRootImpl对象,通过setView方法把它和顶层View关联在一起
这里着重分析setView方法,代码如下:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {//ViewRootImpl与View的关联只能做一次,如果赋值过吗,就不会再执行
            mView = view;//将顶层视图DecorView赋值给全局的mView
            ...
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                //调用IWindowSession的add函数,第一个参数是mWindow,它的类型是W,ViewRootImpl中的内部类 
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
            } catch (RemoteException e) { ... }
            ...
        }
    }
}

特殊说明:

  1. W是ViewRootImpl中的静态内部类,是一个Binder服务类通过addToDisplay方法将mWindow实例传输到WMS中,
  2. W在WMS中的引用对象类型是IWindow,WMS保存了应用中每个顶层窗口的IWindow对象。

 W的关键代码如下:

static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;
}

@3 建立WMS与应用之间的关系
在WMS中,WindowState对象代表一个窗口,WS中定义了大量成员变量表示窗口信息,看关键的2个变量:

final class WindowState implements WindowManagerPolicy.WindowState {
    static final String TAG = "WindowState";
    ...
    final Session mSession;//WMS为客户进程创建的Binder服务对象
    final IWindow mClient;//客户端进程Binder对象,W的引用对象
    ...
}

查看Session类型的定义,代码如下:

final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    ...
    SurfaceSession mSurfaceSession;
    ...
}

这是通过AIDL生成的Binder架构,该类的作用是把来自用户的调用转换成WMS接口。前面@2中调用的addToDisplay,实际上调用的是WMS的addWindow,从Session开始分析。Session是从IWindowSession.stub派生,继续分析Session的addToDisplay,代码如下:

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
        InputChannel outInputChannel) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outStableInsets, outInputChannel);
}

 mService是WMS类型的,继续分析WMS的addWindow实现,代码如下:

public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
    int[] appOp = new int[1];
    int res = mPolicy.checkAddPermission(attrs, appOp);
    if (res != WindowManagerGlobal.ADD_OKAY) {
        return res;
    }
    boolean reportNewConfig = false;
    WindowState attachedWindow = null;
    WindowState win = null;
    long origId;
    final int type = attrs.type;

    synchronized(mWindowMap) {
        ...
        if (mWindowMap.containsKey(client.asBinder())) {
            return WindowManagerGlobal.ADD_DUPLICATE_ADD;
        }
        ...
        //创建WS对象
        win = new WindowState(this, session, client, token,
                attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
        ...
        win.attach();
        ...
    }

    if (reportNewConfig) {
        sendNewConfiguration();
    }
    Binder.restoreCallingIdentity(origId);
    return res;
}

说明:这里addWindow方法中创建了WS对象,并将其加入到mWindowmap列表中,该列表保存了所有顶层窗口的信息。同时这里也调用了WindowState的attach函数,代码如下所示:

void attach() {
    mSession.windowAddedLocked();
}

mSession是Session类型的,它的windowAddedLocked实现如下所示:

void windowAddedLocked() {
    //为空才会继续执行,创建一个SurfaceSession对象并把自己加入到WMS的mSession列表中
    //保证一个Session不会重复加入到WMS的mSessions变量中
    if (mSurfaceSession == null) {
        mSurfaceSession = new SurfaceSession();//创建一个SurfaceSession对象
        mService.mSessions.add(this);
        if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
            mService.dispatchNewAnimatorScaleLocked(this);
        }
    }
    mNumWindow++;
}

@4 总结:Activity中的各种Binder对象关系图以及应用程序和WMS之间的Binder通道关系图分别如下:

Activity中的各种Binder对象关系图如上⬆️所示。

应用程序和WMS之间的Binder通道关系图如上⬆️所示。

3 理解DecorView

在PhoneWindow类中,mDecor的类型是DecorView,当调用setContentView时,如果mDecor还没有创建,则会调用installDecor方法来创建Activity中的DecorView和其他框架的View,如ActionBar等。整个分析流程从setContentView开始。

@1 在onCreate函数中,Activity一般都在这个函数中通过setContentView设置UI界面。 接下来分析setContentView,代码如下:

public void setContentView(View view) {//最常用
    getWindow().setContentView(view);
    initWindowDecorActionBar();
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
    getWindow().setContentView(view, params);
    initWindowDecorActionBar();
}
public void addContentView(View view, ViewGroup.LayoutParams params) {
    getWindow().addContentView(view, params);
    initWindowDecorActionBar();
}

继续分析getWindow,代码实现如下:

public Window getWindow() {
    return mWindow;
}

这里的mWindow类型是PhoneWindow,因此继续分析PhoneWindow的setContentView方法,代码如下:

public void setContentView(View view) {
    //调用另一个setContentView
    setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}

public void setContentView(View view, ViewGroup.LayoutParams params) {
    //mContentParent为ViewGroup类型,它的初值为null 
    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);//把view加入到ViewGroup中
    }
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

说明:mContentParent是一个ViewGroup类型,它从View中派生,所以也是一个UI单元。从它名字中“Group”所表达的意思分析,它还可以包含其他的View元素。即在绘制一个ViewGroup时,它不仅需要把自己的样子画出来,还需要把它包含的View元素的样子也画出来。

@2 再看setContentView中installDecor函数的实现,其代码如下所示:

private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();//创建mDecor,它为DecorView类型,从FrameLayout派生
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        //生成一个layout,如果是Actionbar,则ActionBarOverlayLayout
        mContentParent = generateLayout(mDecor);
        mDecor.makeOptionalFitsSystemWindows();
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            ...
        } else {
            mTitleView = (TextView)findViewById(R.id.title);//创建标题栏
            if (mTitleView != null) {//不支持ActionBar的Activity带有一个Title
                mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {//处理没有Title的情况
                    View titleContainer = findViewById(R.id.title_container);
                    if (titleContainer != null) {
                        titleContainer.setVisibility(View.GONE);
                    } else {
                        mTitleView.setVisibility(View.GONE);
                    }
                    if (mContentParent instanceof FrameLayout) {
                        ((FrameLayout)mContentParent).setForeground(null);
                    }
                } else {
                    mTitleView.setText(mTitle);//设置Title上的文字
                }
            }
            ...
        }

        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }
    ...
    }
}

installDecor的功能:主要是创建DecorView和它的下级Layout,根据需要创建ActionBar。当installDecor执行完,Activity的框架View就都创建出来了,DecorView的定义在PhoneWindow中,是它的一个内部类,代码如下:

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
        ...
}

DecorView继承了FrameLayout ,并且实现了RootViewSurfaceTaker 接口,是Activity中View树的根。

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/93901800
今日推荐