应用与WMS的关联

简介

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

推荐阅读更多精彩内容