Android系列-ION內(nèi)存管理簡介

Android系列-ION內(nèi)存管理簡介

一、ION相關(guān)介紹

Android的ION子系統(tǒng)的目的主要是通過在硬件設(shè)備和用戶空間之間分配和共享內(nèi)存,實現(xiàn)設(shè)備之間零拷貝共享內(nèi)存。說來簡單,其實不易。在Soc硬件中,許多設(shè)備可以進行DMA,這些設(shè)備可能有不同的能力,以及不同的內(nèi)存訪問機制。

ION是Google在Android 4.0 ICS中引入,用于改善對于當(dāng)前不同的android設(shè)備,有著各種不同內(nèi)存管理接口管理相應(yīng)內(nèi)存的狀況。當(dāng)前存在著各種不同的但是功能卻類似的內(nèi)存管理接口,例如在NVIDIA Tegra有一個“NVMAP”機制、在TI OMAP有一個“CMEM”機制、在Qualcomm MSM有一個“PMEM”機制,ION將其進行通用化,通過其接口,可集中分配各類不同內(nèi)存(heap),同時上述三個芯片廠商也正將其內(nèi)存管理策略切換至ION上。

另外,ION在內(nèi)核空間和用戶空間分別有一套接口,它不僅能管理內(nèi)存,還可在其clients(來自內(nèi)核的或者來自用戶空間的)之間共享內(nèi)存。

綜上,ION主要功能:

  • 內(nèi)存管理器:提供通用的內(nèi)存管理接口,通過heap管理各種類型的內(nèi)存。
  • 共享內(nèi)存:可提供驅(qū)動之間、用戶進程之間、內(nèi)核空間和用戶空間之間的共享內(nèi)存。

二、實現(xiàn)原理

在ION中,用不同heap代表不同類型的內(nèi)存,每種heap有自己的內(nèi)存分配策略。

主要的heap:

  • ION_HEAP_TYPE_SYSTEM: 使用vmalloc分配,這個對應(yīng)ion_heap_ops中的map_user函數(shù)
  • ION_HEAP_TYPE_SYSTEM_CONTIG: 通過kmalloc分配
  • ION_HEAP_TYPE_CARVEOUT: 在啟動的時候就保留的物理上連續(xù)的內(nèi)存塊
  • 另外還有兩種,這里不關(guān)注:
  • ION_HEAP_TYPE_CHUNK
  • ION_HEAP_TYPE_DMA: memory allocated via DMA API
圖片.png

每個heap中可分配若干個buffer,每個client通過handle管理對應(yīng)的buffer。每個buffer只能有一個handle對應(yīng),每個用戶進程只能有一個client,每個client可能有多個handle。兩個client通過文件描述符fd(和handle有所對應(yīng),通過handle獲取),通過映射方式,將相應(yīng)內(nèi)存映射,實現(xiàn)共享內(nèi)存。

圖片.png

三、使用方法

下面的內(nèi)容著重講述用戶空間進程之間的內(nèi)存共享。

1、用戶空間內(nèi)使用ION的方法

用戶空間可以使用libion庫實現(xiàn)對ion的操作,這里不講述該庫的操作方法,用戶程序直接通過ioctl和驅(qū)動打交道,ion常見的ioctl命令為:

  • ION_IOC_ALLOC: 分配內(nèi)存
  • ION_IOC_FREE: 釋放內(nèi)存
  • ION_IOC_MAP: 獲得一個只想mmap映射的內(nèi)存的文件描述符
  • ION_IOC_SHARE: 創(chuàng)建一個指向共享的內(nèi)存的文件描述符
  • ION_IOC_IMPORT: 引入一個共享的文件描述符
  • ION_IOC_CUSTOM: 調(diào)用平臺自定義的ioctl

具體使用示例可以參見該庫的文件實現(xiàn)(system/core/lib/ion/),或如下:

sharedMemoryION.txz

(1)獲取一個ION client

需要打開ION設(shè)備:

open("/dev/ion", O_RDONLY)

這里,進程要有訪問權(quán)限,雖然是使用O_RDONLY標(biāo)記但是也返回一個可寫的內(nèi)存。返回的文件描述符號做為表示一個ION client的handle。每個用戶進程只能有一個client。用戶空間的client通過ioctl()系統(tǒng)調(diào)用接口和ION交互。

(2)設(shè)置獲取buffer的參數(shù)

填充結(jié)構(gòu)ion_allocation_data,主要包含如下成員:

struct ion_allocation_data {
    size_t len;
    size_t align;
    unsigned int heap_mask;
    unsigned int flags;
    struct ion_handle *handle;                                                                                                                      
};

這里 handle做為輸出 (struct ion_handle 類型),需要填充的是其中除handle成員之外的成員(整個buffer是 struct ion_allocation_data 類型)。對于其他參數(shù),注意在文檔 (http://lwn.net/Articles/480055/) 中并沒有給出heap_mask,只說flags是一個比特掩碼,標(biāo)識一個或者多個將要分配所使用的ION heap(結(jié)合后面,它的解釋是錯誤的,應(yīng)該是對heap_mask的解釋),但是從源代碼中的注釋看,這些參數(shù)的含義如下:

  • len:分配的大小。
  • align:分配所需的對其參數(shù)。
  • heap_mask:待分配所使用的所有heaps的掩碼(如:ION_HEAP_SYSTEM_MASK)。
  • flags:傳給heap的標(biāo)志(如:ION_FLAG_CACHED),ion系統(tǒng)使用低16位,高16位用于各自heap實現(xiàn)使用。

具體各自取值和實現(xiàn),請參見ion驅(qū)動頭文件定義和驅(qū)動代碼。

(3)分配buffer

將設(shè)置好的buffer參數(shù)傳遞給ioctl:

int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)

