android servicemanager與binder源碼分析二(暫時做廢,後面會從新整理)

抱歉,此文暫時做廢,不會使用segmentfault的刪除功能。我會在後面從新整理後再繼續寫下去。node

繼續上篇的文,這篇打算進入到android的內核世界,真正接觸到binder。
binder是android內部的一個機制,經過設備驅動的協助可以起到進程間通信的(ipc)的做用。那麼binder的設備驅動的源碼在/drivers/staging/android/binder.c這個路徑下。
先看下定義:linux

3632static const struct file_operations binder_fops = {
3633    .owner = THIS_MODULE,
3634    .poll = binder_poll,
3635    .unlocked_ioctl = binder_ioctl,
3636    .compat_ioctl = binder_ioctl,
3637    .mmap = binder_mmap,
3638    .open = binder_open,
3639    .flush = binder_flush,
3640    .release = binder_release,
3641};

這裏說明了設備的各項操做對應的函數。
設備驅動是在系統剛開始的時候就初始化好的,初始化的過程看binder_init,不是重點,所以不在這裏累述。這個初始化的過程若是進入的以及怎麼發展的,有機會再其餘文中敘述吧。
上文的servicemanager的main函數中首先就是open設備,所以先從open開始:android

2941static int binder_open(struct inode *nodp, struct file *filp)
2942{
2943    struct binder_proc *proc;
2944
2945    binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
2946             current->group_leader->pid, current->pid);
2947
2948    proc = kzalloc(sizeof(*proc), GFP_KERNEL);
2949    if (proc == NULL)
2950        return -ENOMEM;
2951    get_task_struct(current);
2952    proc->tsk = current;
2953    INIT_LIST_HEAD(&proc->todo);
2954    init_waitqueue_head(&proc->wait);
2955    proc->default_priority = task_nice(current);
2956
2957    binder_lock(__func__);
2958
2959    binder_stats_created(BINDER_STAT_PROC);
2960    hlist_add_head(&proc->proc_node, &binder_procs);
2961    proc->pid = current->group_leader->pid;
2962    INIT_LIST_HEAD(&proc->delivered_death);
2963    filp->private_data = proc;
2964
2965    binder_unlock(__func__);
2966
2967    if (binder_debugfs_dir_entry_proc) {
2968        char strbuf[11];
2969
2970        snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
2971        proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
2972            binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
2973    }
2974
2975    return 0;
2976}

1.建立binder_proc結構;
2.各類維護性的鏈表及結構的添加;
3.存儲proc到私有數據內;segmentfault

先說下,內核開空間都是使用kzalloc與應用層的malloc相似。
這裏用到一個current結構,是linux的一個指針,指向當前正在運行的進程結構task_struct,這裏仍是先不深究,大致意思瞭解不影響後續便可。後面就是INIT_LIST_HEAD(&proc->todo);初始化鏈表頭,這個鏈表是怎麼回事兒呢?先看下proc的結構吧:網絡

292struct binder_proc {
293    struct hlist_node proc_node;
294    struct rb_root threads;
295    struct rb_root nodes;
296    struct rb_root refs_by_desc;
297    struct rb_root refs_by_node;
298    int pid;
299    struct vm_area_struct *vma;
300    struct mm_struct *vma_vm_mm;
301    struct task_struct *tsk;
302    struct files_struct *files;
303    struct hlist_node deferred_work_node;
304    int deferred_work;
305    void *buffer;
306    ptrdiff_t user_buffer_offset;
307
308    struct list_head buffers;
309    struct rb_root free_buffers;
310    struct rb_root allocated_buffers;
311    size_t free_async_space;
312
313    struct page **pages;
314    size_t buffer_size;
315    uint32_t buffer_free;
316    struct list_head todo;
317    wait_queue_head_t wait;
318    struct binder_stats stats;
319    struct list_head delivered_death;
320    int max_threads;
321    int requested_threads;
322    int requested_threads_started;
323    int ready_threads;
324    long default_priority;
325    struct dentry *debugfs_entry;
326};

這個結構的寫法很c很linux,能夠看到可能會有不少個proc結構被貫穿成爲一個鏈表統一管理,那麼結合以前的內容猜想,binder_proc結構能夠支持多個每一個對應一個進程,而後經過鏈表來維護,那麼進一步思考,自己binder就是爲了支持跨進程通信的,那麼這些通信之間的binder銜接就是在這個鏈表結構中維護。
下面,init_waitqueue_head(&proc->wait);初始化linux的等待隊列。又是個宏,內容以下:async

71#define init_waitqueue_head(q)                \
72    do {                        \
73        static struct lock_class_key __key;    \
74                            \
75        __init_waitqueue_head((q), #q, &__key);    \
76    } while (0)
77
78#ifdef CONFIG_LOCKDEP
79# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \
80    ({ init_waitqueue_head(&name); name; })
81# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) \
82    wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name)
83#else
84# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name)
85#endif
86

帶入的參數是proc結構中的一個成員wait,感受這裏也是個隊列(鏈表),用來維護等待處理的binder_proc結構。那麼大膽猜想下,系統利用這個來創建等待通信處理的binder進程隊列,可在這基礎上進行各類策略調配來管理binder通信的過程,不能放着驅動自個人承載力來決定(可能帶來穩定性隱患)。
再日後看,proc->default_priority = task_nice(current); 記錄當前進程的優先級。看吧,以前的策略這裏就會體現。
而後hlist_add_head(&proc->proc_node, &binder_procs);又一個,真linux真c,不得不說:看系統源碼就必須習慣各類鏈表的這種方式,其實很好,不用額外維護什麼東西,這種原始的方式其實有時候是最適合的,因此說,機制不是多複雜就牛逼的,而是看是否符合當前的體系當前的場景。這個應該是個全局hash表,統計全部binder_proc結構。函數

借用一張網絡上的圖說明下proc結構:
162056116463138.jpgui

最後保存這個proc倒private_data裏,這個私有數據中。而後完了。
再回顧一下吧,每次打開設備就建立一個binder_proc結構,並將當前進程的信息保存在這裏,而後將其掛接在系統的各個鏈表或紅黑樹或hash表中,爲了便於往後的策略和維護。以後再將這個proc結構保留到私有數據中。其實是保存在打開的設備文件的結構中。目前還未涉及到其餘操做,只是binder_open。spa

相關文章
相關標籤/搜索