History

Binder: add TF_UPDATE_TXN to replace outdated txn

When the target process is busy, incoming oneway transactions are queued in the async_todo list. If the clients continue sending extra oneway transactions while the target process is frozen, this queue can become too large to accommodate new transactions. That's why binder driver introduced ONEWAY_SPAM_DETECTION to detect this situation. It's helpful to debug the async binder buffer exhausting issue, but the issue itself isn't solved directly. In real cases applications are designed to send oneway transactions repeatedly, delivering updated inforamtion to the target process. Typical examples are Wi-Fi signal strength and some real time sensor data. Even if the apps might only care about the lastet information, all outdated oneway transactions are still accumulated there until the frozen process is thawed later. For this kind of situations, there's no existing method to skip those outdated transactions and deliver the latest one only. This patch introduces a new transaction flag TF_UPDATE_TXN. To use it, use apps can set this new flag along with TF_ONE_WAY. When such an oneway transaction is to be queued into the async_todo list of a frozen process, binder driver will check if any previous pending transactions can be superseded by comparing their code, flags and target node. If such an outdated pending transaction is found, the latest transaction will supersede that outdated one. This effectively prevents the async binder buffer running out and saves unnecessary binder read workloads.

Li Li committed 4 years ago

Commit 9864bb41 parent 5afbfa83 files · +87 −3Browse files

Unified · Split

3 files
  1. drivers/android/binder.c +82 −3
  2. drivers/android/binder_trace.h +4 −0
  3. include/uapi/linux/android/binder.h +1 −0