這里,client_fd就是剛剛打開的/dev/ioc文件描述符號。分配的buffer通過返回的上述結(jié)構(gòu)的 struct ion_handle *handle 成員來引用,但是這個handle并不是一個CPU訪問的地址。一個client不能有兩個handle指向同樣的buffer。

(4)共享buffer

buffer的handle只能通過如下調(diào)用獲取一個文件描述符號用于buffer共享:

int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data);

其中fd_data如下:

struct ion_fd_data {
        struct ion_handle *handle;
        int fd;
   }

這里, handle是輸入 ,標(biāo)示要共享buffer的handle; fd是輸出 ,標(biāo)示用于共享buffer的文件描述符號。

(5)傳遞待共享的文件描述符號

在android設(shè)備中,可能會通過Binder機制將共享的文件描述符fd發(fā)送給另外一個進程。

為了獲得被共享的buffer,第二個用戶進程必須通過首先調(diào)用 open("/dev/icon", O_RDONLY) 獲取一個client handle,ION通過進程ID跟蹤它的用戶空間clients。 在同一個進程中重復(fù)調(diào)用open("/dev/icon", O_RDONLY)將會返回另外一個文件描述符號,這個文件描述符號會引用內(nèi)核同樣的client結(jié)構(gòu)

獲取到共享文件描述符fd后,共享進程可以通過mmap來操作共享內(nèi)存。

(6)釋放

為了釋放緩存,第二個client需要通過munmap來取消mmap的效果,第一個client需要關(guān)閉通過ION_IOC_SHARE命令獲得的文件描述符號,并且使用ION_IOC_FREE如下:

int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data);

其中:

struct ion_handle_data {
    struct ion_handle *handle;
}

命令會導(dǎo)致handle的引用計數(shù)減少1。當(dāng)這個引用計數(shù)達到0的時候,ion_handle對象會被析構(gòu),同時ION的索引數(shù)據(jù)結(jié)構(gòu)被更新。

用戶進程也可與內(nèi)核驅(qū)動共享ION buffer。

2、內(nèi)核空間內(nèi)使用ION的方法

具體參見參考資料,這里簡略介紹。

(1)獲取一個ION Client

調(diào)用如下函數(shù):

struct ion_client *ion_client_create(struct ion_device *dev,unsigned int heap_mask, const char *debug_name)

內(nèi)核中可以有多個ION clients,每個使用ION的driver擁有一個client。這里,參數(shù)dev就是對應(yīng)/dev/ion的設(shè)備,為何需要這個參數(shù),目前還不確切;參數(shù)heap_mask和前面敘述一樣,用于選擇一個或多個ion heaps類型標(biāo)識堆類型。flags參數(shù)前面說過了。

(2)共享來自用戶空間的ion buffer

用戶傳遞 ion共享文件描述符 給內(nèi)核驅(qū)動,驅(qū)動 轉(zhuǎn)成ion_handle

struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user);

在許多包含多媒體中間件的智能手機中,用戶進程經(jīng)常從ion中分配buffer,然后使用ION_IOC_SHARE命令獲取文件描述符號,然后將文件描述符號傳遞給內(nèi)核驅(qū)動。內(nèi)核驅(qū)動調(diào)用ion_import_fd()將文件描述符轉(zhuǎn)換成ion_handle對象。內(nèi)核驅(qū)動使用ion_handle對象做為對共享buffer的client本地引用。該函數(shù)查找buffer的物理地址一確認(rèn)是否這個client是否之前分配了同樣的buffer,如果是,則僅增加相應(yīng)handle的引用計數(shù)。

有些硬件塊只能操作物理地址連續(xù)的buffer,所以相應(yīng)的驅(qū)動應(yīng) 對ion_handle轉(zhuǎn)換

int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len)

若buffer的物理地址不連續(xù),這個調(diào)用會失敗。

在處理client的調(diào)用之時,ion始終會對input file descriptor,client,和handle arguments進行確認(rèn)。例如:當(dāng)import一個file descriptor(文件描述符)之時,ion會保證這個文件描述符確實是通過ION_IOC_SHARE命令創(chuàng)建的。當(dāng)ion_phys()被調(diào)用之時,ION會驗證buffer handle是否在client允許訪問的handles列表中,若不是,則返回錯誤。這些驗證機制減少了期望之外的訪問與資源泄露。

四、ION 調(diào)試

關(guān)于ION debug,在 /sys/kernel/debug/ion/ 提供一個debugfs 接口。

每個heap都有自己的debugfs目錄,client內(nèi)存使用狀況顯示在 /sys/kernel/debug/ion/<<heap name>>

$cat /sys/kernel/debug/ion/ion-heap-1 
 client              pid             size
test_ion             2890            16384

每個由pid標(biāo)識的client也有一個debugfs目錄/sys/kernel/debug/ion/<a id="orgtarget1"></a>

$cat /sys/kernel/debug/ion/2890 
heap_name:    size_in_bytes
ion-heap-1:    40960 11

五、其它資料

待更新

內(nèi)核空間

注:使用例如“git clone https://android.googlesource.com/kernel/common” 下載之后,目錄為空,這可能是因為存在多個分支,而當(dāng)前分支為空,可以用"git branch -a"查看相應(yīng)分支,然后切換之。

用戶空間

同樣可參照上述方法下載。

整體介紹:

https://wiki.linaro.org/BenjaminGaignard/ion

功能方面:

http://lwn.net/Articles/565469/

使用方面:

http://lwn.net/Articles/480055/

其它參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。