葉炳發,孟小華
(暨南大學計算機系 廣州 510632)
Android作為第一個完整、開放、免費的手機平臺,自推出以來就是業界的熱門話題,由于擁有良好的可移植性和強大的功能,在嵌入式設備方面的應用表現出良好的勢頭。在圖形顯示方面,Android建立在Linux上,但并沒有像一些桌面 Linux使用GTK(GIMP Toolkit)組建XWindows(一個多平臺的圖形用戶接口),也沒有使用Cairo向量圖形鏈接庫實現圖形顯示,而是使用了專為Android而改良的一種2D向量圖形處理函數庫Skia。在3D圖形方面是基于嵌入式3D圖形算法標準OpenGL/ES實現的,該庫可以使用硬件加速。然而,雖然Google開放了Android的源代碼,但相關技術文檔很少,而且圖形系統的實現原理比較復雜,所以本文集中對Android圖形系統的底層原理進行研究。
Android SDK的圖形包主要包括android.graphics、android.view、android.widget和 android.opengl,前 3 個是用于 2D的圖形開發,基于 SGL(Skia graphics library)。android.opengl是用于3D的圖形開發,基于OpenGL/ES。
Skia是一個開放源碼的2D向量圖形處理函數庫,包含字型、坐標轉換以及點陣圖,有著高效能且簡潔的表現,在Android平臺中搭配OpenGL/ES與特定的硬件特征強化了顯示效果。OpenGL/ES是OpenGL的一個子集,是一個跨平臺圖形庫,是專門為嵌入式系統而設計的。
Android圖形系統的組成如圖1所示。上層應用調用2D和3D圖形庫對Surface Manager提供的Surface進行繪制,通過Surface Manager的合成器SurfaceFlinger對各個Surface進行合成,并由EGL接口實現在Framebuffer設備上的顯示。

在Android的圖形系統中,Surface Manager是一個重要組成,Surface Manager對上層提供Surface給應用進行繪制,管理對顯示子系統的訪問,對來自多個應用的2D和3D圖像進行無縫的合成后傳給底層的EGL進行處理,Surface Manager的工作原理如圖2所示。

Surface Manager為Application準備一個或多個Surface后,把Surface傳給 Application,讓 Application可以在上面作圖形處理。應用程序先通過調用圖形庫提供基礎的繪制圖形原語和JNI函數,然后又通過Native Method的繪制圖形原語調用2D和3D的圖形庫對Surface進行繪制。
在Android平臺下,每個Surface都有一個Front Buffer和一個Back Buffer,每個窗口都以一個Surface對象作為基礎。每個Surface又對應一個Layer,SurfaceFlinger將各個Layer的Front Buffer合成后繪制到Frame Buffer上。
關于SurfaceFlinger,在Surface Manager中用于管理邏輯上眾多的Surface,其功能特點如下:
·SurfaceFlinger在一個系統范圍內合成Surface的功能,并把合成后的顯示內容傳給幀緩沖設備;
·SurfaceFlinger能一起合成來自多個程序的2D或3D顯示的Surface;
·Surface通過Android的IPC機制Binder以緩沖的形式進行遞交。
從Surface Manager工作原理分析,可以理解Application與Surface Manager是以C/S的模式進行交互的,Application處理Surface的部分是客戶端,而Surface Manager提供服務,它們之間通過Android的IPC機制Binder來協助完成,如圖3所示。

在Binder中,主要包括兩個方面:本地(native),如BnSurfaceFlingerClient,這是一個需要被繼承和實現的類;代理(proxy),如 BpSurfaceFlingerClient,這是一個在接口框架中被實現,但是在接口中沒有體現的類。在客戶端中,BpSurfaceFlingerClient被調用,通過與BnSurfaceFlinger-Client通信,而 BpSurfaceFlingerClient和 BnSurfaceFlinger-Client派生自 ISurfaceFlingerClient,BClient派生自 BnSurface-FlingerClient。
在客戶端中通過類SurfaceComposerClient,調用BnSurfaceComposer和BnSurface來響應服務端BpSurface-Composer和BpSurface,并通過調用 BpSurfaceFlingerClient來調用服務端的BnSurfaceFlingerClient,由此完成了客戶端和服務端的交互。在交互中的3個接口分別介紹如下。
ISurfaceFlingerClient:派生出BpSurfaceFlingerClient和BnSurfaceFlingerClient,由 BClient實現,通過調用createSurface函數創建一個Surface供Application應用。
ISurface:派生出BpSurface和BnSurface,主要完成對Surface的處理,在 Surface(派生自 BnSurface)的函數 lock、unlockAndPost等,實現了Surface在雙緩沖的處理,SurfaceBuffer(派生自Surface)實現了Layer上的處理。
IS urfaceComposer:派生出BpSurfaceComposer和BnSurfaceComposer,SurfaceFlinger(派生自BnSurface Composer)主要為合成器SurfaceFlinger(Surface Manager的組成部分)對Surface合成的相關處理提供實現方法。
在Android平臺中,雙緩沖技術分別在Surface的處理和底層Framebuffer的處理中使用到,在對Framebuffer處理的雙緩沖技術根據OpenGL的標準實現,而對Surface處理的雙緩沖技術則有所不同,下面將對兩種雙緩沖技術進行比較。
在OpenGL中利用雙緩沖技術,分配兩個幀緩沖區,在連續顯示三維曲面時,一個幀緩沖區中的數據執行繪制曲面命令的同時,另一個幀緩沖區中的數據進行圖形顯示。當前可見視頻緩沖稱為前臺視頻緩沖,不可見的、正在繪圖的視頻緩沖稱為后臺視頻緩沖。當后臺視頻幀緩沖中的數據要求顯示時,OpenGL就將它拷貝到前臺視頻幀緩沖,顯示硬件不斷地讀可見視頻緩沖中的內容,并把結果顯示在屏幕上。應用雙緩沖,每一幀三維曲面只在繪制完成后才顯示出來,所以觀察者可以看到每一幀完整三維曲面,而不是曲面的繪制過程。
每個Surface中都帶有兩個幀緩沖區,分別稱為Front Buffer和Back Buffer,與OpenGL中雙緩沖技術有所不同,當繪制Back Buffer后需要顯示時,并沒有將Back Buffer中的數據拷貝到Front Buffer中,而是直接顯示Back Buffer中的數據到屏幕中,從而最大限度地減少了數據的復制。
圖4是使用Canvas繪制Surface的原理,具體過程如下:
·創建一個bitmap與Canvas關聯起來;

