Skip to content

Android: request_redraw() blocks send_event() #2299

@Rodrigodd

Description

@Rodrigodd

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    B - bugDang, that shouldn't have happenedDS - androidAffects the Android backend

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions