diff options
Diffstat (limited to 'drivers/android/binder')
| -rw-r--r-- | drivers/android/binder/Makefile | 4 | ||||
| -rw-r--r-- | drivers/android/binder/allocation.rs | 10 | ||||
| -rw-r--r-- | drivers/android/binder/defs.rs | 3 | ||||
| -rw-r--r-- | drivers/android/binder/freeze.rs | 11 | ||||
| -rw-r--r-- | drivers/android/binder/node.rs | 30 | ||||
| -rw-r--r-- | drivers/android/binder/node/wrapper.rs | 36 | ||||
| -rw-r--r-- | drivers/android/binder/page_range.rs | 6 | ||||
| -rw-r--r-- | drivers/android/binder/process.rs | 21 | ||||
| -rw-r--r-- | drivers/android/binder/range_alloc/array.rs | 2 | ||||
| -rw-r--r-- | drivers/android/binder/range_alloc/mod.rs | 2 | ||||
| -rw-r--r-- | drivers/android/binder/range_alloc/tree.rs | 2 | ||||
| -rw-r--r-- | drivers/android/binder/rust_binder_main.rs | 14 | ||||
| -rw-r--r-- | drivers/android/binder/rust_binderfs.c | 10 | ||||
| -rw-r--r-- | drivers/android/binder/thread.rs | 66 | ||||
| -rw-r--r-- | drivers/android/binder/transaction.rs | 3 |
15 files changed, 157 insertions, 63 deletions
diff --git a/drivers/android/binder/Makefile b/drivers/android/binder/Makefile index 7e0cd9782a8b..fe474628a94e 100644 --- a/drivers/android/binder/Makefile +++ b/drivers/android/binder/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I$(src) # needed for trace events -obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += rust_binder.o -rust_binder-y := \ +obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += binder.o +binder-y := \ rust_binder_main.o \ rust_binderfs.o \ rust_binder_events.o diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs index 165cb797eb1e..2f0763e6868d 100644 --- a/drivers/android/binder/allocation.rs +++ b/drivers/android/binder/allocation.rs @@ -208,7 +208,7 @@ impl Allocation { let num_close_on_free = files.iter().filter(|entry| entry.close_on_free).count(); let mut close_on_free = KVec::with_capacity(num_close_on_free, GFP_KERNEL)?; - let mut reservations = KVec::with_capacity(files.len(), GFP_KERNEL)?; + let mut reservations = KVVec::with_capacity(files.len(), GFP_KERNEL)?; for file_info in files { let res = FileDescriptorReservation::get_unused_fd_flags(bindings::O_CLOEXEC)?; let fd = res.reserved_fd(); @@ -503,7 +503,7 @@ impl BinderObject { /// The closure should write the bytes for the object into the provided slice. pub(crate) fn read_from_inner<R>(reader: R) -> Result<BinderObject> where - R: FnOnce(&mut [u8; size_of::<BinderObject>()]) -> Result<()>, + R: FnOnce(&mut [u8; size_of::<BinderObject>()]) -> Result, { let mut obj = MaybeUninit::<BinderObject>::zeroed(); @@ -567,7 +567,7 @@ impl BinderObject { #[derive(Default)] struct FileList { - files_to_translate: KVec<FileEntry>, + files_to_translate: KVVec<FileEntry>, close_on_free: KVec<u32>, } @@ -581,7 +581,7 @@ struct FileEntry { } pub(crate) struct TranslatedFds { - reservations: KVec<Reservation>, + reservations: KVVec<Reservation>, /// If commit is called, then these fds should be closed. (If commit is not called, then they /// shouldn't be closed.) close_on_free: FdsCloseOnFree, @@ -595,7 +595,7 @@ struct Reservation { impl TranslatedFds { pub(crate) fn new() -> Self { Self { - reservations: KVec::new(), + reservations: KVVec::new(), close_on_free: FdsCloseOnFree(KVec::new()), } } 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 @@ 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/freeze.rs b/drivers/android/binder/freeze.rs index 66912b4cb527..ea2450f3f16f 100644 --- a/drivers/android/binder/freeze.rs +++ b/drivers/android/binder/freeze.rs @@ -155,7 +155,7 @@ impl DeliverToRead for FreezeMessage { } #[inline(never)] - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { seq_print!(m, "{}has frozen binder\n", prefix); Ok(()) } @@ -177,10 +177,7 @@ impl FreezeListener { } impl Process { - pub(crate) fn request_freeze_notif( - self: &Arc<Self>, - reader: &mut UserSliceReader, - ) -> Result<()> { + pub(crate) fn request_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result { let hc = reader.read::<BinderHandleCookie>()?; let handle = hc.handle; let cookie = FreezeCookie(hc.cookie); @@ -272,7 +269,7 @@ impl Process { Ok(()) } - pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> { + pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result { let cookie = FreezeCookie(reader.read()?); let alloc = FreezeMessage::new(GFP_KERNEL)?; let mut node_refs_guard = self.node_refs.lock(); @@ -313,7 +310,7 @@ impl Process { Ok(()) } - pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> { + pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result { let hc = reader.read::<BinderHandleCookie>()?; let handle = hc.handle; let cookie = FreezeCookie(hc.cookie); diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index 0a82af14cda3..b16ea0ff9ed9 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -51,9 +51,9 @@ pub(crate) struct CouldNotDeliverCriticalIncrement; /// about to drop the weak reference, then the strong increment could be processed after the /// other thread has already exited, which would be too late. /// -/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is +/// Note that trying to create a `ListArc` to the node can succeed even if `has_pushed_node` is /// set. This is because another thread might just have popped the node from a todo list, but not -/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should +/// yet called `do_work`. However, if `has_pushed_node` is false, then creating a `ListArc` should /// always succeed. /// /// Like the other fields in `NodeInner`, the delivery state is protected by the process lock. @@ -255,11 +255,7 @@ impl Node { } #[inline(never)] - pub(crate) fn full_debug_print( - &self, - m: &SeqFile, - owner_inner: &mut ProcessInner, - ) -> Result<()> { + pub(crate) fn full_debug_print(&self, m: &SeqFile, owner_inner: &mut ProcessInner) -> Result { let inner = self.inner.access_mut(owner_inner); seq_print!( m, @@ -738,14 +734,28 @@ impl DeliverToRead for Node { self.do_work_locked(writer, owner_inner) } - fn cancel(self: DArc<Self>) {} + fn cancel(self: DArc<Self>) { + let _drop_outside_lock; + let mut owner_inner = self.owner.inner.lock(); + + // We only do something on BINDER_THREAD_EXIT, not process exit. + if owner_inner.is_dead { + return; + } + + // If BINDER_THREAD_EXIT is invoked on a thread with a pending node refcount update, we + // should move ourselves to ensure the refcount update is still delivered. + if let Some(node) = ListArc::try_from_arc_borrow(self.as_arc_borrow()) { + _drop_outside_lock = owner_inner.push_work(&self.owner, node); + } + } fn should_sync_wakeup(&self) -> bool { false } #[inline(never)] - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { seq_print!( m, "{}node work {}: u{:016x} c{:016x}\n", @@ -1140,7 +1150,7 @@ impl DeliverToRead for NodeDeath { } #[inline(never)] - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { let inner = self.inner.lock(); let dead_binder = inner.dead && !inner.notification_done; diff --git a/drivers/android/binder/node/wrapper.rs b/drivers/android/binder/node/wrapper.rs index 6e4ca01c941a..5a5e5e9883a4 100644 --- a/drivers/android/binder/node/wrapper.rs +++ b/drivers/android/binder/node/wrapper.rs @@ -57,14 +57,46 @@ impl DeliverToRead for NodeWrapper { node.do_work_locked(writer, owner_inner) } - fn cancel(self: DArc<Self>) {} + fn cancel(self: DArc<Self>) { + let _drop_outside_lock; + let node = &self.node; + let mut owner_inner = node.owner.inner.lock(); + + // We only do something on BINDER_THREAD_EXIT, not process exit. + if owner_inner.is_dead { + return; + } + + // We transfer the responsibility of the node refcount update to the scheduled Node because + // NodeWrapper has no way to re-create the ListArc. + let inner = node.inner.access_mut(&mut owner_inner); + + let ds = &mut inner.delivery_state; + assert!(ds.has_pushed_wrapper); + assert!(ds.has_strong_zero2one); + ds.has_pushed_wrapper = false; + + // We are changing the state to one where the Node is the strong zero2one update instead of + // the wrapper. + ds.has_weak_zero2one = false; + + if !ds.has_pushed_node { + if let Some(node2) = ListArc::try_from_arc_borrow(node.as_arc_borrow()) { + ds.has_pushed_node = true; + _drop_outside_lock = owner_inner.push_work(&node.owner, node2); + } else { + // This can't actually happen. + ds.has_strong_zero2one = false; + } + } + } fn should_sync_wakeup(&self) -> bool { false } #[inline(never)] - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { seq_print!( m, "{}node work {}: u{:016x} c{:016x}\n", diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs index 71febd3d5b07..74c99432f867 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -66,7 +66,7 @@ impl Shrinker { } /// Register this shrinker with the kernel. - pub(crate) fn register(&'static self, name: &CStr) -> Result<()> { + pub(crate) fn register(&'static self, name: &CStr) -> Result { // SAFETY: These fields are not yet used, so it's okay to zero them. unsafe { self.inner.get().write(ptr::null_mut()); @@ -352,7 +352,7 @@ impl ShrinkablePageRange { /// Make sure that the given pages are allocated and mapped. /// /// Must not be called from an atomic context. - pub(crate) fn use_range(&self, start: usize, end: usize) -> Result<()> { + pub(crate) fn use_range(&self, start: usize, end: usize) -> Result { if start >= end { return Ok(()); } @@ -398,7 +398,7 @@ impl ShrinkablePageRange { /// /// Assumes that `i` is in bounds. #[cold] - unsafe fn use_page_slow(&self, i: usize) -> Result<()> { + unsafe fn use_page_slow(&self, i: usize) -> Result { let new_page = Page::alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)?; let mm_mutex = self.mm_lock.lock(); diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 5372bfbd93b3..58c84be8ab77 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -548,7 +548,7 @@ impl Process { } #[inline(never)] - pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result<()> { + pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result { seq_print!(m, "proc {}\n", self.pid_in_current_ns()); seq_print!(m, "context {}\n", &*ctx.name); @@ -596,7 +596,7 @@ impl Process { } #[inline(never)] - pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result<()> { + pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result { seq_print!(m, "proc {}\n", self.pid_in_current_ns()); seq_print!(m, "context {}\n", &*ctx.name); @@ -686,8 +686,16 @@ impl Process { pub(crate) fn get_work_or_register<'a>( &'a self, thread: &'a Arc<Thread>, + 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); @@ -1208,11 +1216,10 @@ impl Process { { let inner = self.inner.lock(); - for (node_ptr, node) in &inner.nodes { - if *node_ptr > ptr { - node.populate_debug_info(&mut out, &inner); - break; - } + // cursor_lower_bound retrieves the "key" passed or the next existing larger key + if let Some(cursor) = inner.nodes.cursor_lower_bound(&(ptr + 1)) { + let (_, node) = cursor.current(); + node.populate_debug_info(&mut out, &inner); } } diff --git a/drivers/android/binder/range_alloc/array.rs b/drivers/android/binder/range_alloc/array.rs index 081d19b09d4b..71bf49f9db0d 100644 --- a/drivers/android/binder/range_alloc/array.rs +++ b/drivers/android/binder/range_alloc/array.rs @@ -61,7 +61,7 @@ impl<T> ArrayRangeAllocator<T> { self.ranges.len() == self.ranges.capacity() } - pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result { for range in &self.ranges { seq_print!( m, diff --git a/drivers/android/binder/range_alloc/mod.rs b/drivers/android/binder/range_alloc/mod.rs index 1f4734468ff1..bb6e0ec9650e 100644 --- a/drivers/android/binder/range_alloc/mod.rs +++ b/drivers/android/binder/range_alloc/mod.rs @@ -141,7 +141,7 @@ impl<T> RangeAllocator<T> { } } - pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result { match &self.inner { Impl::Empty(_size) => Ok(()), Impl::Array(array) => array.debug_print(m), diff --git a/drivers/android/binder/range_alloc/tree.rs b/drivers/android/binder/range_alloc/tree.rs index 48796fcdb362..058ff7498fa5 100644 --- a/drivers/android/binder/range_alloc/tree.rs +++ b/drivers/android/binder/range_alloc/tree.rs @@ -111,7 +111,7 @@ impl<T> TreeRangeAllocator<T> { .count() } - pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result { for desc in self.tree.values() { let state = match &desc.state { Some(state) => &state.0, diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs index 955c4c348f73..92bf33f9ff1c 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -81,7 +81,7 @@ mod binderfs { module! { type: BinderModule, - name: "rust_binder", + name: "binder", authors: ["Wedson Almeida Filho", "Alice Ryhl"], description: "Android Binder", license: "GPL", @@ -158,7 +158,7 @@ trait DeliverToRead: ListArcSafe + Send + Sync { /// Generally only set to true for non-oneway transactions. fn should_sync_wakeup(&self) -> bool; - fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result<()>; + fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result; } // Wrapper around a `DeliverToRead` with linked list links. @@ -274,7 +274,7 @@ impl DeliverToRead for DeliverCode { false } - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { seq_print!(m, "{}", prefix); if self.skip.load(Relaxed) { seq_print!(m, "(skipped) "); @@ -545,7 +545,7 @@ unsafe extern "C" fn rust_binder_transactions_show( 0 } -fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> { +fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result { seq_print!(m, "binder transactions:\n"); let contexts = context::get_all_contexts()?; for ctx in contexts { @@ -558,7 +558,7 @@ fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> { Ok(()) } -fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> { +fn rust_binder_stats_show_impl(m: &SeqFile) -> Result { seq_print!(m, "binder stats:\n"); stats::GLOBAL_STATS.debug_print("", m); let contexts = context::get_all_contexts()?; @@ -572,7 +572,7 @@ fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> { Ok(()) } -fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> { +fn rust_binder_state_show_impl(m: &SeqFile) -> Result { seq_print!(m, "binder state:\n"); let contexts = context::get_all_contexts()?; for ctx in contexts { @@ -585,7 +585,7 @@ fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> { Ok(()) } -fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result<()> { +fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result { seq_print!(m, "binder proc state:\n"); let contexts = context::get_all_contexts()?; for ctx in contexts { diff --git a/drivers/android/binder/rust_binderfs.c b/drivers/android/binder/rust_binderfs.c index 300cc65562d1..acc83a179f38 100644 --- a/drivers/android/binder/rust_binderfs.c +++ b/drivers/android/binder/rust_binderfs.c @@ -49,7 +49,7 @@ DEFINE_SHOW_ATTRIBUTE(rust_binder_transactions); DEFINE_SHOW_ATTRIBUTE(rust_binder_proc); char *rust_binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; -module_param_named(rust_devices, rust_binder_devices_param, charp, 0444); +module_param_named(devices, rust_binder_devices_param, charp, 0444); extern u32 rust_binder_debug_mask; module_param_named(debug_mask, rust_binder_debug_mask, uint, 0644); @@ -72,6 +72,7 @@ struct binder_features { bool oneway_spam_detection; bool extended_error; bool freeze_notification; + bool transaction_report; }; static const struct constant_table binderfs_param_stats[] = { @@ -89,6 +90,7 @@ static struct binder_features binder_features = { .oneway_spam_detection = true, .extended_error = true, .freeze_notification = true, + .transaction_report = true, }; static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) @@ -566,6 +568,12 @@ static int init_binder_features(struct super_block *sb) if (IS_ERR(dentry)) return PTR_ERR(dentry); + dentry = rust_binderfs_create_file(dir, "transaction_report", + &binder_features_fops, + &binder_features.transaction_report); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + return 0; } diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 18a14aa8a835..edafce806d27 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -481,7 +481,7 @@ impl Thread { } #[inline(never)] - pub(crate) fn debug_print(self: &Arc<Self>, m: &SeqFile, print_all: bool) -> Result<()> { + pub(crate) fn debug_print(self: &Arc<Self>, m: &SeqFile, print_all: bool) -> Result { let inner = self.inner.lock(); if print_all || inner.current_transaction.is_some() || !inner.work_list.is_empty() { @@ -584,9 +584,21 @@ impl Thread { // mangled symbol names. #[export_name = "rust_binder_wait"] fn get_work(self: &Arc<Self>, wait: bool) -> Result<Option<DLArc<dyn DeliverToRead>>> { + 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 @@ impl Thread { drop(inner); return Ok(self.process.get_work()); } + + // Note that if the thread list is empty, then the call to `pop_work()` has changed + // `process_work_list` back to `false` even if we set it to `true` above. + thread_has_deferred_work = !inner.work_list.is_empty(); } // If the caller doesn't want to wait, try to grab work from the process queue. // // We know nothing will have been queued directly to the thread queue because it is not in - // a transaction and it is not in the process' ready list. + // a transaction and it is not in the process' ready list. We also know the thread list has + // no deferred work due to the `inner.process_work_list |= !wait` call above. if !wait { return self.process.get_work().ok_or(EAGAIN).map(Some); } // Get work from the process queue. If none is available, atomically register as ready. - let reg = match self.process.get_work_or_register(self) { + let reg = match self + .process + .get_work_or_register(self, thread_has_deferred_work) + { GetWorkOrRegister::Work(work) => return Ok(Some(work)), GetWorkOrRegister::Register(reg) => reg, }; @@ -621,14 +641,18 @@ impl Thread { inner.looper_flags &= !(LooperFlag::Waiting | LooperFlag::WaitingProc); if signal_pending || inner.looper_need_return { - // We need to return now. We need to pull the thread off the list of ready threads - // (by dropping `reg`), then check the state again after it's off the list to - // ensure that something was not queued in the meantime. If something has been - // queued, we just return it (instead of the error). + // We need to return now. + // + // We need to pull the thread off the list of ready threads (by dropping `reg`), + // then check the state again after it's off the list to ensure that something was + // not queued in the meantime. If something has been queued (or if there is + // deferred work), we just return it (instead of the error). drop(inner); drop(reg); - let res = match self.inner.lock().pop_work() { + inner = self.inner.lock(); + inner.process_work_list = true; + let res = match inner.pop_work() { Some(work) => Ok(Some(work)), None if signal_pending => Err(EINTR), None => Ok(None), @@ -686,6 +710,12 @@ impl Thread { self.inner.lock().push_return_work(reply); } + pub(crate) fn pop_work_even_if_deferred(&self) -> Option<DLArc<dyn DeliverToRead>> { + let mut thread_inner = self.inner.lock(); + thread_inner.process_work_list = true; + thread_inner.pop_work() + } + fn translate_object( &self, obj_index: usize, @@ -1250,7 +1280,7 @@ impl Thread { cmd: u32, reader: &mut UserSliceReader, info: &mut TransactionInfo, - ) -> Result<()> { + ) -> Result { let td = match cmd { BC_TRANSACTION | BC_REPLY => { reader.read::<BinderTransactionData>()?.with_buffers_size(0) @@ -1281,7 +1311,7 @@ impl Thread { } #[inline(never)] - fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Result<()> { + fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Result { let mut info = TransactionInfo::zeroed(); self.read_transaction_info(cmd, reader, &mut info)?; @@ -1410,8 +1440,16 @@ impl Thread { 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(()) })() @@ -1678,7 +1716,7 @@ impl Thread { self.unwind_transaction_stack(); // Cancel all pending work items. - while let Ok(Some(work)) = self.get_work_local(false) { + while let Some(work) = self.pop_work_even_if_deferred() { work.into_arc().cancel(); } } @@ -1738,7 +1776,7 @@ impl DeliverToRead for ThreadError { false } - fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result { seq_print!( m, "{}transaction error: {}\n", diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 245f1556b5db..888a9e0eba8f 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -39,6 +39,7 @@ kernel::impl_flags!( AcceptFds = TF_ACCEPT_FDS, ClearBuf = TF_CLEAR_BUF, UpdateTxn = TF_UPDATE_TXN, + DeferComplete = TF_DEFER_COMPLETE, } ); @@ -576,7 +577,7 @@ impl DeliverToRead for Transaction { !self.flags.is_oneway() } - fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result<()> { + fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result { self.debug_print_inner(m, tprefix); Ok(()) } |
