Android事件分发的事件由来原理分析

目录
  • Andriod事件分发的事件从何而来
    • 调用WMS中的成员mInputManager
    • 调用的mNative的方法
    • 看看InputManager怎么初始化
  • createInputChannel干了3件事
    • 首先看下openInputChannelPair
    • 回到createInputChannel中

Andriod事件分发的事件从何而来

上一篇最后留下了一个疑问,WMS的事件是哪里来的?

注册事件回调是通过mWindowSession.addToDisplayAsUser来实现的,这是一个Binder调用实际调用的是frameworks/base/services/core/java/com/android/server/wm/Session.java这个类。

 //frameworks/base/services/core/java/com/android/server/wm/Session.java
  @Override
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Rect outAttachedFrame,
            float[] outSizeCompatScale) {
        return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
                requestedVisibilities, outInputChannel, outInsetsState, outActiveControls,
                outAttachedFrame, outSizeCompatScale);
    }
​

这里的mService就是WMS.调用的就是WMS的addWindow,addWindow方法很长,其中与事件相关的就两行

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
......
  final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);
  win.openInputChannel(outInputChannel);
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        mInputChannel = mWmService.mInputManager.createInputChannel(name);
        mInputChannelToken = mInputChannel.getToken();
        mInputWindowHandle.setToken(mInputChannelToken);
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        if (outInputChannel != null) {
          //将native创建的InputChannel复制给参数outInputChannel
            mInputChannel.copyTo(outInputChannel);
        } else {
            // If the window died visible, we setup a fake input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create fake event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
        }
    }

调用WMS中的成员mInputManager

调用了WMS中的成员mInputManager来注册了InputChannel,mInputManager是一个InputManagerService。

这下就对了,事件从InputManagerService中来很合理。

    public InputChannel createInputChannel(String name) {
        return mNative.createInputChannel(name);
    }

调用的mNative的方法

这个对象是在InputManagerService创建的时候初始化的

    public InputManagerService(Context context) {
        this(new Injector(context, DisplayThread.get().getLooper()));
    }
​
    @VisibleForTesting
    InputManagerService(Injector injector) {
        // The static association map is accessed by both java and native code, so it must be
        // initialized before initializing the native service.
        mStaticAssociations = loadStaticInputPortAssociations();
​
        mContext = injector.getContext();
        mHandler = new InputManagerHandler(injector.getLooper());
        mNative = injector.getNativeService(this);
      ....
    }
//frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java
       NativeInputManagerService getNativeService(InputManagerService service) {
            return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
        }
​

最终返回的是一个NativeImpl实例。字面意思就知道了,这是一个Native方法的实现,createInputChannel来到了native层。

//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
        const std::string& name) {
    ATRACE_CALL();
    return mInputManager->getDispatcher().createInputChannel(name);
}

调用了mInputManager的getDispatcher函数看名字就知道应该有个变量mDispatcher,查看mInputManager是怎么创建的可以发现是在NativeInputManager创建的时候初始化的

    InputManager* im = new InputManager(this, this);
    mInputManager = im;

看看InputManager怎么初始化

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
    mReader = createInputReader(readerPolicy, *mBlocker);
}

这里就出现了重要的两个类InputDispatcherInputReader,createInputChanne方法l最终调用到了InputDispatcher中的createInputChannel。

//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
    if (DEBUG_CHANNEL_CREATION) {
        ALOGD("channel '%s' ~ createInputChannel", name.c_str());
    }
    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
  	//调用创建了一个serverChannel和一个clientChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    if (result) {
        return base::Error(result) << "Failed to open input channel pair with name " << name;
    }
    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        int fd = serverChannel->getFd();
        sp<Connection> connection =
                new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
        if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
            ALOGE("Created a new connection, but the token %p is already known", token.get());
        }
        mConnectionsByToken.emplace(token, connection);
        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
    } // release lock
    // Wake the looper because some connections have changed.
    mLooper->wake();
    return clientChannel;
}

