In android, Window::request_redraw() can block UserEvents send by EvenLoopProxy::send_event to reach the event loop callback.
I think this happens because of the way that request_redraw is injected in the Looper. In request_redraw the request is store in the static INTERNAL_EVENT, and the Looper is wakened:
|
pub fn request_redraw(&self) { |
|
*INTERNAL_EVENT.write().unwrap() = Some(InternalEvent::RedrawRequested); |
|
ForeignLooper::for_thread().unwrap().wake(); |
|
} |
And in Poll::Wake, the request is injected in the Looper, taking priority over EventSource::User:
|
Poll::Wake => Some( |
|
INTERNAL_EVENT |
|
.write() |
|
.unwrap() |
|
.take() |
|
.map_or(EventSource::User, EventSource::Internal), |
|
), |
And send_event also wakes up the Looper:
|
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> { |
|
self.queue.lock().unwrap().push_back(event); |
|
self.looper.wake(); |
|
Ok(()) |
|
} |
This means that if both calls to loop.wake() creates a single Poll::Wake, request_event will always be blocking send_event (as happens in my device).
Reproducing the issue
I can reproduce this bug by adding the following example to the examples folder: https://gist.github.com/Rodrigodd/379a24ea39c6bead98a8b5dad5e0753e
And running in android, as instructed in the README.md.
// add this to Cargo.toml
[[example]]
name = "android_send_event_block"
crate-type = ["cdylib"]
cargo apk run --example android_send_event_block
adb logcat RustStdoutStderr:D *:S
Reproducible on Android 11.
In android,
Window::request_redraw()can blockUserEvents send byEvenLoopProxy::send_eventto reach the event loop callback.I think this happens because of the way that request_redraw is injected in the Looper. In
request_redrawthe request is store in the staticINTERNAL_EVENT, and the Looper is wakened:winit/src/platform_impl/android/mod.rs
Lines 676 to 679 in 4dd2b66
And in
Poll::Wake, the request is injected in the Looper, taking priority overEventSource::User:winit/src/platform_impl/android/mod.rs
Lines 220 to 226 in 4dd2b66
And
send_eventalso wakes up the Looper:winit/src/platform_impl/android/mod.rs
Lines 583 to 587 in 4dd2b66
This means that if both calls to
loop.wake()creates a singlePoll::Wake,request_eventwill always be blockingsend_event(as happens in my device).Reproducing the issue
I can reproduce this bug by adding the following example to the
examplesfolder: https://gist.github.com/Rodrigodd/379a24ea39c6bead98a8b5dad5e0753eAnd running in android, as instructed in the README.md.
Reproducible on Android 11.