drivers/android/binder.c+82−3
@@ -2626,6 +2626,56 @@ static int binder_fixup_parent(struct list_head *pf_head, · 2625 unmodified lines
2626 return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);2626 return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);
2627}2627}
2628 2628
2629/**
2630 * binder_can_update_transaction() - Can a txn be superseded by an updated one?
2631 * @t1: the pending async txn in the frozen process
2632 * @t2: the new async txn to supersede the outdated pending one
2633 *
2634 * Return: true if t2 can supersede t1
2635 * false if t2 can not supersede t1
2636 */
2637static bool binder_can_update_transaction(struct binder_transaction *t1,
2638 struct binder_transaction *t2)
2639{
2640 if ((t1->flags & t2->flags & (TF_ONE_WAY | TF_UPDATE_TXN)) !=
2641 (TF_ONE_WAY | TF_UPDATE_TXN) || !t1->to_proc || !t2->to_proc)
2642 return false;
2643 if (t1->to_proc->tsk == t2->to_proc->tsk && t1->code == t2->code &&
2644 t1->flags == t2->flags && t1->buffer->pid == t2->buffer->pid &&
2645 t1->buffer->target_node->ptr == t2->buffer->target_node->ptr &&
2646 t1->buffer->target_node->cookie == t2->buffer->target_node->cookie)
2647 return true;
2648 return false;
2649}
2650
2651/**
2652 * binder_find_outdated_transaction_ilocked() - Find the outdated transaction
2653 * @t: new async transaction
2654 * @target_list: list to find outdated transaction
2655 *
2656 * Return: the outdated transaction if found
2657 * NULL if no outdated transacton can be found
2658 *
2659 * Requires the proc->inner_lock to be held.
2660 */
2661static struct binder_transaction *
2662binder_find_outdated_transaction_ilocked(struct binder_transaction *t,
2663 struct list_head *target_list)
2664{
2665 struct binder_work *w;
2666
2667 list_for_each_entry(w, target_list, entry) {
2668 struct binder_transaction *t_queued;
2669
2670 if (w->type != BINDER_WORK_TRANSACTION)
2671 continue;
2672 t_queued = container_of(w, struct binder_transaction, work);
2673 if (binder_can_update_transaction(t_queued, t))
2674 return t_queued;
2675 }
2676 return NULL;
2677}
2678
2629/**2679/**
2630 * binder_proc_transaction() - sends a transaction to a process and wakes it up2680 * binder_proc_transaction() - sends a transaction to a process and wakes it up
2631 * @t: transaction to send2681 * @t: transaction to send
@@ -2651,6 +2701,7 @@ static int binder_proc_transaction(struct binder_transaction *t, · 19 unmodified lines
2651 struct binder_node *node = t->buffer->target_node;2701 struct binder_node *node = t->buffer->target_node;
2652 bool oneway = !!(t->flags & TF_ONE_WAY);2702 bool oneway = !!(t->flags & TF_ONE_WAY);
2653 bool pending_async = false;2703 bool pending_async = false;
2704 struct binder_transaction *t_outdated = NULL;
2654 2705
2655 BUG_ON(!node);2706 BUG_ON(!node);
2656 binder_node_lock(node);2707 binder_node_lock(node);
@@ -2678,12 +2729,24 @@ static int binder_proc_transaction(struct binder_transaction *t, · 21 unmodified lines
2678 if (!thread && !pending_async)2729 if (!thread && !pending_async)
2679 thread = binder_select_thread_ilocked(proc);2730 thread = binder_select_thread_ilocked(proc);
2680 2731
2681 if (thread)2732 if (thread) {
2682 binder_enqueue_thread_work_ilocked(thread, &t->work);2733 binder_enqueue_thread_work_ilocked(thread, &t->work);
2683 else if (!pending_async)2734 } else if (!pending_async) {
2684 binder_enqueue_work_ilocked(&t->work, &proc->todo);2735 binder_enqueue_work_ilocked(&t->work, &proc->todo);
2685 else2736 } else {
2737 if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) {
2738 t_outdated = binder_find_outdated_transaction_ilocked(t,
2739 &node->async_todo);
2740 if (t_outdated) {
2741 binder_debug(BINDER_DEBUG_TRANSACTION,
2742 "txn %d supersedes %d\n",
2743 t->debug_id, t_outdated->debug_id);
2744 list_del_init(&t_outdated->work.entry);
2745 proc->outstanding_txns--;
2746 }
2747 }
2686 binder_enqueue_work_ilocked(&t->work, &node->async_todo);2748 binder_enqueue_work_ilocked(&t->work, &node->async_todo);
2749 }
2687 2750
2688 if (!pending_async)2751 if (!pending_async)
2689 binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);2752 binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);
@@ -2692,6 +2755,22 @@ static int binder_proc_transaction(struct binder_transaction *t, · 2 unmodified lines
2692 binder_inner_proc_unlock(proc);2755 binder_inner_proc_unlock(proc);
2693 binder_node_unlock(node);2756 binder_node_unlock(node);
2694 2757
2758 /*
2759 * To reduce potential contention, free the outdated transaction and
2760 * buffer after releasing the locks.
2761 */
2762 if (t_outdated) {
2763 struct binder_buffer *buffer = t_outdated->buffer;
2764
2765 t_outdated->buffer = NULL;
2766 buffer->transaction = NULL;
2767 trace_binder_transaction_update_buffer_release(buffer);
2768 binder_transaction_buffer_release(proc, NULL, buffer, 0, 0);
2769 binder_alloc_free_buf(&proc->alloc, buffer);
2770 kfree(t_outdated);
2771 binder_stats_deleted(BINDER_STAT_TRANSACTION);
2772 }
2773
2695 return 0;2774 return 0;
2696}2775}
2697 2776
drivers/android/binder_trace.h+4−0
@@ -311,6 +311,10 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, · 310 unmodified lines
311 TP_PROTO(struct binder_buffer *buffer),311 TP_PROTO(struct binder_buffer *buffer),
312 TP_ARGS(buffer));312 TP_ARGS(buffer));
313 313
314DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release,
315 TP_PROTO(struct binder_buffer *buffer),
316 TP_ARGS(buffer));
317
314TRACE_EVENT(binder_update_page_range,318TRACE_EVENT(binder_update_page_range,
315 TP_PROTO(struct binder_alloc *alloc, bool allocate,319 TP_PROTO(struct binder_alloc *alloc, bool allocate,
316 void __user *start, void __user *end),320 void __user *start, void __user *end),
include/uapi/linux/android/binder.h+1−0
@@ -287,6 +287,7 @@ enum transaction_flags { · 286 unmodified lines
287 TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */287 TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
288 TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */288 TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
289 TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */289 TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */
290 TF_UPDATE_TXN = 0x40, /* update the outdated pending async txn */
290};291};
291 292
292struct binder_transaction_data {293struct binder_transaction_data {