當前位置:首頁 » 安卓系統 » android結構體

android結構體

發布時間: 2023-06-09 18:53:38

『壹』 Android 重學系列 ion驅動源碼淺析

上一篇文章,在解析初始化GraphicBuffer中,遇到一個ion驅動,對圖元進行管理。首先看看ion是怎麼使用的:

我們按照這個流程分析ion的源碼。

如果對ion使用感興趣,可以去這篇文章下面看 https://blog.csdn.net/hexiaolong2009/article/details/102596744

本文基於Android的Linux內核版本3.1.8

遇到什麼問題歡迎來本文討論 https://www.jianshu.com/p/5fe57566691f

什麼是ion?如果是音視頻,Camera的工程師會對這個驅動比較熟悉。最早的GPU和其他驅動協作申請一塊內存進行繪制是使用比較粗暴的共享內存。在Android系統中使用的是匿名內存。最早由三星實現了一個Display和Camera共享內存的問題,曾經在Linux社區掀起過一段時間。之後各路大牛不斷的改進之下,就成為了dma_buf驅動。並在 Linux-3.3 主線版本合入主線。現在已經廣泛的運用到各大多媒體開發中。

首先介紹dma_buf的2個角色,importer和exporter。importer是dma_buf驅動中的圖元消費者,exporter是dma_buf驅動中的圖元生產者。

這里借用大佬的圖片:

ion是基於dma_buf設計完成的。經過閱讀源碼,其實不少思路和Android的匿名內存有點相似。閱讀本文之前就算不知道dma_buf的設計思想也沒關系,我不會仔細到每一行,我會注重其在gralloc服務中的申請流程,看看ion是如何管理共享內存,為什麼要拋棄ashmem。

我們先來看看ion的file_operation:

只有一個open和ioctl函數。但是沒有mmap映射。因此mmap映射的時候一定其他對象在工作。

我們關注顯卡英偉達的初始化模塊。
文件:/ drivers / staging / android / ion / tegra / tegra_ion.c

mole_platform_driver實際上就是我之前經常提到過的mole_init的一個宏,多了一個register注冊到對應名字的平台中的步驟。在這裡面注冊了一個probe方法指針,probe指向的tegra_ion_probe是載入內核模塊注冊的時候調用。

先來看看對應的結構體:

再來看看對應ion內的堆結構體:

完成的事情如下幾個步驟:

我們不關注debug模式。其實整個就是我們分析了很多次的方法。把這個對象注冊miscdevice中。等到insmod就會把整個整個內核模塊從dev_t的map中關聯出來。

我們來看看這個驅動結構體:

文件:/ drivers / staging / android / ion / ion_heap.c

這里有四個不同堆會申請出來,我們主要來看看默認的ION_HEAP_TYPE_SYSTEM對應的heap流程。

其實真正象徵ion的內存堆是下面這個結構體

不管原來的那個heap,會新建3個ion_system_heap,分別order為8,4,0,大於4為大內存。意思就是這個heap中持有一個ion_page_pool 頁資源池子,裡面只有對應order的2的次冪,內存塊。其實就和夥伴系統有點相似。

還會設置flag為ION_HEAP_FLAG_DEFER_FREE,這個標志位後面會用到。

文件:/ drivers / staging / android / ion / ion_page_pool.c

在pool中分為2個鏈表一個是high_items,另一個是low_items。他們之間的區分在此時就是以2為底4的次冪為分界線。

文件:/ drivers / staging / android / ion / ion.c

因為打開了標志位ION_HEAP_FLAG_DEFER_FREE和heap存在shrink方法。因此會初始化兩個回收函數。

文件:/ drivers / staging / android / ion / ion_heap.c

此時會創建一個內核線程,調用ion_heap_deferred_free內核不斷的循環處理。不過由於這個線程設置的是SCHED_IDLE,這是最低等級的時間片輪轉搶占。和Handler那個adle一樣的處理規則,就是閑時處理。

