systemserver的inputdispatcher直接产生CANCEL事件原理分析

编程入门 行业动态 更新时间:2024-10-21 17:43:11

systemserver的inputdispatcher直接产生CANCEL事件<a href=https://www.elefans.com/category/jswz/34/1770123.html style=原理分析"/>

systemserver的inputdispatcher直接产生CANCEL事件原理分析

背景回顾:

上一个blog已经重点讲解了app层面自己产生的Cancel触摸事件,大概产生的原理如下:
上一个blog地址:
即可以看出来,在服务端systemserver其实传递的触摸事件依然是move,只是move事件到了app端后,由于app端自己的业务把这个传递的move事件变成的cancel
视频讲解:/
那么疑问来了?这个有没有存在systemserver传递事件时候就是已经变成cancel了呢?
如下图:

答案当然是有的。下面就进行详细分析

2、systemserver端变成cancel事件

复现场景:
1、手机设置成导航按键模式桌面点击

2 、点击一个应用进入,然后手指一直触摸再应用内
3、然后另一个手点击导航键home按键,让回到桌面

以上3步即可以复现点击进去的应用内接受到一个Cancel事件,因为手其实一直触摸在屏幕,所以当然不存在接受到up,但是毕竟这个时候应用已经被退到后台,所以就只能给一个cancel事件给应用。这个cancel事件就是systemserver中inputdispatcher传递给应用的。

下面来进行源码分析cancel事件在inputdispatcher产生

1、开启日志
开放DEBUG_OUTBOUND_EVENT_DETAILS日志,这里可以用adb 命令也可以直接修改变成true

/*** Log detailed debug messages about each outbound event processed by the dispatcher.* Enable this via "adb shell setprop log.tag.InputDispatcherOutboundEvent DEBUG" (requires restart)*/
const bool DEBUG_OUTBOUND_EVENT_DETAILS =true;// __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundEvent", ANDROID_LOG_INFO);

2、复现时候查看日志

09-10 22:49:50.775  2231  2357 D InputDispatcher: channel 'a1b72df com.android.messaging/com.android.messaging.ui.conversationlist.ConversationListActivity (server)' ~ Synthesized 1 cancelation events to bring channel back in sync with reality: touched window was removed, mode=1.

这里即可以看出有同步一个cancel事件给com.android.messaging/com.android.messaging.ui.conversationlist.ConversationListActivity,大家注意这个原因是“touched window was removed”

可以根据这个reason来追一下相关代码:

test@test:~/nx563j_xiaomi/frameworks/native$ grep "touched window was removed" ./ -rn
./services/inputflinger/dispatcher/InputDispatcher.cpp:4759:                                               "touched window was removed");

找到了在InputDispatcher的4759行:

/*** Called from InputManagerService, update window handle list by displayId that can receive input.* A window handle contains information about InputChannel, Touch Region, Types, Focused,...* If set an empty list, remove all handles from the specific display.* For focused handle, check if need to change and send a cancel event to previous one.* For removed handle, check if need to send a cancel event if already in touch.*/
void InputDispatcher::setInputWindowsLocked(const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {//省略部分//把inputdispatcher的window相关信息变成最新updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);//最为关键的mTouchStatesByDisplay变量,一般保存就是当前触摸事件的派发情况,主要保存了派发触摸相关的window信息std::unordered_map<int32_t, TouchState>::iterator stateIt =mTouchStatesByDisplay.find(displayId);if (stateIt != mTouchStatesByDisplay.end()) {TouchState& state = stateIt->second;for (size_t i = 0; i < state.windows.size();) {TouchedWindow& touchedWindow = state.windows[i];//拿正在触摸的window信息与最新的window的信息比较看看是否还存在,如果不在说明消失了if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) {std::shared_ptr<InputChannel> touchedInputChannel =getInputChannelLocked(touchedWindow.windowHandle->getToken());if (touchedInputChannel != nullptr) {//开始触发相关的cancel事件CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,"touched window was removed");synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);}}state.windows.erase(state.windows.begin() + i);} else {++i;}}
//省略
}

setInputWindowsLocked主要是在系统有窗口window更新时候才会触发调用,比如我们上面演示场景的,按home按键后应用画面要退出后台,这个时候肯定应用的window就没有了,就会触发改方法。
1、updateWindowHandlesForDisplayLocked
这里会把最新的window信息更新到inputdispatcher的mWindowHandlesByDisplay变量中
2、方法内主要变量有一个mTouchStatesByDisplay:

最为关键的mTouchStatesByDisplay变量,一般保存就是当前触摸事件的派发情况,主要保存了派发触摸相关的window信息

即代表当前的触摸事件派发相关window的的记录

3、还有另一个关键方法getWindowHandleLocked

sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const {if (windowHandleToken == nullptr) {return nullptr;}//就是拿传入的windowHandleToken去mWindowHandlesByDisplay遍历看看是否有for (auto& it : mWindowHandlesByDisplay) {const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second;for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {if (windowHandle->getToken() == windowHandleToken) {return windowHandle;}}}return nullptr;
}

4、找到对应删除的window的inputchannel,传递对应的cancel事件
//获取touchedInputChannel
std::shared_ptr touchedInputChannel =
getInputChannelLocked(touchedWindow.windowHandle->getToken());
//派发cancel事件到touchedInputChannel
synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);

如果发现更新之后的window的中已经没有了正在派发事件的window,那么说明window已经被移除,然后就会触发相关的cancel事件到原来的window。

最后更多干货直接找千里马可以+w ; androidframework007

更多推荐

systemserver的inputdispatcher直接产生CANCEL事件原理分析

本文发布于:2024-02-24 21:40:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1696744.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:原理   事件   systemserver   inputdispatcher   CANCEL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!