android input 事件分发 --- 注册input

news2024/9/20 16:44:24

android input 事件分发 --- 注册input

  • 应用注册input事件

应用注册input事件

	应用如果要监听input的事件,那么肯定就存在一个注册监听input事件的过程,跟随着addView方法我们跟着走一下

frameworks/base/core/java/android/view/WindowManagerImpl.java

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

frameworks/base/core/java/android/view/WindowManagerGlobal.java


    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
   			// 省略无关代码,ViewRootImpl是view和window之间的一个沟通的桥梁,在ViewRootImpl构造函数中会做很多事,但目前我们不关心
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
            // 主要看这个方法,在这会创建InputChannel
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
	

frameworks/base/core/java/android/view/ViewRootImpl.java


public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                        // 创建客户(应用)端的InputChannel对象,这里会创建socket进行service和client绑定
                    mInputChannel = new InputChannel();
                }
                mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    // 看这里将上面创建出来的客户端的InputChannel给到WindowSession,我们继续跟一下
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
}

frameworks/base/services/core/java/com/android/server/wm/Session.java

    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
            Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
            // 这里调到了windowManagerService
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
    }

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java


public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {

            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            final boolean hasStatusBarServicePermission =
                    mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
                            == PackageManager.PERMISSION_GRANTED;
            mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }

            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
            // 这个openInputChannel我们会做详细讲解
                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();
        // openInputChannelPair 里边会创建一个socketpair,这是一个Unix socket,应用和inputDispacher分别会作为client和service端,往一个缓冲区去读写
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        // 这里mInputChannel 和 mClientChannel 持有的分别是两个fd
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        if (outInputChannel != null) {
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }

frameworks/base/core/java/android/view/InputChannel.java

    public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        if (DEBUG) {
            Slog.d(TAG, "Opening input channel pair '" + name + "'");
        }
        return nativeOpenInputChannelPair(name);
    }

frameworks/base/core/jni/android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    std::string name = nameChars;
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    // 这里将 serverChannel、clientChannel给到openInputChannelPair进行赋值
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        String8 message;
        message.appendFormat("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, message.string());
        return NULL;
    }

frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    这里去创建socketPair,分别有两个socket Fd, 这里两个socket FD,分别都可以往bufferSize申请的缓存区,写入和读取
    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));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    // 将sockets[0]给到ServerChannel
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    // 将sockets[1]给到outClientChannel
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

类图如下
这里对整个注册过程做了详尽
在这里插入图片描述

这里对创建openInputChannelPair做了详解
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/139041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7 安装 MongoDB

使用docker安装Mongo 1、拉取镜像 注&#xff1a;需要科学上网 docker pull mongo [rootlocalhost ~]# docker pull mongo Using default tag: latest latest: Pulling from library/mongo 846c0b181fff: Pull complete ef773e84b43a: Pull complete 2bfad1efb664: Pull co…

LeetCode:14. 最长公共前缀

14. 最长公共前缀1&#xff09;题目2&#xff09;思路3&#xff09;代码4&#xff09;结果1&#xff09;题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs [“flo…

python常用快捷键

一、编辑&#xff08;Editing&#xff09;Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09;Ctrl Alt Space 快速导入任意类Ctrl Shift Enter 语句完成Ctrl P 参数信息&#xff08;在方法中调用参数&#xff09;Ctrl Q 快速查看文档F1 外部文档Shift F…

c语言 通讯录 动态内存开辟

通讯录 通讯录中能够存放1000人信息 每个人信息&#xff1a; 姓名年龄性别电话地址 2.增加人的信息 3.删除指定人的信息 4修改指定人的信息 5.查找指定人的信息 6.排序通讯录的信息 contact.h 放头文件的声明 tset.c 测试通讯录模块 contact.c 函数的实现 test.c #include &…

基于不同操作系统升级知行之桥的常见问题

此前的文章知行之桥2022版本升级之页面变化以及监控邮件答疑给大家分享了一些升级到知行之桥最新版本关于Web页面显示和监控邮件的一些问题&#xff0c;本篇将分享一些windows和Linux不同操作系统升级部署知行之桥最新版本的一些Q&A。 EDI服务器是windows服务器 Windows操…

Smart JavaScript UI 14.4.0 Crack【htmlelements】

Smart是一个建立在 JavaScript、HTML 和 CSS 之上的全面且创新的 UI 库。Ω578867473使开发人员能够交付专业的、跨浏览器兼容的 Web 应用程序&#xff0c;同时显着缩短他们的开发时间。Smart HTML Elements 包含 60 多个 UI 组件&#xff0c;是 Web 上发展最快的 JavaScript U…

Centos7配置阿里云yum源及epel源

Background 踩坑记录吧。下次可以直接复制粘贴&#xff0c;不用再去排查是哪个字母字符少了多了&#xff0c;我这都是执行成功的命令粘贴过来的。 1、基础知识简介 yum: 全称“Yellow dog Updater, Modified”&#xff0c;是一个专门为了解决包的依赖关系而存在的软件包管理器…

ubuntu 18.04 Pytorch安装GPU版本

