diff --git a/drivers/android/binder/defs.rs b/drivers/android/binder/defs.rs index 8ac9bdd7a499..cc4becd6e168 100644 --- a/drivers/android/binder/defs.rs +++ b/drivers/android/binder/defs.rs @@ -77,7 +77,8 @@ macro_rules! pub_no_prefix { TF_ONE_WAY, TF_ACCEPT_FDS, TF_CLEAR_BUF, - TF_UPDATE_TXN + TF_UPDATE_TXN, + TF_DEFER_COMPLETE, ); pub(crate) use uapi::{ diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 5372bfbd93b3..384ce15e8a1a 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -686,8 +686,16 @@ pub(crate) fn get_work(&self) -> Option> { pub(crate) fn get_work_or_register<'a>( &'a self, thread: &'a Arc, + thread_has_deferred_work: bool, ) -> GetWorkOrRegister<'a> { let mut inner = self.inner.lock(); + + if thread_has_deferred_work && !inner.work.is_empty() { + if let Some(work) = thread.pop_work_even_if_deferred() { + return GetWorkOrRegister::Work(work); + } + } + // Try to get work from the process queue. if let Some(work) = inner.work.pop_front() { return GetWorkOrRegister::Work(work); diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 18a14aa8a835..8b08b8b37ecb 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -584,9 +584,21 @@ fn get_work_local(self: &Arc, wait: bool) -> Result, wait: bool) -> Result>> { + let thread_has_deferred_work; + // Try to get work from the thread's work queue, using only a local lock. { let mut inner = self.inner.lock(); + + // The process_work_list boolean is used to make us go to sleep even if there is work + // in the thread todo-list, but it doesn't apply to the process todo-list. Furthermore, + // work in the thread todo-list must still be delivered before the process list. + // + // Thus, in some scenarios we must return the thread work now even if we were requested + // to wait. Adjust `process_work_list` to `true` accordingly. + inner.process_work_list |= inner.looper_need_return; + inner.process_work_list |= !wait; + if let Some(work) = inner.pop_work() { return Ok(Some(work)); } @@ -594,18 +606,26 @@ fn get_work(self: &Arc, wait: bool) -> Result return Ok(Some(work)), GetWorkOrRegister::Register(reg) => reg, }; @@ -621,14 +641,18 @@ fn get_work(self: &Arc, wait: bool) -> Result Ok(Some(work)), None if signal_pending => Err(EINTR), None => Ok(None), @@ -686,6 +710,12 @@ pub(crate) fn push_return_work(&self, reply: u32) { self.inner.lock().push_return_work(reply); } + pub(crate) fn pop_work_even_if_deferred(&self) -> Option> { + let mut thread_inner = self.inner.lock(); + thread_inner.process_work_list = true; + thread_inner.pop_work() + } + fn translate_object( &self, obj_index: usize, @@ -1410,8 +1440,16 @@ fn reply_inner(self: &Arc, info: &mut TransactionInfo) -> BinderResult { let process = orig.from.process.clone(); let allow_fds = orig.flags.contains(TransactionFlag::AcceptFds); let reply = Transaction::new_reply(self, process, info, allow_fds)?; - // Not notifying: Reply to current thread. - let _ = self.inner.lock().push_work(completion); + { + let mut inner = self.inner.lock(); + if info.flags.contains(TransactionFlag::DeferComplete) { + // The flag is set. Perform a deferred push so that `read` can wait for the + // next incoming transaction without a userspace roundtrip. + inner.push_work_deferred(completion); + } else { + let _ = inner.push_work(completion); + } + } orig.from.deliver_reply(Ok(reply), &orig, None); Ok(()) })() diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 245f1556b5db..f2877ce05f72 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -39,6 +39,7 @@ pub enum TransactionFlag { AcceptFds = TF_ACCEPT_FDS, ClearBuf = TF_CLEAR_BUF, UpdateTxn = TF_UPDATE_TXN, + DeferComplete = TF_DEFER_COMPLETE, } ); diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 701cad36de43..96e5b0184a1b 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -296,6 +296,7 @@ enum transaction_flags { TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ TF_UPDATE_TXN = 0x40, /* update the outdated pending async txn */ + TF_DEFER_COMPLETE = 0x80, /* defer transaction complete to userspace */ }; struct binder_transaction_data {