Android應用程序請求SurfaceFlinger服務創建Surface的過程分析

文章轉載至CSDN社區羅升陽的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/7884628

前面我們已經學習過Android應用程序與SurfaceFlinger服務的連接過程了。連接上SurfaceFlinger服務之后,Android應用程序就可以請求SurfaceFlinger服務創建Surface。而當有了Surface后,Android應用程序就可以用來渲染自己的UI了。在本文中,我們將詳細分析Android應用程序請求SurfaceFlinger服務創建Surface的過程。

?? ? ? ?在講述Android應用程序請求SurfaceFlinger服務創建Surface之前,我們首先了解一個Surface是由什么組成的。我們可以將Surface理解為一個繪圖表面,Android應用程序負責往這個繪圖表面填內容,而SurfaceFlinger服務負責將這個繪圖表面的內容取出來,并且渲染在顯示屏上。

?? ? ? ?在SurfaceFlinger服務這一側,繪圖表面使用Layer類來描述,Layer類的實現如圖1所示。


圖1 Layer類的實現

?? ? ? Layer類繼承了LayerBaseClient類;LayerBaseClient類繼承了LayerBase類;LayerBase類繼續了RefBase類。從這些繼承關系就可以看出,我們可以通過Android系統的智能指針來引用Layer對象,從而可以自動地維護它們的生命周期。

?? ? ? Layer類內部的成員變量mUserClientRef指向了一個ClientRef對象,這個ClientRef對象內部有一個成員變量mControlBlock,它指向了一個SharedBufferServer對象。從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文可以知道,SharedBufferServer類是用來在SurfaceFlinger服務這一側描述一個UI元數據緩沖區堆棧的,即在SurfaceFlinger服務中,每一個繪圖表面,即一個Layer對象,都關聯有一個UI元數據緩沖區堆棧。

?? ? ? LayerBaseClient類內部有一個類型為LayerBaseClient::Surface的弱指針,它引用了一個 Layer::SurfaceLayer對象。這個Layer::SurfaceLayer對象是一個Binder本地對象,它是 SurfaceFlinger服務用來與Android應用程序建立通信的,以便可以共同維護一個繪圖表面。

?? ? ? Layer::SurfaceLayer類繼承了LayerBaseClient::Surface類,它的實現如圖2所示。


圖2 SurfaceLayer類的實現

?? ? ? 理解這個圖需要了解Android系統的Binder進程間通信機制,具體可以參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文。從這里就可以看出,Layer::SurfaceLayer類實現了ISurface接口,而Android應用程序就是通過這個接口來和SurfaceFlinger服務共同維護一個繪圖表面的。

?? ? ??Layer::SurfaceLayer類內部有兩個成員變量mFlinger和mOwner,前者指向了SurfaceFlinger服務,而后者指向了其宿主Layer對象。

?? ? ??ISurface接口定義在文件frameworks/base/include/surfaceflinger/ISurface.h中,它有一個重要的成員函數requestBuffer,如下所示:

?

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. class?ISurface?:?public?IInterface??
  2. {??
  3. ????......??
  4. ??
  5. public:??
  6. ????DECLARE_META_INTERFACE(Surface);??
  7. ??
  8. ????/*?
  9. ?????*?requests?a?new?buffer?for?the?given?index.?If?w,?h,?or?format?are?
  10. ?????*?null?the?buffer?is?created?with?the?parameters?assigned?to?the?
  11. ?????*?surface?it?is?bound?to.?Otherwise?the?buffer's?parameters?are?
  12. ?????*?set?to?those?specified.?
  13. ?????*/??
  14. ????virtual?sp<GraphicBuffer>?requestBuffer(int?bufferIdx,??
  15. ????????????uint32_t?w,?uint32_t?h,?uint32_t?format,?uint32_t?usage)?=?0;??
  16. ??
  17. ????......??
  18. ??
  19. };??


?? ? ? ?Android應用程序就是通過ISurface接口的成員函數requestBuffer來請求SurfaceFlinger服務為它的一個繪圖表面分配一個圖形緩沖區的,這個圖形緩沖區使用一個GraphicBuffer對象來描述。

?? ? ? ?由于Layer::SurfaceLayer是一個Binder本地對象類,因此,就相應地有一個Binder代理對象類,它的名稱為BpSurface,它的實現如圖3所示。


圖3 BpSurface類的實現

?? ? ? 理解這個圖同樣需要了解Android系統的Binder進程間通信機制,具體可以參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文。

?? ? ? 以上都是從SurfaceFlinger服務這一側來理解一個Surface,下面我們再從Android應用程序這一側來理解一個Surface。

?? ? ? 在Android應用程序這一側,每一個繪圖表面都使用一個Surface對象來描述,每一個Surface對象都是由一個SurfaceControl對象來創建的。Surface類和SurfaceControl類的關系以及實現如圖4所示。


圖4 Surface類和SurfaceControl類的關系以及實現

?? ? ? SurfaceControl類的成員變量mClient是一個類型為SurfaceComposerClient的強指針,它指向了Android應用程序進程中的一個SurfaceComposerClient單例對象。在前面Android應用程序與SurfaceFlinger服務的連接過程分析一 文中,我們已經看到過SurfaceComposerClient類的作用了,Android應用程序主要就是通過它來和SurfaceFlinger服 務建立連接的,連接的結果就是得到一個類型為Client的Binder代理對象,保存它的成員變量mClient中。

?? ? ?SurfaceControl類的成員變量mSurface是一個類型為ISurface的強指針,它指向了一個類型為BpSurface的 Binder代理對象,而這個Binder代理對象引用的是一個Layer::SurfaceLayer對象。當Android應用程序請求 SurfaceFlinger服務創建一個繪圖表面的時候,SurfaceFlinger服務就會在內部創建一個Layer::SurfaceLayer 對象,并且將這個Layer::SurfaceLayer對象的一個Binder代理對象返回來給Android應用程序,然后Android應用程序再 將這個Binder代理對象保存在一個SurfaceControl對象的成員變量mSurface中。

?? ? ?SurfaceControl類的成員變量mSurfaceData是一個類型為Surface的強指針,它指向了一個Surface對象。

?? ? ?Surface類就是用來在Android應用程序這一側描述繪圖表面的,它的成員變量mSurface與它的宿主類SurfaceControl的成 員變量mSurface指向的是同一個Binder代理對象,即它們都引用了在SurfaceFlinger服務內部所創建的一個類型為 Layer::SurfaceLayer的Binder本地對象。

?? ? ?Surface類的成員變量mClient指向了Android應用程序進程中的一個SurfaceClient單例對象。在前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文中,我們已經介紹過SurfaceClient類的實現了,Android應用程序就是通過它來請求SurfaceFlinger服務創建共享UI元數據的,并且可以通過它來請求SurfaceFlinger服務渲染一個繪圖表面。

?? ? ?Surface類的成員變量mSharedBufferClient指向了一個SharedBufferClient對象。從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文可以知道,SharedBufferClient類是用來在Android應用程序這一側描述一個UI元數據緩沖區堆棧的,即在Android應用程序中,每一個繪圖表面,即一個Surface對象,都關聯有一個UI元數據緩沖區堆棧。

?? ? ?Surface類繼承了EGLNativeBase類,而EGLNativeBase類又繼承了ANativeWindow類。我們知 道,Android系統是通過OpenGL庫來繪制UI的。OpenGL庫在繪制UI的時候,需要底層的系統提供一個本地窗口給它,以便它可以將UI繪制 在這個本地窗口上。Android系統為OpenGL庫定提供的本地窗口使用ANativeWindow類來描述,Surface類通過 EGLNativeBase類間接地繼承了ANativeWindow類,因此,Surface類也是用來描述OpenGL繪圖所需要的一個本地窗口的。 從這個角度出發,我們可以將Surface類看作OpenGL庫與Android的UI系統之間的一個橋梁。

?? ? ?討論到這里,我們就可以知道,一個繪圖表面,在SurfaceFlinger服務和Android應用程序中分別對應有一個Layer對象和一個 Surface對象,這兩個對象在內部分別使用一個SharedBufferServer對象和一個SharedBufferClient對象來描述這個 繪圖表面的UI元數據緩沖堆棧。在前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文中,我們已經分析過這個UI元數據的創建過程了,接下來,我們再簡要看一下SharedBufferServer類和SharedBufferClient類的定義。

?? ? ?SharedBufferServer類和SharedBufferClient類均是從SharedBufferBase類繼承下來的,如圖5所示。


圖5 SharedBufferBase、SharedBufferServer和SharedBufferClient的關系

?? ? ?在基類SharedBufferBase中,有三個成員變量mSharedClient、mSharedStack和mIdentity。成員變量 mSharedClient指向一塊UI元數據緩沖區,即一個SharedClient對象;成員變量mSharedStack指向一個UI元數據堆棧, 即一個SharedBufferStack對象;成員變量mIdentity用來描述一個繪圖表面的ID。

?? ? ?在前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一 文提到,每一個與UI相關的Android應用程序內部都有一個唯一的SharedClient對象,這個SharedClient對象內部有一個 SharedBufferStack數組surfaces,SharedBufferServer類的成員變量mSharedStack所指向的 SharedBufferStack對象,正是成員變量mSharedClient所指向的一個SharedClient對象內部的一個 SharedBufferStack數組的一個元素,這一點可以從SharedBufferServer類的構造函數實現來看出。

?? ? ?SharedBufferServer類的構造函數frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp文件中,如下所示:

