mirror of
https://github.com/rust-mobile/android-activity.git
synced 2026-07-04 05:47:26 +00:00
Use ALooper_pollOnce instead of pollAll
The `ALooper_pollAll` API is deprecated and considering that `poll_events` never promised the behaviour of `pollAll` we simply change the implementation to use `ALoooper_pollOnce` and assume the caller is going to anyway be calling `poll_events` within its own loop. Note: `pollOnce` can still deliver multiple callback events, and the "once" effectively just refers to only calling `epoll_wait` at most once. Considering winit for example, this should have no effect since winit will be calling `poll_events` in a loop with no assumption about how concurrent events could potentially be batched. Fixes: #170
This commit is contained in:
@@ -15,8 +15,7 @@ use log::{error, trace};
|
||||
|
||||
use jni::sys::*;
|
||||
|
||||
use ndk_sys::ALooper_wake;
|
||||
use ndk_sys::{ALooper, ALooper_pollAll};
|
||||
use ndk_sys::{ALooper, ALooper_pollOnce, ALooper_wake};
|
||||
|
||||
use ndk::asset::AssetManager;
|
||||
use ndk::configuration::Configuration;
|
||||
@@ -346,8 +345,8 @@ impl AndroidAppInner {
|
||||
} else {
|
||||
-1
|
||||
};
|
||||
trace!("Calling ALooper_pollAll, timeout = {timeout_milliseconds}");
|
||||
let id = ALooper_pollAll(
|
||||
trace!("Calling ALooper_pollOnce, timeout = {timeout_milliseconds}");
|
||||
let id = ALooper_pollOnce(
|
||||
timeout_milliseconds,
|
||||
&mut fd,
|
||||
&mut events,
|
||||
@@ -355,8 +354,7 @@ impl AndroidAppInner {
|
||||
);
|
||||
match id {
|
||||
ffi::ALOOPER_POLL_WAKE => {
|
||||
trace!("ALooper_pollAll returned POLL_WAKE");
|
||||
|
||||
trace!("ALooper_pollOnce returned POLL_WAKE");
|
||||
if ffi::android_app_input_available_wake_up(native_app.as_ptr()) {
|
||||
log::debug!("Notifying Input Available");
|
||||
callback(PollEvent::Main(MainEvent::InputAvailable));
|
||||
@@ -365,23 +363,23 @@ impl AndroidAppInner {
|
||||
callback(PollEvent::Wake);
|
||||
}
|
||||
ffi::ALOOPER_POLL_CALLBACK => {
|
||||
// ALooper_pollAll is documented to handle all callback sources internally so it should
|
||||
// ALooper_pollOnce is documented to handle all callback sources internally so it should
|
||||
// never return a _CALLBACK source id...
|
||||
error!("Spurious ALOOPER_POLL_CALLBACK from ALopper_pollAll() (ignored)");
|
||||
error!("Spurious ALOOPER_POLL_CALLBACK from ALooper_pollOnce() (ignored)");
|
||||
}
|
||||
ffi::ALOOPER_POLL_TIMEOUT => {
|
||||
trace!("ALooper_pollAll returned POLL_TIMEOUT");
|
||||
trace!("ALooper_pollOnce returned POLL_TIMEOUT");
|
||||
callback(PollEvent::Timeout);
|
||||
}
|
||||
ffi::ALOOPER_POLL_ERROR => {
|
||||
// If we have an IO error with our pipe to the main Java thread that's surely
|
||||
// not something we can recover from
|
||||
panic!("ALooper_pollAll returned POLL_ERROR");
|
||||
panic!("ALooper_pollOnce returned POLL_ERROR");
|
||||
}
|
||||
id if id >= 0 => {
|
||||
match id as ffi::NativeAppGlueLooperId {
|
||||
ffi::NativeAppGlueLooperId_LOOPER_ID_MAIN => {
|
||||
trace!("ALooper_pollAll returned ID_MAIN");
|
||||
trace!("ALooper_pollOnce returned ID_MAIN");
|
||||
let source: *mut ffi::android_poll_source = source.cast();
|
||||
if !source.is_null() {
|
||||
let cmd_i = ffi::android_app_read_cmd(native_app.as_ptr());
|
||||
@@ -485,7 +483,7 @@ impl AndroidAppInner {
|
||||
trace!("Calling android_app_post_exec_cmd({cmd_i})");
|
||||
ffi::android_app_post_exec_cmd(native_app.as_ptr(), cmd_i);
|
||||
} else {
|
||||
panic!("ALooper_pollAll returned ID_MAIN event with NULL android_poll_source!");
|
||||
panic!("ALooper_pollOnce returned ID_MAIN event with NULL android_poll_source!");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -494,7 +492,7 @@ impl AndroidAppInner {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("Spurious ALooper_pollAll return value {id} (ignored)");
|
||||
error!("Spurious ALooper_pollOnce return value {id} (ignored)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-11
@@ -607,24 +607,46 @@ impl AndroidApp {
|
||||
self.inner.read().unwrap().activity_as_ptr()
|
||||
}
|
||||
|
||||
/// Polls for any events associated with this [AndroidApp] and processes those events
|
||||
/// (such as lifecycle events) via the given `callback`.
|
||||
/// Polls for any events associated with this [AndroidApp] and processes
|
||||
/// those events (such as lifecycle events) via the given `callback`.
|
||||
///
|
||||
/// It's important to use this API for polling, and not call [`ALooper_pollAll`] directly since
|
||||
/// some events require pre- and post-processing either side of the callback. For correct
|
||||
/// behavior events should be handled immediately, before returning from the callback and
|
||||
/// not simply queued for batch processing later. For example the existing [`NativeWindow`]
|
||||
/// is accessible during a [`MainEvent::TerminateWindow`] callback and will be
|
||||
/// set to `None` once the callback returns, and this is also synchronized with the Java
|
||||
/// main thread. The [`MainEvent::SaveState`] event is also synchronized with the
|
||||
/// It's important to use this API for polling, and not call
|
||||
/// [`ALooper_pollAll`] or [`ALooper_pollOnce`] directly since some events
|
||||
/// require pre- and post-processing either side of the callback. For
|
||||
/// correct behavior events should be handled immediately, before returning
|
||||
/// from the callback and not simply queued for batch processing later. For
|
||||
/// example the existing [`NativeWindow`] is accessible during a
|
||||
/// [`MainEvent::TerminateWindow`] callback and will be set to `None` once
|
||||
/// the callback returns, and this is also synchronized with the Java main
|
||||
/// thread. The [`MainEvent::SaveState`] event is also synchronized with the
|
||||
/// Java main thread.
|
||||
///
|
||||
/// Internally this is based on [`ALooper_pollOnce`] and will only poll
|
||||
/// file descriptors once per invocation.
|
||||
///
|
||||
/// # Wake Events
|
||||
///
|
||||
/// Note that although there is an explicit [PollEvent::Wake] that _can_
|
||||
/// indicate that the main loop was explicitly woken up (E.g. via
|
||||
/// [`AndroidAppWaker::wake`]) it's possible that there will be
|
||||
/// more-specific events that will be delivered after a wake up.
|
||||
///
|
||||
/// In other words you should only expect to explicitly see
|
||||
/// [`PollEvent::Wake`] events after an early wake up if there were no
|
||||
/// other, more-specific, events that could be delivered after the wake up.
|
||||
///
|
||||
/// Again, said another way - it's possible that _any_ event could
|
||||
/// effectively be delivered after an early wake up so don't assume there is
|
||||
/// a 1:1 relationship between invoking a wake up via
|
||||
/// [`AndroidAppWaker::wake`] and the delivery of [PollEvent::Wake].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This must only be called from your `android_main()` thread and it may panic if called
|
||||
/// from another thread.
|
||||
/// This must only be called from your `android_main()` thread and it may
|
||||
/// panic if called from another thread.
|
||||
///
|
||||
/// [`ALooper_pollAll`]: ndk::looper::ThreadLooper::poll_all
|
||||
/// [`ALooper_pollOnce`]: ndk::looper::ThreadLooper::poll_once
|
||||
pub fn poll_events<F>(&self, timeout: Option<Duration>, callback: F)
|
||||
where
|
||||
F: FnMut(PollEvent<'_>),
|
||||
|
||||
@@ -194,42 +194,42 @@ impl AndroidAppInner {
|
||||
-1
|
||||
};
|
||||
|
||||
trace!("Calling ALooper_pollAll, timeout = {timeout_milliseconds}");
|
||||
trace!("Calling ALooper_pollOnce, timeout = {timeout_milliseconds}");
|
||||
assert_eq!(
|
||||
ndk_sys::ALooper_forThread(),
|
||||
self.looper.ptr,
|
||||
"Application tried to poll events from non-main thread"
|
||||
);
|
||||
let id = ndk_sys::ALooper_pollAll(
|
||||
let id = ndk_sys::ALooper_pollOnce(
|
||||
timeout_milliseconds,
|
||||
&mut fd,
|
||||
&mut events,
|
||||
&mut source as *mut *mut c_void,
|
||||
);
|
||||
trace!("pollAll id = {id}");
|
||||
trace!("pollOnce id = {id}");
|
||||
match id {
|
||||
ndk_sys::ALOOPER_POLL_WAKE => {
|
||||
trace!("ALooper_pollAll returned POLL_WAKE");
|
||||
trace!("ALooper_pollOnce returned POLL_WAKE");
|
||||
callback(PollEvent::Wake);
|
||||
}
|
||||
ndk_sys::ALOOPER_POLL_CALLBACK => {
|
||||
// ALooper_pollAll is documented to handle all callback sources internally so it should
|
||||
// ALooper_pollOnce is documented to handle all callback sources internally so it should
|
||||
// never return a _CALLBACK source id...
|
||||
error!("Spurious ALOOPER_POLL_CALLBACK from ALopper_pollAll() (ignored)");
|
||||
error!("Spurious ALOOPER_POLL_CALLBACK from ALooper_pollOnce() (ignored)");
|
||||
}
|
||||
ndk_sys::ALOOPER_POLL_TIMEOUT => {
|
||||
trace!("ALooper_pollAll returned POLL_TIMEOUT");
|
||||
trace!("ALooper_pollOnce returned POLL_TIMEOUT");
|
||||
callback(PollEvent::Timeout);
|
||||
}
|
||||
ndk_sys::ALOOPER_POLL_ERROR => {
|
||||
// If we have an IO error with our pipe to the main Java thread that's surely
|
||||
// not something we can recover from
|
||||
panic!("ALooper_pollAll returned POLL_ERROR");
|
||||
panic!("ALooper_pollOnce returned POLL_ERROR");
|
||||
}
|
||||
id if id >= 0 => {
|
||||
match id {
|
||||
LOOPER_ID_MAIN => {
|
||||
trace!("ALooper_pollAll returned ID_MAIN");
|
||||
trace!("ALooper_pollOnce returned ID_MAIN");
|
||||
if let Some(ipc_cmd) = self.native_activity.read_cmd() {
|
||||
let main_cmd = match ipc_cmd {
|
||||
// We don't forward info about the AInputQueue to apps since it's
|
||||
@@ -283,7 +283,7 @@ impl AndroidAppInner {
|
||||
}
|
||||
}
|
||||
LOOPER_ID_INPUT => {
|
||||
trace!("ALooper_pollAll returned ID_INPUT");
|
||||
trace!("ALooper_pollOnce returned ID_INPUT");
|
||||
|
||||
// To avoid spamming the application with event loop iterations notifying them of
|
||||
// input events then we only send one `InputAvailable` per iteration of input
|
||||
@@ -298,7 +298,7 @@ impl AndroidAppInner {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("Spurious ALooper_pollAll return value {id} (ignored)");
|
||||
error!("Spurious ALooper_pollOnce return value {id} (ignored)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user