diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 723e2780933d..0cbaee418ea0 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -698,6 +698,20 @@ static void binder_do_set_priority(struct binder_thread *thread, to_kernel_prio(policy, priority), desired->prio); + spin_lock(&thread->prio_lock); + if (!verify && thread->prio_state == BINDER_PRIO_ABORT) { + /* + * A new priority has been set by an incoming nested + * transaction. Abort this priority restore and allow + * the transaction to run at the new desired priority. + */ + spin_unlock(&thread->prio_lock); + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: %s: aborting priority restore\n", + thread->pid, __func__); + return; + } + /* Set the actual priority */ if (task->policy != policy || is_rt_policy(policy)) { struct sched_param params; @@ -710,6 +724,9 @@ static void binder_do_set_priority(struct binder_thread *thread, } if (is_fair_policy(policy)) set_user_nice(task, priority); + + thread->prio_state = BINDER_PRIO_SET; + spin_unlock(&thread->prio_lock); } static void binder_set_priority(struct binder_thread *thread, @@ -740,8 +757,6 @@ static void binder_transaction_priority(struct binder_thread *thread, return; t->set_priority_called = true; - t->saved_priority.sched_policy = task->policy; - t->saved_priority.prio = task->normal_prio; trace_android_vh_binder_priority_skip(task, &skip); if (skip) @@ -765,6 +780,25 @@ static void binder_transaction_priority(struct binder_thread *thread, desired = node_prio; } + spin_lock(&thread->prio_lock); + if (thread->prio_state == BINDER_PRIO_PENDING) { + /* + * Task is in the process of changing priorities + * saving its current values would be incorrect. + * Instead, save the pending priority and signal + * the task to abort the priority restore. + */ + t->saved_priority = thread->prio_next; + thread->prio_state = BINDER_PRIO_ABORT; + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: saved pending priority %d\n", + current->pid, thread->prio_next.prio); + } else { + t->saved_priority.sched_policy = task->policy; + t->saved_priority.prio = task->normal_prio; + } + spin_unlock(&thread->prio_lock); + binder_set_priority(thread, &desired); trace_android_vh_binder_set_priority(t, task); } @@ -2605,6 +2639,7 @@ static void binder_transaction(struct binder_proc *proc, int t_debug_id = atomic_inc_return(&binder_last_id); char *secctx = NULL; u32 secctx_sz = 0; + bool is_nested = false; e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -2789,6 +2824,7 @@ static void binder_transaction(struct binder_proc *proc, atomic_inc(&from->tmp_ref); target_thread = from; spin_unlock(&tmp->lock); + is_nested = true; break; } spin_unlock(&tmp->lock); @@ -2853,6 +2889,7 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; + t->is_nested = is_nested; if (!(t->flags & TF_ONE_WAY) && binder_supported_policy(current->policy)) { /* Inherit supported policies for synchronous transactions */ @@ -3212,6 +3249,12 @@ static void binder_transaction(struct binder_proc *proc, binder_enqueue_thread_work_ilocked(target_thread, &t->work); target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); + if (in_reply_to->is_nested) { + spin_lock(&thread->prio_lock); + thread->prio_state = BINDER_PRIO_PENDING; + thread->prio_next = in_reply_to->saved_priority; + spin_unlock(&thread->prio_lock); + } wake_up_interruptible_sync(&target_thread->wait); trace_android_vh_binder_restore_priority(in_reply_to, current); binder_restore_priority(thread, &in_reply_to->saved_priority); @@ -4468,6 +4511,8 @@ static struct binder_thread *binder_get_thread_ilocked( thread->return_error.cmd = BR_OK; thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; thread->reply_error.cmd = BR_OK; + spin_lock_init(&thread->prio_lock); + thread->prio_state = BINDER_PRIO_SET; INIT_LIST_HEAD(&new_thread->waiting_thread_node); return thread; } diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index c2bb53e26d19..a25df99bd30b 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -367,6 +367,12 @@ struct binder_priority { int prio; }; +enum binder_prio_state { + BINDER_PRIO_SET, /* desired priority set */ + BINDER_PRIO_PENDING, /* initiated a saved priority restore */ + BINDER_PRIO_ABORT, /* abort the pending priority restore */ +}; + /** * struct binder_proc - binder process bookkeeping * @proc_node: element for binder_procs list @@ -511,6 +517,12 @@ struct binder_proc { * when outstanding transactions are cleaned up * (protected by @proc->inner_lock) * @task: struct task_struct for this thread + * @prio_lock: protects thread priority fields + * @prio_next: saved priority to be restored next + * (protected by @prio_lock) + * @prio_state: state of the priority restore process as + * defined by enum binder_prio_state + * (protected by @prio_lock) * * Bookkeeping structure for binder threads. */ @@ -531,6 +543,9 @@ struct binder_thread { atomic_t tmp_ref; bool is_dead; struct task_struct *task; + spinlock_t prio_lock; + struct binder_priority prio_next; + enum binder_prio_state prio_state; }; /** @@ -567,6 +582,7 @@ struct binder_transaction { struct binder_priority priority; struct binder_priority saved_priority; bool set_priority_called; + bool is_nested; kuid_t sender_euid; struct list_head fd_fixups; binder_uintptr_t security_ctx;