Phenomenon
Version note — reviewed October 13, 2026: This is a historical 2019 case without the complete trace, ROM build, or app versions. The old call chain is checked against AOSP
android-9.0.0_r1as a reference, not an identification of the original ROM. Anandroid-16.0.0_r1comparison is added below. The findings concern the observed configuration, not every accessibility service or current versions of the named apps.
Some users reported that while scrolling on the phone, the list would jitter. This happens when scrolling on the desktop or settings (as long as it is scrollable), but this is not reproducible for everyone; it appears for some users, but not for others.
Onlookers can scroll directly to the bottom to see The Culprit and Self-Check. Those interested in analyzing the problem can read the analysis process.
Systrace Analysis
One of our test phones reproduced it. I took a look: dragging across the launcher or Settings caused stuttering every time on that device. Here is what the trace showed:
I marked the gaps in updates with red arrows. Launcher buffer supply appears intermittent, but this crop lacks complete frame and presentation timing. No new buffer does not mean SurfaceFlinger stopped working; it may keep displaying the previous frame.
The corresponding Launcher trace shows gaps in input-handling and drawing activity, making the input path worth investigating. This alone does not prove that a frame without a new input event cannot draw: animations, flings, and other updates do not require fresh touch input on every frame.
We were dragging continuously, so our first suspicion was a problem with touch sampling or event delivery. Sampling, batching, and display refresh are not one-to-one, however. Before investigating hardware, compare InputReader and InputDispatcher activity:

InputReader remains active, while InputDispatcher follows a different pattern from the comparison below. Thread activity alone does not prove that hardware sampling and every event are correct; event timestamps and wakeup details still need checking.