?

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. SharedBufferBase::SharedBufferBase(SharedClient*?sharedClient,??
  2. ????????int?surface,?int32_t?identity)??
  3. ????:?mSharedClient(sharedClient),??
  4. ??????mSharedStack(sharedClient->surfaces?+?surface),??
  5. ??????mIdentity(identity)??
  6. {??
  7. }??

?? ? ? 其中,參數surface表示mSharedStack指向的是mSharedClient中的SharedBufferStack數組surfaces的第幾個元素。

?? ? ? 在SharedBufferClient類中,有三個成員變量mNumBuffers、tail和queue_head,它們的含義可以參考前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文中的圖6,如下所示。

圖6 SharedBufferClient眼中的SharedBufferStack?

?? ? ? 在Android應用程序這一側,當它需要渲染一個Surface時,它就會首先找到對應的SharedBufferClient對象,然后再調用它的成 員函數dequeue來請求分配一個UI元數據緩沖區。有了這個UI元數據緩沖區之后,Android應用程序再調用這個 SharedBufferClient對象的成員函數setDirtyRegion、setCrop和setTransform來設置對應的 Surface的裁剪區域、紋理坐標以及旋轉方向。此外,Android應用程序還會請求SurfaceFlinger服務為這個Surface分配一個 圖形緩沖區,以便可以往這個圖形緩沖區寫入實際的UI數據。最后,Android應用程序就可以調用這個SharedBufferClient對象的成員 函數queue把前面已經準備好了的UI元數據緩沖區加入到它所描述的一個UI元數據緩沖區堆棧的待渲染隊列中,以便SurfaceFlinger服務可 以在合適的時候對它進行渲染。這個過程我們在下一篇文章中再詳細分析。

?? ? ??SharedBufferServer類的成員變量mNumBuffers的含義可以參考前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文中的圖7,如下所示。

圖7 SharedBufferServer眼中的SharedBufferStack

?? ? ? ?當SurfaceFlinger服務需要渲染一個Surface的時候,它就會找到對應的一個SharedBufferServer對象,然后調用它的 成員函數getQueueCount來檢查它所描述的一個UI元數據緩沖區堆棧的待渲染隊列的大小。如果這個大小大于0,那么 SurfaceFlinger服務就會繼續調用它的成員函數retireAndLock來取出隊列中的第一個UI元數據緩沖區,以及調用它的成員函數 getDirtyRegion、getCrop和getTransform來獲得要渲染的Surface的裁剪區域、紋理坐標和旋轉方向。最 后,SurfaceFlinger服務就可以結合這些信息來將保存這個Surface的圖形緩沖區中的UI數據渲染在顯示屏中。這個過程我們同樣在下一篇 文章中再詳細分析。

?? ? ??SharedBufferServer類的另外一個成員變量mBufferList指向了一個BufferList對象,這個BufferList對 象是用來管理SharedBufferServer類所描述的一個UI元數據緩沖區堆棧的,接下來我們就簡要分析它的定義。

?? ? ??BufferList類定義在frameworks/base/include/private/surfaceflinger/SharedBufferStack.h文件中,如下所示:

?

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. class?SharedBufferServer??
  2. ????:?public?SharedBufferBase,??
  3. ??????public?LightRefBase<SharedBufferServer>??
  4. {??
  5. ????......??
  6. ??
  7. private:??
  8. ????......??
  9. ??
  10. ????/*?
  11. ?????*?BufferList?is?basically?a?fixed-capacity?sorted-vector?of?
  12. ?????*?unsigned?5-bits?ints?using?a?32-bits?int?as?storage.?
  13. ?????*?it?has?efficient?iterators?to?find?items?in?the?list?and?not?in?the?list.?
  14. ?????*/??
  15. ????class?BufferList?{??
  16. ????????size_t?mCapacity;??
  17. ????????uint32_t?mList;??
  18. ????public:??
  19. ????????BufferList(size_t?c?=?SharedBufferStack::NUM_BUFFER_MAX)??
  20. ????????????:?mCapacity(c),?mList(0)?{?}??
  21. ????????status_t?add(int?value);??
  22. ????????status_t?remove(int?value);??
  23. ????????uint32_t?getMask()?const?{?return?mList;?}??
  24. ??
  25. ????????class?const_iterator?{??
  26. ????????????friend?class?BufferList;??
  27. ????????????uint32_t?mask,?curr;??
  28. ????????????const_iterator(uint32_t?mask)?:??
  29. ????????????????mask(mask),?curr(__builtin_clz(mask))?{??
  30. ????????????}??
  31. ????????public:??
  32. ????????????inline?bool?operator?==?(const?const_iterator&?rhs)?const?{??
  33. ????????????????return?mask?==?rhs.mask;??
  34. ????????????}??
  35. ????????????inline?bool?operator?!=?(const?const_iterator&?rhs)?const?{??
  36. ????????????????return?mask?!=?rhs.mask;??
  37. ????????????}??
  38. ????????????inline?int?operator?*()?const?{?return?curr;?}??
  39. ????????????inline?const?const_iterator&?operator?++()?{??
  40. ????????????????mask?&=?~(1<<(31-curr));??
  41. ????????????????curr?=?__builtin_clz(mask);??
  42. ????????????????return?*this;??
  43. ????????????}??
  44. ????????};??
  45. ??
  46. ????????inline?const_iterator?begin()?const?{??
  47. ????????????return?const_iterator(mList);??
  48. ????????}??
  49. ????????inline?const_iterator?end()?const???{??
  50. ????????????return?const_iterator(0);??
  51. ????????}??
  52. ????????inline?const_iterator?free_begin()?const?{??
  53. ????????????uint32_t?mask?=?(1?<<?(32-mCapacity))?-?1;??
  54. ????????????return?const_iterator(?~(mList?|?mask)?);??
  55. ????????}??
  56. ????};??
  57. ??
  58. ????......??
  59. };??

?? ? ? BufferList類的成員變量mCapacity對應于一個UI元數據緩沖區堆棧的容量,即最大緩沖區個數。

?? ? ? BufferList類的另外一個成員變量變量mList用來描述這個堆棧中的緩沖區哪個是空閑的,哪個是正在使用的。空閑的緩沖區對應的位為0,而正在 使用的緩沖區對應的位為1。舉個例子,假如一個UI元數據緩沖區堆棧的大小為5,其中,第1、3、5個數據緩沖區是正在使用的,而第2、4個數據緩沖區是 空閑的,那么對應的mList的值就等于10101000 00000000 00000000 00000000。當我們需要將第2個數據緩沖區設置為正在使用時,那么只要調用成員函數add來將左起第2位設置為1即可,即得到mList的值就等于 11101000 00000000 00000000 00000000,而當我們需要將第1個數據緩沖區設置為空閑時,那么只要調用成員函數remove來將左起第1位設置為0即可,即得到mList的值就 等于00101000 00000000 00000000 00000000。

?? ? ?在BufferList類內部定義了一個迭代器const_iterator,用來從左到右遍歷一個UI元數據緩沖區堆棧中的正在使用或者空閑的緩沖區。仍然以前面的例子為例,當 我們調用BufferList類的成員函數begin時,就可以得到一個const_iterator迭代器,沿著這個迭代器往前走,就可以依次遍歷第 1、3、5個正在使用的緩沖區,而當我們調用BufferList類的成員函數free_begin時,就可以得到另外一個const_iterator 迭代器,沿著這個迭代器往前走,就可以依次遍歷第2、4個空閑的緩沖區。

?? ? ?關于Surface的概念我們就分析到這里。從這些分析可以知道,當Android應用程序請求SurfaceFlinger服務創建一個 Surface的時候,需要在SurfaceFlinger服務這一側創建一個Layer對象、一個Layer::SurfaceLayer對象和一個 SharedBufferServer對象,同時又需要在Android應用程序這一側創建一個SurfaceControl對象、一個Surface對 象和一個SharedBufferClient對象。

?? ? ?在進一步分析Android應用程序請求SurfaceFlinger服務創建Surface的過程之前,我們首先看一下Android系統的開機動畫 應用程序bootanim是如何請求SurfaceFlinger服務創建一個Surface來顯示開機動畫的。

?? ? ?在前面Android系統的開機畫面顯示過程分析一文中, 我們分析Android系統的開機動畫的顯示過程,其中,開機動畫應用程序bootanim是在BootAnimation類的成員函數readyToRun中請求SurfaceFlinger服務創建一個用來顯示開機動畫的Surface的,如下所示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. status_t?BootAnimation::readyToRun()?{????
  2. ????......??
  3. ??
  4. ????//?create?the?native?surface????
  5. ????sp<SurfaceControl>?control?=?session()->createSurface(????
  6. ????????????getpid(),?0,?dinfo.w,?dinfo.h,?PIXEL_FORMAT_RGB_565);????
  7. ????......????
  8. ????
  9. ????sp<Surface>?s?=?control->getSurface();??
  10. ??
  11. ????......??
  12. }????

?? ? ?BootAnimation類的成員函數session返回的是一個SurfaceComposerClient對象。有了這個 SurfaceComposerClient對象之后,我們就可以調用它的成員函數createSurface來請求請求SurfaceFlinger服 務在內部創建一個Layer::SurfaceLayer對象,并且將這個Layer::SurfaceLayer對象的代理對象返回來給 SurfaceComposerClient類,SurfaceComposerClient類接著就將這個Layer::SurfaceLayer代理 對象封裝成一個SurfaceControl對象,并且返回給BootAnimation類,最后BootAnimation類就可以調用這個 SurfaceControl對象的成員函數getSurface來獲得一個Surface對象。

