Activity和WMS的双向通信

说双向通信之前,首先了解下WindowManagerGlobalViewRootImpl的创建

WindowManagerGlobal的创建

创建过程如下图

image.png
  • ActivityManagerService->ActivityThread
    AMS里面的main函数里会创建ActivityThread
public static void main(String[] args) {
//省略...
 ActivityThread thread = new ActivityThread();
//省略...
}

ActivityThread是应用程序的UI线程,它主要负责对Android四大组件的创建和管理,以及控制Activity的生命周期等。

  • ActivityThread-> WindowManagerGlobal

当我们执行startActivity启动一个页面时,最终会执行到ActivityThread
handlerLauncherActivity方法来。在这个方法里,会创建一个WindowManagerGlobal

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 创建Activity之前初始化WindowManagerGlobal
        WindowManagerGlobal.initialize();
       //省略...
    }

ViewRootImpl创建

创建过程如下图

image.png
  • ActivityThread->Activity

创建Activity也是在AndroidThreadhandleLauncherActivity方法里面,创建完WindowManagerGlobal之后调用

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
       //省略...
        // 创建Activity之前初始化WindowManagerGlobal
        Activity a = performLaunchActivity(r, customIntent);
       //省略...
    }
  • Activity->PhoneWindow
    来到performLaunchActivity方法里面创建Activity,并且会执行Activityattach方法来创建PhoneWindow
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //省略...
    Activity activity = null;
 //省略...
 try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            //省略...
        } catch (Exception e) {
             //省略...
        }
}
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, window);
     //省略...

}

- PhoneWindow->WindowManagerImpl

Activity里的attach方法创建完PhoneWindow之后会执行WindowsetWindowManager方法。

 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) {
  //省略...
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
  //省略...
 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());
        }
        mWindowManager = mWindow.getWindowManager();
  //省略...
}

PhoneWindow它是Window的唯一实现类,它会在setContentView方法里面创建DecoView,然后DecoView会添加一个id为content的FrameLayout作为根布局,关系如下图

PhoneWindow.png

创建好PhoneWindow后,继续执行WindowsetWindowManager方法,去创建WindowManagerImpl对象

 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)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
  • WindowManagerImpl->WindowManagerGlobal

WindowManagerImpl里面会和WindowManagerGlobal进行关联,从而通过addView方法,removeView等方法来做为管理View的桥梁,传递给WindowManagerGlobal

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
   @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

调用WindowManagerImpladdView的位置主要有两个地方
1.ActivitymakeVisible方法会调用

  void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
  1. ActivityThreadhandleResumeActivity会直接执行addView方法
      final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    //省略...
if (r.window == null && !a.mFinished && willBeVisible) {
//省略...
 if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
    }
}
    
//省略...
  if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
    //省略...
     if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
     }
    //省略...
}
}

在添加DecoView的时候会调用addView方法,添加DecoViewView的时候就直接调用ActivitymakeVisible的方法,然后在makeVisible调用addView方法。

  • WindowManagerGlobal->ViewRootImpl

WindowManagerGlobaladdView方法里面会创建ViewRootImpl

 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
     //省略...
    ViewRootImpl root;
     //省略...
     root = new ViewRootImpl(view.getContext(), display);
}

ViewRootImpl它主要管理Window中所有的View的类,每个Activity中ViewRootImpl的数量取决于调用mWindowManager.addView的调用次数,Activity提供与AMS通信的Token(IBinder对象),创建Window为View提供显示的地方,而具体的View管理任务由ViewRootImpl来完成。

Activity->WMS通信

Activity到WMS通信主要是通过WindowManagerGlobalViewRootImpl来完成的,上面说到WindowManagerGlobalinitialize方法

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

首先可以知道WindowManagerGlobal是个单例,最终调用的是getWindowManagerService方法。ServiceManager.getService("window")获取一个IBinder对象,来到getService方法

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

然后来到getIServiceManager()方法

  private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

这里可以通过如下图来解释

图片来源https://blog.csdn.net/luoshengyang/article/details/6642463罗老师博客.png

BinderInternal.getContextObject()其实获取的是BinderProxy这个代理类,然后通过asInterface()方法传给IServiceManager的代理类ServiceManagerProxy,也是ServiceManagerJava远程接口,从而实现Binder通信。

然后回到getService()方法,传入一个name参数,然后通过name获取指定的service,比如这里传入的是window,也就是获取到WindowManagerService对应的IBinder对象。最后调用IWindowManager.Stub.asInterface()方法获取到WindowManagerService的抽象类IWindowManager

获取到WMS之后,然后会在ViewRootImpl初始化的时候调用openSession,获取IWindowSession

 final IWindowSession mWindowSession;
 public ViewRootImpl(Context context, Display display) {
      mWindowSession = WindowManagerGlobal.getWindowSession();
}

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

通过上面获取到的IWindowManager去调用openSession获取IWindowSession对象。然后通过IWindowSession进行通信。如下图

image.png

IWindowSessionClient端的代理,而它的Server端是SessionSession接收到请求后,就会转交给WMS进行处理。流程如下图

时序图.png

这样就实现了ActivityWMS的通信

WMS -> Activity通信

WMSActivity通信,也是使用的代理模式,通过IWindow.Stub接口来实现,而WMS的代理对象就是在ViewRootImpl里面的W内部类,它通过上面获取的IWindowSession来在ViewRootImplsetView方法里面调用addToDisplay方法把W代理传递给WMS

 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  //..省略
 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
 //..省略
}

它传递的第一个参数mWindow就是WmWindow中保存了W类型的Binder本地对象,这样通过函数addToDisplay就可以将W的代理对象传递Session然后给WMS服务。SessionaddToDisplay如下

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

然后来到WindowManagerServiceaddWindow方法,从这里可以看出每次ViewRootImplsetView调用一次,对应一个Session请求。然后来到addWindow方法里面,在里面创建了一个WindowState对象,并且把W保存的Binder对象和Session保存在WindowState中,

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
      //省略...
       WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
      //省略...
    win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
     win.attach();
      win.applyScrollIfNeeded();
    win.applyAdjustForImeIfNeeded();
}

创建WindowState

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
           int viewVisibility, final DisplayContent displayContent) {
  mWindowId = new IWindowId.Stub() {
            @Override
            public void registerFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.registerFocusObserver(observer);
            }
            @Override
            public void unregisterFocusObserver(IWindowFocusObserver observer) {
                WindowState.this.unregisterFocusObserver(observer);
            }
            @Override
            public boolean isFocused() {
                return WindowState.this.isFocused();
            }
        };
}

创建IWindowId主要是用于标识指定窗口。它会在ViewgetWindowId方法里面获取到。

综上,WMSActivity的通信主要是通过IWindow的代理对象W来进行通信。过程如下

WMS到Activity.png

Activity到WMS是通过IWindowSession来通信,WMS到Activity是通过IWindow代理w来通信

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

推荐阅读更多精彩内容