Looking back at the problematic trace, I noticed that some InputDispatcher activity aligned more closely with Vsync. This suggests a different delivery path for those events, not that every InputDispatcher wakeup became Vsync-driven.
I then opened the scheduling details and saw some wakeups from the system_server main thread rather than InputReader. The retained crop does not expose those scheduler details, so this remains a recorded observation requiring the full trace to verify. Aligned slices alone do not establish the waking thread.
Next, inspect the conditions that divert input from direct enqueueing.
Code Analysis
The following touch-Move path uses AOSP android-9.0.0_r1 as a reference. These are platform excerpts, not a standalone application; the first omits debug logging. The needWake condition means a new wakeup is not required for every event when work is already queued.
1 | void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { |
When filterInputEvent() returns false, this notifyMotion() call skips direct enqueueing and its wakeup. The filter has taken responsibility for the event; that does not mean the event is permanently lost or InputReader stopped running.
Continue with the JNI filterInputEvent implementation:
1 | bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) { |
JNI calls InputManagerService.filterInputEvent. The object-creation failure and Java-exception paths above allow normal dispatch by returning true; these branches should not be omitted.
1 | // Native callback. |
Here we examine mInputFilter as an AccessibilityInputFilter. AccessibilityManagerService.updateInputFilter combines enabled-feature flags and installs a filter when needed. Not every accessibility switch enables the same MotionEvent path.
InputFilter posts to its Handler. The second fragment below belongs inside H.handleMessage(). AccessibilityInputFilter uses context.getMainLooper(); the system_server main thread must not be confused with the separately named android.ui thread.
1 | final public void filterInputEvent(InputEvent event, int policyFlags) { |
Continue with AccessibilityInputFilter.onInputEvent:
1 |
|
Continue to look at processMotionEvent
1 | private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) { |
Continue to look at batchMotionEvent
1 | private void batchMotionEvent(MotionEvent event, int policyFlags) { |
Continue to look at scheduleProcessBatchedEvents
1 | private void scheduleProcessBatchedEvents() { |
The task is scheduled for Choreographer’s CALLBACK_INPUT phase. Actual execution still depends on main-Looper scheduling, so delivery is not guaranteed exactly one Vsync later. The complete Runnable is:
1 | private final Runnable mProcessBatchedEventsRunnable = new Runnable() { |
processBatchedEvents() adds another timing condition: only entries older than frameNanos are processed; remaining entries at or after that time wait for a later callback.
1 | private void processBatchedEvents(long frameNanos) { |
Events forwarded after transformation reach AccessibilityInputFilter.onMotionEvent(), then InputFilter.sendInputEvent() and InputManagerService.InputFilterHost.sendInputEvent(), which asynchronously inject them into native dispatch with FLAG_FILTERED. A filter can also consume or transform events intentionally, so the earlier return alone does not establish event loss.
Main-thread queuing, the batch cutoff, and later dispatch can add latency on this Android 9 path. That is consistent with the recorded timing change, but does not prove every enabled service causes dropped frames or adds exactly 16 ms to every event. These remain the original case annotations:

Android 16 Path Change
In the same class at AOSP android-16.0.0_r1, processMotionEvent() calls handleMotionEvent() directly instead of the old batchMotionEvent()/Choreographer queue:
1 | private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) { |
This comparison establishes a change between the checked implementations, not the first fixed release or the absence of accessibility-related delays on every modern device. Filtering, scheduling, service behavior, and OEM modifications still require investigation on the actual system.
The Culprit
We traced the symptom to certain enabled accessibility services, involving iFlytek Input Method and Yingyongbao, and saw similar behavior on Pixel and other vendors’ devices. Without the ROM/app versions and full comparison data, these remain 2019 case observations, not findings about current releases of those apps.
Accessibility services help users with visual, motor, and other access needs; some apps also use them for automation. Different capabilities enable different input-processing features. The historical settings page lists services, not proof that all were enabled or implicated:

The next permission dialog is for Voice Access, not a record of data accessed by iFlytek or Yingyongbao. It warns that these capabilities may expose sensitive UI information. The dialog does not prove that a service read all passwords, card numbers, or conversations. Access depends on declared capabilities, OS version, exposed accessibility nodes, and field protection.

Android 14 (API 34) added mechanisms such as accessibilityDataSensitive, restricting interactions with sensitive views by services not marked isAccessibilityTool. That declaration is not a certification of trustworthiness or a substitute for inspecting actual data exposure.
“Perform gestures” in the iFlytek dialog below is not merely gesture listening. The canPerformGestures capability permits gesture injection through dispatchGesture(), introduced in Android 7.0 (API 24).

In Android 9, updatePerformGesturesLocked() checks bound services for CAPABILITY_CAN_PERFORM_GESTURES, enabling FLAG_FEATURE_INJECT_MOTION_EVENTS, which belongs to FEATURES_AFFECTING_MOTION_EVENTS. That enabled capability can therefore route real touch input through the old filter path even without an active dispatchGesture() call. Magnification and touch exploration can also enable related paths; this is not one universal “gesture listener” switch.
Self-Check
Unused services can be disabled, but do not indiscriminately turn off screen reading, voice control, or other assistance you rely on. To investigate a suspected newly enabled service:
- Record the device, OS build, app version, enabled services, and reproducible scenario. Settings names and locations vary by vendor.
- If it does not prevent you from operating the device, change one suspected service at a time, repeat the same scrolling scenario, and restore needed functionality. One apparently smoother run does not establish causation or implicate all accessibility services.
- Developers should align input timestamps, main-Looper queuing, InputDispatcher delivery, and visible updates in Perfetto or equivalent traces. FrameTimeline on Android 12 and later can help, but is not a complete input-latency measurement: waiting that produces no new frame may not appear as a deadline miss for a generated frame.
- Service developers should declare only needed capabilities and measure the target system’s input path. Required gesture injection and touch exploration should be made responsive rather than removed from users who need them.
Zhihu Address of this article
Since blog message communication is inconvenient, for likes or communication, please move to the Zhihu interface of this article
Zhihu - Analysis of Global Stutter Caused by Accessibility Services of Yingyongbao and iFlytek Input Method on Android Platform
About Me && Blog
Below are personal introduction and related links. I hope to communicate more with everyone in the industry. If three people walk together, there must be one who can be my teacher!
- Blogger Personal Introduction: There are personal WeChat and WeChat group links inside.
- This Blog Content Navigation: A navigation of personal blog content.
- Excellent blog articles organized and collected by individuals - A must-know for Android efficiency optimization: Everyone is welcome to recommend themselves and recommend others (WeChat private chat is fine)
- Android Performance Optimization Knowledge Planet: The paid community stopped operating in 2026 and no longer accepts new members; this link preserves its history.
One person can go faster, a group of people can go further
