說到binder,很多Android開發者會覺得很復雜,因為binder橫跨了整個Android系統架構,從framework到kernel,binder無處不在,在日常的面試程序中,binder也是一個繞不開的話題,為啥binder這么重要,跨行程通信方式已經有了管道、socket、共享記憶體等,為啥Android還要使用binder,今天,我們帶著這些問題深入了解下Binder機制,
引子
日常應用
我們平時開發中,可能一些代碼反復寫了N多次了,所以寫起來很流暢,但我們不會注意這些流程,例如:
ActivityA 啟動 ActivityB 的程序中,我們通過intent,傳遞資料,搞定,兩個activity可以相互通信了,想過沒有,為什么使用intent序列化之后才能傳遞資料?這里面就涉及到binder,因為AMS和app是兩個行程,
我們現在很多大型app都是多行程,而多行程相互之間要通信,就需要binder,一些小企業基本用不到多行程app,而大廠就會涉及到了,例如:微信,微博等 他們都是多行程開發的,多行程有什么好處呢?
首先,系統會給每個app行程分配一個jvm,而這個jvm的大小是系統給定的,當我們一個app的使用記憶體變大后,記憶體不夠用,就會出現崩潰,而我們使用多行程時,就會給app開辟更多的記憶體,
其次,多行程開發實作了行程隔離,當一個子行程crash掉后,不會影響主行程,
最后,多行程開發使得行程保活幾率提升,一個行程被殺后,其他行程會相互拉,
Binder的優勢
linux自帶了很多IPC跨行程通信方式(管道,信號量,socket,共享記憶體),Android為啥還要搞一個binder出來?自然時binder的性能要優于其他方式,
binder只需要拷貝一次,
在性能方面,共享記憶體 > Binder > socket
在安全方面,Binder 是最安全的,他會給每個app都分配單獨的UID,并支持實名和匿名,Socket用的PID,不靠譜,
Binder拷貝一次的流程
整個Linux系統分為用戶空間和內核空間 用戶空間的資源是獨立的 內核空間的資源是共享的,

可以看到,binder通過mmap技術,將內核空間的虛擬地址和server端的虛擬地址映射到同一塊物理記憶體上,而這塊物理記憶體的大小是由server端決定的,
mmap
Linux通過將一個虛擬記憶體區域與磁盤上的物件關聯起來,以初始化 這個虛擬記憶體區域的內容,這個程序稱為記憶體映射(memory mapping),
對檔案進行mmap,會在行程的虛擬記憶體分配地址空間,創建映射關系, 實作這樣的映射關系后,就可以采用指標的方式讀寫操作這一段記憶體,而系統會自動回寫到對應的檔案磁盤上
Binder框架
要想搞明白binder的底層實作,必須搞懂整個binder框架,

這張圖就是整個binder的框架結構,從framework到kernel,經歷了jni和native的跨越,
接下來我們從下往上依次分析binder的整個程序,
binder原始碼決議
Kernel層
我們先看下binder驅動的流程圖:

從上圖可以看到binder驅動最重要的四個方法:binder_init()、binder_open()、binder_mmap()、binder_ioctl(). 接下來我們依次分析這四個方法,看他們做了哪些事情,
1. binder_init()
static int __init binder_init(void)
{
int ret;
char *device_name, *device_names;
struct binder_device *device;
struct hlist_node *tmp;
// 首先創建名字為“binder”的單執行緒作業佇列,
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
...
/*
* Copy the module_parameter string, because we don't want to
* tokenize it in-place.
*/
device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
if (!device_names) {
ret = -ENOMEM;
goto err_alloc_device_names_failed;
}
strcpy(device_names, binder_devices_param);
while ((device_name = strsep(&device_names, ","))) {
ret = init_binder_device(device_name);
if (ret)
goto err_init_binder_device_failed;
}
return ret;
err_init_binder_device_failed:
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
misc_deregister(&device->miscdev);
hlist_del(&device->hlist);
kfree(device);
}
err_alloc_device_names_failed:
debugfs_remove_recursive(binder_debugfs_dir_entry_root);
destroy_workqueue(binder_deferred_workqueue);
return ret;
}
static int __init init_binder_device(const char *name)
{
int ret;
struct binder_device *binder_device;
//分配記憶體
binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
return -ENOMEM;
// 初始化binder設備
binder_device->miscdev.fops = &binder_fops;
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
binder_device->miscdev.name = name;
binder_device->context.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
kfree(binder_device);
return ret;
}
hlist_add_head(&binder_device->hlist, &binder_devices);
return ret;
}
-
為binder設備分配記憶體,
-
初始化設備
-
將binder設備加入binder_devices鏈表
2. binder_open()
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
struct binder_device *binder_dev;
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
current->group_leader->pid, current->pid);
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
proc->tsk = current;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
binder_dev = container_of(filp->private_data, struct binder_device,
miscdev);
proc->context = &binder_dev->context;
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);
hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
binder_unlock(__func__);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
/*
* proc debug entries are shared between contexts, so
* this will fail if the process tries to open the driver
* again with a different context. The priting code will
* anyway print all contexts that a given PID has, so this
* is not a problem.
*/
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc,
(void *)(unsigned long)proc->pid,
&binder_proc_fops);
}
return 0;
}
-
初始化binder_proc物件,binder_proc這個結構體就是用來保存binder行程的資訊,
-
將當前行程資訊保存在proc里
-
filp->private_data = proc;
-
添加到binder_procs鏈表中
3. binder_mmap()
static int binder_mmap(struct file *filp, struct vm_area_struct *vma) /* 行程的虛擬記憶體 */
{
int ret;
struct vm_struct *area; /* 內核的虛擬記憶體 */
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
if (proc->tsk != current)
return -EINVAL;
// 大小不能超過4M 4M----驅動給定的
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
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) {
ret = -EPERM;
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
mutex_lock(&binder_mmap_lock);
if (proc->buffer) {
ret = -EBUSY;
failure_string = "already mapped";
goto err_already_mapped;
}
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
if (area == NULL) {
ret = -ENOMEM;
failure_string = "get_vm_area";
goto err_get_vm_area_failed;
}
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
mutex_unlock(&binder_mmap_lock);
#ifdef CONFIG_CPU_CACHE_VIPT
if (cache_is_vipt_aliasing()) {
while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
vma->vm_start += PAGE_SIZE;
}
}
#endif
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
if (proc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
proc->buffer_size = vma->vm_end - vma->vm_start;
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
ret = -ENOMEM;
failure_string = "alloc small buf";
goto err_alloc_small_buf_failed;
}
buffer = proc->buffer;
INIT_LIST_HEAD(&proc->buffers);
list_add(&buffer->entry, &proc->buffers);
buffer->free = 1;
binder_insert_free_buffer(proc, buffer);
proc->free_async_space = proc->buffer_size / 2;
barrier();
proc->files = get_files_struct(current);
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
/*pr_info("binder_mmap: %d %lx-%lx maps %p\n",
proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
return 0;
err_alloc_small_buf_failed:
kfree(proc->pages);
proc->pages = NULL;
err_alloc_pages_failed:
mutex_lock(&binder_mmap_lock);
vfree(proc->buffer);
proc->buffer = NULL;
err_get_vm_area_failed:
err_already_mapped:
mutex_unlock(&binder_mmap_lock);
err_bad_arg:
pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
return ret;
}
-
通過用戶空間的虛擬記憶體大小,分配一塊內核的虛擬記憶體
-
分配一塊物理記憶體 ------4KB
-
把這塊物理記憶體分別映射到用戶空間的虛擬記憶體 和 內核的虛擬記憶體
4. binder_ioctl()
讀寫操作 BINDER_WRITE_READ
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);*/
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
binder_lock(__func__);
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;
case BINDER_SET_MAX_THREADS:
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
goto err;
break;
case BINDER_THREAD_EXIT:
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
proc->pid, thread->pid);
binder_free_thread(proc, thread);
thread = NULL;
break;
case BINDER_VERSION: {
struct binder_version __user *ver = ubuf;
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {
ret = -EINVAL;
goto err;
}
break;
}
default:
ret = -EINVAL;
goto err;
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
-
進入休眠,直到中斷喚醒
-
根據當前行程的pid, 從binder_proc中查找binder_thread,如果當前執行緒已經加入到proc的執行緒佇列,則直接回傳;如果不存在binder_thread,則創建binder_thread,并將其添加到當前的proc,
-
進行binder的讀寫操作
-
首先將用戶空間資料ubuf拷貝到bwr中,
-
當寫快取中有資料,則執行binder寫操作
-
當讀快取中有資料,則執行binder讀操作
-
行程todo佇列不為空,則喚醒該佇列中的執行緒
-
把內核空間資料bwr拷貝到ubuf
-
JNI層
我們知道,native層的binder要想和framework層通信,首先得通過jni注冊,這個注冊在zygote行程啟動時,通過app_main.cpp中的main方法,
frameworks/base/cmds/app_process/app_main.cpp
// 186
int main(int argc, char* const argv[])
// 248 將zygote標志位置為true,
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
}
// 306 運行AndroidRuntime.cpp的start方法
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
然后呼叫startReg方法來完成jni方法的注冊,
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
//回圈注冊jni方法
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[] = {
...
REG_JNI(register_android_os_Binder),
...
};
可以看到,register_android_os_Binder 這個是binder的jni方法,我們進入看下:
代碼路徑在:frameworks/base/core/jni/android_util_Binder.cpp
int register_android_os_Binder(JNIEnv* env)
{
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;
jclass clazz = FindClassOrDie(env, "android/util/Log");
gLogOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gLogOffsets.mLogE = GetStaticMethodIDOrDie(env, clazz, "e",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
clazz = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
gParcelFileDescriptorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gParcelFileDescriptorOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>",
"(Ljava/io/FileDescriptor;)V");
clazz = FindClassOrDie(env, "android/os/StrictMode");
gStrictModeCallbackOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
"onBinderStrictModePolicyChange", "(I)V");
return 0;
}
這里分為三個階段:
1.int_register_android_os_Binder
const char* const kBinderPathName = "android/os/Binder";
static int int_register_android_os_Binder(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderPathName);
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
-
通過kBinderPathName查找檔案,此時的檔案是:“android/os/Binder”,回傳class物件,
-
通過gBinderOffsets結構體,保存Java層Binder類的資訊,為JNI層訪問Java層提供通道,
-
通過RegisterMethodsOrDie,將為gBinderMethods陣列完成映射關系,從而為Java層訪問JNI層提供通道,
2.int_register_android_os_BinderInternal
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
static int int_register_android_os_BinderInternal(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderInternalPathName);
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
-
通過kBinderInternalPathName查找檔案,回傳class物件
-
通過gBinderInternalOffsets結構體,保存java層binder類的資訊,為JNI層訪問Java層提供通道
-
通過RegisterMethodsOrDie,為gBinderInternalMethods陣列完成映射關系,從而為Java層訪問JNI層提供通道
3. int_register_android_os_BinderProxy
const char* const kBinderProxyPathName = "android/os/BinderProxy";
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, "java/lang/Error");
gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
clazz = FindClassOrDie(env, kBinderProxyPathName);
gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;)V");
gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf",
"Ljava/lang/ref/WeakReference;");
gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J");
clazz = FindClassOrDie(env, "java/lang/Class");
gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
return RegisterMethodsOrDie(
env, kBinderProxyPathName,
gBinderProxyMethods, NELEM(gBinderProxyMethods));
}
-
通過kBinderProxyPathName查找檔案,回傳class物件
-
通過gBinderProxyOffsets結構體,保存Java層binder類的資訊,為JNI層訪問java層提供通道,
-
通過RegisterMethodsOrDie,為gBinderProxyMethods陣列完成映射關系,從而為java層訪問JNI層提供通道
Native層
ServiceManager服務的注冊
service_manager就是一個大管家,負責管理各種服務,包括系統服務(AMS、PMS等),service_manage的handle = 0,啟動servicemanager通過決議init.rc,進入service_manager.c的main方法
int main(int argc, char **argv)
{
struct binder_state *bs;
// 打開binder驅動,申請128KB位元組大小的記憶體空間,進行記憶體映射
bs = binder_open(128*1024);
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
// 設定servicemanager為binder大管家
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
...
// 進行無限回圈,處理client發來的請求
binder_loop(bs, svcmgr_handler);
return 0;
}
上面的main方法 我們可以看到,SM的注冊主要分為三個步驟:
-
打開驅動 記憶體映射,設定記憶體大小為128kb (ServiceManager服務的大小)
-
設定servicemanager為大管家
-
開啟監聽 不斷輪詢
首先,先看下他是如何將servicemanager設定為大管家的,進入代碼:
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
...
// 創建SM物體 node
context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
...
return ret;
}
static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_uintptr_t ptr,
binder_uintptr_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else
return NULL;
}
// 申請記憶體 創建node物件
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (node == NULL)
return NULL;
binder_stats_created(BINDER_STAT_NODE);
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
node->debug_id = ++binder_last_id;
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
return node;
}
-
創建binder_node結構體物件
-
proc -> binder_node
-
創建 work 和 todo ====》類似 messageQueue
其次,看SM如何進入loop等待狀態:這里很關鍵的一個命令:BC_ENTER_LOOPE命令
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
// 1.將bwr結構體初始化為0
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
// 2.設定執行緒的狀態為loop狀態
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
// 3. read_size 不為0, 進入binder_thread_read
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
/* 不斷地 binder讀資料,沒有資料會進入休眠狀態 */
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
// 1.將bwr結構體初始化為0
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
// 2.設定執行緒的狀態為loop狀態
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
// 3. read_size 不為0, 進入binder_thread_read
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
/* 不斷地 binder讀資料,沒有資料會進入休眠狀態 */
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
- 進入kernel層的binder.c, 通過BINDER_WRITE_READ命令,呼叫
binder_ioctl_write_read函式, 前面我們判斷了write_buffer是有值的,所以執行binder_thread_write,
在binder_thread_write里
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
/* 獲取命令,即 BC_ENTER_LOOPER */
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
...
switch (cmd) {
...
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
/* 設定執行緒loop狀態為回圈狀態 */
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
...
}
}
- 此時,第一步已經完成,就是寫入了執行緒的loop狀態,再回到binder_loop函式中,進入for回圈,將read_size賦值了,read_size 不為0, 進入binder_thread_read,再看這個函式
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
...
if (*consumed == 0) {
/* 設定命令為BR_NOOP */
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
/* wait_for_proc_work為true */
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
...
/* 準備就緒的執行緒數 + 1 */
if (wait_for_proc_work)
proc->ready_threads++;
...
if (non_block) { /* 非阻塞操作,servicemanager是阻塞的,所以進入else */
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}
總結大致做了以下作業:
-
寫入狀態Loop
-
去讀資料:binder_thread_read:ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); 進入等待
此時,servicemanager已經注冊完成,準備就緒了,
整體流程圖如下:

ServiceManager服務的獲取
獲取ServiceManager是通過defaultServiceManager()方法來完成的,
sp<IServiceManager> defaultServiceManager()
{
/* 單例模式,如果不為空,直接回傳 */
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
/* 這里分三步走 */
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
1. ProcessState::self()
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
/* 單例模式 */
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}
這一步很簡單,就是實體化ProcessState物件,
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
#else
mDriverFD = -1;
#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
可以看到,初始化物件時,首先呼叫open_driver打開驅動,其次通過mmap記憶體映射,給 binder分配一塊大小為 **(1M-8K)**的虛擬地址空間,用來接收事務,進入open_driver看下:
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; /* 15 */
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}
呼叫open打開 /dev/binder設備,建立與內核的 Binder驅動的互動通道,通過ioctl設定binder驅動,能支持的最大執行緒數為15個,
2. getContextObject(NULL)
通過gProcess物件,呼叫getContextObject(NULL)函式,而這個函式做什么事情,
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
回傳一個getStrongProxyForHandle函式,引數為0,獲取service_manager服務,看下這個函式:
{
sp<IBinder> result;
AutoMutex _l(mLock);
/* 查找handle對應的資源項 */
handle_entry* e = lookupHandleLocked(handle);
/* e不為空 進入if */
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
/* 通過ping操作測驗binder是否準備就緒 */
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
/* 創建BpBinder物件 */
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
主要的任務就是創建了BpBinder物件,(客戶端)
3. interface_cast< IServiceManager >()
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
可以看到,這是一個模板函式,就相當于java里的泛型,我們指定泛型型別為IServiceManager,
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { }
展開即可得:
const android::String16
IServiceManager::descriptor(“android.os.IServiceManager”);
const android::String16& IServiceManager::getInterfaceDescriptor() const
{
return IServiceManager::descriptor;
}
android::sp<IServiceManager> IServiceManager::asInterface(const
android::sp<android::IBinder>& obj)
{
android::sp<IServiceManager> intr;
if(obj != NULL) {
intr = static_cast<IServiceManager *>(
obj->queryLocalInterface(IServiceManager::descriptor).get());
if (intr == NULL) {
// 等價于 new BpServiceManager(BpBinder)
intr = new BpServiceManager(obj);
}
}
return intr;
}
IServiceManager::IServiceManager () { }
IServiceManager::~ IServiceManager() { }
從展開得函式中看到,這一步主要作業就是new BpServiceManager(BpBinder),
真正通過remote.transcat 遠程呼叫,而remote等價BpBinder,
Java層
java層的服務注冊是從SystemServer開始的,
服務的注冊和獲取 以AMS為例
AMS的注冊
1. getIServiceManager()
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
這里又分為兩步:
-
BinderInternal.getContextObject()
進入native方法:
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b); /* 回傳BinderProxy物件 */
}
1. ProcessState::self()->getContextObject(NULL): 創建一個BpBinder
2. javaObjectForIBinder(env, b):系結BinderProxy和BpBinder
- ServiceManagerNative.asInterface
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
這里,我們得知obj就是BinderProxy,所以看下BinderProxy的queryLocalInterface方法
public IInterface queryLocalInterface(String descriptor) {
return null;
}
這個方法回傳一個null,所以直接new ServiceManagerProxy(BinderProxy),
總結: getIServiceManager() 最侄訓傳:new ServiceManagerProxy(BinderProxy),
2. addService(name, service, false)
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
-
data.writeStrongBinder(service); service == AMS 將AMS放入data中,
-
mRemote.transact mRemote == BinderProxy
-
獲取BpBinder ---- IPCThreadState::transact
-
writeTransactionData 往out中寫入BC_TRANSACTION命令,在write里處理BC_TRANSACTION命令
-
waitForResponse
-
talkWithDriver — 非常重要
-
binder_transaction
-
handle == 0 ----> SM
-
獲取target_node
-
獲取proc物件
-
獲取todo 和 wait
-
創建t,tcomplete
-
資料拷貝**(真正一次拷貝的地方)**
-
binder_transaction_binder -----> handle
-
thread -> transaction_stack = t; -----> 方便SM找到客戶端
-
t->work.type = BINDER_WORK_TRANSACTION; 給SM做事
-
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; 給客戶端掛起
-
wake_up_interruptible(target_wait); 喚醒SM
-
-
-
client掛起
-
處理BR_NOOP、BR_TRANSACTION_COMPLETE命令
-
wait_event_freezable ----- 掛起
-
-
sm處理添加服務
-
BINDER_WORK_TRANSACTION,要處理的 cmd == BR_TRANSACTION
-
reply初始化
-
res = func(bs, txn, &msg, &reply); — 函式指標,指向svcmgr_handler
作用:獲取或者添加 service
- sm 是用 svclist 保存所有服務的
-
binder_send_reply — BC_REPLY
-
t->work.type = BINDER_WORK_TRANSACTION; — 給Client list_add_tail(&t->work.entry, target_list); tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; – 給SM — 被掛起 list_add_tail(&tcomplete->entry, &thread->todo);
-
wake_up_interruptible(target_wait); – 喚醒 Client
-
-
client 被喚醒
-
-
附上一張 addService 的流程圖:

3. SM 處理 onTransact
IPCThreadState::executeCommand
-
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);
-
JavaBBinder.onTransact — C++
-
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast(&data), reinterpret_cast(reply), flags); – Binder.java.execTransact 方法
至此,binder的整理流程就分析完了,說實話,邏輯很復雜,可能第一次看完 一頭霧水,多看幾次,把整體流程理清楚就會明白很多,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/297332.html
標籤:其他