?? ? ?接下來,我們就從SurfaceComposerClient類的成員函數createSurface開始描述Android應用程序請求SurfaceFlinger服務創建Surface的過程,如圖8所示。

圖8 Android應用程序請求SurfaceFlinger服務創建Surface的過程?

?? ? ? 這個過程可以劃分為20個步驟,接下來我們就詳細分析每一個步驟。

?? ? ? Step 1.?SurfaceComposerClient.createSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<SurfaceControl>?SurfaceComposerClient::createSurface(??
  2. ????????int?pid,??
  3. ????????DisplayID?display,??
  4. ????????uint32_t?w,??
  5. ????????uint32_t?h,??
  6. ????????PixelFormat?format,??
  7. ????????uint32_t?flags)??
  8. {??
  9. ????String8?name;??
  10. ????const?size_t?SIZE?=?128;??
  11. ????char?buffer[SIZE];??
  12. ????snprintf(buffer,?SIZE,?"<pid_%d>",?getpid());??
  13. ????name.append(buffer);??
  14. ??
  15. ????return?SurfaceComposerClient::createSurface(pid,?name,?display,??
  16. ????????????w,?h,?format,?flags);??
  17. }??

?? ? ? 這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SurfaceComposerClient.cpp文件中。

?? ? ? 參數pid用來描述當前進程的PID,參數display的值等于0,表示要在第一個顯示屏上創建一個Surface,參數w和h表示要創建的 Surface的寬度和高度,它們的值剛好等于第一個顯示屏的寬度和高度,參數format的值等于PIXEL_FORMAT_RGB_565,表示要創 建的Surface的像素格式為PIXEL_FORMAT_RGB_565,即每一個點使用2個字節來描述,其中,R、G和B分量分別占5位、6位和5 位,參數flags是一個默認參數,它等于默認值0,表示要創建的Surface的用途。

?? ? ? 這個函數將參數pid格式化成一個字符串之后,再調用SurfaceComposerClient類的另外一個版本的成員函數createSurface來請求SurfaceFlinger服務創建一個Surface,如下所示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<SurfaceControl>?SurfaceComposerClient::createSurface(??
  2. ????????int?pid,??
  3. ????????const?String8&?name,??
  4. ????????DisplayID?display,??
  5. ????????uint32_t?w,??
  6. ????????uint32_t?h,??
  7. ????????PixelFormat?format,??
  8. ????????uint32_t?flags)??
  9. {??
  10. ????sp<SurfaceControl>?result;??
  11. ????if?(mStatus?==?NO_ERROR)?{??
  12. ????????ISurfaceComposerClient::surface_data_t?data;??
  13. ????????sp<ISurface>?surface?=?mClient->createSurface(&data,?pid,?name,??
  14. ????????????????display,?w,?h,?format,?flags);??
  15. ????????if?(surface?!=?0)?{??
  16. ????????????result?=?new?SurfaceControl(this,?surface,?data,?w,?h,?format,?flags);??
  17. ????????}??
  18. ????}??
  19. ????return?result;??
  20. }??


?? ? ? SurfaceComposerClient類的成員變量mClient指向了一個類型為BpSurfaceComposerClient的Binder 代理對象,它引用了一個類型為Client的Binder本地對象。這個類型Client的Binder本地對象是在SurfaceFlinger服務內 部創建的,用來和Android應用程序建立連接。連接的過程可以參考前面Android應用程序與SurfaceFlinger服務的連接過程分析一文。

?? ? ??SurfaceComposerClient類的成員函數createSurface調用成員變量mClient的成員函數 createSurface請求SurfaceFlinger服務創建一個Surface之后,就得到了一個類型為BpSurface的Binder代理 對象surface。從前面的描述可以知道,Binder代理對象surface引用了在SurfaceFlinger服務這一側的一個 Layer::SurfaceLayer對象。此外,SurfaceComposerClient類的成員函數createSurface還得到了一個 surface_data_t對象data,它里面包含了剛才所創建的一個Surface的信息,例如,寬度、高度、像素格式和ID值等。

?? ? ?最后,SurfaceComposerClient類的成員函數createSurface就將SurfaceFlinger服務返回來的Binder 代理對象surface和surface_data_t對象data封裝成一個SurfaceControl對象result,并且返回給調用者。接下 來,我們首先分析SurfaceFlinger服務創建Surface的過程,接著再分析SurfaceControl對象result的封裝過程。

?? ? ?Step 2. Client.createSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<ISurface>?Client::createSurface(??
  2. ????????ISurfaceComposerClient::surface_data_t*?params,?int?pid,??
  3. ????????const?String8&?name,??
  4. ????????DisplayID?display,?uint32_t?w,?uint32_t?h,?PixelFormat?format,??
  5. ????????uint32_t?flags)??
  6. {??
  7. ????return?mFlinger->createSurface(this,?pid,?name,?params,??
  8. ????????????display,?w,?h,?format,?flags);??
  9. }??

?? ? ?這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ?Client類的成員變量mFlinger指向了SurfaceFlinger服務,因此,接下來就會調用SurfaceFlinger類的成員函數createSurface來創建一個Surface。

?? ? ?Step 3.?SurfaceFlinger.createSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<ISurface>?SurfaceFlinger::createSurface(const?sp<Client>&?client,?int?pid,??
  2. ????????const?String8&?name,?ISurfaceComposerClient::surface_data_t*?params,??
  3. ????????DisplayID?d,?uint32_t?w,?uint32_t?h,?PixelFormat?format,??
  4. ????????uint32_t?flags)??
  5. {??
  6. ????sp<LayerBaseClient>?layer;??
  7. ????sp<LayerBaseClient::Surface>?surfaceHandle;??
  8. ??
  9. ????if?(int32_t(w|h)?<?0)?{??
  10. ????????LOGE("createSurface()?failed,?w?or?h?is?negative?(w=%d,?h=%d)",??
  11. ????????????????int(w),?int(h));??
  12. ????????return?surfaceHandle;??
  13. ????}??
  14. ??
  15. ????//LOGD("createSurface?for?pid?%d?(%d?x?%d)",?pid,?w,?h);??
  16. ????sp<Layer>?normalLayer;??
  17. ????switch?(flags?&?eFXSurfaceMask)?{??
  18. ????????case?eFXSurfaceNormal:??
  19. ????????????if?(UNLIKELY(flags?&?ePushBuffers))?{??
  20. ????????????????layer?=?createPushBuffersSurface(client,?d,?w,?h,?flags);??
  21. ????????????}?else?{??
  22. ????????????????normalLayer?=?createNormalSurface(client,?d,?w,?h,?flags,?format);??
  23. ????????????????layer?=?normalLayer;??
  24. ????????????}??
  25. ????????????break;??
  26. ????????case?eFXSurfaceBlur:??
  27. ????????????layer?=?createBlurSurface(client,?d,?w,?h,?flags);??
  28. ????????????break;??
  29. ????????case?eFXSurfaceDim:??
  30. ????????????layer?=?createDimSurface(client,?d,?w,?h,?flags);??
  31. ????????????break;??
  32. ????}??
  33. ??
  34. ????if?(layer?!=?0)?{??
  35. ????????layer->initStates(w,?h,?flags);??
  36. ????????layer->setName(name);??
  37. ????????ssize_t?token?=?addClientLayer(client,?layer);??
  38. ??
  39. ????????surfaceHandle?=?layer->getSurface();??
  40. ????????if?(surfaceHandle?!=?0)?{??
  41. ????????????params->token?=?token;??
  42. ????????????params->identity?=?surfaceHandle->getIdentity();??
  43. ????????????params->width?=?w;??
  44. ????????????params->height?=?h;??
  45. ????????????params->format?=?format;??
  46. ????????????if?(normalLayer?!=?0)?{??
  47. ????????????????Mutex::Autolock?_l(mStateLock);??
  48. ????????????????mLayerMap.add(surfaceHandle->asBinder(),?normalLayer);??
  49. ????????????}??
  50. ????????}??
  51. ??
  52. ????????setTransactionFlags(eTransactionNeeded);??
  53. ????}??
  54. ??
  55. ????return?surfaceHandle;??
  56. }??

?? ? ??這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ? 第一個if語句判斷參數w和h的值是否為負數,如果是的話,那么就直接出錯返回了,因為創建的Surface的寬度和高度值不可能為負數。

?? ? ??eFXSurfaceNormal、eFXSurfaceBlur、eFXSurfaceDim和eFXSurfaceMask是四個枚舉值,它們定 義在文件frameworks/base/include/surfaceflinger/ISurfaceComposer.h中,如下所示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. class?ISurfaceComposer?:?public?IInterface??
  2. {??
  3. public:??
  4. ????......??
  5. ??
  6. ????enum?{?//?(keep?in?sync?with?Surface.java)??
  7. ????????......??
  8. ????????ePushBuffers????????=?0x00000200,??
  9. ??
  10. ????????eFXSurfaceNormal????=?0x00000000,??
  11. ????????eFXSurfaceBlur??????=?0x00010000,??
  12. ????????eFXSurfaceDim???????=?0x00020000,??
  13. ????????eFXSurfaceMask??????=?0x000F0000,??
  14. ????};??
  15. ??
  16. ????......??
  17. };??

?? ? ? 回到SurfaceFlinger類的成員函數createSurface中,參數flags的值等于0,因此,在接下來的switch語句中,會調用 SurfaceFlinger類的成員函數createNormalSurface來在顯示屏上創建一個Layer。順便提一句,如果參數flags的值 等于eFXSurfaceBlur或者eFXSurfaceDim,那么就表示要創建的是一個模糊或者漸變的Surface,這兩種類型的Surface 是在原有的一個Surface上進行創建的,用來對原來的Surface進行模糊或者漸變處理。

