diff options
| author | Martijn Coenen <maco@android.com> | 2017-11-15 03:21:35 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-11-28 10:33:03 -0500 |
| commit | 148ade2c4d4f46b3ecc1ddad1c762371e8708e35 (patch) | |
| tree | 0fbd781537b7128cdb6a7a8c42f65e29cd422fd9 /drivers/android | |
| parent | 39b759cad5da88ee8ac55e186a00da4692b44e17 (diff) | |
ANDROID: binder: Add thread->process_todo flag.
This flag determines whether the thread should currently
process the work in the thread->todo worklist.
The prime usecase for this is improving the performance
of synchronous transactions: all synchronous transactions
post a BR_TRANSACTION_COMPLETE to the calling thread,
but there's no reason to return that command to userspace
right away - userspace anyway needs to wait for the reply.
Likewise, a synchronous transaction that contains a binder
object can cause a BC_ACQUIRE/BC_INCREFS to be returned to
userspace; since the caller must anyway hold a strong/weak
ref for the duration of the call, postponing these commands
until the reply comes in is not a problem.
Note that this flag is not used to determine whether a
thread can handle process work; a thread should never pick
up process work when thread work is still pending.
Before patch:
------------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------------
BM_sendVec_binderize/4 45959 ns 20288 ns 34351
BM_sendVec_binderize/8 45603 ns 20080 ns 34909
BM_sendVec_binderize/16 45528 ns 20113 ns 34863
BM_sendVec_binderize/32 45551 ns 20122 ns 34881
BM_sendVec_binderize/64 45701 ns 20183 ns 34864
BM_sendVec_binderize/128 45824 ns 20250 ns 34576
BM_sendVec_binderize/256 45695 ns 20171 ns 34759
BM_sendVec_binderize/512 45743 ns 20211 ns 34489
BM_sendVec_binderize/1024 46169 ns 20430 ns 34081
After patch:
------------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------------
BM_sendVec_binderize/4 42939 ns 17262 ns 40653
BM_sendVec_binderize/8 42823 ns 17243 ns 40671
BM_sendVec_binderize/16 42898 ns 17243 ns 40594
BM_sendVec_binderize/32 42838 ns 17267 ns 40527
BM_sendVec_binderize/64 42854 ns 17249 ns 40379
BM_sendVec_binderize/128 42881 ns 17288 ns 40427
BM_sendVec_binderize/256 42917 ns 17297 ns 40429
BM_sendVec_binderize/512 43184 ns 17395 ns 40411
BM_sendVec_binderize/1024 43119 ns 17357 ns 40432
Signed-off-by: Martijn Coenen <maco@android.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android')
| -rw-r--r-- | drivers/android/binder.c | 151 |
1 files changed, 107 insertions, 44 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a73596a4f804..e9d22dd85a19 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
| @@ -577,6 +577,8 @@ enum { | |||
| 577 | * (protected by @proc->inner_lock) | 577 | * (protected by @proc->inner_lock) |
| 578 | * @todo: list of work to do for this thread | 578 | * @todo: list of work to do for this thread |
| 579 | * (protected by @proc->inner_lock) | 579 | * (protected by @proc->inner_lock) |
| 580 | * @process_todo: whether work in @todo should be processed | ||
| 581 | * (protected by @proc->inner_lock) | ||
| 580 | * @return_error: transaction errors reported by this thread | 582 | * @return_error: transaction errors reported by this thread |
| 581 | * (only accessed by this thread) | 583 | * (only accessed by this thread) |
| 582 | * @reply_error: transaction errors reported by target thread | 584 | * @reply_error: transaction errors reported by target thread |
| @@ -602,6 +604,7 @@ struct binder_thread { | |||
| 602 | bool looper_need_return; /* can be written by other thread */ | 604 | bool looper_need_return; /* can be written by other thread */ |
| 603 | struct binder_transaction *transaction_stack; | 605 | struct binder_transaction *transaction_stack; |
| 604 | struct list_head todo; | 606 | struct list_head todo; |
| 607 | bool process_todo; | ||
| 605 | struct binder_error return_error; | 608 | struct binder_error return_error; |
| 606 | struct binder_error reply_error; | 609 | struct binder_error reply_error; |
| 607 | wait_queue_head_t wait; | 610 | wait_queue_head_t wait; |
| @@ -787,6 +790,16 @@ static bool binder_worklist_empty(struct binder_proc *proc, | |||
| 787 | return ret; | 790 | return ret; |
| 788 | } | 791 | } |
| 789 | 792 | ||
| 793 | /** | ||
| 794 | * binder_enqueue_work_ilocked() - Add an item to the work list | ||
| 795 | * @work: struct binder_work to add to list | ||
| 796 | * @target_list: list to add work to | ||
| 797 | * | ||
| 798 | * Adds the work to the specified list. Asserts that work | ||
| 799 | * is not already on a list. | ||
| 800 | * | ||
| 801 | * Requires the proc->inner_lock to be held. | ||
| 802 | */ | ||
| 790 | static void | 803 | static void |
| 791 | binder_enqueue_work_ilocked(struct binder_work *work, | 804 | binder_enqueue_work_ilocked(struct binder_work *work, |
| 792 | struct list_head *target_list) | 805 | struct list_head *target_list) |
| @@ -797,22 +810,56 @@ binder_enqueue_work_ilocked(struct binder_work *work, | |||
| 797 | } | 810 | } |
| 798 | 811 | ||
| 799 | /** | 812 | /** |
| 800 | * binder_enqueue_work() - Add an item to the work list | 813 | * binder_enqueue_deferred_thread_work_ilocked() - Add deferred thread work |
| 801 | * @proc: binder_proc associated with list | 814 | * @thread: thread to queue work to |
| 802 | * @work: struct binder_work to add to list | 815 | * @work: struct binder_work to add to list |
| 803 | * @target_list: list to add work to | ||
| 804 | * | 816 | * |
| 805 | * Adds the work to the specified list. Asserts that work | 817 | * Adds the work to the todo list of the thread. Doesn't set the process_todo |
| 806 | * is not already on a list. | 818 | * flag, which means that (if it wasn't already set) the thread will go to |
| 819 | * sleep without handling this work when it calls read. | ||
| 820 | * | ||
| 821 | * Requires the proc->inner_lock to be held. | ||
| 807 | */ | 822 | */ |
| 808 | static void | 823 | static void |
| 809 | binder_enqueue_work(struct binder_proc *proc, | 824 | binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, |
| 810 | struct binder_work *work, | 825 | struct binder_work *work) |
| 811 | struct list_head *target_list) | ||
| 812 | { | 826 | { |
| 813 | binder_inner_proc_lock(proc); | 827 | binder_enqueue_work_ilocked(work, &thread->todo); |
| 814 | binder_enqueue_work_ilocked(work, target_list); | 828 | } |
| 815 | binder_inner_proc_unlock(proc); | 829 | |
| 830 | /** | ||
| 831 | * binder_enqueue_thread_work_ilocked() - Add an item to the thread work list | ||
| 832 | * @thread: thread to queue work to | ||
| 833 | * @work: struct binder_work to add to list | ||
| 834 | * | ||
| 835 | * Adds the work to the todo list of the thread, and enables processing | ||
| 836 | * of the todo queue. | ||
| 837 | * | ||
| 838 | * Requires the proc->inner_lock to be held. | ||
| 839 | */ | ||
| 840 | static void | ||
| 841 | binder_enqueue_thread_work_ilocked(struct binder_thread *thread, | ||
| 842 | struct binder_work *work) | ||
| 843 | { | ||
| 844 | binder_enqueue_work_ilocked(work, &thread->todo); | ||
| 845 | thread->process_todo = true; | ||
| 846 | } | ||
| 847 | |||
| 848 | /** | ||
| 849 | * binder_enqueue_thread_work() - Add an item to the thread work list | ||
| 850 | * @thread: thread to queue work to | ||
| 851 | * @work: struct binder_work to add to list | ||
| 852 | * | ||
| 853 | * Adds the work to the todo list of the thread, and enables processing | ||
| 854 | * of the todo queue. | ||
| 855 | */ | ||
| 856 | static void | ||
| 857 | binder_enqueue_thread_work(struct binder_thread *thread, | ||
| 858 | struct binder_work *work) | ||
| 859 | { | ||
| 860 | binder_inner_proc_lock(thread->proc); | ||
| 861 | binder_enqueue_thread_work_ilocked(thread, work); | ||
| 862 | binder_inner_proc_unlock(thread->proc); | ||
| 816 | } | 863 | } |
| 817 | 864 | ||
| 818 | static void | 865 | static void |
| @@ -927,7 +974,7 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) | |||
| 927 | static bool binder_has_work_ilocked(struct binder_thread *thread, | 974 | static bool binder_has_work_ilocked(struct binder_thread *thread, |
| 928 | bool do_proc_work) | 975 | bool do_proc_work) |
| 929 | { | 976 | { |
| 930 | return !binder_worklist_empty_ilocked(&thread->todo) || | 977 | return thread->process_todo || |
| 931 | thread->looper_need_return || | 978 | thread->looper_need_return || |
| 932 | (do_proc_work && | 979 | (do_proc_work && |
| 933 | !binder_worklist_empty_ilocked(&thread->proc->todo)); | 980 | !binder_worklist_empty_ilocked(&thread->proc->todo)); |
| @@ -1215,6 +1262,17 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, | |||
| 1215 | node->local_strong_refs++; | 1262 | node->local_strong_refs++; |
| 1216 | if (!node->has_strong_ref && target_list) { | 1263 | if (!node->has_strong_ref && target_list) { |
| 1217 | binder_dequeue_work_ilocked(&node->work); | 1264 | binder_dequeue_work_ilocked(&node->work); |
| 1265 | /* | ||
| 1266 | * Note: this function is the only place where we queue | ||
| 1267 | * directly to a thread->todo without using the | ||
| 1268 | * corresponding binder_enqueue_thread_work() helper | ||
| 1269 | * functions; in this case it's ok to not set the | ||
| 1270 | * process_todo flag, since we know this node work will | ||
| 1271 | * always be followed by other work that starts queue | ||
| 1272 | * processing: in case of synchronous transactions, a | ||
| 1273 | * BR_REPLY or BR_ERROR; in case of oneway | ||
| 1274 | * transactions, a BR_TRANSACTION_COMPLETE. | ||
| 1275 | */ | ||
| 1218 | binder_enqueue_work_ilocked(&node->work, target_list); | 1276 | binder_enqueue_work_ilocked(&node->work, target_list); |
| 1219 | } | 1277 | } |
| 1220 | } else { | 1278 | } else { |
| @@ -1226,6 +1284,9 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, | |||
| 1226 | node->debug_id); | 1284 | node->debug_id); |
| 1227 | return -EINVAL; | 1285 | return -EINVAL; |
| 1228 | } | 1286 | } |
| 1287 | /* | ||
| 1288 | * See comment above | ||
| 1289 | */ | ||
| 1229 | binder_enqueue_work_ilocked(&node->work, target_list); | 1290 | binder_enqueue_work_ilocked(&node->work, target_list); |
| 1230 | } | 1291 | } |
| 1231 | } | 1292 | } |
| @@ -1915,9 +1976,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, | |||
| 1915 | binder_pop_transaction_ilocked(target_thread, t); | 1976 | binder_pop_transaction_ilocked(target_thread, t); |
| 1916 | if (target_thread->reply_error.cmd == BR_OK) { | 1977 | if (target_thread->reply_error.cmd == BR_OK) { |
| 1917 | target_thread->reply_error.cmd = error_code; | 1978 | target_thread->reply_error.cmd = error_code; |
| 1918 | binder_enqueue_work_ilocked( | 1979 | binder_enqueue_thread_work_ilocked( |
| 1919 | &target_thread->reply_error.work, | 1980 | target_thread, |
| 1920 | &target_thread->todo); | 1981 | &target_thread->reply_error.work); |
| 1921 | wake_up_interruptible(&target_thread->wait); | 1982 | wake_up_interruptible(&target_thread->wait); |
| 1922 | } else { | 1983 | } else { |
| 1923 | WARN(1, "Unexpected reply error: %u\n", | 1984 | WARN(1, "Unexpected reply error: %u\n", |
| @@ -2536,18 +2597,16 @@ static bool binder_proc_transaction(struct binder_transaction *t, | |||
| 2536 | struct binder_proc *proc, | 2597 | struct binder_proc *proc, |
| 2537 | struct binder_thread *thread) | 2598 | struct binder_thread *thread) |
| 2538 | { | 2599 | { |
| 2539 | struct list_head *target_list = NULL; | ||
| 2540 | struct binder_node *node = t->buffer->target_node; | 2600 | struct binder_node *node = t->buffer->target_node; |
| 2541 | bool oneway = !!(t->flags & TF_ONE_WAY); | 2601 | bool oneway = !!(t->flags & TF_ONE_WAY); |
| 2542 | bool wakeup = true; | 2602 | bool pending_async = false; |
| 2543 | 2603 | ||
| 2544 | BUG_ON(!node); | 2604 | BUG_ON(!node); |
| 2545 | binder_node_lock(node); | 2605 | binder_node_lock(node); |
| 2546 | if (oneway) { | 2606 | if (oneway) { |
| 2547 | BUG_ON(thread); | 2607 | BUG_ON(thread); |
| 2548 | if (node->has_async_transaction) { | 2608 | if (node->has_async_transaction) { |
| 2549 | target_list = &node->async_todo; | 2609 | pending_async = true; |
| 2550 | wakeup = false; | ||
| 2551 | } else { | 2610 | } else { |
| 2552 | node->has_async_transaction = 1; | 2611 | node->has_async_transaction = 1; |
| 2553 | } | 2612 | } |
| @@ -2561,19 +2620,17 @@ static bool binder_proc_transaction(struct binder_transaction *t, | |||
| 2561 | return false; | 2620 | return false; |
| 2562 | } | 2621 | } |
| 2563 | 2622 | ||
| 2564 | if (!thread && !target_list) | 2623 | if (!thread && !pending_async) |
| 2565 | thread = binder_select_thread_ilocked(proc); | 2624 | thread = binder_select_thread_ilocked(proc); |
| 2566 | 2625 | ||
| 2567 | if (thread) | 2626 | if (thread) |
| 2568 | target_list = &thread->todo; | 2627 | binder_enqueue_thread_work_ilocked(thread, &t->work); |
| 2569 | else if (!target_list) | 2628 | else if (!pending_async) |
| 2570 | target_list = &proc->todo; | 2629 | binder_enqueue_work_ilocked(&t->work, &proc->todo); |
| 2571 | else | 2630 | else |
| 2572 | BUG_ON(target_list != &node->async_todo); | 2631 | binder_enqueue_work_ilocked(&t->work, &node->async_todo); |
| 2573 | |||
| 2574 | binder_enqueue_work_ilocked(&t->work, target_list); | ||
| 2575 | 2632 | ||
| 2576 | if (wakeup) | 2633 | if (!pending_async) |
| 2577 | binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); | 2634 | binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); |
| 2578 | 2635 | ||
| 2579 | binder_inner_proc_unlock(proc); | 2636 | binder_inner_proc_unlock(proc); |
| @@ -3068,10 +3125,10 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 3068 | } | 3125 | } |
| 3069 | } | 3126 | } |
| 3070 | tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; | 3127 | tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; |
| 3071 | binder_enqueue_work(proc, tcomplete, &thread->todo); | ||
| 3072 | t->work.type = BINDER_WORK_TRANSACTION; | 3128 | t->work.type = BINDER_WORK_TRANSACTION; |
| 3073 | 3129 | ||
| 3074 | if (reply) { | 3130 | if (reply) { |
| 3131 | binder_enqueue_thread_work(thread, tcomplete); | ||
| 3075 | binder_inner_proc_lock(target_proc); | 3132 | binder_inner_proc_lock(target_proc); |
| 3076 | if (target_thread->is_dead) { | 3133 | if (target_thread->is_dead) { |
| 3077 | binder_inner_proc_unlock(target_proc); | 3134 | binder_inner_proc_unlock(target_proc); |
| @@ -3079,13 +3136,21 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 3079 | } | 3136 | } |
| 3080 | BUG_ON(t->buffer->async_transaction != 0); | 3137 | BUG_ON(t->buffer->async_transaction != 0); |
| 3081 | binder_pop_transaction_ilocked(target_thread, in_reply_to); | 3138 | binder_pop_transaction_ilocked(target_thread, in_reply_to); |
| 3082 | binder_enqueue_work_ilocked(&t->work, &target_thread->todo); | 3139 | binder_enqueue_thread_work_ilocked(target_thread, &t->work); |
| 3083 | binder_inner_proc_unlock(target_proc); | 3140 | binder_inner_proc_unlock(target_proc); |
| 3084 | wake_up_interruptible_sync(&target_thread->wait); | 3141 | wake_up_interruptible_sync(&target_thread->wait); |
| 3085 | binder_free_transaction(in_reply_to); | 3142 | binder_free_transaction(in_reply_to); |
| 3086 | } else if (!(t->flags & TF_ONE_WAY)) { | 3143 | } else if (!(t->flags & TF_ONE_WAY)) { |
| 3087 | BUG_ON(t->buffer->async_transaction != 0); | 3144 | BUG_ON(t->buffer->async_transaction != 0); |
| 3088 | binder_inner_proc_lock(proc); | 3145 | binder_inner_proc_lock(proc); |
| 3146 | /* | ||
| 3147 | * Defer the TRANSACTION_COMPLETE, so we don't return to | ||
| 3148 | * userspace immediately; this allows the target process to | ||
| 3149 | * immediately start processing this transaction, reducing | ||
| 3150 | * latency. We will then return the TRANSACTION_COMPLETE when | ||
| 3151 | * the target replies (or there is an error). | ||
| 3152 | */ | ||
| 3153 | binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); | ||
| 3089 | t->need_reply = 1; | 3154 | t->need_reply = 1; |
| 3090 | t->from_parent = thread->transaction_stack; | 3155 | t->from_parent = thread->transaction_stack; |
| 3091 | thread->transaction_stack = t; | 3156 | thread->transaction_stack = t; |
| @@ -3099,6 +3164,7 @@ static void binder_transaction(struct binder_proc *proc, | |||
| 3099 | } else { | 3164 | } else { |
| 3100 | BUG_ON(target_node == NULL); | 3165 | BUG_ON(target_node == NULL); |
| 3101 | BUG_ON(t->buffer->async_transaction != 1); | 3166 | BUG_ON(t->buffer->async_transaction != 1); |
| 3167 | binder_enqueue_thread_work(thread, tcomplete); | ||
| 3102 | if (!binder_proc_transaction(t, target_proc, NULL)) | 3168 | if (!binder_proc_transaction(t, target_proc, NULL)) |
| 3103 | goto err_dead_proc_or_thread; | 3169 | goto err_dead_proc_or_thread; |
| 3104 | } | 3170 | } |
| @@ -3177,15 +3243,11 @@ err_invalid_target_handle: | |||
| 3177 | BUG_ON(thread->return_error.cmd != BR_OK); | 3243 | BUG_ON(thread->return_error.cmd != BR_OK); |
| 3178 | if (in_reply_to) { | 3244 | if (in_reply_to) { |
| 3179 | thread->return_error.cmd = BR_TRANSACTION_COMPLETE; | 3245 | thread->return_error.cmd = BR_TRANSACTION_COMPLETE; |
| 3180 | binder_enqueue_work(thread->proc, | 3246 | binder_enqueue_thread_work(thread, &thread->return_error.work); |
| 3181 | &thread->return_error.work, | ||
| 3182 | &thread->todo); | ||
| 3183 | binder_send_failed_reply(in_reply_to, return_error); | 3247 | binder_send_failed_reply(in_reply_to, return_error); |
| 3184 | } else { | 3248 | } else { |
| 3185 | thread->return_error.cmd = return_error; | 3249 | thread->return_error.cmd = return_error; |
| 3186 | binder_enqueue_work(thread->proc, | 3250 | binder_enqueue_thread_work(thread, &thread->return_error.work); |
| 3187 | &thread->return_error.work, | ||
| 3188 | &thread->todo); | ||
| 3189 | } | 3251 | } |
| 3190 | } | 3252 | } |
| 3191 | 3253 | ||
| @@ -3489,10 +3551,9 @@ static int binder_thread_write(struct binder_proc *proc, | |||
| 3489 | WARN_ON(thread->return_error.cmd != | 3551 | WARN_ON(thread->return_error.cmd != |
| 3490 | BR_OK); | 3552 | BR_OK); |
| 3491 | thread->return_error.cmd = BR_ERROR; | 3553 | thread->return_error.cmd = BR_ERROR; |
| 3492 | binder_enqueue_work( | 3554 | binder_enqueue_thread_work( |
| 3493 | thread->proc, | 3555 | thread, |
| 3494 | &thread->return_error.work, | 3556 | &thread->return_error.work); |
| 3495 | &thread->todo); | ||
| 3496 | binder_debug( | 3557 | binder_debug( |
| 3497 | BINDER_DEBUG_FAILED_TRANSACTION, | 3558 | BINDER_DEBUG_FAILED_TRANSACTION, |
| 3498 | "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", | 3559 | "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", |
| @@ -3572,9 +3633,9 @@ static int binder_thread_write(struct binder_proc *proc, | |||
| 3572 | if (thread->looper & | 3633 | if (thread->looper & |
| 3573 | (BINDER_LOOPER_STATE_REGISTERED | | 3634 | (BINDER_LOOPER_STATE_REGISTERED | |
| 3574 | BINDER_LOOPER_STATE_ENTERED)) | 3635 | BINDER_LOOPER_STATE_ENTERED)) |
| 3575 | binder_enqueue_work_ilocked( | 3636 | binder_enqueue_thread_work_ilocked( |
| 3576 | &death->work, | 3637 | thread, |
| 3577 | &thread->todo); | 3638 | &death->work); |
| 3578 | else { | 3639 | else { |
| 3579 | binder_enqueue_work_ilocked( | 3640 | binder_enqueue_work_ilocked( |
| 3580 | &death->work, | 3641 | &death->work, |
| @@ -3629,8 +3690,8 @@ static int binder_thread_write(struct binder_proc *proc, | |||
| 3629 | if (thread->looper & | 3690 | if (thread->looper & |
| 3630 | (BINDER_LOOPER_STATE_REGISTERED | | 3691 | (BINDER_LOOPER_STATE_REGISTERED | |
| 3631 | BINDER_LOOPER_STATE_ENTERED)) | 3692 | BINDER_LOOPER_STATE_ENTERED)) |
| 3632 | binder_enqueue_work_ilocked( | 3693 | binder_enqueue_thread_work_ilocked( |
| 3633 | &death->work, &thread->todo); | 3694 | thread, &death->work); |
| 3634 | else { | 3695 | else { |
| 3635 | binder_enqueue_work_ilocked( | 3696 | binder_enqueue_work_ilocked( |
| 3636 | &death->work, | 3697 | &death->work, |
| @@ -3804,6 +3865,8 @@ retry: | |||
| 3804 | break; | 3865 | break; |
| 3805 | } | 3866 | } |
| 3806 | w = binder_dequeue_work_head_ilocked(list); | 3867 | w = binder_dequeue_work_head_ilocked(list); |
| 3868 | if (binder_worklist_empty_ilocked(&thread->todo)) | ||
| 3869 | thread->process_todo = false; | ||
| 3807 | 3870 | ||
| 3808 | switch (w->type) { | 3871 | switch (w->type) { |
| 3809 | case BINDER_WORK_TRANSACTION: { | 3872 | case BINDER_WORK_TRANSACTION: { |
