☰
6a828下Android 5.0 USB触摸屏SHOW_TOUCHES轨迹异常:多次点击与双点无响应的排查与TaoToken调试通道
2026/10/8 22:30:03 网站建设 项目流程

1. 6a828 平台 Android 5.0 USB 触摸屏 SHOW_TOUCHES 轨迹异常问题复现

在 6a828(MStar pitaya 方案)的 Android 5.0 电视盒子上,我遇到过一类很典型的现象:USB 免驱触摸屏平时用得好好的,一旦打开开发者选项里的「显示触摸位置」(也就是Settings.System.SHOW_TOUCHES),系统就开始抽风。具体表现是多次点击、双点操作时系统没反应,遥控器按键打印正常但界面卡死不动,am start也拉不起 Activity,而且不会重启,属于「假死」状态。

这个问题的核心检索词就是 android usb触摸屏 SHOW_TOUCHES 轨迹异常,它牵扯到hid-multitouch上报、ENABLE_HWCURSOR编译开关、以及 Android 输入子系统里 PointerController 的绘制逻辑。适合正在做 Android 5.0 智能硬件、机顶盒、一体机触摸调试的嵌入式工程师参考。

先把现象拆清楚,方便你对照自己的板子:

当SHOW_TOUCHES = false时,多次点击、双点、遥控器操作全部正常,触摸屏走hid-multitouch标准驱动,PC 上和其他硬件平台都工作正常,说明触摸屏硬件和驱动本身没问题。

当SHOW_TOUCHES = true时,问题来了。getevent抓到的原始事件完全正常,logcat也有输出,但系统点击就是没反应。触摸按下的白色圆点(就是 SHOW_TOUCHES 画出来的那个轨迹点)再也不出现了。比如进计算器 App,白色圆点消失,但按屏幕数字键还能起作用;从计算器用遥控器返回桌面就黑屏了。即使黑屏,getevent依然正常上报。更关键的一点:只要两个手指同时按下,马上触发这个问题。

这里有个容易误判的点:很多人看到getevent正常就以为输入链路没问题,其实getevent读的是/dev/input/eventX的原始事件,而 SHOW_TOUCHES 的轨迹绘制发生在 Android framework 的 InputReader/InputDispatcher 之后,走的是 PointerController 和 SpriteController。原始事件正常不代表上层绘制正常,这两层要分开看。

getevent -p的输出能帮我们确认设备注册了哪些事件类型。以我这块板子为例:

shell@pitaya:/ # getevent -p add device 1: /dev/input/event4 name: "SZiB0ardelectronics IboardDevice" events: KEY (0001): 014a ABS (0003): 0000 : value 21987, min 0, max 32767, fuzz 0, flat 0, resolution 0 0001 : value 22047, min 0, max 32767, fuzz 0, flat 0, resolution 0 002f : value 0, min 0, max 9, fuzz 0, flat 0, resolution 0 0035 : value 0, min 0, max 32767, fuzz 0, flat 0, resolution 0 0036 : value 0, min 0, max 32767, fuzz 0, flat 0, resolution 0 0039 : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0 input props: INPUT_PROP_DIRECT could not get driver version for /dev/input/mouse2, Not a typewriter add device 2: /dev/input/event0

注意INPUT_PROP_DIRECT这个属性,它表示这是直接输入设备(触摸屏),不是间接设备(鼠标)。ABS_MT_POSITION_X/Y(0035/0036)、ABS_MT_TRACKING_ID(0039)、ABS_MT_SLOT(002f)都在,说明hid-multitouch正确注册了多点触控能力。问题不在驱动注册,而在上层对轨迹的处理。

我实测下来,这个现象和ENABLE_HWCURSOR编译开关强相关。在./mstar/pitaya/BoardConfigCommon.mk第 144 行有:

ENABLE_HWCURSOR := true

把它改成undef ENABLE_HWCURSOR(或者注释掉),问题就消失了。这个开关控制的是硬件光标层,涉及PointerController.cpp和SpriteController.cpp两个文件。有意思的是,只注释PointerController.cpp不行,必须同时注释SpriteController.cpp才好用。这说明 SHOW_TOUCHES 的轨迹绘制和 HWCURSOR 的光标绘制在 Sprite 层产生了冲突,两个绘制源抢同一块 sprite 资源,导致输入事件被吞掉。