createInputChannel干了3件事

  • 首先使用openInputChannelPair创建了2个InputChannel,一个clientChannel和一个serverChannel
  • 将serverChannel封装成connection,并放入成员变量mConnectionsByToken中管理,这样在事件到来的时候就可以使用connection向客户端发送事件了
  • 利用Looper持续监听serverChannel,事件处理的回调消息会就到InputDispatcher::handleReceiveCallback回调,最后把clientChannel返回给客户端,也就是最初在WMS中得到的InputChannel。

首先看下openInputChannelPair

//frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
                                            std::unique_ptr<InputChannel>& outServerChannel,
                                            std::unique_ptr<InputChannel>& outClientChannel) {
    int sockets[2];
  	//真正创建了socket
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%s(%d)", name.c_str(),
              strerror(errno), errno);
        outServerChannel.reset();
        outClientChannel.reset();
        return result;
    }
	//设置了socket传输的大小为32k
    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    sp<IBinder> token = new BBinder();
    std::string serverChannelName = name + " (server)";
    android::base::unique_fd serverFd(sockets[0]);
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}

熟悉Linux的话就知道socketpair创建了一对双向的socket,往socket[0]中写能从socket[1]读,反向也是一样,分别创建了outServerChannel和outClientChannel,两个InputChannel有着同一个BBinder作为token。

回到createInputChannel中

 const sp<IBinder>& token = serverChannel->getConnectionToken();
        int fd = serverChannel->getFd();//拿到socket fd
        sp<Connection> connection =
                new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
        if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
            ALOGE("Created a new connection, but the token %p is already known", token.get());
        }
        mConnectionsByToken.emplace(token, connection);
 std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);

这里将创建的serverChannel封装成了connection,同时用token作为key,存到了mConnectionsByToken中,这样就可以利用token来快速找到serverChannel封装的connection。最后监听serverChannel的fd,有事件时回调给InputDispatcher::handleReceiveCallback方法的最后把创建的clientChannel返回给了客户端,就是开头的WMS中。这样在WMS就也能通过clientChannel来获取事件了。

