ANDROID: rust_binder: add TF_UPDATE_TXN support

When a process is frozen, incoming oneway transactions are held in a
queue until the process is unfrozen. If many oneway transactions are
sent, then the process could run out of space for them. This patch adds
a flag that avoids this by replacing previous oneway transactions in the
queue to avoid having transactions of the same type build up. This can
be useful when only the most recent transaction is necessary.

Link: https://lore.kernel.org/rust-for-linux/20231101-rust-binder-v1-16-08ba9197f637@google.com/
Change-Id: I2f99cc54a065c0eef60324e860610b562e910a8d
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Bug: 278052745
This commit is contained in:
Alice Ryhl 2023-07-24 11:43:49 +00:00
parent 50259804b1
commit 6249f06992
3 changed files with 52 additions and 1 deletions

View File

@ -63,7 +63,13 @@ pub_no_prefix!(
FLAT_BINDER_FLAG_TXN_SECURITY_CTX
);
pub_no_prefix!(transaction_flags_, TF_ONE_WAY, TF_ACCEPT_FDS, TF_CLEAR_BUF);
pub_no_prefix!(
transaction_flags_,
TF_ONE_WAY,
TF_ACCEPT_FDS,
TF_CLEAR_BUF,
TF_UPDATE_TXN
);
pub(crate) use bindings::{
BINDER_TYPE_BINDER, BINDER_TYPE_FD, BINDER_TYPE_FDA, BINDER_TYPE_HANDLE, BINDER_TYPE_PTR,

View File

@ -356,6 +356,25 @@ impl Node {
}
}
}
/// Finds an outdated transaction that the given transaction can replace.
///
/// If one is found, it is removed from the list and returned.
pub(crate) fn take_outdated_transaction(
&self,
new: &Transaction,
guard: &mut Guard<'_, ProcessInner, SpinLockBackend>,
) -> Option<DLArc<Transaction>> {
let inner = self.inner.access_mut(guard);
let mut cursor_opt = inner.oneway_todo.cursor_front();
while let Some(cursor) = cursor_opt {
if new.can_replace(&cursor.current()) {
return Some(cursor.remove());
}
cursor_opt = cursor.next();
}
None
}
}
impl DeliverToRead for Node {

View File

@ -202,6 +202,9 @@ impl Transaction {
///
/// Not used for replies.
pub(crate) fn submit(self: DLArc<Self>) -> BinderResult {
// Defined before `process_inner` so that the destructor runs after releasing the lock.
let mut _t_outdated = None;
let oneway = self.flags & TF_ONE_WAY != 0;
let process = self.to.clone();
let mut process_inner = process.inner.lock();
@ -212,6 +215,10 @@ impl Transaction {
if let Some(target_node) = self.target_node.clone() {
if process_inner.is_frozen {
process_inner.async_recv = true;
if self.flags & TF_UPDATE_TXN != 0 {
_t_outdated =
target_node.take_outdated_transaction(&self, &mut process_inner);
}
}
match target_node.submit_oneway(self, &mut process_inner) {
Ok(()) => return Ok(()),
@ -252,6 +259,25 @@ impl Transaction {
}
}
/// Check whether one oneway transaction can supersede another.
pub(crate) fn can_replace(&self, old: &Transaction) -> bool {
if self.from.process.task.pid() != old.from.process.task.pid() {
return false;
}
if self.flags & old.flags & (TF_ONE_WAY | TF_UPDATE_TXN) != (TF_ONE_WAY | TF_UPDATE_TXN) {
return false;
}
let target_node_match = match (self.target_node.as_ref(), old.target_node.as_ref()) {
(None, None) => true,
(Some(tn1), Some(tn2)) => Arc::ptr_eq(tn1, tn2),
_ => false,
};
self.code == old.code && self.flags == old.flags && target_node_match
}
fn prepare_file_list(&self) -> Result<TranslatedFds> {
let mut alloc = self.allocation.lock().take().ok_or(ESRCH)?;