下面我会从内核配置、input 事件抓取、TaoToken 调试通道整理日志三个角度,给出一套可复现的排查清单。

2. TaoToken 统一 Key/API 通道整理调试日志

排查这类输入子系统问题时,最烦的不是定位,而是日志太散:getevent一份、logcat一份、内核dmesg一份、编译配置又一份,来回切换很容易漏掉关键线索。我习惯用 TaoToken 的统一 API 通道把这些日志喂给模型做交叉分析,省得自己一行行对。

TaoToken 是一个统一的大模型 API 接入通道,官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。它能做什么?简单说,就是把不同模型的调用收敛到一个 Base URL 和一把 Key 上,你不用为每个模型单独配环境。适合谁?像我这样在嵌入式调试里需要频繁让模型帮忙读日志、比对配置、生成排查脚本的人。

为什么调试输入子系统要用它?因为这类问题的线索是跨层的:getevent的原始事件、logcat里 InputReader 的 dispatch 记录、dmesg里 hid-multitouch 的 probe 信息、还有BoardConfigCommon.mk的编译开关。人眼在四个终端之间跳,很容易看花。把这几份日志拼成一段上下文丢给模型,让它找出「SHOW_TOUCHES 打开后哪一层开始丢事件」,效率高很多。

前置准备很简单,你只需要:

第一,拿到一把可用的 API Key。进控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 创建,或者在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 管理你的密钥。建议给调试用途单独建一把 Key,方便随时吊销。

第二,确认 Base URL。API 调用统一走 https://taotoken.net/api ,注意这个地址不带 UTM 参数,是纯接口地址。

第三,选一个模型 ID。调试日志分析这种任务,用长上下文、推理稳的模型比较合适,具体模型名在模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 能看到当前可用的列表。

如果你是要长期做 Android 输入子系统调试、甚至想接 Agent 自动跑排查流程,可以看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,它更适合持续性的编码和调试任务,不用每次手动拼上下文。

这里要提醒一句:TaoToken 是调试辅助通道,不是替代你本地 adb 和串口工具的东西。getevent、logcat、dmesg还是得在板子上跑,TaoToken 负责的是把这些输出汇总分析。别指望它直接连你的设备,它连的是模型。

我踩过的坑是:一开始把整份logcat不加过滤全丢进去,几万行里大部分是无关的 GC 和 SurfaceFlinger 日志,模型反而抓不住重点。后来改成只截取问题复现前后 30 秒的窗口,再配合getevent的原始事件,定位速度快了一倍。所以日志整理这一步,筛选比堆量重要。

3. 可复制的内核配置与 settings 片段

这一节给你可以直接抄的配置片段。先说结论:问题的根因在ENABLE_HWCURSOR和 SHOW_TOUCHES 的绘制冲突,所以配置要分两块处理——一块是编译期的 BoardConfig,一块是运行期的 Settings。

先看编译期配置。打开./mstar/pitaya/BoardConfigCommon.mk,找到第 144 行附近:

# 原始配置,会导致 SHOW_TOUCHES 轨迹异常 ENABLE_HWCURSOR := true # 修改方案一:直接 undef undef ENABLE_HWCURSOR # 修改方案二:注释掉 # ENABLE_HWCURSOR := true

改完之后要重新编译 system 镜像并刷机,因为这是编译期宏,运行期改不了。刷完后验证:

adb shell getprop | grep -i hwcursor # 期望输出为空,说明 HWCURSOR 未启用

如果你不想动编译配置,只想在运行期控制 SHOW_TOUCHES,可以用 Settings 命令。Android 5.0 里 SHOW_TOUCHES 是Settings.System的一个整型值:

# 打开触摸轨迹显示 adb shell settings put system show_touches 1 # 关闭触摸轨迹显示 adb shell settings put system show_touches 0 # 读取当前值 adb shell settings get system show_touches

代码里对应的写法就是 excerpt 里那段:

Settings.System.putInt( ShowTouchEnableActivity.this.getContentResolver(), Settings.System.SHOW_TOUCHES, Integer.parseInt(result));

注意Settings.System.SHOW_TOUCHES这个常量在 Android 5.0 里是隐藏 API,普通 App 调不了,得是系统签名或者有WRITE_SETTINGS权限。这也是为什么很多人在应用层改这个值没效果。