先上成功的图片 过程总结&#xff1a; 之前也配置过&#xff0c;但是时间流逝&#xff0c;之前的方法也过时了&#xff08;旧方法一般会提到先装nvidia驱动&#xff0c;再cuda&#xff0c;再cudnn之类&#xff09;。 我今天尝试安装cuda 11.7时&#xff0c;发现cuda会自动安装…

使用 dict 对象创建多重索引 DataFrame

使用 dict 对象创建多重索引 DataFrame创作背景查看所需 dict 的格式结尾创作背景 本菜鸡最近碰到了需要使用字典创建多重索引 DataFrame 的场景&#xff0c;谨以本文记录解决过程。 如果觉得我这篇文章写的好的话&#xff0c;能不能给我 点个赞 &#xff0c;评论 、收藏 一条…

对近似算法概念的学习

近似算法基本概念可近似分类最小顶点覆盖问题近似算法的分析&#xff1a;多机调度问题近似算法贪心G-MPS近似算法递降贪心法DG-MPS货郎问题最近邻NN算法最小生成树法MST最小权匹配MM算法0-1背包问题贪心G-KK多项式近似方案完全多项式时间的近似方案背包问题的对偶问题总结基本概…

彻底搞懂UML图

用例图 用例图的结构主要分为三个部分&#xff1a;参与者、用例、参与者与用例之间的关系。 参与者&#xff1a;不是特指人&#xff0c;是指系统以外的&#xff0c;在使用系统或与系统交互中所扮演的角色。因此参与者可以是人&#xff0c;可以是事物&#xff0c;也可以是时间…

关于alpine如何制作JDK镜像

Docker制作jdk镜像(v1.0)1.1首先编写Dockerfile文件#1.指定基础镜像&#xff0c;并且必须是第一条指令RROM centos:7#2.指明该镜像的作者和其电子邮件MAINTAINER xnx "zwcqq.com"#3.在构建镜像时&#xff0c;指定镜像的工作目录&#xff0c;之后的命令都是基于此工作…

Python自制简易版计算器小程序

前言 今天来给你们分享一个自制的桌面小程序【简易版计算器】 文章内有效果展示&#xff0c;你们可以自行看看哦 不想看文章&#xff0c;想直接领取源码的话&#xff0c;可以直接点击文章末尾的名片哈 环境准备 Python 3.6 Pycharm 代码展示 界面设置 导入模块 所有 源码 …

STM32读取SHT3x系列温湿度传感器,标准库和HAL库

STM32读取SHT3x系列(SHT30、SHT31、SHT35)温湿度传感器的数据并显示在0.96寸OLED屏上。 我下面提供两份代码&#xff0c;一份是标准库使用硬件I2C的&#xff0c;另一份是HAL库使用软件模拟IIC的。 我用的单片机是STM32F103C8T6&#xff0c;温湿度传感器是SHT30。 STM32软件I…

Spring Cloud与Nacos部署Spring Boot项目

本文记录一个用于Spring Cloud 和nacos的一个项目配置方案 本文主要通过nacos实现了两点功能&#xff1a; 1、服务的注册与发现 2、nacos的动态配置 项目中主要包括了nacos-consumer和nacos-provider&#xff0c;一个消费者&#xff0c;一个生产者的角色&#xff0c;消费者负责…

旋转目标检测复现-yolov5-obb

复现源码&#xff1a; https://github.com/hukaixuan19970627/yolov5_obb 亲测可行 安装流程&#xff1a; 按照https://github.com/hukaixuan19970627/yolov5_obb/blob/master/docs/install.md 确保安装过程不报错&#xff0c;否则影响后续训练 安装成功即可准备数据集 hf_t…

MySQL复制技术方案——组复制

1&#xff0e;原理 增强半同步复制虽然解决了HA切换之后的幻读问题&#xff0c;也从一定程度上使得主从实例 之间的数据一致性保障得到增强&#xff0c;但是仍然还有很多问题需要解决。 例如&#xff1a; HA切换程度需要依赖于MySQL服务器之外的第三方程序实现&#xff0c;维…

2022年12月安全事件盘点

2022年12月安全事件盘点 一、基本信息 2022年12月安全事件共造成约8327万美元损失&#xff0c;金额数量较上月有所下降。本月RugPull数量基本与上月持平。但临近年底&#xff0c;熊市社媒诈骗等较上个月有所增加&#xff0c;Discord攻击诈骗成为重灾区。另外本月依然有钱包&…

产线工控设备安全现状分析

工控设备安全现状 工业控制系统是支撑国民经济的重要设施&#xff0c;是工业领域的神经中枢。现在工业控制系统已经广泛应用于电力、通信、化工、交通、航天等工业领域&#xff0c;支撑起国计民生的关键基础设施。 随着传统的工业转型&#xff0c;数字化、网络化和智能化的工…

IB课程为什么深受国际学生的喜爱?

凯恩斯是一个被大自然包围的城市。由于得天独厚的地理位置&#xff0c;在凯恩斯随时都可以让你感受到与自然融为一体的亲近与惬意。此外&#xff0c;安全性高也是一大优势&#xff0c;昆士兰当地人对国际学生非常热情友好&#xff0c;在你需要帮助的时候&#xff0c;从来不会感…