?? ? ? ?前面所創建的Layer保存在變量layer中,接下來SurfaceFlinger類的成員函數createNormalSurface會調用來另外 一個成員函數addClientLayer來將它保存在內部的一個列表中,接著再調用前面所創建的Layer的成員函數getSurface來獲得一個 Layer::SurfaceLayer對象surfaceHandle。

?? ? ? ?在將Layer::SurfaceLayer對象surfaceHandle的一個Binder代理對象返回給Android應用程序之 前,SurfaceFlinger類的成員函數createNormalSurface還會以它的一個IBinder接口為關鍵字,將前面所創建的 Layer保存在SurfaceFlinger類的成員變量mLayerMap所描述的一個Map中,這樣就可以將一個 Layer::SurfaceLayer對象surfaceHandle與它的宿主Layer對象關聯起來。

?? ? ? ?接下來,我們首先分析SurfaceFlinger類的成員函數createNormalSurface和addClientLayer的實現,接著再分析Layer的成員函數getSurface的實現,以便可以了解一個Surface的創建的過程。

?? ? ? ?Step 4.?SurfaceFlinger.createNormalSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<Layer>?SurfaceFlinger::createNormalSurface(??
  2. ????????const?sp<Client>&?client,?DisplayID?display,??
  3. ????????uint32_t?w,?uint32_t?h,?uint32_t?flags,??
  4. ????????PixelFormat&?format)??
  5. {??
  6. ????//?initialize?the?surfaces??
  7. ????switch?(format)?{?//?TODO:?take?h/w?into?account??
  8. ????case?PIXEL_FORMAT_TRANSPARENT:??
  9. ????case?PIXEL_FORMAT_TRANSLUCENT:??
  10. ????????format?=?PIXEL_FORMAT_RGBA_8888;??
  11. ????????break;??
  12. ????case?PIXEL_FORMAT_OPAQUE:??
  13. #ifdef?NO_RGBX_8888??
  14. ????????format?=?PIXEL_FORMAT_RGB_565;??
  15. #else??
  16. ????????format?=?PIXEL_FORMAT_RGBX_8888;??
  17. #endif??
  18. ????????break;??
  19. ????}??
  20. ??
  21. #ifdef?NO_RGBX_8888??
  22. ????if?(format?==?PIXEL_FORMAT_RGBX_8888)??
  23. ????????format?=?PIXEL_FORMAT_RGBA_8888;??
  24. #endif??
  25. ??
  26. ????sp<Layer>?layer?=?new?Layer(this,?display,?client);??
  27. ????status_t?err?=?layer->setBuffers(w,?h,?format,?flags);??
  28. ????if?(LIKELY(err?!=?NO_ERROR))?{??
  29. ????????LOGE("createNormalSurfaceLocked()?failed?(%s)",?strerror(-err));??
  30. ????????layer.clear();??
  31. ????}??
  32. ????return?layer;??
  33. }??

?? ? ? 這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ? 函數開頭的switch語句判斷要創建的Surface是否要使用透明色。如果要使用的話,那么就將參數format的值修改為 PIXEL_FORMAT_RGBA_8888。另一方面,如果要創建的Surface不需要使用透明色,那么就將參數format的值修改為 PIXEL_FORMAT_RGB_565或者PIXEL_FORMAT_RGBX_8888,取決于是否定義了宏NO_RGBX_8888。

?? ? ?函數接下來創建了一個Layer對象,并且調用這個Layer對象的成員函數setBuffers來在內部創建一個Layer::SurfaceLayer對象,最后就將這個Layer對象返回給調用者。

?? ? ?接下來,我們首先分析Layer對象的創建過程,接著再分析Layer對象的成員函數setBuffers的實現。

?? ? ?Step 5. new Layer

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. Layer::Layer(SurfaceFlinger*?flinger,??
  2. ????????DisplayID?display,?const?sp<Client>&?client)??
  3. ????:???LayerBaseClient(flinger,?display,?client),??
  4. ????????mGLExtensions(GLExtensions::getInstance()),??
  5. ????????mNeedsBlending(true),??
  6. ????????mNeedsDithering(false),??
  7. ????????mSecure(false),??
  8. ????????mTextureManager(),??
  9. ????????mBufferManager(mTextureManager),??
  10. ????????mWidth(0),?mHeight(0),?mNeedsScaling(false),?mFixedSize(false),??
  11. ????????mBypassState(false)??
  12. {??
  13. }??

?? ? ?這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ?Layer類的構造函數只是執行一些簡單的初始化工作,接下來我們再繼續分析它的進一步初始化工作,這是通過Layer類的成員函數setBuffers來實現的。

?? ? ?Step 6. Layer.setBuffers

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. status_t?Layer::setBuffers(?uint32_t?w,?uint32_t?h,??
  2. ????????????????????????????PixelFormat?format,?uint32_t?flags)??
  3. {??
  4. ????//?this?surfaces?pixel?format??
  5. ????PixelFormatInfo?info;??
  6. ????status_t?err?=?getPixelFormatInfo(format,?&info);??
  7. ????if?(err)?return?err;??
  8. ??
  9. ????//?the?display's?pixel?format??
  10. ????const?DisplayHardware&?hw(graphicPlane(0).displayHardware());??
  11. ????uint32_t?const?maxSurfaceDims?=?min(??
  12. ????????????hw.getMaxTextureSize(),?hw.getMaxViewportDims());??
  13. ??
  14. ????//?never?allow?a?surface?larger?than?what?our?underlying?GL?implementation??
  15. ????//?can?handle.??
  16. ????if?((uint32_t(w)>maxSurfaceDims)?||?(uint32_t(h)>maxSurfaceDims))?{??
  17. ????????return?BAD_VALUE;??
  18. ????}??
  19. ??
  20. ????PixelFormatInfo?displayInfo;??
  21. ????getPixelFormatInfo(hw.getFormat(),?&displayInfo);??
  22. ????const?uint32_t?hwFlags?=?hw.getFlags();??
  23. ??
  24. ????mFormat?=?format;??
  25. ????mWidth??=?w;??
  26. ????mHeight?=?h;??
  27. ??
  28. ????mReqFormat?=?format;??
  29. ????mReqWidth?=?w;??
  30. ????mReqHeight?=?h;??
  31. ??
  32. ????mSecure?=?(flags?&?ISurfaceComposer::eSecure)???true?:?false;??
  33. ????mNeedsBlending?=?(info.h_alpha?-?info.l_alpha)?>?0;??
  34. ??
  35. ????//?we?use?the?red?index??
  36. ????int?displayRedSize?=?displayInfo.getSize(PixelFormatInfo::INDEX_RED);??
  37. ????int?layerRedsize?=?info.getSize(PixelFormatInfo::INDEX_RED);??
  38. ????mNeedsDithering?=?layerRedsize?>?displayRedSize;??
  39. ??
  40. ????mSurface?=?new?SurfaceLayer(mFlinger,?this);??
  41. ????return?NO_ERROR;??
  42. }??

?? ? ??這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ? 參數format是一個整數值,用來描述要創建的Surface的像素格式,函數首先調用另外一個函數getPixelFormatInfo來將它轉換為 一個PixelFormatInfo對象info,以便可以獲得更多的該種類型的像素格式的信息,例如,一個像素點占多少個字節,每個顏色分量又分別占多 少位等。函數getPixelFormatInfo定義文件frameworks/base/libs/ui/PixelFormat.cpp文件中,有 興趣的讀者可以自己研究一下。

?? ? ? Layer類的成員函數graphicPlane是從父類LayerBase繼承下來,用來獲得系統的第N個顯示屏,這個成員函數最終又是通過調用SurfaceFlinger類的成員函數graphicPlane來實現的,如下所示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. const?GraphicPlane&?LayerBase::graphicPlane(int?dpy)?const??
  2. {??
  3. ????return?mFlinger->graphicPlane(dpy);??
  4. }??

?? ? ?SurfaceFlinger類的成員函數graphicPlane的實現如下示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. const?GraphicPlane&?SurfaceFlinger::graphicPlane(int?dpy)?const??
  2. {??
  3. ????LOGE_IF(uint32_t(dpy)?>=?DISPLAY_COUNT,?"Invalid?DisplayID?%d",?dpy);??
  4. ????const?GraphicPlane&?plane(mGraphicPlanes[dpy]);??
  5. ????return?plane;??
  6. }??

?? ? ?SurfaceFlinger類有一個類型為DisplayHardware的數組,它的大小等于4,表示Android系統最多支持4個顯示屏,每一 個顯示屏都使用一個DisplayHardware對象來描述。實際上,Android系統目前只支持一個顯示屏,因此,在調用 SurfaceFlinger類的成員函數graphicPlane的時候,傳進來的參數dpy的值都是等于0。

?? ? ?回到Layer類的成員函數setBuffers中,它接下來獲得了用來描述系統第1個顯示屏的DisplayHardware對象hw,接著再調用函 數getPixelFormatInfo來獲得用來描述該顯示屏的像素格式信息的PixelFormatInfo對象displayInfo。

?? ? ?Layer類的成員函數setBuffers接下來再將要創建的Surface的像素格式以及大小記錄下來,即分別將參數format、w和h的值保存 在成員變量mFormat、mWidth、mHeight和mReqFormat、mReqWidth、mReqHeight中。

