summaryrefslogtreecommitdiff
path: root/drivers/android/binder/thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/android/binder/thread.rs')
-rw-r--r--drivers/android/binder/thread.rs126
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)