在這個循環中,不斷的循環銷毀處理heap的free_list裡面已經沒有用的ion_buffer緩沖對象。

文件:/ drivers / staging / android / ion / ion_system_heap.c

注冊了heap的銷毀內存的方法。當系統需要銷毀頁的時候,就會調用通過register_shrinker注冊進來的函數。

文件:/ drivers / staging / android / ion / ion_page_pool.c

整個流程很簡單,其實就是遍歷循環需要銷毀的頁面數量,接著如果是8的次冪就是移除high_items中的page緩存。4和0則銷毀low_items中的page緩存。至於為什麼是2的次冪其實很簡單,為了銷毀和申請簡單。__free_pages能夠整頁的銷毀。

文件:/ drivers / staging / android / ion / ion.c

主要就是初始化ion_client各個參數,最後把ion_client插入到ion_device的clients。來看看ion_client結構體:

核心還是調用ion_alloc申請一個ion緩沖區的句柄。最後把數據拷貝會用戶空間。

這個實際上就是找到最小能承載的大小,去申請內存。如果8kb申請內存,就會拆分積分在0-4kb,4kb-16kb,16kb-128kb區間找。剛好dma也是在128kb之內才能申請。超過這個數字就禁止申請。8kb就會拆成2個4kb保存在第一個pool中。

最後所有的申請的page都添加到pages集合中。

文件:/ drivers / staging / android / ion / ion_page_pool.c

能看到此時會從 ion_page_pool沖取出對應大小區域的空閑頁返回上層,如果最早的時候沒有則會調用ion_page_pool_alloc_pages申請一個新的page。由於引用最終來自ion_page_pool中,因此之後申請之後還是在ion_page_pool中。

這里的處理就是為了避免DMA直接內存造成的緩存差異(一般的申請,默認會帶一個DMA標志位)。換句話說,是否打開cache其實就是,關閉了則使用pool的cache,打開了則不使用pool緩存,只依賴DMA的緩存。

我們可以看另一個dma的heap,它是怎麼做到dma內存的一致性.
文件: drivers / staging / android / ion / ion_cma_heap.c

能看到它為了能辦到dma緩存的一致性,使用了dma_alloc_coherent創建了一個所有強制同步的地址,也就是沒有DMA緩存的地址。

這里出現了幾個新的結構體,sg_table和scatterlist

文件:/ lib / scatterlist.c

這裡面實際上做的事情就是一件:初始化sg_table.
sg_table中有一個核心的對象scatterlist鏈表。如果pages申請的對象數量<PAGE_SIZE/sizeof(scatterlist),每一項sg_table只有一個scatterlist。但是超出這個數字就會增加一個scatterlist。

用公式來說:

換句話說,每一次生成scatterlist的鏈表就會直接盡可能占滿一頁,讓內存更好管理。

返回了sg_table。

初始化ion_handle,並且記錄對應的ion_client是當前打開文件的進程,並且設置ion_buffer到handle中。使得句柄能夠和buffer關聯起來。

每當ion_buffer需要銷毀,

『貳』 Android之Binder通信篇

Binder跨進程通信的本質是依賴內核驅動將屬於不同Binder進程的數據,從原始進程復制到目標進程,這樣就完成了跨進程通信了。

Binder通過獨特的內存映射機制,在跨進程通信時,可以做到一次拷貝,兩個空間同時使用!如下圖:

Binder跨進程通信是要傳遞數據的,既然有數據必然要佔用內存空間,Android系統規定每一個進程都有一塊Binder內存區,也就是圖1中的 共享內存 ,系統最多隻能給該區域分配4M的物理內存,由於申請這塊內存是通過系統的mmap函數完成的,所以整個映射機制又被稱為mmap機制
為了把這部分說明白,就再盜圖一張,命名圖2吧!

