6a828下Android 5.0 USB触摸屏SHOW_TOUCHES轨迹异常:多次点击与双点无响应的排查与TaoToken调试通道
发布时间:2026/10/8 22:30:05 锦皓数字建站

1. 6a828 平台 Android 5.0 USB 触摸屏 SHOW_TOUCHES 轨迹异常问题复现在 6a828MStar 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的输出能帮我们确认设备注册了哪些事件类型。以我这块板子为例shellpitaya:/ # 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/Y0035/0036、ABS_MT_TRACKING_ID0039、ABS_MT_SLOT002f都在说明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_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它能做什么简单说就是把不同模型的调用收敛到一个 Base URL 和一把 Key 上你不用为每个模型单独配环境。适合谁像我这样在嵌入式调试里需要频繁让模型帮忙读日志、比对配置、生成排查脚本的人。为什么调试输入子系统要用它因为这类问题的线索是跨层的getevent的原始事件、logcat里 InputReader 的 dispatch 记录、dmesg里 hid-multitouch 的 probe 信息、还有BoardConfigCommon.mk的编译开关。人眼在四个终端之间跳很容易看花。把这几份日志拼成一段上下文丢给模型让它找出「SHOW_TOUCHES 打开后哪一层开始丢事件」效率高很多。前置准备很简单你只需要第一拿到一把可用的 API Key。进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 创建或者在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 管理你的密钥。建议给调试用途单独建一把 Key方便随时吊销。第二确认 Base URL。API 调用统一走 https://taotoken.net/api 注意这个地址不带 UTM 参数是纯接口地址。第三选一个模型 ID。调试日志分析这种任务用长上下文、推理稳的模型比较合适具体模型名在模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 能看到当前可用的列表。如果你是要长期做 Android 输入子系统调试、甚至想接 Agent 自动跑排查流程可以看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 它更适合持续性的编码和调试任务不用每次手动拼上下文。这里要提醒一句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_MULTITOUCHy CONFIG_HID_GENERICy CONFIG_INPUT_EVDEVy CONFIG_INPUT_FF_MEMLESSy如果触摸屏是 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然后快速多次点击、双指同时按下。如果问题复现界面会卡住白色圆点消失。这时候抓logcatadb logcat -v threadtime -b main -b system /tmp/touch_bug.log重点看 InputReader 和 InputDispatcher 的 tagadb 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 或 401401 说明通了但没带 Key如果返回 401说明地址对是 Key 的问题往下看。报错二401 UnauthorizedKey 没带、带错、或者过期。检查请求头-H Authorization: Bearer $TAOTOKEN_API_KEY注意Bearer后面有一个空格Key 不要有多余换行。如果你在 shell 里用变量先echo $TAOTOKEN_API_KEY确认变量真的有值。Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 管理过期了就重新生成一把。报错三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_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 能查到当前可用的。报错五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_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 里面有完整的接口说明和参数列表。Key 的管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 建议给调试、生产、测试分别建不同的 Key方便追踪用量和随时吊销。如果你只是想快速验证某个模型对这段触摸日志的分析能力直接去模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 粘贴日志试一下不用写代码。如果是要长期做 Android 输入子系统的调试和 Agent 自动化Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 更合适它按持续任务设计不用每次手动拼请求。最后说个实用技巧把getevent和logcat的抓取命令写成一行问题复现时一键执行日志自动带时间戳存到固定目录。这样下次再遇到 SHOW_TOUCHES 轨迹异常直接拿日志去分析不用现场手忙脚乱。我现在的习惯是板子一上电就跑一个后台脚本持续抓 input 相关日志出问题时回捞最近几分钟的窗口比事后复现靠谱得多。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。