Binder ——binder的jni注册和binder驱动

news2024/11/14 21:32:09

环境:

  1. Android 11源码

  1. Android 11 内核源码

  1. 源码阅读器 sublime text

binder的jni方法注册

  1. zygote启动

1-1、启动zygote进程

zygote是由init进程通过解析init.zygote.rc文件而创建的,zygote所对应的可执行程序是app_process,所对应的源文件是app_main.cpp,进程名为zygote

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
1-2、执行app-main.cpp中的main方法
位置:frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    ...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            // 将zygote标志位TRUE
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } 
    // 运行AndroidRuntime.cpp 的strat方法
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

AppRuntime继承自AndroidRuntime

1-3、AndroidRuntime::start

调用startReg方法来完成jni方法注册

位置:frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...
    /* start the virtual machine,启动Android虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    ...
    /*
     * 注册Android的jni方法
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ...
}
位置:frameworks/base/core/jni/AndroidRuntime.cpp

/*
*在VM中注册Android的native方法
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
    env->PushLocalFrame(200);
    //注册jni方法
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}
位置:frameworks/base/core/jni/AndroidRuntime.cpp

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }
    return 0;
}

static const RegJNIRec gRegJNI[] = {
    ...
        //注册binder(jni动态注册)
        REG_JNI(register_android_os_Binder),
        REG_JNI(register_android_os_Parcel),
        REG_JNI(register_android_os_HidlMemory),
        REG_JNI(register_android_os_HidlSupport),
    ...

}

  1. register_android_os_Binder

位置:frameworks/base/core/jni/android_util_Binder.cpp

int register_android_os_Binder(JNIEnv* env)
{
    //开始注册binder
    if (int_register_android_os_Binder(env) < 0)
        return -1;
    if (int_register_android_os_BinderInternal(env) < 0)
        return -1;
    if (int_register_android_os_BinderProxy(env) < 0)
        return -1;
    ...
}
2-1、int_register_android_os_Binder
位置:frameworks/base/core/jni/android_util_Binder.cpp

const char* const kBinderPathName = "android/os/Binder";

//jni动态注册
static const JNINativeMethod gBinderMethods[] = {
     /* name, signature, funcPtr */
    // @CriticalNative
    { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
    // @CriticalNative
    { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
    // @CriticalNative
    { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction },
    ...
    { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
    { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
    { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
    { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
    { "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
    { "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
};

static int int_register_android_os_Binder(JNIEnv* env)
{
    //根据kBinderPathName获取对应的clazz对象
    jclass clazz = FindClassOrDie(env, kBinderPathName);
    //根据clazz获取对应的mClass,保存到gBinderOffsets结构体
    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    //根据方法名、方法签名获取方法
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    //根据方法名、方法签名获取方法
    gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
        "()Ljava/lang/String;");
    //获取属性、变量
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");

    //通过RegisterMethodsOrDie,将gBinderMethods数组完成映射关系,从而为java层访问jni层提供通道
    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

2-2、int_register_android_os_BinderInternal和int_register_android_os_BinderProxy的流程和int_register_android_os_Binder大致差不多。

binder驱动

整体流程如下:

1、binder_init
位置:kernel/common/drivers/android/binder.c
//函数指针
device_initcall(binder_init);
//binder的设备参数集合
char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;

static int __init binder_init(void)
{
    int ret;
    char *device_name, *device_tmp;
    struct binder_device *device;
    struct hlist_node *tmp;
    char *device_names = NULL;

    ret = binder_alloc_shrinker_init();
    if (ret)
        return ret;
    ...
    // 创建一个名为"binder"的目录
    binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
    if (binder_debugfs_dir_entry_root)
        //在binder目录下创建一个proc目录
        binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                         binder_debugfs_dir_entry_root);

    // 在binder目录下创建各种文件
    if (binder_debugfs_dir_entry_root) {
        ...
    }
    
    if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&
        // binder_devices_param不为空
        strcmp(binder_devices_param, "") != 0) {
        /*
        * Copy the module_parameter string, because we don't want to
        * tokenize it in-place.
         */
        // binder_devices_param分配GFP_KERNEL大小内存
        device_names = kstrdup(binder_devices_param, GFP_KERNEL);
        if (!device_names) {
            ret = -ENOMEM;
            goto err_alloc_device_names_failed;
        }

        device_tmp = device_names;
        //用strsep方法循环处理CONFIG_ANDROID_BINDER_DEVICES参数,
        while ((device_name = strsep(&device_tmp, ","))) {
            ret = init_binder_device(device_name);
            if (ret)
                goto err_init_binder_device_failed;
        }
    }
    ...
}

CONFIG_ANDROID_BINDER_DEVICES在哪呢。位置:kernel/common/drivers/android/Kconfig

config ANDROID_BINDER_DEVICES
    string "Android Binder devices"
    depends on ANDROID_BINDER_IPC
    default "binder,hwbinder,vndbinder"
    help
      Default value for the binder.devices parameter.

      The binder.devices parameter is a comma-separated list of strings
      that specifies the names of the binder device nodes that will be
      created. Each binder device has its own context manager, and is
      therefore logically separated from the other devices.

init_binder_device()

位置:kernel/common/drivers/android/binder.c

struct miscdevice  {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const struct attribute_group **groups;
    const char *nodename;
    umode_t mode;
};

/**
 * struct binder_device - information about a binder device node
 * @hlist:          list of binder devices (only used for devices requested via
 *                  CONFIG_ANDROID_BINDER_DEVICES)
 * @miscdev:        information about a binder character device node
 * @context:        binder context information
 * @binderfs_inode: This is the inode of the root dentry of the super block
 *                  belonging to a binderfs mount.
 */
struct binder_device {
    struct hlist_node hlist;
    struct miscdevice miscdev;
    struct binder_context context;
    struct inode *binderfs_inode;
    refcount_t ref;
};

static int __init init_binder_device(const char *name)
{
    int ret;
    //binder设备的结构体,保存相关的设备信息
    struct binder_device *binder_device;
    //为binder设备分配内存
    binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
    if (!binder_device)
        return -ENOMEM;
    //初始化设备 相关信息
    binder_device->miscdev.fops = &binder_fops;
    binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
    binder_device->miscdev.name = name;

    refcount_set(&binder_device->ref, 1);
    binder_device->context.binder_context_mgr_uid = INVALID_UID;
    binder_device->context.name = name;
    mutex_init(&binder_device->context.context_mgr_node_lock);
    //mics注册
    ret = misc_register(&binder_device->miscdev);
    if (ret < 0) {
        kfree(binder_device);
        return ret;
    }
    // 将当前的设备信息结构体binder_devices,放在hlist链表的表头
    hlist_add_head(&binder_device->hlist, &binder_devices);

    return ret;
}
2.binder_open
位置:kernel/common/drivers/android/binder.c

//binder_proc结构体,描述binder进程及其他的一些相关信息
struct binder_proc {
    struct hlist_node proc_node;//进程节点
    struct rb_root threads;//binder_thread红黑树的根节点
    struct rb_root nodes;//binder_node红黑树的根节点
    struct rb_root refs_by_desc; // binder_ref红黑树的根节点(以handle为key)
    struct rb_root refs_by_node; // binder_ref红黑树的根节点(以ptr为key)
    struct list_head waiting_threads;
    int pid; //相应进程id
    struct task_struct *tsk;
    const struct cred *cred;
    struct hlist_node deferred_work_node;
    int deferred_work;
    int outstanding_txns;
    bool is_dead;
    bool is_frozen;
    bool sync_recv;
    bool async_recv;
    wait_queue_head_t freeze_wait;

    struct list_head todo;
    struct binder_stats stats;
    struct list_head delivered_death;
    int max_threads;
    int requested_threads;
    int requested_threads_started;
    int tmp_ref;
    struct binder_priority default_priority;
    struct dentry *debugfs_entry;
    struct binder_alloc alloc;
    struct binder_context *context;
    spinlock_t inner_lock;
    spinlock_t outer_lock;
    struct dentry *binderfs_entry;
    bool oneway_spam_detection_enabled;
};

static int binder_open(struct inode *nodp, struct file *filp)
{
    struct binder_proc *proc, *itr;
    struct binder_device *binder_dev;
    struct binderfs_info *info;
    struct dentry *binder_binderfs_dir_entry_proc = NULL;
    bool existing_pid = false;
    //为binder_proc分配内存空间
    proc = kzalloc(sizeof(*proc), GFP_KERNEL);
    if (proc == NULL)
        return -ENOMEM;
    spin_lock_init(&proc->inner_lock);
    spin_lock_init(&proc->outer_lock);
    //获取当前进程的task_struct
    get_task_struct(current->group_leader);
    //将当前进程的task_struct保存到binder_proc的task_struct
    proc->tsk = current->group_leader;
    proc->cred = get_cred(filp->f_cred);
    //初始化binder_proc的todo工作列表
    INIT_LIST_HEAD(&proc->todo);
    //初始化binder_proc的等待处理所有未完成事务的进程的等待队列
    init_waitqueue_head(&proc->freeze_wait);
    ...
    refcount_inc(&binder_dev->ref);
    proc->context = &binder_dev->context;
    //初始化proc->alloc
    binder_alloc_init(&proc->alloc);

    binder_stats_created(BINDER_STAT_PROC);
    //proc->pid进程pid
    proc->pid = current->group_leader->pid;
    //初始化进程的已分发的死亡通知列表
    INIT_LIST_HEAD(&proc->delivered_death);
    //初始化进程的等待进程列表
    INIT_LIST_HEAD(&proc->waiting_threads);
    //将binder_proc与filp关联起来,这样下次通过filp(文件)就能找到binder_proc了,
    filp->private_data = proc;
    ...

}
3.binder_mmap
位置:kernel/common/drivers/android/binder.c

/*
 * This struct describes a virtual memory area. There is one of these
 * per VM-area/task. A VM area is any part of the process virtual memory
 * space that has a special rule for the page-fault handlers (ie a shared
 * library, the executable area etc).
 */
// 虚拟内存区域结构体
struct vm_area_struct {
    /* The first cache line has the info for VMA tree walking. */

    unsigned long vm_start;        /* Our start address within vm_mm. */
    unsigned long vm_end;        /* The first byte after our end address
                       within vm_mm. */

    /* linked list of VM areas per task, sorted by address */
    struct vm_area_struct *vm_next, *vm_prev;

    struct rb_node vm_rb;

    /*
     * Largest free memory gap in bytes to the left of this VMA.
     * Either between this VMA and vma->vm_prev, or between one of the
     * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
     * get_unmapped_area find a free area of the right size.
     */
    unsigned long rb_subtree_gap;

    /* Second cache line starts here. */

    struct mm_struct *vm_mm;    /* The address space we belong to. */

    /*
     * Access permissions of this VMA.
     * See vmf_insert_mixed_prot() for discussion.
     */
    pgprot_t vm_page_prot;
    unsigned long vm_flags;        /* Flags, see mm.h. */

    /*
     * For areas with an address space and backing store,
     * linkage into the address_space->i_mmap interval tree.
     *
     * For private anonymous mappings, a pointer to a null terminated string
     * in the user process containing the name given to the vma, or NULL
     * if unnamed.
     */
    union {
        struct {
            struct rb_node rb;
            unsigned long rb_subtree_last;
        } shared;
        const char __user *anon_name;
    };

    /*
     * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
     * list, after a COW of one of the file pages.    A MAP_SHARED vma
     * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
     * or brk vma (with NULL file) can only be in an anon_vma list.
     */
    struct list_head anon_vma_chain; /* Serialized by mmap_lock &
                      * page_table_lock */
    struct anon_vma *anon_vma;    /* Serialized by page_table_lock */

    /* Function pointers to deal with this struct. */
    const struct vm_operations_struct *vm_ops;

    /* Information about our backing store: */
    unsigned long vm_pgoff;        /* Offset (within vm_file) in PAGE_SIZE
                       units */
    struct file * vm_file;        /* File we map to (can be NULL). */
    void * vm_private_data;        /* was vm_pte (shared mem) */

#ifdef CONFIG_SWAP
    atomic_long_t swap_readahead_info;
#endif
#ifndef CONFIG_MMU
    struct vm_region *vm_region;    /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
    struct mempolicy *vm_policy;    /* NUMA policy for the VMA */
#endif
    struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{    //根据filp找到binder_proc
    struct binder_proc *proc = filp->private_data;

    if (proc->tsk != current->group_leader)
        return -EINVAL;

    binder_debug(BINDER_DEBUG_OPEN_CLOSE,
             "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
             __func__, proc->pid, vma->vm_start, vma->vm_end,
             (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
             (unsigned long)pgprot_val(vma->vm_page_prot));

    if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
        pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
               proc->pid, vma->vm_start, vma->vm_end, "bad vm_flags", -EPERM);
        return -EPERM;
    }
    //下面的操作就是把binder_proc保存到vm_area_struct
    vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
    vma->vm_flags &= ~VM_MAYWRITE;

    vma->vm_ops = &binder_vm_ops;
    vma->vm_private_data = proc;
    // mmap给binder_proc分配内存
    return binder_alloc_mmap_handler(&proc->alloc, vma);
}
位置:kernel/common/drivers/android/binder.c

/**
 * struct binder_buffer - buffer used for binder transactions
 * @entry:              entry alloc->buffers
 * @rb_node:            node for allocated_buffers/free_buffers rb trees
 * @free:               %true if buffer is free
 * @clear_on_free:      %true if buffer must be zeroed after use
 * @allow_user_free:    %true if user is allowed to free buffer
 * @async_transaction:  %true if buffer is in use for an async txn
 * @oneway_spam_suspect: %true if total async allocate size just exceed
 * spamming detect threshold
 * @debug_id:           unique ID for debugging
 * @transaction:        pointer to associated struct binder_transaction
 * @target_node:        struct binder_node associated with this buffer
 * @data_size:          size of @transaction data
 * @offsets_size:       size of array of offsets
 * @extra_buffers_size: size of space for other objects (like sg lists)
 * @user_data:          user pointer to base of buffer space
 * @pid:                pid to attribute the buffer to (caller)
 *
 * Bookkeeping structure for binder transaction buffers
 */
// binder数据处理的缓冲区buffer
struct binder_buffer {
    struct list_head entry; /* free and allocated entries by address */
    struct rb_node rb_node; /* free entry by size or allocated entry */
                /* by address */
    unsigned free:1; //标记是否是空闲buffer,占位1bit
    unsigned clear_on_free:1;
    unsigned allow_user_free:1;// 是否允许用户释放
    unsigned async_transaction:1;
    unsigned oneway_spam_suspect:1;
    unsigned debug_id:27; //debugid占位27bit

    struct binder_transaction *transaction; //该缓存区的需要处理的事务

    struct binder_node *target_node; //改缓存区所处理的binder实体
    size_t data_size; // 数据大小
    size_t offsets_size; // 数据偏移量
    size_t extra_buffers_size;
    void __user *user_data;
    int    pid;
};

/**
 * struct binder_alloc - per-binder proc state for binder allocator
 * @vma:                vm_area_struct passed to mmap_handler
 *                      (invarient after mmap)
 * @tsk:                tid for task that called init for this proc
 *                      (invariant after init)
 * @vma_vm_mm:          copy of vma->vm_mm (invarient after mmap)
 * @buffer:             base of per-proc address space mapped via mmap
 * @buffers:            list of all buffers for this proc
 * @free_buffers:       rb tree of buffers available for allocation
 *                      sorted by size
 * @allocated_buffers:  rb tree of allocated buffers sorted by address
 * @free_async_space:   VA space available for async buffers. This is
 *                      initialized at mmap time to 1/2 the full VA space
 * @pages:              array of binder_lru_page
 * @buffer_size:        size of address space specified via mmap
 * @pid:                pid for associated binder_proc (invariant after init)
 * @pages_high:         high watermark of offset in @pages
 * @oneway_spam_detected: %true if oneway spam detection fired, clear that
 * flag once the async buffer has returned to a healthy state
 *
 * Bookkeeping structure for per-proc address space management for binder
 * buffers. It is normally initialized during binder_init() and binder_mmap()
 * calls. The address space is used for both user-visible buffers and for
 * struct binder_buffer objects used to track the user buffers
 */
//binder虚拟空间的结构体
struct binder_alloc {
    struct mutex mutex;//锁
    struct vm_area_struct *vma;//虚拟空间结构体
    struct mm_struct *vma_vm_mm;
    void __user *buffer;//通过mmap映射的每个进程地址空间
    struct list_head buffers;
    struct rb_root free_buffers;
    struct rb_root allocated_buffers;
    size_t free_async_space;
    struct binder_lru_page *pages;
    size_t buffer_size;
    uint32_t buffer_free;
    int pid;
    size_t pages_high;
    bool oneway_spam_detected;
};

/**
 * binder_alloc_mmap_handler() - map virtual address space for proc
 * @alloc:    alloc structure for this proc
 * @vma:    vma passed to mmap()
 *
 * Called by binder_mmap() to initialize the space specified in
 * vma for allocating binder buffers
 *
 * Return:
 *      0 = success
 *      -EBUSY = address space already mapped
 *      -ENOMEM = failed to map memory to given address space
 */
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
                  struct vm_area_struct *vma)
{
    int ret;
    const char *failure_string;
    struct binder_buffer *buffer;

    mutex_lock(&binder_alloc_mmap_lock);
    if (alloc->buffer_size) {
        ret = -EBUSY;
        failure_string = "already mapped";
        goto err_already_mapped;
    }
    //分配4M内存
    alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start,
                   SZ_4M);
    mutex_unlock(&binder_alloc_mmap_lock);
    //和虚拟地址进行映射
    alloc->buffer = (void __user *)vma->vm_start;
    //分配物理页的指针数组
    alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE,
                   sizeof(alloc->pages[0]),
                   GFP_KERNEL);
    if (alloc->pages == NULL) {
        ret = -ENOMEM;
        failure_string = "alloc page array";
        goto err_alloc_pages_failed;
    }
    //给buffer分配内存
    buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    if (!buffer) {
        ret = -ENOMEM;
        failure_string = "alloc buffer struct";
        goto err_alloc_buf_struct_failed;
    }

    buffer->user_data = alloc->buffer;
    // 
    list_add(&buffer->entry, &alloc->buffers);
    // 1 表示内存可用
    buffer->free = 1;
    //将buffer插入到binder_alloc->free_buffers链表中
    binder_insert_free_buffer(alloc, buffer);
    //异步操作的内存为4/2M
    alloc->free_async_space = alloc->buffer_size / 2;
    //将binder_alloc和vm_area_struct绑定
    binder_alloc_set_vma(alloc, vma);
    mmgrab(alloc->vma_vm_mm);

    return 0;

err_alloc_buf_struct_failed:
    kfree(alloc->pages);
    alloc->pages = NULL;
err_alloc_pages_failed:
    alloc->buffer = NULL;
    mutex_lock(&binder_alloc_mmap_lock);
    alloc->buffer_size = 0;
err_already_mapped:
    mutex_unlock(&binder_alloc_mmap_lock);
    binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
               "%s: %d %lx-%lx %s failed %d\n", __func__,
               alloc->pid, vma->vm_start, vma->vm_end,
               failure_string, ret);
    return ret;
}
4.binder_ioctl
位置:kernel/common/drivers/android/binder.c

//binder的读写操作方法
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;

    /*pr_info("binder_ioctl: %d:%d %x %lx\n",
            proc->pid, current->pid, cmd, arg);*/

    binder_selftest_alloc(&proc->alloc);

    trace_binder_ioctl(cmd, arg);
    // 休眠状态,直到中断唤醒
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret)
        goto err_unlocked;
    /*
     *根据当前的currend进程的pid,从binder_pro中查找binder_thread,
     *如果当前线程已经加入到binder_pro的线程队列中,则直接return,
     *如果不存在则创建binder_thread,然后添加到binder_pro中
     */
    thread = binder_get_thread(proc);
    if (thread == NULL) {
        ret = -ENOMEM;
        goto err;
    }
    switch (cmd) {
    //读写命令
    case BINDER_WRITE_READ:
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);
        if (ret)
            goto err;
        break;
    // 设置binder最大线程数
    case BINDER_SET_MAX_THREADS: {
        int max_threads;

        if (copy_from_user(&max_threads, ubuf,
                   sizeof(max_threads))) {
            ret = -EINVAL;
            goto err;
        }
        binder_inner_proc_lock(proc);
        proc->max_threads = max_threads;
        binder_inner_proc_unlock(proc);
        break;
    }
    // binder->servicemanager
    case BINDER_SET_CONTEXT_MGR_EXT: {
        struct flat_binder_object fbo;

        if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {
            ret = -EINVAL;
            goto err;
        }
        ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
        if (ret)
            goto err;
        break;
    }
    case BINDER_SET_CONTEXT_MGR:
        ret = binder_ioctl_set_ctx_mgr(filp, NULL);
        if (ret)
            goto err;
        break;
    ...
}
位置:kernel/common/drivers/android/binder.c