對於Binder驅動,通過 binder_procs 鏈表記錄所有創建的 binder_proc 結構體,binder 驅動層的每一個 binder_proc 結構體都與用戶空間的一個用於 binder 通信的進程一一對應,且每個進程有且只有一個 ProcessState 對象,這是通過單例模式來保證的。在每個進程中可以有很多個線程,每個線程對應一個 IPCThreadState 對象,IPCThreadState 對象也是單例模式,即一個線程對應一個 IPCThreadState 對象,在 Binder 驅動層也有與之相對應的結構,那就是 Binder_thread 結構體。在 binder_proc 結構體中通過成員變數 rb_root threads,來記錄當前進程內所有的 binder_thread。

Binder 線程池:每個 Server 進程在啟動時創建一個 binder 線程池,並向其中注冊一個 Binder 線程;之後 Server 進程也可以向 binder 線程池注冊新的線程,或者 Binder 驅動在探測到沒有空閑 binder 線程時主動向 Server 進程注冊新的的 binder 線程。對於一個 Server 進程有一個最大 Binder 線程數限制,默認為16個 binder 線程,例如 Android 的 system_server 進程就存在16個線程。對於所有 Client 端進程的 binder 請求都是交由 Server 端進程的 binder 線程來處理的。

『叄』 Android中mmap原理及應用簡析

mmap是Linux中常用的系統調用API,用途廣泛,Android中也有不少地方用到,比如匿名共享內存,Binder機制等。本文簡單記錄下Android中mmap調用流程及原理。mmap函數原型如下:

幾個重要參數

返回值是void *類型,分配成功後,被映射成虛擬內存地址。

mmap屬於系統調用,用戶控制項間接通過swi指令觸發軟中斷,進入內核態(各種環境的切換),進入內核態之後,便可以調用內核函數進行處理。 mmap->mmap64->__mmap2->sys_mmap2-> sys_mmap_pgoff ->do_mmap_pgoff

而 __NR_mmap在系統函數調用表中對應的減值如下:

通過系統調用,執行swi軟中斷,進入內核態,最終映射到call.S中的內核函數:sys_mmap2

sys_mmap2最終通過sys_mmap_pgoff在內核態完成後續邏輯。

sys_mmap_pgoff通過宏定義實現

進而調用do_mmap_pgoff:

get_unmapped_area用於為用戶空間找一塊內存區域,

current->mm->get_unmapped_area一般被賦值為arch_get_unmapped_area_topdown,

先找到合適的虛擬內存(用戶空間),幾經周轉後,調用相應文件或者設備驅動中的mmap函數,完成該設備文件的mmap,至於如何處理處理虛擬空間,要看每個文件的自己的操作了。

這里有個很關鍵的結構體

它是文件驅動操作的入口,在open的時候,完成file_operations的綁定,open流程跟mmap類似

先通過get_unused_fd_flags獲取個未使用的fd,再通過do_file_open完成file結構體的創建及初始化,最後通過fd_install完成fd與file的綁定。

重點看下path_openat:

拿Binder設備文件為例子,在注冊該設備驅動的時候,對應的file_operations已經注冊好了,

open的時候,只需要根根inode節點,獲取到file_operations既可,並且,在open成功後,要回調file_operations中的open函數

open後,就可以利用fd找到file,之後利用file中的file_operations *f_op調用相應驅動函數,接著看mmap。

Binder機制中mmap的最大特點是一次拷貝即可完成進程間通信 。Android應用在進程啟動之初會創建一個單例的ProcessState對象,其構造函數執行時會同時完成binder mmap,為進程分配一塊內存,專門用於Binder通信,如下。

第一個參數是分配地址,為0意味著讓系統自動分配,流程跟之前分子類似,先在用戶空間找到一塊合適的虛擬內存,之後,在內核空間也找到一塊合適的虛擬內存,修改兩個控制項的頁表,使得兩者映射到同一塊物力內存。

