美文网首页
应用与WMS的关联

应用与WMS的关联

作者: 我叫王菜鸟 | 来源:发表于2017-11-29 21:52 被阅读0次

简介

我之前分析过,但是感觉当时迷迷糊糊的,自己也没彻底弄清楚,今天我再次突破,这次感觉比以前清楚了,为什么要写这个关系,因为在项目中Activity中见到Window win = getWindow();这种写法。所以要想了解Wundow类我们就要明白WMS与我们的应用到底有什么联系。

应用于WMS关联的来源

AT.handleLaunchActivity


private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    handleConfigurationChanged(null, null);
    //获取WMS代理对象
    WindowManagerGlobal.initialize();//[1.1]
    Activity a = performLaunchActivity(r, customIntent);//[1.2]
    if (a != null) {
        //最终回调目标Activity的onStart,onResume.
        handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);//[1.3]
        ...
    } else {
        ...
    }
    ...
}
image.png

1.1

我们在WindowManagerGlobal.java中看看

public final class WindowManagerGlobal {
    ...
    public static void initialize() {
        getWindowManagerService();
    }
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
                ...
            }
            return sWindowManagerService;
        }
    }
    ...
}

通过这里可以看到WindowManagerGlobal 持有WMS的Binder代理并且唯一。

1.2

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    ...

    Activity activity = null;
    //获取ClassLoader
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    //创建目标Activity对象
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    ...
    //创建Application对象
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    if (activity != null) {
        ...
        //变量赋值操作
        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);//[2.1]
        ...
    }
    ...
    return activity;
}
  • 创建目标Activity对象
  • 创建Application对象
  • 执行activity.attach()

2.1

public class Activity extends ContextThemeWrapper implements ... {
    private Window mWindow;
    
    final void attach(...) {
        ...
        mWindow = new PhoneWindow(this); //创建PhoneWindow
        ...
        mUiThread = Thread.currentThread(); //获取UI线程
        mToken = token; //远程ActivityRecord的appToken的代理端
        mApplication = application; //所属的Appplication
        ...
        //设置并获取WindowManagerImpl对象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ...
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
        ...
    }
}

Window.setWindowManager

由于PhoneWindow继承Window

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,boolean hardwareAccelerated) { 
    ...    
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    ...
}

我们看到通过mWindow.setWindowManager()这个方法我们创建并获取了WindowManagerImpl对象

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ....
}

这里我们就看出,当Activity执行到attach方法的时候就会创建PhoneWindow,PhoneWindow创建WindowManagerImpl,WindowManagerImpl持有WindowManagerGlobal

所以每个Activity的mWindowManager 是WindowManagerImpl对象,WindowManagerImpl 存有WindowManagerGlobal这个对象是进程唯一。

public final class WindowManagerGlobal {
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();
    ...

WindowManagerGlobal这个对象管理当前进程里面所有的View(DecorView),ViewRootImpl,WindowManager.LayoutParams(顶层View的layout参数)

AT.handleLaunchActivity.png

应用程序如何通知WMS呢?

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        
        final W mWindow;
        final IWindowSession mWindowSession;
        
        public ViewRootImpl(Context context, Display display) {
            ...
            mWindowSession = WindowManagerGlobal.getWindowSession();//[1.1]
            ...
        }
}        

1.1

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

由于前面说过getWindowManagerService()返回的是WMS的代理,所以在WMS方法如下:

WMS

@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
        IInputContext inputContext) {
        ...
    Session session = new Session(this, callback, client, inputContext);
    return session;
}

Session是用aidl生成的Binder对象。因此WMS将这个Binder代理返回给了应用程序,这样应用程序就可以通过WindowManagerGlobal 与WMS进行通信了。其中WindowManagerGlobal持有的sWindowSession是WMS中的Session代理对象。

小结

也就是当前应用中有一份WindowManagerGlobal 唯一,这里有WMS的代理也有ViewRootImpl,ViewRootImpl 中的sWindowSession变量映射着WMS的Session Binder代理。

WMS如何通知应用程序呢?

要想知道这个问题我们就要研究ViewRootImpl这个类,我们就从它的成员变量开始:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    
    final IWindowSession mWindowSession;
    final W mWindow;
    
    public ViewRootImpl(Context context, Display display) {
        
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
    }
    ...
}

我们看到了W对象,这个对象是Binder对象。

与此同时我们应该看看WindowState对象。

final class WindowState implements WindowManagerPolicy.WindowState {
    
    final WindowManagerService mService;
    final Session mSession;
    final IWindow mClient;
    
    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
           
        ...
        mService = service;
        mSession = s;
        mClient = c;
        ...   
    }
}

在WMS中:

public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        InputChannel outInputChannel) {
        ...
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
            appOp[0], seq, attrs, viewVisibility, session.mUid,
            session.mCanAddInternalSystemWindow);
        ...
        win.attach();
        ...
}

我们看到在WMS中我们将这些核心的参数传递进去,比如Session,client等。

上面这两段代码说明,WindowState持有WMS,client,mSession的引用。持有这些引用就可以管理。Session我们知道,就是每一个WindowManagerGlobal持有唯一的一个由WMS产生的Session与app进程对应。client是什么?

这个就又要追溯到我们Activity的启动时候了。(也就是我们在AT.handleLaunchActivity中写的1.3)

1.3

ActivityThread

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
    //执行到onResume方法()
    ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        final Activity a = r.activity;
        ...
        if (...) {
            ...
            mNumVisibleActivities++;
            if (...) {
                //添加视图[1.3.1]
                r.activity.makeVisible(); 
            }
        }
        ...
    } else {
        ...
    }
}

1.3.1

Activity.makeVisible

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();//得到WindowManagerImpl对象此对象内部拥有WindowManagerGlobal 
        
        wm.addView(mDecor, getWindow().getAttributes());//[1.3.2]
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

1.3.2

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

在这里也可以看的出来,WindowManagerImpl其实都是转调WindowManagerGlobal进行操作。

WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
        root = new ViewRootImpl(view.getContext(), display);
        mViews.add(view);//这里的View是顶层View
        mRoots.add(root);
        mParams.add(wparams);
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ...
            throw e;
        }
}

我们看到利用ViewRootImpl去做setView的工作。

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    final W mWindow;
    
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
        
            mView = view;//将顶层View保存
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
            ...
        }
}

mWindowSession是持有WMS里面的Session,使用addToDisplay,我们将mWindow也就是W对象传入到Session。所以WMS就可以通过W对象与应用程序进行通信了。

我们最后小结核心就好:

  • WindowManagerImpl持有WindowManagerGlobal的引用
  • WindowManagerGlobal可以和WMS进行通信
  • PhoneWindow可以得到WindowManagerImpl
  • PhoneWindow在actvitiy的attach中创建
  • WindowManagerGlobal.getWindowSession()得到WMS中Session(Binder)的代理
  • ViewRootImpl持有sessopn代理
  • ViewRootImpl中创建W对象
  • W对象在activity启动过程中setView方法到了WMS中
  • WMS在addView过程中通过WindowState将Session与W代理和WMS引用都保存。

应用向WMS通信

image.png

WMS向应用通信

image.png

相关文章

网友评论

      本文标题:应用与WMS的关联

      本文链接:https://www.haomeiwen.com/subject/ultmbxtx.html