?? ? ?Layer類的成員函數setBuffers接下來再檢查參數flags的ISurfaceComposer::eSecure位是否等于1。如果等于 1的話,就將成員變量mSecure的值設置為true,否則就設置為false。當參數flags的 ISurfaceComposer::eSecure位等于1的時候,就表示正在創建的Surface的UI數據是可以安全地從一個進程拷貝到另外一個進 程的。有些Surface的UI數據是不可以隨便拷貝的,因為這涉及到安全問題,例如,用來創建屏幕截圖的Surface的UI數據就是不可以隨便從一個 進程拷貝到另外一個進程的,因為屏幕截圖可能會包含隱私信息。

?? ? ?Layer類的成員函數setBuffers接下來又檢查要創建的Surface的像素格式的Alpha通道的高8位是否大于低8位。如果是的話,就將成員變量mNeedsBlending的值設置為true,表示在渲染時要執行混合操作。

?? ? ?Layer類的成員函數setBuffers接下來還檢查要創建的Surface的像素格式的Red通道的大小是否大于系統第1個顯示屏的像素格式的 Red通道的大小。如果是的話,就將成員變量mNeedsDithering的值設置為true,表示在渲染時要執行抖動操作。

?? ? ?最后,Layer類的成員函數setBuffers就創建了一個SurfaceLayer對象,并且保存成員變量mSurface中。

?? ? ?接下來,我們就繼續分析SurfaceLayer對象的創建過程。

?? ? ?Step 7. new SurfaceLayer

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. Layer::SurfaceLayer::SurfaceLayer(const?sp<SurfaceFlinger>&?flinger,??
  2. ????????const?sp<Layer>&?owner)??
  3. ????:?Surface(flinger,?owner->getIdentity(),?owner)??
  4. {??
  5. }??

?? ? ? 這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ? SurfaceLayer類的構造函數的實現很簡單,它只是使用參數flinger以及owner來初始其父類Surface,其中,參數flinger 指向的是SurfaceFlinger服務,而參數owner指向的是正在創建的SurfaceLayer對象的宿主Layer對象。

?? ? ? 這一步執行完成之后, ?沿著調用路徑返回到SurfaceFlinger類的成員函數createSurface中,這時候就創建好一個Layer對象及其內部的一個 SurfaceLayer對象了,接下來,我們繼續分析SurfaceFlinger類的成員函數addClientLayer的實現,以便可以了解 SurfaceFlinger服務是如何維護它所創建的Layer的,即它所創建的Surface。

?? ? ? Step 8.?SurfaceFlinger.addClientLayer

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. ssize_t?SurfaceFlinger::addClientLayer(const?sp<Client>&?client,??
  2. ????????const?sp<LayerBaseClient>&?lbc)??
  3. {??
  4. ????Mutex::Autolock?_l(mStateLock);??
  5. ??
  6. ????//?attach?this?layer?to?the?client??
  7. ????ssize_t?name?=?client->attachLayer(lbc);??
  8. ??
  9. ????//?add?this?layer?to?the?current?state?list??
  10. ????addLayer_l(lbc);??
  11. ??
  12. ????return?name;??
  13. }??

?? ? ??這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ? 參數client指向了一個Client對象,它是用來描述當前正在請求SurfaceFlinger服務的一個Android應用程序的;參數lbc指 向的是我們在前面Step 4中所創建的一個Layer對象。函數首先調用參數client所指向的一個Client對象的成員函數attachLayer來關聯參數lbc所指向的 一個Layer對象,以表示參數lbc所指向的一個Layer對象是由參數client所指向的一個Client對象所描述的一個Android應用程序 請求創建的,接下來再調用SurfaceFlinger類的成員函數addLayer_l來將參數lbc所指向的一個Layer對象保存在 SurfaceFlinger的內部。

?? ? ? 接下來,我們首先分析Client類的成員函數attachLayer的實現,接著再分析SurfaceFlinger類的成員函數addLayer_l的實現。

?? ? ? Step 9.?Client.attachLayer

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. ssize_t?Client::attachLayer(const?sp<LayerBaseClient>&?layer)??
  2. {??
  3. ????int32_t?name?=?android_atomic_inc(&mNameGenerator);??
  4. ????mLayers.add(name,?layer);??
  5. ????return?name;??
  6. }??

?? ? ??這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ? 從前面Android應用程序與SurfaceFlinger服務的連接過程分析一 文可以知道,Client類的成員變量mNameGenerator是用來生成Surface名稱的,它的初始值等于1,每當Android應用程序請求 SurfaceFlinger服務為它創建一個Surface,SurfaceFlinger服務就會將對應的Client對象的成員變量 mNameGenerator的值增加1,這樣就可以依次得到名稱等于1、2、3......的Surface。

?? ? ? 為正在創建的Surface生成好名稱name之后,Client類的成員函數attachLayer就以變量name為關鍵字,將用來描述正在創建的 Surface的一個Layer對象layer保存Client類的成員變量mLayers所描述的一個Map中。從這里就可以知道,一個Android 應用程序所創建的Surface,都保存在與它所對應的一個Client對象的成員變量mLayers中。

?? ? ?step 10.?SurfaceFlinger.addLayer_l

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. status_t?SurfaceFlinger::addLayer_l(const?sp<LayerBase>&?layer)??
  2. {??
  3. ????ssize_t?i?=?mCurrentState.layersSortedByZ.add(layer);??
  4. ????return?(i?<?0)???status_t(i)?:?status_t(NO_ERROR);??
  5. }??

?? ? ?這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ?SurfaceFlinger類的成員變量mCurrentState指向了一個State對象,這個State對象內部有一個成員變量 layersSortedByZ,它用來描述一個類型為LayerVector的向量,用來保存SurfaceFlinger服務所創建的每一個 Layer,并且這些Layer是按照Z軸坐示來排列的。這樣,SurfaceFlinger服務在渲染Surface的時候,就可以根據這個向量來計算 可見性。

?? ? ?這一步執行完成之后,回到SurfaceFlinger類的成員函數createSurface中,這時候SurfaceFlinger服務就將前面所 創建的一個Layer對象保存好在內部了,接下來就會調用這個Layer對象的成員函數getSurface來獲得在前面Step 6中所創建的一個SurfaceLayer對象,以便可以將它的一個Binder代理對象返回請求Surface的Android應用程序。

?? ? ?Layer類的成員函數getSurface是從父類LayerBaseClient繼承下來的,因此,接下來我們就繼續分析LayerBaseClient類的成員函數getSurface的實現。

?? ? ?Step 11.?LayerBaseClient.getSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<LayerBaseClient::Surface>?LayerBaseClient::getSurface()??
  2. {??
  3. ????sp<Surface>?s;??
  4. ????Mutex::Autolock?_l(mLock);??
  5. ????s?=?mClientSurface.promote();??
  6. ????if?(s?==?0)?{??
  7. ????????s?=?createSurface();??
  8. ????????mClientSurface?=?s;??
  9. ????}??
  10. ????return?s;??
  11. }??

?? ? ? 這個函數定義在文件frameworks/base/services/surfaceflinger/LayerBase.cpp中。

?? ? ??LayerBaseClient類的成員變量mClientSurface是一個類型為Surface的弱指針,它指向了一個Surface子類對 象。函數首先將LayerBaseClient類的成員變量mClientSurface升級為一個強指針s。如果升級失敗,即得到的強指針的值等于0, 那么就說明要么還沒有初始化LayerBaseClient類的成員變量mClientSurface,要么LayerBaseClient類的成員變量 mClientSurface所指向的一個Surface子類對象已經被銷毀了。在這種情況下,函數就會調用由其子類來重寫的成員函數 createSurface來獲得一個Surface子類對象,并且保存在成員變量mClientSurface中。最后再將得到的Surface子類對 象返回給調用者。弱指針升級為強指針的原理,可以參考Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析一文。

?? ? ?在我們這個場景中,LayerBaseClient的子類即為Layer類,因此,接下來我們就繼續分析它的成員函數createSurface的實現。

?? ? ?Step 12. Layer.createSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<LayerBaseClient::Surface>?Layer::createSurface()?const??
  2. {??
  3. ????return?mSurface;??
  4. }??

?? ? ?這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ?從前面的Step 6可以知道,?Layer類的成員變量mSurface已經指向了一個SurfaceLayer對象,因此,函數就可以直接將它返回給調用者。

?? ? ?這一步執行完成之后,回到SurfaceFlinger類的成員函數createSurface中,這時候SurfaceFlinger服務就完成了 Android應用程序所請求創建的Surface了,最后就會將用來描述這個Surface的一個urfaceLayer對象的一個Binder代理對 象返回Android應用程序,以便Android應用程序可以將它封裝成一個SurfaceControl對象,如前面的Step 1所示。

?? ? ?接下來,我們就回到Android應用程序這一側,繼續分析SurfaceControl對象的創建過程。

?? ? ?Step 13. new SurfaceControl

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. SurfaceControl::SurfaceControl(??
  2. ????????const?sp<SurfaceComposerClient>&?client,??
  3. ????????const?sp<ISurface>&?surface,??
  4. ????????const?ISurfaceComposerClient::surface_data_t&?data,??
  5. ????????uint32_t?w,?uint32_t?h,?PixelFormat?format,?uint32_t?flags)??
  6. ????:?mClient(client),?mSurface(surface),??
  7. ??????mToken(data.token),?mIdentity(data.identity),??
  8. ??????mWidth(data.width),?mHeight(data.height),?mFormat(data.format),??
  9. ??????mFlags(flags)??
  10. {??
  11. }??