以上就是Android事件分发的事件由来原理分析的详细内容,更多关于Android事件分发事件由来的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android报错Didn‘t find class “android.view.x“问题解决原理剖析

    目录 前言 shrinkResources Safe Strict android.view.x 自定义保留 总结 前言 今天同事提到了一个问题,我们的一款App在debug包时没有问题,但是在release包时就是crash,报错如下: 可以看到问题是Didn‘t find class “android.view.x“,但是实际上我们代码中并没有这个类,由于是release包的问题,所以第一时间想到的是混淆问题,检查了一番后发现与混淆无关,经过上网查询发现有人提到说将build.gradle中

  • Android ViewModel创建不受横竖屏切换影响原理详解

    目录 ViewModel的创建方式 参数 1 ViewModelStoreOwner: 参数 2 Factory: ViewModel 为什么不受 Activity 横竖屏生命周期的影响 1.在 Activity 走到 onDestroy 方法时,做了判断 isChangingConfigurations 2.在 Activity 获取 getViewModelStore 时, 3.onRetainNonConfigurationInstance 调用 总结 1.介绍了ViewModel的创建

  • ReactNative错误采集原理在Android中实现详解

    目录 引言 1 JS错误 1.1 Error 1.2 常见的错误 SyntaxError:语法错误 ReferenceError:引用错误 TypeError:类型错误 RangeError:边界错误 URIError:URI错误 1.3 自定义错误 2 RN错误处理 2.1 JS部分 2.1.1 MessageQueue 2.1.2 ErrorUtils 2.1.3 ExceptionsManager 2.2 Native部分 2.2.1 ExceptionsManagerModule 2.2

  • Android ViewGroup事件分发和处理源码分析

    目录 正文 处理ACTION_DOWN事件 检测是否截断事件 不截断ACTION_DOWN事件 寻找处理事件的子View 事件分发给子View ViewGroup自己处理ACTION_DOWN事件 处理ACTION_DOWN总结 处理ACTION_MOVE事件 检测是否截断ACTION_MOVE事件 不截断ACTION_MOVE 事件分发给mFirstTouchTarget.child 截断ACTION_MOVE 处理 ACTION_UP 和 ACTION_CANCEL 事件 正确地使用requ

  • android事件分发机制的实现原理

    android中的事件处理,以及解决滑动冲突问题都离不开事件分发机制,android中的事件流,即MotionEvent都会经历一个从分发,拦截到处理的一个过程.即dispatchTouchEvent(),onInterceptEvent()到onTouchEvent()的一个过程,在dispatchTouchEvent()负责了事件的分发过程,在dispatchTouchEvent()中会调用onInterceptEvent()与onTouchEvent(),如果onInterceptEven

  • Flex 事件分发(FlexViewer事件机制)剥离过程

    将FlexViewer里面的事件分发及监听事件机制剥离出来在其他项目中使用 AppEvent.as package com { import flash.events.Event; /** * @author SamSung * 创建时间:2014-7-24 下午1:21:05 * */ public class AppEvent extends Event { //-----------------------------------------------------------------

  • 解析Android点击事件分发机制

    开头说说初衷 网上关于点击事件分发的文章一搜一大堆,标题一看,不是"30分钟让你弄明白XXX"就是"这是讲解XXX最好的文章",满怀憧憬与信心,忍不住兴奋的点进去一看,发现不是代码就全是图,我基本上看完了所有相关的文章,结果硬是看了三个小时也没搞懂.所以最后还是决定自己去试一试,看一看点击事件分发到底是怎么个流程,我写的肯定不会比其他文章好多少,但是呢,带着一个初学者的心,去分析这个东西,自己能弄明白的同时,也让想学习这个的人看了之后有些许收获,那就足够了. 运行的

  • Android从源码的角度彻底理解事件分发机制的解析(上)

    其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用ImageView?等等--对于这些问题,我并没有给出非常详细的回答,因为我知道如果想要彻底搞明白这些问题,掌握Android事件分发机

  • Android事件分发机制(下) View的事件处理

    综述 在上篇文章Android中的事件分发机制(上)--ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析.在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View.并交由子View进行处理.那么现在就来分析一下子View接收到事件以后是如何处理的. View的事件处理 对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元

  • Android事件分发机制全面解析

    事件分发机制 事件分发机制的两个阶段: 分发:事件从父视图往子视图分发,被拦截后不再传递,进入回溯阶段 回溯:事件从子视图往父视图回溯,被消费后不再回溯 关键方法: ViewGroup.dispatchTouchEvent 往子视图分发事件 ViewGroup.onInterceptTouchEvent 返回 true 表示拦截分发事件,不再传递,进入当前视图 onTouchEvent View.dispatchTouchEvent 默认事件分发,调用 onTouchEvent View.onT

  • 分析Lua观察者模式最佳实践之构建事件分发系统

    目录 一.前言 二.观察者模式 三.事件分发系统 四.使用事件分发系统解决问题 五.注册监听事件接口 六.反注册事件监听接口 七.事件派发接口 八.更多 一.前言 试想这样一个问题,当某个事件发生时,比如在游戏中A模块修改了用户的金币数,而B模块和C模块提供的功能都依赖于用户的金币数,那么,A模块在修改金币数的同时,就需要通知B模块和C模块.常规的方法就是A模块持有B模块和C模块的对象,然后分别通过调用对象接口的方式告诉它们,"嘿,我修改了用户的金币数,改成了10金币". 但这样就带来

  • Android AccessibilityService 事件分发原理分析总结

    目录 AccessibilityService 监听事件的调用逻辑 onAccessibilityEvent onIntercept AccessibilityService 事件的外部来源 AccessibilityServiceInfo AccessibilityManager AccessibilityManagerService AccessibilityServiceConnection 前言: 在了解了无障碍服务基础使用之后,我们来探究一下 AccessibilityService

  • Android事件分发机制 ViewGroup分析

    目录 整体流程 源码分析 前言: 事件分发从手指触摸屏幕开始,即产生了触摸信息,被底层系统捕获后会传递给Android的输入系统服务IMS,通过Binder把消息发送到activity,activity会通过phoneWindow.DecorView最终发送给ViewGroup.这里就直接分析ViewGroup的事件分发 整体流程 配合图在看一段伪代码: public boolean dispatchTouchEvent(MotionEvent ev) :Boolean{ val result

随机推荐