原文出處——>[Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析](http://blog.csdn.net/luoshengyang/article/details/6666491)
在前面一篇文章Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析中,我們系統地介紹了Android系統匿名共享內存的實現原理,其中著重介紹了它是如何輔助內存管理系統來有效地管理內存的,在再前面一篇文章Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃中,我們還提到,Android系統匿名共享內存的另外一特點是通過Binder進程間通信機制來實現進程間共享的,本文中,將詳細介紹Android系統匿名共享內存是如何使用Binder進程間通信機制來實現進程間共享的。
由于Android系統匿名共享內存在進程間共享的原理涉及到Binder進程間通信機制的相關知識,所以希望讀者在繼續閱讀本文之前,最好對Android系統的Binder進程間通信機制有一定的了解,具體可以參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃這篇文章。
在Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃這篇文章中,我們舉了一個例子來簡要地介紹了Android系統的匿名共享內存機制及其使用方法,在這篇文章中,我們繼續以這個實例來說明Android系統的匿名共享內存是如何使用Binder進程間通信機制來實現進程間共享的。為了方便描述,結合前面的Binder進程間通信機制知識,我們通過下面這個序列圖來總結這個實例中的匿名共享內存文件的文件描述符在進程間傳輸的過程:

這里, 我們需要關注的便是虛線框部分了,它在Binder驅動程序中實現了在兩個進程中共享同一個打開文件的方法。我們知道,在Linux系統中,文件描述符其實就是一個整數。每一個進程在內核空間都有一個打開文件的數組,這個文件描述符的整數值就是用來索引這個數組的,而且,這個文件描述符只是在本進程內有效,也就是說,在不同的進程中,相同的文件描述符的值,代表的可能是不同的打開文件。因此,在進程間傳輸文件描述符時,不能簡要地把一個文件描述符從一個進程傳給另外一個進程,中間必須做一過轉換,使得這個文件描述在目標進程中是有效的,并且它和源進程的文件描述符所對應的打開文件是一致的,這樣才能保證共享。
在淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路一文中,我們介紹了用來傳輸的Binder對象的數據結構struct flat_binder_object,它定義在**kernel/common/drivers/staging/android/binder.h** 文件中:
~~~
/*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void *cookie;
};
~~~
域type是一個枚舉類型,它的取值范圍是:
~~~
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
~~~
這里我們要介紹的Binder對象的type便是BINDER_TYPE_FD了,要傳輸的文件描述符的值保存在handle域中。
在Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文中,我們詳細介紹了Binder對象在進程間通信傳輸的完整過程,這里就不再詳述了,有興趣的讀都可以回過頭去參考一下。這里,我們只關注文件描述符類型的Binder對象在Binder驅動程序中的相關處理邏輯。
文件描述符類型的Binder對象在Binder驅動程序中的相關處理邏輯實現在binder_transact函數,這個函數定義在**kernel/common/drivers/staging/android/binder.c**文件中:
~~~
static void
binder_transaction(struct binder_proc *proc, struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
struct binder_work *tcomplete;
size_t *offp, *off_end;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error;
......
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
......
off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
......
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
......
case BINDER_TYPE_FD: {
int target_fd;
struct file *file;
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if (!target_node->accept_fds) {
binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
file = fget(fp->handle);
if (file == NULL) {
binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd < 0) {
fput(file);
return_error = BR_FAILED_REPLY;
goto err_get_unused_fd_failed;
}
task_fd_install(target_proc, target_fd, file);
if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd);
/* TODO: fput? */
fp->handle = target_fd;
} break;
......
}
}
......
}
~~~
這里,我們先明確一下在Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃這篇文章中所舉的例子獲取匿名共享內存文件的文件描述符的場景。匿名共享內存文件是在Server進程創建的,Client通過IMemoryService.getFileDescriptor去獲取Server進程所創建的匿名共享內存文件的文件描述符,Server進程在返回這個文件描述符的過程中進入到Binder驅動程序,即這里的binder_transact函數。因此,這里的當前執行binder_transact函數的進程是Server進程,即源進程是Server進程,而目標進程是Client進程,就是這里的target_proc所表示的進程了。
函數binder_transaction處理文件描述符類型的Binder對象就在中間的for循環里面。
首先是獲得Binder對象,并保存在本地變量fp中:
~~~
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
~~~
文件描述符的值就保存在fp->handle中,通過fget函數取回這個文件描述符所對應的打開文件結構:
~~~
file = fget(fp->handle);
~~~
這里的file是一個struct file指針,它表示一個打開文件結構。注間,在Linux系統中,打開文件結構struct file是可以在進程間共享的,它與文件描述符不一樣。
接著在目標進程中獲得一個空閑的文件描述符:
~~~
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
~~~
現在,在目標進程中,打開文件結構有了,文件描述符也有了,接下來就可以把這個文件描述符和這個打開文件結構關聯起來就可以了:
~~~
task_fd_install(target_proc, target_fd, file);
~~~
由于這個Binder對象最終是要返回給目標進程的,所以還要修改fp->handle的值,它原來表示的是在源進程中的文件描述符,現在要改成目標進程的文件描述符:
~~~
fp->handle = target_fd;
~~~
這樣,對文件描述符類型的Binder對象的處理就完成了。目標進程拿到這個文件描述符后,就可以和源進程一起共享打開文件了。
至此,Android系統匿名共享內存利用Binder進程間通信機制來實現進程間共享的學習就結束了,整個Android系統匿名共享內存機制的學習也完成了,希望對讀者有所幫助,重新學習Android系統匿名共享內存機制請回到Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃一文。
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析