?? ? ?這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。

?? ? ?SurfaceControl類的構造函數的實現很簡單,它只是對各個成員變量進行初始化,其中,我們需要重點關注的是,SurfaceControl 類的成員變量mSurface指向的是一個類型為BpSurface的Binder代理對象,這個Binder代理對象引用的是由 SurfaceFlinger服務所創建的一個類型為SurfaceLayer的Binder本地對象。

?? ? ?這一步執行完成之后,返回到開機動畫應用程序bootanim中,即BootAnimation類的成員函數readyToRun中,接下來它就會調用 在這一步所創建的SurfaceControl對象的成員函數getSurface來獲得一個Surface對象。

?? ? ?接下來,我們就繼續分析SurfaceControl類的成員函數getSurface的實現。

?? ? ?Step 14. SurfaceControl.getSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. sp<Surface>?SurfaceControl::getSurface()?const??
  2. {??
  3. ????Mutex::Autolock?_l(mLock);??
  4. ????if?(mSurfaceData?==?0)?{??
  5. ????????mSurfaceData?=?new?Surface(const_cast<SurfaceControl*>(this));??
  6. ????}??
  7. ????return?mSurfaceData;??
  8. }??

?? ? ?這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。

?? ? ?SurfaceControl類的成員函數getSurface第一次被調用時,成員變量mSurfaceData的值等于0,因此,函數接下來就會創建一個Surface對象,并且保存在成員變量mSurfaceData中。

?? ? ?接下來,我們就繼續分析Surface對象的創建過程。

?? ? ?Step 15. new Surface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. Surface::Surface(const?sp<SurfaceControl>&?surface)??
  2. ????:?mBufferMapper(GraphicBufferMapper::get()),??
  3. ??????mClient(SurfaceClient::getInstance()),??
  4. ??????mSharedBufferClient(NULL),??
  5. ??????mInitCheck(NO_INIT),??
  6. ??????mSurface(surface->mSurface),??
  7. ??????mIdentity(surface->mIdentity),??
  8. ??????mFormat(surface->mFormat),?mFlags(surface->mFlags),??
  9. ??????mWidth(surface->mWidth),?mHeight(surface->mHeight)??
  10. {??
  11. ????init();??
  12. }??

?? ? ? 這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。

?? ? ? Surface類的成員變量mBufferMapper指向了一個GraphicBufferMapper對象,它是用來將分配到的圖形緩沖區映射到 Android應用程序進程的地址空間的,在接下來的一篇文章介紹Surface的渲染過程時,我們再詳細分析。

?? ? ? Surface類的成員變量mClient指向了Android應用程序進程中的一個SurfaceClient單例。從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一 文可以知道,這個SurfaceClient單例是有來創建Android應用程序與SurfaceFlinger服務的共享UI元數據的。當 SurfaceClient類的成員函數getInstance第一次在進程中被調用時,Android應用程序便會請求SurfaceFlinger服 務創建這塊共享UI元數據。

?? ? ? Surface類的成員變量mSharedBufferClient指向了一個SharedBufferClient對象。文章開始時提 到,SharedBufferClient是用來在Android應用程序這一側描述一個Surface的UI元數據緩沖區堆棧的,后面我們再分析它的創 建過程。

?? ? ??Surface類的成員變量mSurface指向了一個類型為BpSurface的Binder代理對象。從Surface類的構造函數就可以看出,這個Binder代理對象引用的是在前面Step 6中創建的一個SurfaceLayer對象。

?? ? ??Surface類的其余成員變量mIdentity、mFormat、mFlags、mWidth和mHeight分別用來描述一個Surface的ID、像素格式、用途、寬度和高度。

?? ? ??Surface類的構造函數接下來調用另外一個成員函數init進一步執行初始化的工作,接下來,我們就繼續分析Surface類的成員函數init的實現。

?? ? ? Step 16. Surface.init

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. void?Surface::init()??
  2. {??
  3. ????ANativeWindow::setSwapInterval??=?setSwapInterval;??
  4. ????ANativeWindow::dequeueBuffer????=?dequeueBuffer;??
  5. ????ANativeWindow::cancelBuffer?????=?cancelBuffer;??
  6. ????ANativeWindow::lockBuffer???????=?lockBuffer;??
  7. ????ANativeWindow::queueBuffer??????=?queueBuffer;??
  8. ????ANativeWindow::query????????????=?query;??
  9. ????ANativeWindow::perform??????????=?perform;??
  10. ??
  11. ????DisplayInfo?dinfo;??
  12. ????SurfaceComposerClient::getDisplayInfo(0,?&dinfo);??
  13. ????const_cast<float&>(ANativeWindow::xdpi)?=?dinfo.xdpi;??
  14. ????const_cast<float&>(ANativeWindow::ydpi)?=?dinfo.ydpi;??
  15. ????//?FIXME:?set?real?values?here??
  16. ????const_cast<int&>(ANativeWindow::minSwapInterval)?=?1;??
  17. ????const_cast<int&>(ANativeWindow::maxSwapInterval)?=?1;??
  18. ????const_cast<uint32_t&>(ANativeWindow::flags)?=?0;??
  19. ??
  20. ????mNextBufferTransform?=?0;??
  21. ????mConnected?=?0;??
  22. ????mSwapRectangle.makeInvalid();??
  23. ????mNextBufferCrop?=?Rect(0,0);??
  24. ????//?two?buffers?by?default??
  25. ????mBuffers.setCapacity(2);??
  26. ????mBuffers.insertAt(0,?2);??
  27. ??
  28. ????if?(mSurface?!=?0?&&?mClient.initCheck()?==?NO_ERROR)?{??
  29. ????????int32_t?token?=?mClient.getTokenForSurface(mSurface);??
  30. ????????if?(token?>=?0)?{??
  31. ????????????mSharedBufferClient?=?new?SharedBufferClient(??
  32. ????????????????????mClient.getSharedClient(),?token,?2,?mIdentity);??
  33. ????????????mInitCheck?=?mClient.getSharedClient()->validate(token);??
  34. ????????}??
  35. ????}??
  36. }??

?? ? ? 這個函數定義在文件frameworks/base/libs/surfaceflinger_client/Surface.cpp中。

?? ? ? 這個函數的初始化工作分為兩部分。

?? ? ? 第一部分初始化工作是與OpenGL庫相關的,主要就是設置OpenGL指定的一系列回調接口,以及設置設備顯示屏信息。前面提到,Surface類是從 ANativeWindow類繼承下來的,作為OpenGL庫與Android系統的本地窗口的連接橋梁。

?? ? ? ANativeWindow類定義了setSwapInterval、dequeueBuffer、cancelBuffer、lockBuffer、 queueBuffer、query和perform一共7個回調接口,它們分別被設置為Surface類的靜態成員函數 setSwapInterval、dequeueBuffer、cancelBuffer、lockBuffer、queueBuffer、query和 perform。我們主要關注dequeueBuffer和queueBuffer兩個回調接口,前者用來從UI元數據緩沖區堆棧中獲得一個緩沖區,而后 者用來將一個緩沖區插入到UI元數據緩沖區堆棧的待渲染隊列中。在接下來的一篇文章介紹Surface的渲染過程時,我們再詳細分析這兩個回調接口。

?? ? ?ANativeWindow類還定義了四個成員變量xdpi、ydpi、minSwapInterval、maxSwapInterval和 flags,這幾個成員變量也是要由Surface類來初始化的。成員變量xdpi和ydpi用來描述設備顯示度的密度,即每英寸點數。設備顯示屏的密碼 信息可以通過調用SurfaceComposerClient類的靜態成員函數getDisplayInfo來獲得。成員變量 minSwapInterval和maxSwapInterval用來描述前后兩個緩沖區進行交換的最小和最大時間間隔。成員變量flags用來描述一些 標志信息。

?? ? ?第二部分初始化工作是與UI元數據緩沖區相關。

?? ? ?Surface類的成員變量mNextBufferTransform、mSwapRectangle和mNextBufferCrop分別用來描述下一個要渲染的圖形緩沖區的旋轉方向、裁剪區域和紋理坐標。

?? ? ?Surface類的成員變量mBuffers用來描述一個類型為sp<GraphicBuffer>的Vector,主要是用來保存一個 Surface所使用的圖形緩沖區(GraphicBuffer)的。一開始的時候,這個向量的大小被設置為2,后面會根據實際需要來增加容量。

?? ? ?Surface類的成員變量mSharedBufferClient指向了一個SharedBufferClient對象,用來描述一個UI元數據緩沖區堆棧,它的創建過程是最重要的,因此,接下來我們就詳細分析這個過程。

?? ? ?Surface類的成員函數init首先調用成員變量mClient的成員函數getTokenForSurface來獲得成員變量mSurface所 描述的一個Surface的token值。有了這個token值之后,接下就可以創建一個SharedBufferClient對象,并且保存 在?Surface類的成員變量mSharedBufferClient中了。

?? ? ?在前面的Step 15中提到,Surface類的成員變量mClient指向的是一個SurfaceClient對象,因此,接下來我們首先分析 SurfaceClient類的成員函數getTokenForSurface的實現,接著再分析SharedBufferClient對象的創建過程。

?? ? ?從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一 文可以知道,SurfaceClient類的成員函數getTokenForSurface實際上是調用了其成員變量mClient所指向的一個類型為 BpSurfaceComposerClient的Binder代理對象的成員函數getTokenForSurface來請求 SurfaceFlinger服務返回一個Surface的token值。由于這個Binder代理對象引用的是一個類型為UserClient的 Binder本地對象,這個Binder本地對象是運行在SurfaceFlinger服務這一側的。接下來,我們就直接分析UserClient類的成 員函數getTokenForSurface的實現。