再看hid-multitouch相关的内核配置。确认你的 defconfig 里有:

CONFIG_HID_MULTITOUCH=y CONFIG_HID_GENERIC=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_FF_MEMLESS=y

如果触摸屏是 USB 免驱的,hid-multitouch会自动匹配。可以在dmesg里确认:

adb shell dmesg | grep -i multitouch # 期望看到类似: # hid-multitouch 0003:xxxx:xxxx.0001: input,hidraw0: USB HID v1.10 Device ...

关于PointerController.cpp和SpriteController.cpp的修改,如果你选择走源码路径而不是编译开关,位置在:

frameworks/base/services/input/PointerController.cpp frameworks/base/libs/ui/SpriteController.cpp

只注释PointerController.cpp里的 sprite 更新逻辑不够,因为SpriteController还在独立维护 sprite 状态,两个控制器对同一个 sprite 的引用计数会打架。必须同时处理SpriteController.cpp里的 sprite 创建和销毁路径,才能彻底避免冲突。这也是为什么「只注释一个不行,两个一起注释才好用」。

这里给一个对照表,方便你判断该改哪一层:

配置项位置作用改动后是否需重编
ENABLE_HWCURSORBoardConfigCommon.mk控制硬件光标层是
SHOW_TOUCHESSettings.System控制触摸轨迹显示否
CONFIG_HID_MULTITOUCHdefconfig多点触控驱动是
PointerControllerframeworks/base指针绘制是
SpriteControllerframeworks/baseSprite 绘制是

注意:改BoardConfigCommon.mk后一定要make installclean或者至少清掉 system 镜像的中间产物,否则宏可能不生效。我遇到过改了没重编、刷完还是老样子,白折腾半天。

4. 验证请求与成功结果

配置改完,怎么确认问题真的解决了?不能只看「感觉好了」,要有可复现的验证步骤。下面这套流程我实测有效。

第一步,抓原始事件,确认触摸屏上报正常。开两个终端,一个跑getevent,一个操作触摸屏:

adb shell getevent -lt /dev/input/event4

正常的多点触控上报长这样:

[ 12345.678901] EV_ABS ABS_MT_SLOT 00000000 [ 12345.678902] EV_ABS ABS_MT_TRACKING_ID 00000001 [ 12345.678903] EV_ABS ABS_MT_POSITION_X 00001234 [ 12345.678904] EV_ABS ABS_MT_POSITION_Y 00005678 [ 12345.678905] EV_SYN SYN_REPORT 00000000

双指按下时,应该看到两个不同的ABS_MT_SLOT和ABS_MT_TRACKING_ID。如果这里就异常,那问题在驱动层,跟 SHOW_TOUCHES 无关。

第二步,打开 SHOW_TOUCHES,复现问题:

adb shell settings put system show_touches 1

然后快速多次点击、双指同时按下。如果问题复现,界面会卡住,白色圆点消失。这时候抓logcat:

adb logcat -v threadtime -b main -b system > /tmp/touch_bug.log

重点看 InputReader 和 InputDispatcher 的 tag:

adb logcat -s InputReader InputDispatcher PointerController

问题复现时,你可能会看到类似这样的输出,说明事件被吞:

E InputDispatcher: Dropping event because the pointer is not down W PointerController: Sprite already in use, skip update

第三步,改配置后重新验证。把ENABLE_HWCURSORundef,重编刷机,再跑一遍上面的流程。成功的结果是:

adb shell settings put system show_touches 1 # 多次点击、双指按下,界面正常响应 # 白色圆点正常显示和消失 # 遥控器返回桌面正常,不黑屏

第四步,用 TaoToken 做交叉验证。把getevent输出和logcat片段拼成一段上下文,通过 API 发给模型分析。请求示例:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-id", "messages": [ {"role": "user", "content": "以下是 Android 5.0 触摸屏调试日志,getevent 正常但 logcat 显示 InputDispatcher 丢事件,请分析 SHOW_TOUCHES 与 ENABLE_HWCURSOR 的冲突点:\n<粘贴日志>"} ] }'

成功的话,模型会指出 sprite 资源竞争的具体位置,和你手动定位的结论互相印证。这一步不是必须的,但在日志量大、线索乱的时候能帮你省时间。

