diff options
Diffstat (limited to 'drivers/android/binder/thread.rs')
| -rw-r--r-- | drivers/android/binder/thread.rs | 126 |
1 files changed, 65 insertions, 61 deletions
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 0e832af484ce..f5965e838a96 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -345,13 +345,13 @@ impl InnerThread { } } - fn push_return_work(&mut self, reply: u32) { + fn push_return_work(&mut self, reply: u32) -> PushWorkRes { if let Ok(work) = ListArc::try_from_arc(self.return_work.clone()) { work.set_error_code(reply); - // Not notifying: Reply to current thread. - let _ = self.push_work(work); + self.push_work(work) } else { pr_warn_ratelimited!("Thread return work is already in use.\n"); + PushWorkRes::Ok } } @@ -694,8 +694,12 @@ impl Thread { pub(crate) fn push_work_if_looper(&self, work: DLArc<dyn DeliverToRead>) -> BinderResult { let mut inner = self.inner.lock(); if inner.is_looper() && !inner.is_dead { - // Not notifying: Reply to current thread. - let _ = inner.push_work(work); + // Not notifying work_condvar: Reply to current thread. + let res = inner.push_work(work); + drop(inner); + if matches!(res, PushWorkRes::OkNotifyPoll) { + self.process.notify_poll(false); + } Ok(()) } else { drop(inner); @@ -708,7 +712,11 @@ impl Thread { } pub(crate) fn push_return_work(&self, reply: u32) { - self.inner.lock().push_return_work(reply); + // Not notifying work_condvar: Reply to current thread. + let res = self.inner.lock().push_return_work(reply); + if matches!(res, PushWorkRes::OkNotifyPoll) { + self.process.notify_poll(false); + } } pub(crate) fn pop_work_even_if_deferred(&self) -> Option<DLArc<dyn DeliverToRead>> { @@ -1071,17 +1079,7 @@ impl Thread { size_of::<u64>(), ); let secctx_off = aligned_data_size + offsets_size + buffers_size; - let mut alloc = match to_process.buffer_alloc(debug_id, len, info) { - Ok(alloc) => alloc, - Err(err) => { - pr_warn!( - "Failed to allocate buffer. len:{}, is_oneway:{}", - len, - info.is_oneway(), - ); - return Err(err); - } - }; + let mut alloc = to_process.buffer_alloc(debug_id, len, info)?; trace_transaction_alloc_buf(debug_id, data_size, offsets_size, buffers_size); @@ -1334,38 +1332,19 @@ impl Thread { self.transaction_inner(&mut info) }; + // This runs when return work is passed to the caller. This is not + // always the same as the transaction failing, as reply errors are + // delivered to the remote process. if let Err(err) = ret { self.push_return_work(err.reply); if err.reply != BR_TRANSACTION_COMPLETE { info.reply = err.reply; info.error_line = Some(err.line); - if let Some(source) = &err.source { - info.errno = source.to_errno(); + if let Some(source) = err.source { + info.errno = Some(source); - { - let mut inner = self.inner.lock(); - inner.extended_error = - ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno()); - } - - binder_debug!( - FailedTransaction, - "transaction {} to {}:{} failed {:?}, code {} size {}-{} line {}", - if info.is_reply { - "reply" - } else if info.is_oneway() { - "async" - } else { - "call" - }, - info.to_pid, - info.to_tid, - err, - info.code, - info.data_size, - info.offsets_size, - err.line - ); + self.inner.lock().extended_error = + ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno()); } } } @@ -1377,8 +1356,33 @@ impl Thread { // useful in case the transaction failed with BR_TRANSACTION_PENDING_FROZEN. info.report_netlink(BR_ONEWAY_SPAM_SUSPECT, &self.process.ctx); } + // This runs when the transaction failed. if info.reply != 0 { info.report_netlink(info.reply, &self.process.ctx); + if let Some(errno) = info.errno { + let error_line: &dyn kernel::fmt::Display = match &info.error_line { + Some(line) => line, + None => &0, + }; + binder_debug!( + FailedTransaction, + "transaction {} to {}:{} failed {:?}, code {} size {}-{} line {}", + if info.is_reply { + "reply" + } else if info.is_oneway() { + "async" + } else { + "call" + }, + info.to_pid, + info.to_tid, + errno, + info.code, + info.data_size, + info.offsets_size, + error_line + ); + } } Ok(()) @@ -1454,14 +1458,15 @@ 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)?; - { - 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); + 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. + self.inner.lock().push_work_deferred(completion); + } else { + // Not notifying work_condvar: Reply to current thread. + let res = self.inner.lock().push_work(completion); + if matches!(res, PushWorkRes::OkNotifyPoll) { + self.process.notify_poll(false); } } orig.from.deliver_reply(Ok(reply), &orig, None); @@ -1471,18 +1476,12 @@ impl Thread { // At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let // the sender know that the transaction has completed (with an error in this case). - pr_warn!( - "{}:{} reply to {} failed: {err:?}", - info.from_pid, - info.from_tid, - info.to_pid - ); let param = err.source.as_ref().map_or(0, |e| e.to_errno()); let ee = ExtendedError::new(info.debug_id as u32, err.reply, param); orig.from .deliver_reply(Err(BR_FAILED_REPLY), &orig, Some(ee)); info.reply = BR_FAILED_REPLY; - info.errno = param; + info.errno = err.source; info.error_line = Some(err.line); err.reply = BR_TRANSACTION_COMPLETE; err @@ -1505,10 +1504,15 @@ impl Thread { let list_completion = DTRWrap::arc_try_new(DeliverCode::new(code, self.process.task.pid()))?; let completion = list_completion.clone_arc(); - // Not notifying: Reply to current thread. - let _ = self.inner.lock().push_work(list_completion); + // Not notifying work_condvar: Reply to current thread. + let res = self.inner.lock().push_work(list_completion); match transaction.submit(info) { - Ok(()) => Ok(()), + Ok(()) => { + if matches!(res, PushWorkRes::OkNotifyPoll) { + self.process.notify_poll(false); + } + Ok(()) + } Err(err) => { completion.skip(); Err(err) |
