Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

binder: return pending info for frozen async txns

An async transaction to a frozen process will still be successfully
put in the queue. But this pending async transaction won't be processed
until the target process is unfrozen at an unspecified time in the
future. Pass this important information back to the user space caller
by returning BR_TRANSACTION_PENDING_FROZEN.

Signed-off-by: Li Li <dualli@google.com>
Acked-by: Carlos Llamas <cmllamas@google.com>
Link: https://lore.kernel.org/r/20221123201654.589322-2-dualli@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Li Li and committed by
Greg Kroah-Hartman
0567461a 7feb35bc

+34 -8
+26 -6
drivers/android/binder.c
··· 2728 2728 * 2729 2729 * Return: 0 if the transaction was successfully queued 2730 2730 * BR_DEAD_REPLY if the target process or thread is dead 2731 - * BR_FROZEN_REPLY if the target process or thread is frozen 2731 + * BR_FROZEN_REPLY if the target process or thread is frozen and 2732 + * the sync transaction was rejected 2733 + * BR_TRANSACTION_PENDING_FROZEN if the target process is frozen 2734 + * and the async transaction was successfully queued 2732 2735 */ 2733 2736 static int binder_proc_transaction(struct binder_transaction *t, 2734 2737 struct binder_proc *proc, ··· 2741 2738 bool oneway = !!(t->flags & TF_ONE_WAY); 2742 2739 bool pending_async = false; 2743 2740 struct binder_transaction *t_outdated = NULL; 2741 + bool frozen = false; 2744 2742 2745 2743 BUG_ON(!node); 2746 2744 binder_node_lock(node); ··· 2755 2751 2756 2752 binder_inner_proc_lock(proc); 2757 2753 if (proc->is_frozen) { 2754 + frozen = true; 2758 2755 proc->sync_recv |= !oneway; 2759 2756 proc->async_recv |= oneway; 2760 2757 } 2761 2758 2762 - if ((proc->is_frozen && !oneway) || proc->is_dead || 2759 + if ((frozen && !oneway) || proc->is_dead || 2763 2760 (thread && thread->is_dead)) { 2764 2761 binder_inner_proc_unlock(proc); 2765 2762 binder_node_unlock(node); 2766 - return proc->is_frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY; 2763 + return frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY; 2767 2764 } 2768 2765 2769 2766 if (!thread && !pending_async) ··· 2775 2770 } else if (!pending_async) { 2776 2771 binder_enqueue_work_ilocked(&t->work, &proc->todo); 2777 2772 } else { 2778 - if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) { 2773 + if ((t->flags & TF_UPDATE_TXN) && frozen) { 2779 2774 t_outdated = binder_find_outdated_transaction_ilocked(t, 2780 2775 &node->async_todo); 2781 2776 if (t_outdated) { ··· 2811 2806 kfree(t_outdated); 2812 2807 binder_stats_deleted(BINDER_STAT_TRANSACTION); 2813 2808 } 2809 + 2810 + if (oneway && frozen) 2811 + return BR_TRANSACTION_PENDING_FROZEN; 2814 2812 2815 2813 return 0; 2816 2814 } ··· 3615 3607 } else { 3616 3608 BUG_ON(target_node == NULL); 3617 3609 BUG_ON(t->buffer->async_transaction != 1); 3618 - binder_enqueue_thread_work(thread, tcomplete); 3619 3610 return_error = binder_proc_transaction(t, target_proc, NULL); 3620 - if (return_error) 3611 + /* 3612 + * Let the caller know when async transaction reaches a frozen 3613 + * process and is put in a pending queue, waiting for the target 3614 + * process to be unfrozen. 3615 + */ 3616 + if (return_error == BR_TRANSACTION_PENDING_FROZEN) 3617 + tcomplete->type = BINDER_WORK_TRANSACTION_PENDING; 3618 + binder_enqueue_thread_work(thread, tcomplete); 3619 + if (return_error && 3620 + return_error != BR_TRANSACTION_PENDING_FROZEN) 3621 3621 goto err_dead_proc_or_thread; 3622 3622 } 3623 3623 if (target_thread) ··· 4456 4440 binder_stat_br(proc, thread, cmd); 4457 4441 } break; 4458 4442 case BINDER_WORK_TRANSACTION_COMPLETE: 4443 + case BINDER_WORK_TRANSACTION_PENDING: 4459 4444 case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT: { 4460 4445 if (proc->oneway_spam_detection_enabled && 4461 4446 w->type == BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT) 4462 4447 cmd = BR_ONEWAY_SPAM_SUSPECT; 4448 + else if (w->type == BINDER_WORK_TRANSACTION_PENDING) 4449 + cmd = BR_TRANSACTION_PENDING_FROZEN; 4463 4450 else 4464 4451 cmd = BR_TRANSACTION_COMPLETE; 4465 4452 binder_inner_proc_unlock(proc); ··· 6178 6159 "BR_FAILED_REPLY", 6179 6160 "BR_FROZEN_REPLY", 6180 6161 "BR_ONEWAY_SPAM_SUSPECT", 6162 + "BR_TRANSACTION_PENDING_FROZEN" 6181 6163 }; 6182 6164 6183 6165 static const char * const binder_command_strings[] = {
+2 -1
drivers/android/binder_internal.h
··· 133 133 }; 134 134 135 135 struct binder_stats { 136 - atomic_t br[_IOC_NR(BR_ONEWAY_SPAM_SUSPECT) + 1]; 136 + atomic_t br[_IOC_NR(BR_TRANSACTION_PENDING_FROZEN) + 1]; 137 137 atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; 138 138 atomic_t obj_created[BINDER_STAT_COUNT]; 139 139 atomic_t obj_deleted[BINDER_STAT_COUNT]; ··· 152 152 enum binder_work_type { 153 153 BINDER_WORK_TRANSACTION = 1, 154 154 BINDER_WORK_TRANSACTION_COMPLETE, 155 + BINDER_WORK_TRANSACTION_PENDING, 155 156 BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT, 156 157 BINDER_WORK_RETURN_ERROR, 157 158 BINDER_WORK_NODE,
+6 -1
include/uapi/linux/android/binder.h
··· 450 450 451 451 BR_FROZEN_REPLY = _IO('r', 18), 452 452 /* 453 - * The target of the last transaction (either a bcTRANSACTION or 453 + * The target of the last sync transaction (either a bcTRANSACTION or 454 454 * a bcATTEMPT_ACQUIRE) is frozen. No parameters. 455 455 */ 456 456 ··· 459 459 * Current process sent too many oneway calls to target, and the last 460 460 * asynchronous transaction makes the allocated async buffer size exceed 461 461 * detection threshold. No parameters. 462 + */ 463 + 464 + BR_TRANSACTION_PENDING_FROZEN = _IO('r', 20), 465 + /* 466 + * The target of the last async transaction is frozen. No parameters. 462 467 */ 463 468 }; 464 469