验证清单总结成一张表:

验证项命令期望结果
原始事件getevent -lt多点 slot/tracking_id 正常
轨迹显示settings put show_touches 1白点正常出现消失
双指操作双指同时按下界面不卡死
遥控器返回按返回键不黑屏
日志分析TaoToken API定位 sprite 冲突

5. 本篇常见报错排查

这一节把排查过程中真实会撞到的报错列出来,对照着看能少走弯路。

报错一:local proxy failed或连接超时

这个通常出现在你用 curl 调 TaoToken API 的时候。先确认 Base URL 写的是https://taotoken.net/api,不要带多余路径。再确认网络能通:

curl -I https://taotoken.net/api # 期望返回 HTTP/2 200 或 401(401 说明通了但没带 Key)

如果返回 401,说明地址对,是 Key 的问题,往下看。

报错二:401 Unauthorized

Key 没带、带错、或者过期。检查请求头:

-H "Authorization: Bearer $TAOTOKEN_API_KEY"

注意Bearer后面有一个空格,Key 不要有多余换行。如果你在 shell 里用变量,先echo $TAOTOKEN_API_KEY确认变量真的有值。Key 在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 管理,过期了就重新生成一把。

报错三:reading choices相关解析错误

这个一般是你把模型返回的 JSON 直接当文本处理了。模型返回的是标准 chat completion 结构,内容在choices[0].message.content里。用jq提取:

curl ... | jq -r '.choices[0].message.content'

如果jq报Cannot index array with string,说明返回结构和你预期的不一样,先curl ... | jq .看完整结构再取字段。

报错四:OAuth相关提示

如果你用的是 Claude Code 之类的工具接 TaoToken,可能会碰到 OAuth 配置问题。这类工具需要三件套齐全:Base URL、Key、Model ID。以 Claude Code 为例,配置里要写全:

{ "base_url": "https://taotoken.net/api", "api_key": "your-token-key", "model": "your-model-id" }

三件套缺一个都会报 OAuth 或认证失败。Model ID 在模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 能查到当前可用的。

报错五:getevent有输出但系统无响应

这就是本篇的核心问题,不是报错,是现象。排查顺序:

先确认ENABLE_HWCURSOR是否为 true,是的话 undef 重编。再确认PointerController.cpp和SpriteController.cpp是否都处理了,只改一个不够。最后确认SHOW_TOUCHES的值,用settings get system show_touches读。

报错六:am start无响应

这是问题复现后的连带现象,不是独立故障。界面卡死后am start拉不起 Activity,因为 InputDispatcher 卡在丢事件的循环里。解决根因后这个现象自然消失,不用单独处理。

报错七:could not get driver version for /dev/input/mouse2, Not a typewriter

这个在getevent -p里很常见,是mouse2节点不是标准 input 设备导致的,属于无害提示,不影响触摸屏功能。不用管它。

排查时建议按这个顺序:先看getevent确认驱动层,再看logcat确认 framework 层,最后看编译配置确认 HWCURSOR。三层逐层排除,比一上来就改代码高效。

6. 接入文档与 API Keys 快速通道

调试通道配好之后,日常用起来其实就三步:抓日志、拼上下文、发请求。如果你想把这套流程固化下来,建议把常用的 curl 命令写成脚本,Key 用环境变量管理,别硬编码在脚本里。

接入相关的文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,里面有完整的接口说明和参数列表。Key 的管理在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,建议给调试、生产、测试分别建不同的 Key,方便追踪用量和随时吊销。

如果你只是想快速验证某个模型对这段触摸日志的分析能力,直接去模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 粘贴日志试一下,不用写代码。如果是要长期做 Android 输入子系统的调试和 Agent 自动化,Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 更合适,它按持续任务设计,不用每次手动拼请求。

最后说个实用技巧:把getevent和logcat的抓取命令写成一行,问题复现时一键执行,日志自动带时间戳存到固定目录。这样下次再遇到 SHOW_TOUCHES 轨迹异常,直接拿日志去分析,不用现场手忙脚乱。我现在的习惯是板子一上电就跑一个后台脚本持续抓 input 相关日志,出问题时回捞最近几分钟的窗口,比事后复现靠谱得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询