Linux的內存分用戶空間跟內核空間,同時頁表有也分兩類,用戶空間頁表跟內核空間頁表,每個進程有一個用戶空間頁表,但是系統只有一個內核空間頁表。而Binder mmap的關鍵是:也更新用戶空間對應的頁表的同時也同步映射內核頁表,讓兩個頁表都指向同一塊地址,這樣一來,數據只需要從A進程的用戶空間,直接拷貝拷貝到B所對應的內核空間,而B多對應的內核空間在B進程的用戶空間也有相應的映射,這樣就無需從內核拷貝到用戶空間了。

binder_update_page_range完成了內存分配、頁表修改等關鍵操作:

可以看到,binder一次拷貝的關鍵是,完成內存的時候,同時完成了內核空間跟用戶空間的映射,也就是說,同一份物理內存,既可以在用戶空間,用虛擬地址訪問,也可以在內核空間用虛擬地址訪問。

普通文件的訪問方式有兩種:第一種是通過read/write系統調訪問,先在用戶空間分配一段buffer,然後,進入內核,將內容從磁碟讀取到內核緩沖,最後,拷貝到用戶進程空間,至少牽扯到兩次數據拷貝;同時,多個進程同時訪問一個文件,每個進程都有一個副本,存在資源浪費的問題。

另一種是通過mmap來訪問文件,mmap()將文件直接映射到用戶空間,文件在mmap的時候,內存並未真正分配,只有在第一次讀取/寫入的時候才會觸發,這個時候,會引發缺頁中斷,在處理缺頁中斷的時候,完成內存也分配,同時也完成文件數據的拷貝。並且,修改用戶空間對應的頁表,完成到物理內存到用戶空間的映射,這種方式只存在一次數據拷貝,效率更高。同時多進程間通過mmap共享文件數據的時候,僅需要一塊物理內存就夠了。

共享內存是在普通文件mmap的基礎上實現的,其實就是基於tmpfs文件系統的普通mmap,有機會再分析,不再啰嗦。

Android中mmap原理及應用簡析

僅供參考,歡迎指正

『肆』 Android通信方式篇(七)-Binder機制(Native層(下))

本篇文章針對向ServiceManager注冊服務 和 獲取服務兩個流程來做總結。在這兩個過程中,ServiceManager都扮演的是服務端,與客戶端之間的通信也是通過Binder IPC。

在此之前先了解下Binder的進程與線程的關系:

用戶空間 :ProcessState描述一個進程,IPCThreadState對應一個進程中的一個線程。
內核空間 :binder_proc描述一個進程,統一由binder_procs全局鏈表保存,binder_thread對應進程的一個線程。
ProcessState與binder_proc是一一對應的。