?? ? ?Step 17.?UserClient.getTokenForSurface

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. ssize_t?UserClient::getTokenForSurface(const?sp<ISurface>&?sur)?const??
  2. {??
  3. ????int32_t?name?=?NAME_NOT_FOUND;??
  4. ????sp<Layer>?layer(mFlinger->getLayer(sur));??
  5. ????if?(layer?==?0)?return?name;??
  6. ??
  7. ????//?if?this?layer?already?has?a?token,?just?return?it??
  8. ????name?=?layer->getToken();??
  9. ????if?((name?>=?0)?&&?(layer->getClient()?==?this))??
  10. ????????return?name;??
  11. ??
  12. ????name?=?0;??
  13. ????do?{??
  14. ????????int32_t?mask?=?1LU<<name;??
  15. ????????if?((android_atomic_or(mask,?&mBitmap)?&?mask)?==?0)?{??
  16. ????????????//?we?found?and?locked?that?name??
  17. ????????????status_t?err?=?layer->setToken(??
  18. ????????????????????const_cast<UserClient*>(this),?ctrlblk,?name);??
  19. ????????????if?(err?!=?NO_ERROR)?{??
  20. ????????????????//?free?the?name??
  21. ????????????????android_atomic_and(~mask,?&mBitmap);??
  22. ????????????????name?=?err;??
  23. ????????????}??
  24. ????????????break;??
  25. ????????}??
  26. ????????if?(++name?>=?SharedBufferStack::NUM_LAYERS_MAX)??
  27. ????????????name?=?NO_MEMORY;??
  28. ????}?while(name?>=?0);??
  29. ??
  30. ????//LOGD("getTokenForSurface(%p)?=>?%d?(client=%p,?bitmap=%08lx)",??
  31. ????//????????sur->asBinder().get(),?name,?this,?mBitmap);??
  32. ????return?name;??
  33. }??

?? ? ? 這個函數定義在文件frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp中。

?? ? ? 從前面的調用過程可以知道,參數sur指向了一個SurfaceLayer對象,并且這個SurfaceLayer對象是在前面的Step 6中創建的。

?? ? ? UserClient類的成員變量mFlinger指向了SurfaceFlinger服務,函數首先調用它的成員函數getLayer來獲得參數sur 所指向的SurfaceLayer對象的宿主Layer對象layer,接著調用這個Layer對象layer的成員函數getToken來獲得它的 token值。如果這個token值大于等于0,那么就說明已經為Layer對象layer分配過token值了,即已經為參數sur所描述的 Surface分配過token值了。在這種情況下,就直接將該token值返回給Android應用程序。否則的話,UserClient類的成員函數 getTokenForSurface接下來就需要為參數sur所描述的Surface分配一個token值。

?? ? ??UserClient類的成員變量mBitmap是一個int32_t值,它是用來為Android應用程序的Surface分配Token值的,即 如果它的第n位等于1,那么就表示值等于n的Token已經被分配出去使用了。UserClient類的成員函數getTokenForSurface使 用一個while循環來在成員變量mBitmap中從低位到高位找到一個值等于0的位,接著再將位所在的位置值作為參數sur所描述的一個Surface 的token值,最后還會將這個token值設置到Layer對象layer里面去,這是通過調用Layer類的成員函數setToken來實現的。

?? ? ?接下來,我們就繼續分析Layer類的成員函數setToken的實現。

?? ? ?Step 18. Layer.setToken

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. status_t?Layer::setToken(const?sp<UserClient>&?userClient,??
  2. ????????SharedClient*?sharedClient,?int32_t?token)??
  3. {??
  4. ????sp<SharedBufferServer>?lcblk?=?new?SharedBufferServer(??
  5. ????????????sharedClient,?token,?mBufferManager.getDefaultBufferCount(),??
  6. ????????????getIdentity());??
  7. ??
  8. ????status_t?err?=?mUserClientRef.setToken(userClient,?lcblk,?token);??
  9. ??
  10. ????LOGE_IF(err?!=?NO_ERROR,??
  11. ????????????"ClientRef::setToken(%p,?%p,?%u)?failed",??
  12. ????????????userClient.get(),?lcblk.get(),?token);??
  13. ??
  14. ????if?(err?==?NO_ERROR)?{??
  15. ????????//?we?need?to?free?the?buffers?associated?with?this?surface??
  16. ????}??
  17. ??
  18. ????return?err;??
  19. }??

?? ? ??這個函數定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ? 參數userClient指向了一個UserClient對象,而參數sharedClient指向了該UserClient對象內部的成員變量ctrlblk所指向的一個SharedClient對象。從前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文可以知道,這個SharedClient對象是用來描述一組UI元數據緩沖區堆棧的。

?? ? ? Layer類的成員變量mBufferManager指向了一個BufferManager對象,通過調用它的成員函數 getDefaultBufferCount就可以獲得一個UI元數據緩沖區堆棧的大小,即這個堆棧里面所包含的UI元數據緩沖區的個數。有了這些信息之 后,Layer類的成員函數setToken就可以創建一個SharedBufferServer對象lcblk了,并且會將這個 SharedBufferServer對象lcblk保存在Layer類的成員變量mUserClientRef所描述的一個ClientRef對象的內 部。這是通過調用ClientRef類的成員函數setToken來實現的,如下所示:

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. status_t?Layer::ClientRef::setToken(const?sp<UserClient>&?uc,??
  2. ????????const?sp<SharedBufferServer>&?sharedClient,?int32_t?token)?{??
  3. ????Mutex::Autolock?_l(mLock);??
  4. ??
  5. ????{?//?scope?for?strong?mUserClient?reference??
  6. ????????sp<UserClient>?userClient(mUserClient.promote());??
  7. ????????if?(mUserClient?!=?0?&&?mControlBlock?!=?0)?{??
  8. ????????????mControlBlock->setStatus(NO_INIT);??
  9. ????????}??
  10. ????}??
  11. ??
  12. ????mUserClient?=?uc;??
  13. ????mToken?=?token;??
  14. ????mControlBlock?=?sharedClient;??
  15. ????return?NO_ERROR;??
  16. }??

?? ? ?這個函數同樣是定義在文件frameworks/base/services/surfaceflinger/Layer.cpp中。

?? ? ?ClientRef類有三個成員變量mUserClient、mToken和mControlBlock。其中,mUserClient是一個類型為 UserClient的弱指針,它指向了參數uc所描述的一個UserClient對象,mToken是一個int32_t值,用來描述它的宿主 Layer對象的token值,mControlBlock是一個類型為SharedBufferServer強指針,它指向了參數 sharedCient所描述一個haredBufferServer對象,用來在SurfaceFlinger服務這一側描述一個UI元數據緩沖區堆 棧。

?? ? 回到Layer類的成員函數setToken中,接下來我們繼續分析一個SharedBufferServer對象的創建過程。

?? ? Step 19. new SharedBufferServer

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. SharedBufferServer::SharedBufferServer(SharedClient*?sharedClient,??
  2. ????????int?surface,?int?num,?int32_t?identity)??
  3. ????:?SharedBufferBase(sharedClient,?surface,?identity),??
  4. ??????mNumBuffers(num)??
  5. {??
  6. ????mSharedStack->init(identity);??
  7. ????mSharedStack->token?=?surface;??
  8. ????mSharedStack->head?=?num-1;??
  9. ????mSharedStack->available?=?num;??
  10. ????mSharedStack->queued?=?0;??
  11. ????mSharedStack->reallocMask?=?0;??
  12. ????memset(mSharedStack->buffers,?0,?sizeof(mSharedStack->buffers));??
  13. ????for?(int?i=0?;?i<num?;?i++)?{??
  14. ????????mBufferList.add(i);??
  15. ????????mSharedStack->index[i]?=?i;??
  16. ????}??
  17. }??

?? ? ? 這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。

?? ? ??SharedBufferServer類的構造函數主要是用來初始它所描述的一個UI元數據緩沖區堆棧的,這個UI元數據緩沖區堆棧是通過其父類的成 員變量mSharedStack所指向的一個SharedBufferStack對象來描述的。SharedBufferStack類的各個成員變量的含 義可以參考前面前面Android應用程序與SurfaceFlinger服務之間的共享UI元數據(SharedClient)的創建過程分析一文,這里不再復述。

?? ? ? 這一步執行完成之后,沿著調用路徑,一直返回到前面的Step 16中,即Surface類的成員函數init中,這時候Android應用程序就獲得了正在創建的Surface的token值,接下來就可以以這個 token值為參數,來創建一個SharedBufferClient對象了。

?? ? ? Step 20. new SharedBufferClient

