binder: freeze multiple contexts

binder freeze stops at the first context found for any pid, but
multiple ones are possible with the result that a process might end
up with inconsistent context states after freezing or unfreezing its
binder.

Freeze or unfreeze all contexts in a process upon a BINDER_FREEZE
ioctl.

Bug: 176996063
Test: verified that all contexts in a specific process with multiple
binders are frozen or unfrozen.
Signed-off-by: Marco Ballesio <balejs@google.com>

Change-Id: If0822e078e830e9fde10cc17b99e39ec7cf358d5
Signed-off-by: Ruchit <risen@pixelexperience.org>
urubino
Marco Ballesio 3 years ago committed by Jenna-they-them
parent ed093f6739
commit d5e7c319b1
  1. 108
      drivers/android/binder.c

@ -4998,20 +4998,66 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc,
return 0;
}
static int binder_ioctl_freeze(struct binder_freeze_info *info,
struct binder_proc *target_proc)
{
int ret = 0;
if (!info->enable) {
binder_inner_proc_lock(target_proc);
target_proc->sync_recv = false;
target_proc->async_recv = false;
target_proc->is_frozen = false;
binder_inner_proc_unlock(target_proc);
return 0;
}
/*
* Freezing the target. Prevent new transactions by
* setting frozen state. If timeout specified, wait
* for transactions to drain.
*/
binder_inner_proc_lock(target_proc);
target_proc->sync_recv = false;
target_proc->async_recv = false;
target_proc->is_frozen = true;
binder_inner_proc_unlock(target_proc);
if (info->timeout_ms > 0)
ret = wait_event_interruptible_timeout(
target_proc->freeze_wait,
(!target_proc->outstanding_txns),
msecs_to_jiffies(info->timeout_ms));
if (!ret && target_proc->outstanding_txns)
ret = -EAGAIN;
if (ret < 0) {
binder_inner_proc_lock(target_proc);
target_proc->is_frozen = false;
binder_inner_proc_unlock(target_proc);
}
return ret;
}
static int binder_ioctl_get_freezer_info(
struct binder_frozen_status_info *info)
{
struct binder_proc *target_proc;
bool found = false;
info->sync_recv = 0;
info->async_recv = 0;
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(target_proc, &binder_procs, proc_node) {
if (target_proc->pid == info->pid) {
found = true;
binder_inner_proc_lock(target_proc);
target_proc->tmp_ref++;
info->sync_recv |= target_proc->sync_recv;
info->async_recv |= target_proc->async_recv;
binder_inner_proc_unlock(target_proc);
break;
}
}
mutex_unlock(&binder_procs_lock);
@ -5019,13 +5065,6 @@ static int binder_ioctl_get_freezer_info(
if (!found)
return -EINVAL;
binder_inner_proc_lock(target_proc);
info->sync_recv = target_proc->sync_recv;
info->async_recv = target_proc->async_recv;
binder_inner_proc_unlock(target_proc);
binder_proc_dec_tmpref(target_proc);
return 0;
}
@ -5150,7 +5189,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case BINDER_FREEZE: {
struct binder_freeze_info info;
struct binder_proc *target_proc;
bool found = false;
ret = -EINVAL;
if (copy_from_user(&info, ubuf, sizeof(info))) {
ret = -EFAULT;
@ -5159,51 +5198,22 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(target_proc, &binder_procs, proc_node) {
if (target_proc->pid == info.pid) {
found = true;
binder_inner_proc_lock(target_proc);
target_proc->tmp_ref++;
binder_inner_proc_unlock(target_proc);
break;
mutex_unlock(&binder_procs_lock);
ret = binder_ioctl_freeze(&info, target_proc);
mutex_lock(&binder_procs_lock);
binder_proc_dec_tmpref(target_proc);
if (ret < 0)
break;
}
}
mutex_unlock(&binder_procs_lock);
if (!found) {
ret = -EINVAL;
goto err;
}
if (!info.enable) {
binder_inner_proc_lock(target_proc);
target_proc->sync_recv = false;
target_proc->async_recv = false;
target_proc->is_frozen = false;
binder_inner_proc_unlock(target_proc);
binder_proc_dec_tmpref(target_proc);
break;
}
/*
* Freezing the target. Prevent new transactions by
* setting frozen state. If timeout specified, wait
* for transactions to drain.
*/
binder_inner_proc_lock(target_proc);
target_proc->sync_recv = false;
target_proc->async_recv = false;
target_proc->is_frozen = true;
binder_inner_proc_unlock(target_proc);
if (info.timeout_ms > 0)
ret = wait_event_interruptible_timeout(
target_proc->freeze_wait,
(!target_proc->outstanding_txns),
msecs_to_jiffies(info.timeout_ms));
if (!ret && target_proc->outstanding_txns) {
ret = -EAGAIN;
}
if (ret < 0) {
binder_inner_proc_lock(target_proc);
target_proc->is_frozen = false;
binder_inner_proc_unlock(target_proc);
}
binder_proc_dec_tmpref(target_proc);
if (ret < 0)
goto err;
break;

Loading…
Cancel
Save