FROMLIST: ANDROID: binder: Add BINDER_GET_NODE_INFO_FOR_REF ioctl.
authorMartijn Coenen <maco@android.com>
Sat, 25 Aug 2018 20:50:56 +0000 (13:50 -0700)
committerDanny Wood <danwood76@gmail.com>
Fri, 8 Nov 2019 12:03:13 +0000 (12:03 +0000)
This allows the context manager to retrieve information about nodes
that it holds a reference to, such as the current number of
references to those nodes.

Such information can for example be used to determine whether the
servicemanager is the only process holding a reference to a node.
This information can then be passed on to the process holding the
node, which can in turn decide whether it wants to shut down to
reduce resource usage.

Signed-off-by: Martijn Coenen <maco@android.com>
Change-Id: I2fa9b6e2b1d1d6c84fca954125c3ec776dc2c04f

drivers/android/binder.c
include/uapi/linux/android/binder.h

index c180f919c3b674c526284dcb6822970d68ac4dc3..a8eae74bd2798700cc096d09ac6695bc53807eeb 100644 (file)
@@ -4703,6 +4703,42 @@ out:
        return ret;
 }
 
+static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc,
+               struct binder_node_info_for_ref *info)
+{
+       struct binder_node *node;
+       struct binder_context *context = proc->context;
+       __u32 handle = info->handle;
+
+       if (info->strong_count || info->weak_count || info->reserved1 ||
+           info->reserved2 || info->reserved3) {
+               binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.",
+                                 proc->pid);
+               return -EINVAL;
+       }
+
+       /* This ioctl may only be used by the context manager */
+       mutex_lock(&context->context_mgr_node_lock);
+       if (!context->binder_context_mgr_node ||
+               context->binder_context_mgr_node->proc != proc) {
+               mutex_unlock(&context->context_mgr_node_lock);
+               return -EPERM;
+       }
+       mutex_unlock(&context->context_mgr_node_lock);
+
+       node = binder_get_node_from_ref(proc, handle, true, NULL);
+       if (!node)
+               return -EINVAL;
+
+       info->strong_count = node->local_strong_refs +
+               node->internal_strong_refs;
+       info->weak_count = node->local_weak_refs;
+
+       binder_put_node(node);
+
+       return 0;
+}
+
 static int binder_ioctl_get_node_debug_info(struct binder_proc *proc,
                                struct binder_node_debug_info *info) {
        struct rb_node *n;
@@ -4796,6 +4832,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                }
                break;
        }
+       case BINDER_GET_NODE_INFO_FOR_REF: {
+               struct binder_node_info_for_ref info;
+
+               if (copy_from_user(&info, ubuf, sizeof(info))) {
+                       ret = -EFAULT;
+                       goto err;
+               }
+
+               ret = binder_ioctl_get_node_info_for_ref(proc, &info);
+               if (ret < 0)
+                       goto err;
+
+               if (copy_to_user(ubuf, &info, sizeof(info))) {
+                       ret = -EFAULT;
+                       goto err;
+               }
+
+               break;
+       }
        case BINDER_GET_NODE_DEBUG_INFO: {
                struct binder_node_debug_info info;
 
index 973d56605e755658344d6c7a5485ef26c53c0f44..2ff6b15ac9183c2bcfcc162a94b5331c9e79e71f 100644 (file)
@@ -243,6 +243,15 @@ struct binder_node_debug_info {
        __u32            has_weak_ref;
 };
 
+struct binder_node_info_for_ref {
+       __u32            handle;
+       __u32            strong_count;
+       __u32            weak_count;
+       __u32            reserved1;
+       __u32            reserved2;
+       __u32            reserved3;
+};
+
 #define BINDER_WRITE_READ              _IOWR('b', 1, struct binder_write_read)
 #define        BINDER_SET_IDLE_TIMEOUT         _IOW('b', 3, __s64)
 #define        BINDER_SET_MAX_THREADS          _IOW('b', 5, __u32)
@@ -251,6 +260,7 @@ struct binder_node_debug_info {
 #define        BINDER_THREAD_EXIT              _IOW('b', 8, __s32)
 #define BINDER_VERSION                 _IOWR('b', 9, struct binder_version)
 #define BINDER_GET_NODE_DEBUG_INFO     _IOWR('b', 11, struct binder_node_debug_info)
+#define BINDER_GET_NODE_INFO_FOR_REF   _IOWR('b', 12, struct binder_node_info_for_ref)
 
 /*
  * NOTE: Two special error codes you should check for when calling