編輯:關於Android編程
打開/dev/graphics/fb0這個設備的調用過程如下:
1.在HWComposer中,加載module
HWComposer::HWComposer( const sp& flinger, EventHandler& handler) { ... // Note: some devices may insist that the FB HAL be opened before HWC. int fberr = loadFbHalModule(); loadHwcModule(); ... }
1)loadFbHalModule()直接從下面的路徑打開fb,初始化並保存framebuffer_device_t類型成員變量mFbDev。
gralloc_device_open()->fb_device_open()->mapFrameBuffer() -> mapFrameBufferLocked()
這裡gralloc_device_open定義在HAL層定義的:
//gralloc.cpp文件中 static struct hw_module_methods_t gralloc_module_methods = { .open = gralloc_device_open }; struct private_module_t HAL_MODULE_INFO_SYM = { .base = { .common = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = GRALLOC_HARDWARE_MODULE_ID, .name = "Graphics Memory Allocator Module", .author = "The Android Open Source Project", .methods = &gralloc_module_methods }, .registerBuffer = gralloc_register_buffer, .unregisterBuffer = gralloc_unregister_buffer, .lock = gralloc_lock, .unlock = gralloc_unlock, }, .framebuffer = 0, .flags = 0, .numBuffers = 0, .bufferMask = 0, .lock = PTHREAD_MUTEX_INITIALIZER, .currentBuffer = 0, };
這個Module會在HWComposer::loadFbHalModule()中被加載,調用對應的open函數。
看以下代碼注釋
int HWComposer::loadFbHalModule() { hw_module_t const* module; //根據GRALLOC_HARDWARE_MODULE_ID這個值,加載對應的module代碼,也就是上面說的內容 int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err != 0) { ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID); return err; } return framebuffer_open(module, &mFbDev); } //這裡methods->open當然就是調用上面module的open函數,也就是gralloc_device_open() static inline int framebuffer_open(const struct hw_module_t* module, struct framebuffer_device_t** device) { return module->methods->open(module, GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device); } //由於第二個參數是GRALLOC_HARDWARE_FB0,所以會跑到fb_device_open中 int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { const private_module_t* m = reinterpret_cast( module); gpu_context_t *dev; IAllocController* alloc_ctrl = IAllocController::getInstance(); dev = new gpu_context_t(m, alloc_ctrl); if(!dev) return status; *device = &dev->common; status = 0; } else { status = fb_device_open(module, name, device); } return status; } //由於name是GRALLOC_HARDWARE_FB0,會跑到if語句裡進行初始化工作,包括打開/dev/graphics/fb0等 int fb_device_open(hw_module_t const* module, const char* name, hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { alloc_device_t* gralloc_device; status = gralloc_open(module, &gralloc_device); if (status < 0) return status; /* initialize our state here */ fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); if(dev == NULL) { gralloc_close(gralloc_device); return status; } memset(dev, 0, sizeof(*dev)); /* initialize the procs */ dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = 0; dev->device.common.module = const_cast (module); dev->device.common.close = fb_close; dev->device.setSwapInterval = fb_setSwapInterval; dev->device.post = fb_post; dev->device.setUpdateRect = 0; dev->device.compositionComplete = fb_compositionComplete; status = mapFrameBuffer((framebuffer_device_t*)dev); private_module_t* m = (private_module_t*)dev->device.common.module; if (status >= 0) { int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3); const_cast (dev->device.flags) = 0; const_cast (dev->device.width) = m->info.xres; const_cast (dev->device.height) = m->info.yres; const_cast (dev->device.stride) = stride; const_cast (dev->device.format) = m->fbFormat; const_cast (dev->device.xdpi) = m->xdpi; const_cast (dev->device.ydpi) = m->ydpi; const_cast (dev->device.fps) = m->fps; const_cast (dev->device.minSwapInterval) = PRIV_MIN_SWAP_INTERVAL; const_cast (dev->device.maxSwapInterval) = PRIV_MAX_SWAP_INTERVAL; const_cast (dev->device.numFramebuffers) = m->numBuffers; dev->device.setUpdateRect = 0; *device = &dev->device.common; } // Close the gralloc module gralloc_close(gralloc_device); } return status; }
2)loadHwcModule()函數通過以下路徑打開fb,初始化並保存hwc_composer_device_1_t類型的成員變量mHwc。
HWComposer::loadHwcModule()->hw_get_module(HWC_HARDWARE_MODULE_ID, &module) 然後在調用hwc_open_1(module, &mHwc)->hwc_device_open()->initContext()-> CopyBit::CopyBit()[hwc_copybit.cpp]->hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) ->open_copybit()->open("/dev/graphics/fb0", O_RDWR, 0);
這裡的module加載以及調用open函數的過程基本和上面的一樣,不多說了。
到此可以知道framework層是怎麼打開的/dev/graphics/fb0節點,以待後續進行處理的!!
在SurfaceFlinger中最後進行數據刷新的函數,我們知道是postFrameBuffer()函數。定義如下:
void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); #ifdef PRODUCT_DEV if (CC_UNLIKELY(mDebugFps)) { debugShowFPS(); } /* if(CC_UNLIKELY(ATRACE_ENABLED())){ debugShowGPUInfoToSysTrace(); }*/ #endif const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { if (!hwc.supportsFramebufferTarget()) { getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); } //這個函數當然就是調用HWComposer::commit()函數,,不言而喻~ hwc.commit(); } ... } status_t HWComposer::commit() { int err = NO_ERROR; if (mHwc) { ... //這裡的mHwc是加載了/hardware/qcom/display/libhwcomposer/Hwc.cpp的內容的 //理由嗎,,和上面說的一樣,根據id來選擇module加載~ //所以set函數就是需要在Hwc.cpp文件中尋找了~ err = mHwc->set(mHwc, mNumDisplays, mLists); .... } return (status_t)err; } static int hwc_set(hwc_composer_device_1 *dev, size_t numDisplays, hwc_display_contents_1_t** displays) { int ret = 0; hwc_context_t* ctx = (hwc_context_t*)(dev); for (int dpy = 0; dpy < (int)numDisplays; dpy++) { hwc_display_contents_1_t* list = displays[dpy]; switch(dpy) { case HWC_DISPLAY_PRIMARY: //這個就是主屏!!!看hwc_set_primary()函數 ret = hwc_set_primary(ctx, list); break; case HWC_DISPLAY_EXTERNAL: ret = hwc_set_external(ctx, list); break; case HWC_DISPLAY_VIRTUAL: if(ctx->mHWCVirtual) ret = ctx->mHWCVirtual->set(ctx, list); break; default: ret = -EINVAL; } } return ret; } static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { ATRACE_CALL(); int ret = 0; const int dpy = HWC_DISPLAY_PRIMARY; if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && !ctx->dpyAttr[dpy].isPause) { ... //利用copybit或者mdp,每個layer都有幾個flags來標記用哪個去畫 //以做過的一個平台為例,有以下兩種方式 //// LayerProp::flag values /* enum { HWC_MDPCOMP = 0x00000001, HWC_COPYBIT = 0x00000002, }; */ if (ctx->mCopyBit[dpy]) { if (ctx->mMDP.version < qdutils::MDP_V4_0) copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); else fd = ctx->mMDPComp[dpy]->drawOverlap(ctx, list); } ... if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { ALOGE("%s: MDPComp draw failed", __FUNCTION__); ret = -1; } ... if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, lRoi, rRoi)) { ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); ret = -1; } ... } }
在加載完fb相關的module之後,SurfaceFlinger就可以通過HWC把Layer畫上去。流程如下:
SurfaceFlinger creates a list of layers and sends them to the HWC in the到這裡就可以知道怎麼加載的模塊,也看了SurfaceFlinger通過HWComposer和HWC.cpp模塊的內容進行顯示數據的刷寫的過程。接下來看一下SurfaceFlinger,,
?GCM網絡管理器能讓app注冊能執行面向網絡的服務,每個任務只是完成一個工作。它的API能處理這些任務,允許Google Play Services通過系統集中處理這些
寫代碼的時候過度依賴鼠標可能會遇到比低效率更嚴重的問題。這裡的技巧幫助你寫更少的代碼,充分發揮鍵盤的功能,因此你可以避免發生這樣的情況:hanks Obama.這裡的絕大
實現思路:該View是通過ListView實現的,通過實體兩個字段內容content和時間time來展示每個ListItem時間軸是使用上面一條線(20dp)
本文要演示的Android開發實例是如何完成一個Android中的miniTwitter登錄界面,下面將分步驟講解怎樣實現圖中的界面效果,讓大家都能輕松的做出美觀的登錄界