HarmonyOS的多模输入服务(Multimodal Input Service)负责分发触摸、按键等事件。当用户触摸屏幕时,输入事件会被发送到应用的主线程(Main Thread)消息队列中等待处理。
系统规定,应用必须在 5秒 内对输入事件完成派发和处理。如果主线程被其他耗时任务(如复杂计算、IO操作)占用,导致输入事件在队列中排队等待超过5秒仍未被执行,系统为了防止设备“假死”,会判定为输入阻塞,触发APP_INPUT_BLOCK故障,生成AppFreeze日志并终止进程。
通过DevEco Studio的FaultLog面板,或者通过命令hdc file recv /data/log/faultlog/faultlogger/ .导出以appfreeze-开头的日志文件。
打开日志,关注Event和Timestamp,确认故障类型为输入阻塞。
Generated by HiviewDFX ... Event: APP_INPUT_BLOCK <-- 故障类型:输入阻塞 Timestamp: 2024-05-21 10:00:05 <-- 日志生成时间 Reason: Input dispatching timed out <-- 触发原因:输入分发超时
输入事件被阻塞,通常是因为主线程正在执行另一个耗时任务,导致无法处理输入事件。需要查看Main handler dump中的Current Running,找出当前在执行的任务。
输入:查看日志中的Current Running字段。
Event: APP_INPUT_BLOCK Timestamp: 2025/06/28-14:08:30.500 <-- 1. 系统判定超时的时间 ... Main handler dump is: EventHandler dump begin curTime: 2025-06-28 14:08:30.200 Current Running: start at 2025-06-28 14:08:24.100, <-- 2. 正在执行的任务开始时间 task name = .ets/pages/Index.ts:onPageShow, <-- 3. 任务名称(如生命周期函数) caller = [ohos_loop_handler.cpp(OnTriggered:72)]
判定公式:
阻塞时长=日志生成时间(Timestamp)-当前任务开始时间。
实际日志计算:
Timestamp(14:08:30.500)-start at(14:08:24.100)≈6.4秒。
判断:该任务(onPageShow)执行超过了5秒,导致在此期间用户产生的点击事件无法被响应。
在日志下方找到Tid与主线程Pid一致的堆栈信息(Name:main)。
#00 pc 000000000018a2d0 /system/lib64/libark_runtime.so (ArkJS::Interpreter::Run+200) <-- 纯JS执行 #01 pc 000000000008b100 /data/storage/el1/bundle/.../entry.hap (Utils.ets:50) <-- 具体的计算逻辑行号 #02 pc 000000000008c2a0 /data/storage/el1/bundle/.../entry.hap (Index.ets:45) <-- onClick 调用处
#00 pc ... libipc_core.z.so (OHOS::BinderDriver::Transact+...) #01 pc ... libaa.z.so (WaitSystemAbility+...)
APP_INPUT_BLOCK与THREAD_BLOCK_6S的根本原因高度重合,区别在于触发时机:前者是在用户交互时触发,后者是通用检测。
文件读写(File)、数据库操作(RDB)、首选项(Preferences)及跨进程通信(IPC)不要在主线程使用同步接口(Sync后缀方法),替换为Promise或AsyncCallback形式的API。
如果界面布局过于复杂,或者列表数据量过大,会导致构建(Build)和布局(Layout)阶段占用主线程过久,无法及时响应输入。
对于onTouch(触摸移动)、onScroll(滚动)、onTextChange(文本变化)等高频触发的回调,如果处理逻辑过重,会瞬间堆积大量任务导致主线程卡死。
检查主线程是否在等待一把被子线程持有的锁(如AppStorage的读写锁、Native层的std::mutex)。
以下是一些细分场景分类:
# | 细分场景分类 | 详细成因与代码行为 | 关键堆栈/函数特征 |
|---|---|---|---|
1 | UI: 复杂列表加载 | 在 List 或 Grid 的 LazyForEach 中,itemGenerator 构建函数逻辑过于复杂,或主线程一次性加载了成千上万条数据。 | OHOS::Ace::Framework::...BuildItem ArkJS::Interpreter |
2 | LifeCycle: 阻塞初始化 | 在 Ability 的 onCreate 或页面的 aboutToAppear 中同步初始化大型 SDK 或读取大型 JSON 配置文件。 | entry.hap (源码行号) libark_runtime.so |
3 | Event: 连点阻塞 | 用户第一次点击触发了耗时任务 A(运行在主线程),此时任务 A 尚未结束,用户再次点击,第二次点击引发 Input Block。 | onClick 对应的匿名函数 |
4 | Layout: 嵌套灾难 | 页面布局嵌套层级过深(如 >30层),导致测量和布局计算(Measure/Layout)耗时超过阈值,且发生在用户交互触发刷新时。 | OHOS::Ace::RenderNode::Layout OHOS::Ace::FlutterRender |
5 | IPC: 等待 Window 服务 | 应用尝试调整窗口大小、亮度或模式,同步调用 WindowManager 接口,但 WindowManagerService 繁忙或卡死。 | OHOS::Rosen::Window::SetBrightness OHOS::BinderDriver::Transact |
6 | Asset: 同步加载大图 | 在主线程使用 ImageSource.createPixelMap 同步解码 4K/8K 级大图,用于点击后的弹窗展示。 | ImageSource::CreatePixelMap libimage_source.z.so |
7 | Logic: 剪切板阻塞 | 用户点击“粘贴”按钮,应用在主线程同步读取系统剪切板大量数据,或等待剪切板服务响应。 | OHOS::Pasteboard::PasteboardClient |