[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. SharedBufferClient::SharedBufferClient(SharedClient*?sharedClient,??
  2. ????????int?surface,?int?num,?int32_t?identity)??
  3. ????:?SharedBufferBase(sharedClient,?surface,?identity),??
  4. ??????mNumBuffers(num),?tail(0)??
  5. {??
  6. ????SharedBufferStack&?stack(?*mSharedStack?);??
  7. ????tail?=?computeTail();??
  8. ????queued_head?=?stack.head;??
  9. }??

?? ? ??這個函數定義在文件frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp中。

?? ? ??SharedBufferClient類的構造函數主要是用來初始化成員變量tail和queued_head的值。這兩個成員變量的含義可以參考前 面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃一文中的圖6,這里不再詳述。

?? ? ? 這里我們需要注意的是,這里的參數sharedClient指向了一個SharedClient對象,這個SharedClient對象與在前面Step 18中用來創建SharedBufferServer對象的SharedClient對象描述的是同一塊匿名共享內存,而且這里的參數surface與在 前面Step 18中用來創建SharedBufferServer對象的token的值是相等的,這意味著這一步所創建的SharedBufferClient對象與 前面Step 19所創建的SharedBufferServer對象描述的是同一個SharedBufferStack對象,即同一個UI元數據緩沖區堆棧,并且這個 UI元數據緩沖區堆棧已經在前面的Step 19中初始化好了。

?? ? ? 至此,Android應用程序請求SurfaceFlinger服務創建Surface的過程就分析完成了。我們需要重點掌握的是,當Android應用 程序請求SurfaceFlinger服務創建一個Surface的時候,需要在SurfaceFlinger服務這一側創建一個Layer對象、一個 Layer::SurfaceLayer對象和一個SharedBufferServer對象,同時又需要在Android應用程序這一側創建一個 SurfaceControl對象、一個Surface對象和一個SharedBufferClient對象。掌握了這些知識之后,在接下來的一篇文章 中,我們就可以分析Android應用程序請求SurfaceFlinger服務渲染Surface的過程了,敬請期待!

老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關注!

轉載于:https://www.cnblogs.com/Free-Thinker/p/4142600.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376429.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376429.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376429.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Oracle面試題(基礎篇)

1. Oracle跟SQL Server 2005的區別&#xff1f; 宏觀上&#xff1a; 1). 最大的區別在于平臺&#xff0c;oracle可以運行在不同的平臺上&#xff0c;sql server只能運行在windows平臺上&#xff0c;由于windows平臺的穩定性和安全性影響了sql server的穩定性和安全性 2). oracl…

160 - 23 Chafe.1

環境 Windows xp sp3 工具 exeinfope ollydbg 查殼 用exeinfoe查殼 測試 可以從左下角狀態欄看出serial是無效的 直接OD載入字符串搜索 00401274 |. /75 17 jnz XChafe_1.0040128D 00401276 |. |6A 00 push 0x0 ; /Ti…

fis 詳細介紹(mac版) - 12-26沒有弄完 - 暫停

fis可以讓fe進入角色&#xff0c;而不必擔心底層的架構&#xff0c;性能得到優化。僅需三條命令&#xff0c;即可解決所有前端開發要求fis是nodejs寫的&#xff0c;發布在vpn(&#xff1f;)上下載 www.nodejs.org&#xff0c;并安裝nodejs&#xff0c;其中包括npm安裝fis: sudo…

用文件模擬CMOS保存數據

Hi3520D 芯片的內置CMOS最多只有5個字節可以用&#xff0c;但是我需要保存的數據有很多。 其中一個解決辦法是&#xff1a;可以把其他需要保存的數據放到一個配置文件中。每次寫的時候寫到配置文件&#xff0c;用的時候再從配置文件讀出數據即可。 用文件寫&#xff1a; 1 stat…

160 - 24 Chafe.2

環境&#xff1a; Windows xp sp3 工具 exeinfope OllyDBG 查殼 用exeinfope查殼&#xff0c;發現是沒有殼的。 測試 可以看出是從紅色框框里面的內容判斷serial是否有效 OD載入&#xff0c;字符串搜索可以得到&#xff1a; 004011EC . 55 pus…

十個利用矩陣乘法解決的經典題目

轉載自 Matrix67: The Aha Moments 好像目前還沒有這方面題目的總結。這幾天連續看到四個問這類題目的人&#xff0c;今天在這里簡單寫一下。這里我們不介紹其它有關矩陣的知識&#xff0c;只介紹矩陣乘法和相關性質。 不要以為數學中的矩陣也是黑色屏幕上不斷變化的綠色…

[C++]搞清楚類中構造與析構的順序

定義一個類對象時&#xff0c;首先根據初始化列表初始化類的成員&#xff08;就算沒有顯式定義初始化列表&#xff0c;編譯器也會默認地初始化一次&#xff09;&#xff0c;然后運行構造函數。因此&#xff0c;類成員的構造函數必定先于類的構造函數運行。 class A { public:A(…

160 - 25 CodeZero.1

環境 Windows xp sp3 工具 exeinfope OllyDBG 查殼 無殼的VB程序 測試 運行程序后出現Nag窗口&#xff0c;所以這次的目標是除Nag窗口和找到serial 程序運行后彈出Nag窗口&#xff0c;并且等待5秒后按鈕的標題改成“Continue..”&#xff0c;點擊后才會彈出輸入seria…

WP8開發學習筆記動態修改啟動時導航的第一個頁面(如登錄前啟動頁為LoginPage,登錄后變為MainPage)...

很多時候我們需要在啟動程序的時候根據狀態改變初始導航頁面&#xff0c;比如程序在啟動的時候判斷用戶是否登錄&#xff0c; 如果未登錄則跳轉到LoginPage.xaml否則跳轉到MainPage界面。 這時候就要分析程序的啟動和導航的過程。 程序的啟動是App.xamlcs負責的。 App類的構造器…

6.數組和Hash表

當顯示多條結果時&#xff0c;存儲在變量中非常智能&#xff0c;變量類型會自動轉換為一個數組。 在下面的例子中&#xff0c;使用GetType()可以看到$a變量已經不是我們常見的string或int類型&#xff0c;而是Object類型&#xff0c;使用-is操作符來判斷是否是個數組&#xff0…

160 - 26 Colormaster

環境 Windows xp sp3 查殼 無殼的VB程序 測試&#xff1a; 輸入 Name:123456 Serial:12345 字符串搜索&#xff0c;找到判斷位置。 判斷Name的長度要大于等于5&#xff1a; 00402CBC . 33C9 xor ecx,ecx 00402CBE . 83F8 04 cmp eax,0x4 00…

Android 菜單(OptionMenu)大全 建立你自己的菜單

菜單是用戶界面中最常見的元素之一&#xff0c;使用非常頻繁&#xff0c;在Android中&#xff0c;菜單被分為如下三種&#xff0c;選項菜單&#xff08;OptionsMenu&#xff09;、上下文菜單&#xff08;ContextMenu&#xff09;和子菜單&#xff08;SubMenu&#xff09;&#…

160 - 27 Cosh.1

環境 Windows XP sp3 工具 exeinfope ollydbg 查殼 無殼的MFC程序 測試 彈出這個&#xff1a; 是一個CD-CHECK保護的程序。 字符串搜索&#xff0c;一下子就能來到這里&#xff1a; 0040121A . 68 9C304000 push Cosh_1.0040309C …

什么時候加上android.intent.category.DEFAULT

1、要弄清楚這個問題&#xff0c;首先需要弄明白什么是implicit(隱藏) intent什么是explicit(明確) intent。 Explicit Intent明確的指定了要啟動的Acitivity &#xff0c;比如以下Java代碼&#xff1a; Intent intent new Intent(this, B.class) Implicit Intent沒有明確的指…

[BZOJ 2165] 大樓 【DP + 倍增 + 二進制】

題目鏈接&#xff1a;BZOJ - 2165 題目分析&#xff1a; 這道題我讀了題之后就想不出來怎么做&#xff0c;題解也找不到&#xff0c;于是就請教了黃學長&#xff0c;黃學長立刻秒掉了這道題&#xff0c;然后我再看他的題解才寫出來。。Orz 使用 DP 倍增 &#xff0c;用狀態 f[…

oracle創建表空間

注意點&#xff1a; 1.如果在PL/SQL 等工具里打開的話&#xff0c;直接修改下面的代碼中[斜體加粗部分]執行 2.確保路徑存在&#xff0c;比如【D:\oracle\oradata\Oracle9i\】也就是你要保存文件的路徑存在 /*分為四步 */ /*第1步&#xff1a;創建臨時表空間 */ create tempor…

160 - 28 CoSH.2

環境 Windows xp sp3 工具 exeinfope ollydbg 查殼 無殼的MFC程序 測試 輸入 Nmae:123456 Serial:12345 點擊“CHECK”后彈出錯誤提示的消息框&#xff0c;然后程序自己結束掉 依然是字符串搜索&#xff1a; 004014DB . 8B1D FC214000 mov ebx,dword ptr ds…

負載均衡情況下獲取真實ip的方法

公司用了硬件負載均衡&#xff0c;最近發現日志中的用戶ip都為負載均衡器的ip&#xff0c;業務需要所以要改為用戶真實ip&#xff0c;下面記錄一下&#xff01; 1、打開文件&#xff1a;/etc/httpd/conf/httd.conf。2、在文件中查找&#xff1a;”CustomLog”,找到如下配置塊: …

ASP.NET MVC5 + EF6 入門教程 (5) Model和Entity Framework

文章來源&#xff1a; Slark.NET-博客園 http://www.cnblogs.com/slark/p/mvc-5-ef-6-get-started-model.html 上一節&#xff1a;ASP.NET MVC 5 入門教程 (4) View和ViewBag 下一節&#xff1a;ASP.NET MVC5 EF6 入門教程 (6) View中的Razor使用 源碼下載&#xff1a;點我下…

160 - 29 cosh.3

環境 Windows xp sp3 工具 exeinfope ollydbg 查殼 無殼的MFC程序 測試 字符串搜索&#xff1a; 004014F5 |. E8 AA030000 call <jmp.&MFC42.#CWnd::GetWindowTextLengthA_> 004014FA |. 8945 EC mov [local.5],eax 004014FD |. 837D EC 0…