//binder读写结构体
struct binder_write_read {
  binder_size_t write_size;//大小
  binder_size_t write_consumed;//
  binder_uintptr_t write_buffer;//缓冲
  binder_size_t read_size;
  binder_size_t read_consumed;
  binder_uintptr_t read_buffer;
};

static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{
    int ret = 0;
    struct binder_proc *proc = filp->private_data;
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;

    if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
    }
    // 把用户空间的数据ubuf拷贝到bwr
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d write %lld at %016llx, read %lld at %016llx\n",
             proc->pid, thread->pid,
             (u64)bwr.write_size, (u64)bwr.write_buffer,
             (u64)bwr.read_size, (u64)bwr.read_buffer);
    //当写缓冲中有数据,执行binder的写操作
    if (bwr.write_size > 0) {
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
        trace_binder_write_done(ret);
        if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    //当读缓冲中有数据,执行binder的读操作
    if (bwr.read_size > 0) {
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                     bwr.read_size,
                     &bwr.read_consumed,
                     filp->f_flags & O_NONBLOCK);
        trace_binder_read_done(ret);
        binder_inner_proc_lock(proc);
        //当todo队列不为空,唤醒该队列中的线程,默认是同步线程
        if (!binder_worklist_empty_ilocked(&proc->todo))
            binder_wakeup_proc_ilocked(proc);
        binder_inner_proc_unlock(proc);
        if (ret < 0) {
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
             proc->pid, thread->pid,
             (u64)bwr.write_consumed, (u64)bwr.write_size,
             (u64)bwr.read_consumed, (u64)bwr.read_size);
    //把内核空间的数据bwr拷贝到ubuf
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

因果推断12--dragonnet论文和代码学习

目录 论文 dragonnet 1介绍 2 Dragonnet 3定向正则化 4相关工作 5实验 6讨论 NN-Based的模型 dragonnet 如何更新参数 dragonnet的损失函数 CausalML Dragonnet类 论文代码 论文 dragonnet Adapting Neural Networks for the Estimation of Treatment Effects 应…

二叉搜索树的实现

什么是二叉搜索树1.若它的左子树不为空&#xff0c;那么左子树上所有节点都小于根节点2.若它的右子树不为空&#xff0c;那么右子树上所有节点都小于根节点3.它的左右子树也分别是二叉搜索树4.使用中序遍历结果是从小到大定义节点&#xff0c;使用静态内部类static class TreeN…

http组成及状态及参数传递

http组成及状态及参数传递 早期的网页都是通过后端渲染来完成的&#xff1a;服务器端渲染&#xff08;SSR&#xff0c;server side render&#xff09;&#xff1a; 客户端发出请求 -> 服务端接收请求并返回相应HTML文档 -> 页面刷新&#xff0c;客户端加载新的HTML文档&…

7综合项目 旅游网 【7.精选分类】

精选旅游人气旅游→收藏次数最高最新旅游→日期最新主题旅游→主题关键字相同在首页将精选的内容动态展示的实现分析首页中的精选包含“人气旅游”、“最新旅游”、“主题旅游”三个部分index.html//页面加载完成,发送ajax请求根据点击不同分类展示不同内容人气旅游→收藏次数最…

分享17个提升开发效率的工具“轮子”

本文是向大家介绍平时在开发中经常用到的小工具&#xff0c;它能够极大得提升我们的开发效率&#xff0c;能够解决平时开发中遇到的问题。前言在java的庞大体系中&#xff0c;其实有很多不错的小工具&#xff0c;也就是我们平常说的“轮子“。如果在我们的日常工作当中&#xf…

数据结构课程设计:高铁信息管理系统(C++实现)

目录 简介实验输出实验要求代码运行环境结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖…

嵌入式Linux驱动开发(一)chrdevbase虚拟字符设备

Linux下三大驱动&#xff1a;字符设备&#xff0c;块设备&#xff0c;网络设备。一个硬件可以从属于不同的设备分类。 0. Linux应用程序对驱动程序的调用流程 驱动加载成功后会在/dev目录下生成一个文件&#xff0c;对该文件的操作就是对设备的操作。当我们在用户态调用一个函…

Element-UI实现复杂table表格结构

Element-UI组件el-table用于展示多条结构类似的数据&#xff0c;可对数据进行排序、筛选、对比或其他自定义操作。将使用到以下两项&#xff0c;来完成今天demo演示&#xff1a;多级表头&#xff1a;数据结构比较复杂的时候&#xff0c;可使用多级表头来展现数据的层次关系。合…

Web3中文|Web3CN加速器第二期「Web3项目征集」火热报名

Web3CN加速器第二期「Web3项目征集」火热征集中&#xff0c;本次征集活动是由Web3CN加速器联合专业web3媒体Web3CN、VC机构Tiger VC DAO核心发起&#xff0c;数百家加密VC机构、加密社区等联合发起的&#xff0c;为早期Web3创新创业项目提供加速服务。如果你正在进行web3相关的…

VC常见问题(.obj : error LNK2019、fatal error C1083、编译64位Detours)

VC常用问题VC常见问题*.obj : error LNK2019: 无法解析的外部符号 __imp_FindWindow ,该符号在函数 YAWindows环境下用nmake编译常见问题fatal error C1083: 无法打开包括文件:“excpt.h”vs2012编译64位Detours&#xff08;其他vs版本同理&#xff09;vs项目设置选项编译使用了…

Java基础面试题(三)

Java基础面试题 一、JavaWeb专题 1.HTTP响应码有哪些 1、1xx&#xff08;临时响应&#xff09; 2、2xx&#xff08;成功&#xff09; 3、3xx&#xff08;重定向&#xff09;&#xff1a;表示要完成请求需要进一步操作 4、4xx&#xff08;错误&#xff09;&#xff1a;表示请…

Nuxt实战教程基础-Day01

Nuxt实战教程基础-Day01Nuxt是什么&#xff1f;Nuxt.js框架是如何运作的&#xff1f;Nuxt特性流程图服务端渲染(通过 SSR)单页应用程序 (SPA)静态化 (预渲染)Nuxt优缺点优点缺点安装运行项目总结前言&#xff1a;本教程基于Nuxt2&#xff0c;作为教程的第一天&#xff0c;我们先…

BUUCTF-[RoarCTF2019]polyre

题目下载&#xff1a;下载 这道题目是一个关于控制流平坦化和虚假流程。 首先了解一下控制流平坦化&#xff1a;利用符号执行去除控制流平坦化 - 博客 - 腾讯安全应急响应中心https://www.cnblogs.com/zhwer/p/14081454.htmlbuuctf RoarCTF2019 polyre writeup - 『脱壳破解区…

单点登录的几种实现方式探讨

单点登录&#xff08;Single Sign On&#xff09;&#xff0c;简称为 SSO&#xff0c;是解决企业内部的一系列产品登录问题的方案。SSO 的定义是在多个应用系统中&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统&#xff0c;用于减少用户重复的登录操作&#…

PyTorch的自动微分(autograd)

PyTorch的自动微分(autograd) 计算图 计算图是用来描述运算的有向无环图 计算图有两个主要元素&#xff1a;结点&#xff08;Node&#xff09;和边&#xff08;Edge&#xff09; 结点表示数据&#xff0c;如向量、矩阵、张量 边表示运算&#xff0c;如加减乘除卷积等 用计算…

共话开源 | 开放原子开源基金会专题调研openKylin社区!

3月8日&#xff0c;开放原子开源基金会秘书长冯冠霖、运营部部长李博、业务发展部部长朱其罡、研发部副部长周济一行莅临openKylin社区调研交流&#xff0c;麒麟软件高级副总经理韩乃平、副总裁董军平、终端研发部副总经理陆展、产品规划部经理常亚武、市场与政府事务部高级经理…

力扣sql简单篇练习(二十五)

力扣sql简单篇练习(二十五) 1 无效的推文 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT tweet_id FROM Tweets WHERE CHAR_LENGTH(content)>151.3 运行截图 2 求关注者的数量 2.1 基本题目内…

【Linux实战篇】二、在Linux上部署各类软件

一、实战章节&#xff1a;在Linux上部署各类软件 二、MySQL数据库管理系统安装部署【简单】 简介 MySQL数据库管理系统&#xff08;后续简称MySQL&#xff09;&#xff0c;是一款知名的数据库系统&#xff0c;其特点是&#xff1a;轻量、简单、功能丰富。 MySQL数据库可谓是…

在矩池云运行 Stable Diffusion web UI,使用v1.5模型和 ControlNet 插件

今天给大家介绍下如何在矩池云使用 Stable Diffusion web UI v1.5 模型和 Stable Diffusion ControlNet 插件。 租用机器 租用机器需要选择内存大于8G的机器&#xff0c;比如 A2000&#xff0c;不然 Stable Diffusion web UI 启动加载模型会失败。&#xff08;Killed 内存不足…

近20个省市加快房屋网签备案,君子签电子签章助推掌上办理

2020年以来&#xff0c;上海、北京、深圳、长沙、武汉、杭州、山东、郑州、西安、佛山、青岛、江门、昆明、韶关、南京、石家庄等全国近20个省市纷纷响应住建部政策要求&#xff0c;鼓励使用电子签名、电子签章等技术加快推动商品房、二手房或租赁房交易合同网签备案&#xff0…