您当前的位置: 首页 > 
  • 3浏览

    0关注

    417博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

06.输入系统:第10课第12节_输入系统_APP跟输入系统建立联系_InputChannel和Connection

江南才尽,年少无知! 发布时间:2019-03-12 17:56:25 ,浏览量:3

在继续分析Dispatcher线程之前,我们先来讲解APP怎么与输入系统建立联系,他的核心就是scoketpair。在这之前我们先来回顾一下之前的知识: 1.InputRead线程从驱动读取到输入事件之后,稍作处理(比如来电的时候,按下音量键,就马上处理为静音),然后把这个输入事件放入到mInboundQueue队列中,然后唤醒Dispatcher线程。 2.Dispatcher线程从队列取出事件之后,也会稍作处理(如果为Global按键,或者System按键,处理完成之后,会直接抛弃),把user按键事件放入队列,然后查看目标APP,获得一个connection,然后把事件放入对应的onnection的队列中。

那么他是怎么查找,怎么放入connection的队列中的呢?这些就是该课时需要讲解的内容,前面提到过,他的核心是scoketpair。

我们可以想象到,pc机同时运行很多应用程序,一般只有最前面的应用程序能接受到输入事件,那么谁去告诉输入系统运行到屏幕最外面的应用程序是哪个呢?这里涉及到一个WindowManagerService(窗口管理服务),在其中,每一个应用程序都用一个WindowState结构体进行表示。

框架分析

在这里插入图片描述 上面是一个流程框图,看起来比较混乱,不过大家不要着急,慢慢为大家讲解:假设APP1,APP2已经存在,其中在WindowManagerService中都有对应的WindowState结构体对其进行描述,假设我们增加了一个APP3,那么APP3经过addToDisply,WindowManagerService收到后,为其创建一个新的WindowState与SocketPair,SocketPair会获得两个句柄fd0与fd1,其中fd1直接返回给应用程序,根据d0创建一个InputChannel,该InputChannel会放入到SocketPair中,并且通过registerInputChannel 注册到InputDisputcher,

在InputDisputcher.h文件中可以看到

KeyedVector mConnectionsByFd

定义,其中mConnectionsByFd中的Connections代表一个复数,表明KeyedVector中可能含有多个Connection。

通过registerInputChannel注册到InputDisputcher之后,InputDisputcher创建出一个Connection,把这个Connection放入到KeyedVector中。其中Connection包括:InputChannel以及fd。

这样,当Dispatcher线程获取到事件,会从根据屏幕最前面的应用程序,从KeyedVector中找出Connection中对应的fd,然后把事件放入其中,那么另外一个fd马上就能收到事件(应用程序)。

APP3在得到一个fd之后,会把他封装成一个InputChannel,然后再封装成windowInputEvenReceiver,最终把fd放入到Looper中,使用epoll进行查询等待。

我们要注意一点,框图中的InputRead线程与Dispatcher线程以及WindowManagerService线程他们处于SystemServer进程中,所以这三个进程之间是可以直接通信的,不需要通过binder。当需要跟APP1,APP2,APP3等等通信时,才需要使用binder实现进程之间的通信(或者使用事先建立的scoketpair)。我们要注意其中的一点差别,scoketpair中的fd是通过binder返回给应用程序APP的。

下面我们进入源码,验证以上的分析过程。

源码分析

下图是源码中的详细调用过程: 在这里插入图片描述 对于应用程序,他肯定会调用自己对应的handleResumeActivity,其位于ActivityThread中,我们打开文件ActivityThread.java,他首先通过a.getWindowManager获得一个ViewManger wm,注意该WindowManager是本地的一个服务,不是系统service,然后通过wm.addView(decor,l)添加到本地的WindowManager服务中。

其中wm.addView方法定义于WindowManagerImpl.java文件,根据框图我们可以知道最终会调用到

mWindowSession.addToDisplay()

其是在ViewRootImpl.java中的root.setView方法中被调用,那么我们为什么认为addToDisplay()为一个远程调用呢?我们可以在ViewRootImpl.java中找到

mWindowSession = WindowManagerGlobal.getWindowSession();
	sWindowSession = windowManager.openSession()/*他会调用到IWindowManager.java文件中的penSession,该文件是andriod编译过程中自动生成,其位于
	out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowManager.java*/
		@Override public android.view.IWindowSession openSession(android.view.IWindowSessionCallback callback, com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteExceptio
			/*发起一个远程调用*/
			mRemote.transact(Stub.TRANSACTION_openSession, _data, _reply, 0);
			_reply.readException();
			/*把返回结果转换为Stub.asInterface*/
			_result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());				

可以知道mWindowSession是对远程服务的一个引用,其上的mWindowSession.addToDisplay()实际调用的为,SDKout/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession.java中的addToDisplay:

@Override public int addToDisplay(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, android.graphics.Rect outContentInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.view.InputChannel outInputChannel) throws android.os.RemoteException
	mRemote.transact(Stub.TRANSACTION_addToDisplay, _data, _reply, 0);//发起远程调用
	outOutsets.readFromParcel(_reply)//获取fd

通过远程调用,就实现了进程之间的通信(APP与WindowManagerService),APP在调用addToDisplay中进而调用outOutsets.readFromParcel(_reply);获得fd,

上述的框图讲解比较详细,就不在逐一讲解了。

关注
打赏
1592542134
查看更多评论
立即登录/注册

微信扫码登录

0.0377s