·把準備顯示的圖形提交到Canvas上;
· lockCanvas,鎖定 Canvas;
·drawCanvas,把bitmap中的數據寫入到Back Buffer中;
· unlockCanvasAndPost,解鎖 Canvas,Back Buffer替換Front Buffer,替換后Back Buffer作為前臺緩沖,Front Buffer作為后臺緩沖。
OpenGL/ES為附加功能和可能的平臺特性開發了擴展機制,但仍然需要一個可以讓OpenGL/ES和本地視窗系統交互且平臺無關的層。EGL是OpenGL/ES和底層Native平臺視窗系統之間的接口,是為OpenGL/ES提供平臺獨立性而設計。OpenGL/ES本質上是一個圖形渲染管線的狀態機,而EGL則是用于監控這些狀態以及維護Frame Buffer和其他渲染Surface的外部層。
在Android的底層源代碼中,egl_native_window_t是一個提供了對本地窗口的所有定義以及用于EGL操作本地窗口的所有方法的類。EGLNativeSurface派生自egl_native_window_t,EGLDisplaySurface派生自 EGLNativeSurface。EGLDisplay-Surface通過函數 mapFrameBuffer打開 Framebuffer設備,并創建兩個緩沖區,函數swapBuffer把后臺視頻緩沖區復制到前臺視頻緩沖區。DisplayHardware類中初始化了EGL,SurfaceFlinger使用了DisplayHardware去和本地窗口打交道。
Android是基于Linux的,但在Linux的幀緩沖驅動中并沒有直接支持雙緩沖,修改驅動包括兩個方面:一是劃分兩個緩沖區;二是添加緩沖區的切換功能。本文是在PXA270上進行研究的,對應的驅動文件是/drivers/video/pxafb.c。
在Android中,double buffer設計成上下兩個buffer的模式,在函數 pxafb_setmode()“var->yres_virtual=var->yres”修改為“var->yres_virtual=var->yres*2”,在檢查參數的函數pxafb_check_var()中“var->yres_virtual=max(var->yres_virtual,var->yres)”修 改 為 “var->yres_virtual=max(var->yres_virtual,var->yres*2)”。相對應的緩沖長度也要修改為默認的兩邊,即在函數pxafb_decode_mode_info()中添加“smemlen*=2;”。
當一個緩沖區已寫好,在切換時就需要調用到pan函數,該函數將一個新的yoffset傳給LCD控制器。在結構體fb_ops pxafb_ops中添加pan函數,即插入“.fb_pan_display=pxafb_pan_display,”到fb_ops pxafb_ops中。在初始化幀緩沖的函數pxafb_init_fbinfo()中,將“fbi->fb.fix.ypanstep=0;”修改為“fbi->fb.fix.ypanstep=1;”,這里是說明驅動需要用到pan函數。以下是需要添加或修改的函數。


對Android的應用開發來說,圖形開發是其中一個主要工作,了解Android圖形系統的工作原理可以對應用程序性能上的提供有所幫助。在Android移植到其他嵌入式設備中,Android圖形系統的底層驅動移植是其中一個關鍵部分,通過對底層圖形接口以及對幀緩沖驅動移植的研究,將更有效地實現Android在其他嵌入式設備上的移植。
1 宋寶華.Linux設備驅動開發詳解.北京:人民郵電出版社,2008
2 姚昱旻,劉衛國.Android的架構與應用開發研究.計算機系統應用,2008(11)
3 Patrick Brady.Anatomy&Physiology of an Android.http://sites.google.com/site/io/anatomy--physiology-of-an-android
4 David Blythe,Affie Munshi.OpenGL ES 1.0.02 Specification.http://www.khronos.org/registry/gles/specs/1.0/opengles_spec_1_0.pdf