Binder驅動的使用

afxstarx發表於2018-08-10

Binder驅動建立:

static const struct file_operations binder_fops = {
	.owner = THIS_MODULE,
	.poll = binder_poll,
	.unlocked_ioctl = binder_ioctl,
	.compat_ioctl = binder_ioctl,
	.mmap = binder_mmap,
	.open = binder_open,
	.flush = binder_flush,
	.release = binder_release,
};

static struct miscdevice binder_miscdev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "binder",
	.fops = &binder_fops
};
複製程式碼

Binder驅動初始化:

  • static int __init binder_init(void)
  • 註冊binder裝置驅動ret = misc_register(&binder_miscdev);
  • 註冊裝置驅動的操作binder_open、binder_mmap、binder_ioctl、binder_release

Binder主要結構體:

struct binder_work {
    struct list_head entry;
    enum {
        BINDER_WORK_TRANSACTION = 1,
        BINDER_WORK_TRANSACTION_COMPLETE,
        BINDER_WORK_NODE
        BINDER_WORK_DEAD_BINDER,
        BINDER_WORK_DEAD_BINDER_AND_CLEAR,
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
    } type;
} 

struct binder_node {
    int debug_id;
    struct binder_work work;
    struct rb_node rb_node;
    struct hlist_node dead_node;

    struct binder_proc *proc;
    struct hlist_head refs;
    int internal_strong_refs;
    int local_weak_refs;
    int local_strong_refs;

    binder_unitptr_t ptr;
    binder_unitptr_t cookie;

    unsigned has_strong_ref:1;
    unsigned pending_strong_ref:1;
    unsigned has_weak_ref:1;
    unsigned pending_weak_ref:1;
    unsigned has_async_transaction:1;
    unsigned accept_fds:1;
    unsigned min_priority:8;

    struct list_head async_todo;
} 

struct binder_ref_death {
    struct binder_work work;
    binder_unitptr_t cookie;
}

struct binder_ref {
    int debug_id;
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node node_entry;
    struct binder_proc *proc;
    struct binder_node *node;
    unit32_t desc;
    int strong;
    int weak;
    struct binder_ref_death *death;
}

struct binder_buffer {
    struct list_head entry;
    struct rb_node rb_node;

    unsigned free:1;
    unsigned allow_user_free:1;
    unsigned async_transaction:1;
    unsigned debug_id:29;

    struct binder_transaction *transaction;
    struct binder_node *target_node;
    
    size_t data_size;
    size_t offsets_size;
    unit8_t data[0];
}

struct binder_proc {
    struct hlist_node proc_node;
    struct rb_root threads;
    struct rb_root nodes;
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;

    int pid;
    struct vm_area_struct *vma;
    struct mm_struct *vma_vm_mm;
    struct task_struct *files;
    struct hlist_node deferred_work_node;
    int deferred_work;
    void *buffer;
    ptrdiff_t user_buffer_offset;

    struct list_head buffers;
    struct rb_root free_buffers;
    struct rb_root allocated_buffers;
    size_t free_async_space;

    struct page **pages;
    size_t buffer_size;
    unit32_t buffer_free;
    struct list_head todo;
    wait_queue_head_t wait;
    struct binder_stats stats;
    struct list_head delivered_death;
    int max_threads;
    int requested_threads;
    int requested_hreads_started;
    int ready_threads;
    long default_priority;
    struct dentry *debugfs_entry;
}

struct binder_proc {
    int debug_id;
    struct binder_work work;
    struct binder_thread *from;
    struct binder_transction *from_parent;
    struct binder_proc *to_proc;
    struct binder_thread *to_thread;
    struct binder_transation *to_parent;
    unsigned need_reply:1;
    
    struct binder_buffer *buffer;
    unsigned int code;
    unsighed int flags;
    long priority;
    long saved_priority;
    kuid_t sender_euid;
}
複製程式碼

先看看C++層怎麼用:

androidxref.com/6.0.0_r1/xr…

1.原始碼路徑:

C++: /android/frameworks/native/cmds/servicemanager/

Java: /android/frameworks/base/core/java/android/os/

2.servicemanager的啟動:

Android在init程式啟動以後,通過指令碼init.rc,啟動ServiceManager:

    service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart keystore
複製程式碼

3.主要入口:

int main(int argc, char **argv)
{
    struct binder_state *bs;
    bs = binder_open(128*1024);
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    selinux_enabled = is_selinux_enabled();
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {
            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
            abort();
        }

        if (getcon(&service_manager_context) != 0) {
            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
            abort();
        }
    }

    union selinux_callback cb;
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    cb.func_log = selinux_log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    binder_loop(bs, svcmgr_handler);

    return 0;
}
複製程式碼

4.binder操作函式

binder_open
複製程式碼
  1. 開啟裝置驅動/dev/binder,檔案描述符儲存到bs->fd當中
  2. 對映128k記憶體到bs->mmaped
binder_loop
複製程式碼
  1. 發起 BINDER_WRITE_READ操作 命令BC_ENTER_LOOPER
  2. 發起 BINDER_WRITE_READ操作 一直等待有資料返回
  3. 開始解析返回的bind_transaction_data
binder_write
複製程式碼
  1. 發起操作 BINDER_WRITE_READ操作 (bs->fd, data, len)
binder_parse
複製程式碼
  1. 解析出命令:BR_TRANSACTION、BR_REPLY等
  2. 解析出資料:binder_transaction_data

5.業務函式:

find_svc()   
複製程式碼

查詢svcinfo

svcinfo_death()  
複製程式碼

binder驅動通過handle找到bind_ref釋放

do_find_service()  
複製程式碼

查詢svcinfo並返回binder控制程式碼

do_add_service()   
複製程式碼

呼叫binder_acquire向binder驅動中新增一個node、鑑定death通知

svcmgr_handler()  
複製程式碼

接收客戶端發來的訊息

  1. 獲取服務 得到根據名字得到控制程式碼handle,並寫入flat_binder_object到reply中,最後回傳reply
  2. 新增服務 將handle加入到svclist中,binder_acquire註冊handle到驅動中,監聽death通知
  3. 列出所有服務 將所有服務命令寫入到reply中

總結一下:

  • server_manager在init程式解析init.rc時被啟動,在入口函式main中首先開啟/dev/binder驅動,將自己設為CONTEXT_MGR在核心中成為0號控制程式碼的Binder、進入Binder訊息迴圈讀取訊息(返回服務、新增服務、列出所有服務),所有的訊息都記錄在了svcinfo list結構體中,服務在新增時會傳送命令註冊到/dev/binder驅動中。
  • binder驅動的使用方法即:開啟裝置驅動/dev/binder,ioctl監控驅動訊息,處理驅動訊息(也可以回發訊息)。

相關文章