Binder線程池 :每個Server進程在啟動時會創建一個binder線程池,並向其中注冊一個Binder線程;之後Server進程也可以向binder線程池注冊新的線程,或者Binder驅動在探測到沒有空閑binder線程時會主動向Server進程注冊新的的binder線程。對於一個Server進程有一個最大Binder線程數限制15,(#define DEFAULT_MAX_BINDER_THREADS 15)。對於所有Client端進程的binder請求都是交由Server端進程的binder線程來處理的。我的理解是:binder線程是進程進行binder ipc時的一條數據處理路徑。

MediaPlayerService向ServiceManager注冊過程如下:

相關類:

整個過程總結如下:
1 獲取BpServiceManager 與 BpBinder
由defaultServiceManager()返回的是BpServiceManager,同時會創建ProcessState對象和BpBinder對象。然後通過BpBinder執行transact,把真正工作交給IPCThreadState來處理。

2 BpBinder transact
Binder代理類調用transact()方法,真正工作還是交給IPCThreadState來進行transact工作。

3 通過IPCThreadState 包裝並轉換數據並進行transact事務處理
每個線程都有一個IPCThreadState,每個IPCThreadState中都有一對Parcel變數:mIn、mOut。相當於兩根數據管道:

最後執行talkWithDriver。

writeTransactionData:將BC Protocol + binder_transaction_data結構體 寫入mOut, 然後執行waitForResponse:

由talkWithDriver將數據進一步封裝到binder_write_read結構體,通過ioctl(BINDER_WRITE_READ)與驅動通信。同時等待驅動返回的接收BR命令,從mIn取出返回的數據。

mIn包裝的數據結構(注冊服務handle = 0 ,code 為ADD_SERVICE_TRANSACTION):

4 Binder Driver
把binder_write_read結構體write_buffer里數據取出來,分別得到BC命令和封裝好數據的事務binder_transaction_data, 然後根據handler,在當前binder_proc中,找到相應的binder_ref,由binder_ref再找到目標binder_node實體,由目標binder_node再找到目標進程binder_proc。然後就是插入數據:當binder驅動可以找到合適的線程,就會把binder_transaction節點插入到servciemanager的線程的todo隊列中,如果找不到合適的線程,就把節點之間插入servciemanager的binder_proc的todo隊列。

5 ServiceManager
經過Binder Driver的處理,數據已經到了ServiceManager進程,在BR_TRANSACTION的引導下,在binder_loop()中執行binder_parser()取出數據,執行do_add_service()操作,最終向 svcinfo 列表中添加已經注冊的服務(沒有數據的返回)。最後發送 BR_REPLY 命令喚醒等待的線程,通知注冊成功。結束MediaPlayerService進程 waitForResponse()的狀態,整個注冊過程結束。

獲取服務的過程與注冊類似,首先 ServiceManager 向 Binder 驅動發送 BC_TRANSACTION 命令攜帶 CHECK_SERVICE_TRANSACTION 命令,同時獲取服務的線程進入等待狀態 waitForResponse()。Binder 驅動收到請求命令向 ServiceManager 的發送 BC_TRANSACTION 查詢已注冊的服務,會區分請求服務所屬進程情況。

查詢到直接響應 BR_REPLY 喚醒等待的線程。若查詢不到將與 binder_procs 鏈表中的服務進行一次通訊再響應。

以startService為例來簡單總結下執行流程:

3.1 從方法執行流程來看:

Client :

1 AMP.startService 標記方法以及通過Parcel包裝數據;

2 BinderProxy.transact 實際調用native的 android_os_BinderProxy_transact 傳遞數據;

3 獲取BpServiceManager 與 BpBinder 同時會創建ProcessState。然後通過BpBinder執行transact,把真正工作交給IPCThreadState來處理;

4 IPC.transact 主要執行writeTransactionData,將上層傳來的數據重新包裝成binder_transaction_data,並將BC Protocol + binder_transaction_data結構體 寫入mOut;

5 IPC waitForResponse talkWithDriver + 等待返回數據;

6 talkWithDriver 將數據進一步封裝成binder_write_read,通過ioctl(BINDER_WRITE_READ)與驅動通信;

Kernel :

7 binder ioctl 接收BINDER_WRITE_READ ioctl命令;

8 binder_ioctl_write_read 把用戶空間數據ubuf拷貝到內核空間bwr;

9 binder_thread_write 當bwr寫緩存有數據,則執行binder_thread_write;當寫失敗則將bwr數據寫回用戶空間並退出;

10 binder_transaction 找到目標進程binder_proc並插入數據到目標進程的線程todo隊列,最終執行到它
時,將發起端數據拷貝到接收端進程的buffer結構體;

11 binder_thread_read 根據binder_transaction結構體和binder_buffer結構體數據生成新的binder_transaction_data結構體,寫入bwr的read_buffer,當bwr讀緩存有數據,則執行binder_thread_read;當讀失敗則再將bwr數據寫回用戶空間並退出;最後,把內核數據bwr拷貝到用戶空間ubuf。

12 binder_thread_write + binder_ioctl BR命令和數據傳遞

Server:

13 IPC.executeCommand 解析kernel傳過來的binder_transaction_data數據,找到目標BBinder並調用其transact()方法;

14 IPC.joinThreadPool 採用循環不斷地執行getAndExecuteCommand()方法, 處理事務。當bwr的讀寫buffer都沒有數據時,則阻塞在binder_thread_read的wait_event過程. 另外,正常情況下binder線程一旦創建則不會退出.

15 BBinder.transact 到Binder.exeTransact 調用 AMN.onTransact

16 AMN.onTransact 把數據傳遞到AMS.starService去執行

17 AMS.starService Server處理了Client的請求了

然後原路replay回去,talkWithDriver 到Kernel ,然後找到Client進程,把數據拷貝到read_buffer里,最終喚醒IPC,把反饋傳遞回AMP.startService。完成啟動服務。

3.2 從通信協議流程來看:

非oneWay:

oneway:

oneway與非oneway區別: 都是需要等待Binder Driver的回應消息BR_TRANSACTION_COMPLETE. 主要區別在於oneway的通信收到BR_TRANSACTION_COMPLETE則返回,而不會再等待BR_REPLY消息的到來. 另外,oneway的binder IPC則接收端無法獲取對方的pid.

3.3 從數據流來看

從用戶空間開始:

進入驅動後:

回到用戶空間:

參考:
http://gityuan.com/2016/09/04/binder-start-service/
http://gityuan.com/2015/11/28/binder-summary/
http://gityuan.com/2015/11/14/binder-add-service/
http://gityuan.com/2015/11/15/binder-get-service/

『伍』 Android圖形系統系統篇之HWC

HWC (hwcomposer)是Android中進行窗口( Layer )合成和顯示的HAL層模塊,其實現是特定於設備的,而且通常由顯示設備製造商 (OEM)完成,為 SurfaceFlinger 服務提供硬體支持。

SurfaceFlinger 可以使用 OpenGL ES 合成 Layer ,這需要佔用並消耗GPU資源。大多數GPU都沒有針對圖層合成進行優化,當 SurfaceFlinger 通過GPU合成圖層時,應用程序無法使用GPU進行自己的渲染。而 HWC 通過硬體設備進行圖層合成,可以減輕GPU的合成壓力。

顯示設備的能力千差萬別,很難直接用API表示硬體設備支持合成的 Layer 數量, Layer 是否可以進行旋轉和混合模式操作,以及對圖層定位和硬體合成的限制等。因此HWC描述上述信息的流程是這樣的:

雖然每個顯示設備的能力不同,但是官方要求每個 HWC 硬體模塊都應該支持以下能力:

但是並非所有情況下 HWC 都比GPU更高效,例如:當屏幕上沒有任何變化時,尤其是疊加層有透明像素並且需要進行圖層透明像素混合時。在這種情況下, HWC 可以要求部分或者全部疊加層都進行GPU合成,然後 HWC 持有合成的結果Buffer,如果 SurfaceFlinger 要求合成相同的疊加圖層列表, HWC 可以直接顯示之前合成的結果Buffer,這有助於提高待機設備的電池壽命。

HWC 也提供了 VSync 事件,用於管理渲染和圖層合成時機,後續文章會進行介紹。

Android7.0提供了HWC和HWC2兩個版本,默認使用HWC,但是手機廠商也可以選擇HWC2,如下所示:

SurfaceFlinger 通過 HWComposer 使用 HWC 硬體能力, HWComposer 構造函數通過 loadHwcMole 方法載入HWC模塊,並封裝成 HWC2::Device 結構,如下所示:

上述通過 hw_get_mole 方法(hardware\libhardware\hardware.c)載入 hwcomposer 模塊,此模塊由硬體廠商提供實現,例如:hardware\libhardware\moles\hwcomposer\hwcomposer.cpp是 hwcomposer 模塊基於HWC1的default實現,對應的共享庫是 hwcomposer.default.so ;hardware\qcom\display\msm8994\libhwcomposer\hwc.cpp是高通MSM8994基於HWC1的實現,對應的共享庫是 hwcomposer.msm8994.so 。
如果是基於HWC2協議實現,則需要實現hwcomposer2.h中定義的 hwc2_device_t 介面,例如: class VendorComposer : public hwc2_device_t 。Android7.0的 hwcomposer 模塊默認都是基於HWC1協議實現的。
每個HAL層模塊實現都要定義一個 HAL_MODULE_INFO_SYM 數據結構,並且該結構的第一個欄位必須是 hw_mole_t ,下面是高通MSM8994 hwcomposer 模塊的定義:

frameworks\native\services\surfaceflinger\DisplayHardware\HWC2.h主要定義了以下三個結構體:

它們是對 HWC 硬體模塊的進一步封裝,方便進行調用。 HWC2::Device 持有一個 hwc2_device_t ,用於連接硬體設備,它包含了很多HWC2_PFN開頭的函數指針變數,這些函數指針定義在 hwcomposer2.h 。
在 HWC2::Device 的構造函數中,會通過 Device::loadFunctionPointers -> loadFunctionPointer(FunctionDescriptor desc, PFN& outPFN) -> hwc2_device_t::getFunction 的調用鏈從硬體設備中獲取具體的函數指針實現。關鍵模板函數如下所示:

這些函數指針主要分為三類:

通過上述函數指針可以與 hwc2_device_t 表示的硬體合成模塊進行交互。三類指針分別選取了一個示例:

可以通過類圖,直觀感受下引用關系。

HWC2::Device 構造函數除了完成獲取函數指針實現以外,還會通過 Device::registerCallbacks 向硬體設備注冊三個 Display 的回調:熱插拔,刷新和VSync信號,如下所示:

總結一下, HWC2::Device 構造函數向硬體設備注冊三個 Display 回調:熱插拔,刷新和VSync信號。當 HWC2::Device 收到這些回調時,會通過監聽器向外回調到對應的HWComposer函數: HWComposer::hotplug / HWComposer::invalidate / HWComposer::vsync 。HWComposer再通過這些信息驅動對應工作,後續文章進行介紹。

上文提到 HWC2::Device 中的函數指針是hardware\libhardware\include\hardware\hwcomposer2.h中定義的,除此之外,該頭文件還定義了一些重要的結構體,這里介紹兩個比較重要的:

DisplayType 表示顯示屏類型,上面注釋已經介紹,重點看下Layer合成類型:

那麼一個 Layer 的合成方式是怎麼確定的那?大致流程如下所示:

本篇文章只是簡單介紹了HWC模塊的相關類: HWComposer 、 HWC2::Device 、 HWC2::Display 和 HWC2::Layer ,以及它們的關系。此外,還著重介紹了Layer的合成方式和合成流程。後續文章會更加全面的介紹 SurfaceFlinger 是如何通過HWC模塊完成Layer合成和上屏的(虛擬屏幕是到離屏緩沖區)。

熱點內容
壓縮空氣有啥 發布:2025-02-08 14:26:01 瀏覽:702
python輸入一個數 發布:2025-02-08 14:26:00 瀏覽:448
普惠e卡最初密碼是多少 發布:2025-02-08 14:21:57 瀏覽:474
亞索後q腳本 發布:2025-02-08 14:21:06 瀏覽:324
官方源碼 發布:2025-02-08 14:09:25 瀏覽:437
python過濾器 發布:2025-02-08 14:05:06 瀏覽:617
火山幣演算法 發布:2025-02-08 14:04:49 瀏覽:669
jffs2解壓 發布:2025-02-08 13:55:15 瀏覽:388
如何向伺服器發送大數據包 發布:2025-02-08 13:55:12 瀏覽:662
伺服器pop地址是什麼 發布:2025-02-08 13:39:21 瀏覽:386