Android系統之Binder通訊機制
前言
在Linunx
程式中使用的通訊方式有:socket
(套接字通訊),named
(命令管道),pipe
(管道),message queque
(報文佇列),signal
(訊號),share memory
(共享記憶體)。
在Java
程式中使用的通訊方式有:socket
,named
,pipe
等。
在Android
程式中使用的通訊方式主要是Binder
通訊,下面就來看看Binder
通訊機制
Binder通訊機制
Binder
是由Client
,Server
,ServiceManager
,Binder
驅動程式組成。
ServiceManager
其中ServiceManager
是Binder
機制的守護程式,同時也是一個特殊的Service
。它在init.rc
裡面就開始啟動了,其中Android7.0
把servicemanager
的啟動程式碼拆分到servicemanager.rc
裡面,程式碼如下:
//frameworks/native/master/./cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
writepid /dev/cpuset/system-background/tasks
shutdown critical
從上面程式碼可知啟動了servicemanager
程式,從而執行service_manager.c
的main
函式,同時重啟了下面幾個模組
-
healthd
監聽電池的狀態和資訊,同時傳遞給BatteryService
,從而展示電池相關的資訊。 -
zygote
當zygote
被kill
的時候,servicemanager
會在這裡嘗試重新喚醒它 -
audioserver
,media
音視訊相關的服務 -
surfaceflinger
繪製應用程式的使用者介面的服務 -
inputflinger
系統輸入事件服務 -
drm
數字版權管理服務 -
cameraserver
相機服務 -
keystore
應用簽名檔案 -
gatekeeperd
系統的圖案/密碼認證
接下來在init.rc
裡面呼叫啟動servicemanager
//init.rc
//....
class_start core
//....
通過class_start core
就啟動了servicemanager
。
接下里就來看看service_manager.c
的main
函式
//frameworks/native/master/./cmds/servicemanager/service_manager.c
int main()
{
struct binder_state *bs;
bs = binder_open(128*1024);
//....
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
//....
binder_loop(bs, svcmgr_handler);
return 0;
}
主要做了下面幾種
-
binder_open
開啟Binder
裝置 -
binder_become_context_manager
通知Binder驅動程式自己是Binder上下文管理者 -
binder_loop
進入一個無窮迴圈,充當Server的角色,等待Client的請求
Binder驅動程式初始化
Binder
驅動程式原始碼位於/drivers/staging/android/binder.c
,在原始碼中可以看到這行程式碼
device_initcall(binder_init);
binder_init()
在Linux
載入完核心的時候,init
函式會執行device_initcall
。從而執行binder_init
函式,初始化binder
驅動程式。再來看看binder_init()
函式
//android/kernel/msm/android-7.1.2_r0.33/./drivers/staging/android/ binder.c
static int __init binder_init(void)
{
int ret;
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
binder_debugfs_dir_entry_root);
ret = misc_register(&binder_miscdev);
if (binder_debugfs_dir_entry_root) {
debugfs_create_file("state",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("stats",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_stats_fops);
debugfs_create_file("transactions",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log_failed,
&binder_transaction_log_fops);
}
return ret;
}
create_singlethread_workqueue
建立了一個binder
的worker_thread
單一核心程式
debugfs_create_dir
debugfs
是一種核心除錯的虛擬檔案系統,核心開發者通過debugfs
和使用者空間交換資料,它是在Linux
執行的時候建立。這裡就是建立debugfs
相應的檔案
misc_register
它傳的引數是一個結構體如下
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR, //次裝置號動態分配
.name = "binder",//裝置號
.fops = &binder_fops// 裝置的檔案作業系統
};
通過misc_register
函式為binder
驅動註冊一個misc
裝置
接下來就是建立proc
和state
目錄下的一些檔案
binder_open()
binder_init
初始化之後,接下來service_manager.c
的main
函式會呼叫binder_open
。先來看看binder_open()
函式。
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
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_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->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
}
return 0;
}
binder_proc
它是儲存開啟/dev/binder
裝置的程式的結構體,儲存的資訊如下
struct binder_proc {
//...
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
struct task_struct *tsk;
struct list_head todo;
wait_queue_head_t wait;
int max_threads;
long default_priority;
//...
};
-
threads
儲存binder_proc
程式內的用來使用者請求處理的執行緒,執行緒最大數由max_threads
決定 -
nodes
儲存binder_proc
程式內的binder
的實體 -
refs_by_desc
和refs_by_node
儲存binder_proc
程式內的binder
的引用 -
tsk
儲存binder_proc
程式的地址 -
todo
待處理的事務連結串列 -
wait
等待處理的連結串列 -
default_priority
預設處理的事務優先順序
get_task_struct
Linux
核心方法,原始碼如下
#define get_task_struct(tsk) do{ atomic_inc&((tsk) ->[usage] } while(0)
最終呼叫atomic_add
函式,通過原子加的形式實現當前程式引用的計數
接下來就是對binder_proc
連結串列的初始化以及其他程式相關資訊進行初始化賦值。
binder_mmap()
在binder_open
裡面有一句程式碼是
static int binder_open(struct inode *nodp, struct file *filp)
{
//....
filp->private_data = proc;
//....
}
前面說到binder_init
裡面會把binder驅動註冊一個misc裝置。進去misc.c
會看到
//kernel/common/drivers/char/misc.c
/ * The structure passed is linked into the kernel and may not be
* destroyed until it has been unregistered. By default, an open()
* syscall to the device sets file->private_data to point to the
* structure. Drivers don't need open in fops for this.
*/
int misc_register(struct miscdevice * misc)
{
//....
list_add(&misc->list, &misc_list);
out:
mutex_unlock(&misc_mtx);
return err;
}
把裝置儲存在misc_list
裡面,在上面的註釋可知,它是在file->private_data
具有指標指向的時候系統會自動呼叫misc_open
函式,而在misc_open
函式,會遍歷file->private_data
裡面所有儲存的裝置的fops
。
static int misc_open(struct inode * inode, struct file * file)
{
//...
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
//...
}
這裡fops
是傳入的binder_miscdev
結構體裡面的fops
,fops
對應的是binder_fops
結構體
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,
};
從這裡可以找出初始化binder_mmap
函式。再來看看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;
//....
}
通過filp->private_data
得到在開啟裝置檔案 /dev/binder
建立的struct binder_proc
結構,記憶體對映資訊放在vma引數中。其中vma
是vm_area_struct
結構體,它是給程式使用的一塊連續的虛擬地址空間,而vm_struct
是個核心使用的一塊連續的虛擬地址空間。在同一個物理頁面中,一方對映到程式虛擬地址空間,一方面對映到核心虛擬地址空間,這樣,程式和核心之間就可以減少一次記憶體拷貝了。接下來該函式就是處理記憶體對映和管理的詳細步驟。
binder_ioctl()
再來看看binder_ioctl
函式
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_preempt_disabled(&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_preempt_disabled(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;
}
它主要是負責在兩個程式間進行收發資料
相關文章
- Android 系統原始碼-2:Binder 通訊機制Android原始碼
- Binder通訊機制
- Android高階進階之路【五】深入剖析Android系統Binder通訊機制Android
- Binder通訊機制與IPC通訊.md
- android-IPC/Binder/D-BUS(Binder/Messager/AIDL)程式間通訊(訊息機制)AndroidAI
- Android 之 Binder與程式間通訊Android
- 從AIDL開始談Android程式間Binder通訊機制AIAndroid
- Android 程式通訊機制之 AIDLAndroidAI
- Binder機制之AIDLAI
- Android Binder機制淺析Android
- Android的IPC機制BinderAndroid
- Android程式間通訊(IPC)機制Binder簡要介紹和學習計劃Android
- Android進階(六)Binder機制Android
- android Binder機制深入淺出Android
- Android Binder機制文章轉載Android
- Binder機制
- Android 之訊息機制Android
- 圖解Android中的binder機制圖解Android
- 理解 Android Binder 機制(三):Java層AndroidJava
- android之 Android訊息機制Android
- 徹底理解 Android Binder 通訊架構Android架構
- Android外掛化原理解析——Hook機制之Binder HookAndroidHook
- Android程式間通訊–訊息機制及IPC機制實現薦Android
- 理解 Android Binder 機制(二):C++層AndroidC++
- 理解 Android Binder 機制(一):驅動篇Android
- Binder學習(二)Binder機制解析
- 藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈AIAndroid
- Android C++層使用Binder通訊的方法AndroidC++
- Android 外掛化原理解析(3):Hook 機制之 Binder HookAndroidHook
- Android通過繼承Binder類實現多程式通訊Android繼承
- Binder學習(三)通過AIDL分析Binder通訊流程AI
- Android IPC機制(三):淺談Binder的使用Android
- Android的IPC機制(三)——Binder連線池Android
- 【Android原始碼】Binder機制和AIDL分析Android原始碼AI
- Android系統安全機制Android
- Spark原始碼分析之BlockManager通訊機制Spark原始碼BloC
- Binder機制分析(1)——Binder結構簡介
- Android訊息傳遞之Handler訊息機制Android