安卓6.0有时间显示到秒的6.0xposed模块推荐吗

Android6.0 显示系统(四) 图像显示相关
通常使用Framebuffer来用作显示输出,Framebuffer就是一块内存区域,它通常是显示驱动的内部缓冲区在内存中的映射。一旦用户进程把图像数据复制到Framebuffer中,显示驱动会一个像素一个像素地扫描整个Framebuffer,并根据其中的值更新屏幕上像素点的颜色。驱动中这种更新屏幕的动作是固定的,它的周期就是我们常说的刷新率。
但是在屏幕更新一半时,用户进程更新了Framebuffer中的数据,将导致屏幕上画面的上半部分是前一帧的画面,下半部分变成了新的画面。当然错误会在下次刷新时纠正过来,但是这样也会有闪烁的感觉。这个可以使用双缓冲机制,双缓冲就是提供两块Framebuffer,一块用于显示,一块用于数据更新。数据准备好后,通过ioctl操作告诉显示设备切换用于显示的FrameBuffer,这样图像就能快速的显示出来。
但是双缓冲并没有完全解决问题,虽然双缓冲切换的速度很快,但是如果切换的时间点不对,在画面更新一半的时候切换,还是会出现闪烁的问题。当然,我们可以在底层进行控制,收到切换请求的时候,内部并不马上执行,等到刷新完成后再切换,这样完全避免了画面重叠问题。但是这样也有问题,如果用ioctl操作告诉底层可以进行切换了,但是缓冲区没有切换,这样应用层就不能确定何时可以再使用缓冲区,因此只能不断的通过ioctl来查询缓冲区的状态,一直到切换完成了。这种方式效率太低,拖慢了整个。解决这个问题就是底层固定发送信号给用户进程,通知进程切换的时机。这个信号就是VSync信号。
VSync信号是一个硬件信号,一般是显示设备刷新的周期到了会发送。
一、VSync信号的产生
通过VSync机制来提高显示效果,那么VSync是如何产生的?通常这个信号是由显示驱动产生,这样才能达到最佳效果。但是Android为了能运行在不支持VSync机制的设备上,也提供了软件模拟产生VSync信号的手段。
SurfaceFlinger中用HWComposer类来表示硬件显示设备,
HWComposer::HWComposer(
const sp& flinger,
EventHandler& handler)
: mFlinger(flinger),
mFbDev(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mDebugForceFakeVSync(false)
bool needVSyncThread =
// Note: some devices may insist that the FB HAL be opened before HWC.
int fberr = loadFbHalModule();//装载FrameBuffer的硬件模块
loadHwcModule();//装载HWComposer的硬件模块,这个函数中会将mHwc置为true
if (mHwc) {//这个为true代表硬件设备打开了
ALOGI(&Using %s version %u.%u&, HWC_HARDWARE_COMPOSER,
(hwcApiVersion(mHwc) && 24) & 0xff,
(hwcApiVersion(mHwc) && 16) & 0xff);
if (mHwc-&registerProcs) {
mCBContext-&hwc =
mCBContext-&procs.invalidate = &hook_
mCBContext-&procs.vsync = &hook_//vsync回调函数
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext-&procs.hotplug = &hook_
mCBContext-&procs.hotplug = NULL;
memset(mCBContext-&procs.zero, 0, sizeof(mCBContext-&procs.zero));
mHwc-&registerProcs(mHwc, &mCBContext-&procs);
// don't need a vsync thread if we have a hardware composer
needVSyncThread =//打开硬件设备成功了,将needVSncThread为false
if (needVSyncThread) {
// we don't have VSYNC support, we need to fake it
mVSyncThread = new VSyncThread(*this);
通过loadHwcModule来装载硬件模块,如果成功,mHwc为true,needVSyncThread为false。如果不成功,needVsyncThread为true,然后就要创建VSyncThread对象了,它就是产生VSync信号的软件手段了。
VSyncThread是一个thread,在onFirstRef中会调用run函数,就是执行threadLoop,这个函数只要返回true就会一直执行。
bool HWComposer::VSyncThread::threadLoop() {
{ // scope for lock
Mutex::Autolock _l(mLock);
while (!mEnabled) {
mCondition.wait(mLock);
const nsecs_t period = mRefreshP
const nsecs_t now = systemTime(CLOCK_MONOTONIC);
nsecs_t next_vsync = mNextFakeVS
nsecs_t sleep = next_vsync -
if (sleep & 0) {
// we missed, find where the next vsync should be
sleep = (period - ((now - next_vsync) % period));
next_vsync = now +
mNextFakeVSync = next_vsync +
spec.tv_sec
= next_vsync / ;
spec.tv_nsec = next_vsync % ;
err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
} while (err&0 && errno == EINTR);
if (err == 0) {
mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
这个函数会间隔模拟产生VSync的信号的原理是在固定时间发送消息给HWCompoer的消息对象mEventHandler,这个其实就到SurfaceFlinger的onVSyncReceived函数了。用软件模拟VSync信号在系统比较忙的时候可能会丢失一些信号。
Android再hardware/lib/libhardware/modules下有一个hwcomposer目录,里面是一个Android提供的缺省的硬件HWComposer模块的例子,这个例子只实现了一个open接口,并不能真正工作。在前面HWComposer的构造函数中,有如下代码
mCBContext-&procs.vsync = &hook_
这里指定了vsync的回调函数是hook_vsync,如果硬件中产生了VSync信号,将通过这个函数来通知上层,看看它的代码:
void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
int64_t timestamp) {
cb_context* ctx = reinterpret_cast(
const_cast(procs));
ctx-&hwc-&vsync(disp, timestamp);
然后又调用了vsync函数,这个函数最后也是调用了mEventHandler.onVSyncReceived函数,这个函数最后回到SurfaceFlinger中的onVsyncReceived函数中。
void HWComposer::vsync(int disp, int64_t timestamp) {
if (uint32_t(disp) & HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
Mutex::Autolock _l(mLock);
// There have been reports of HWCs that signal several vsync events
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
if (timestamp == mLastHwVSync[disp]) {
ALOGW(&Ignoring duplicate VSYNC event from HWC (t=%& PRId64 &)&,
timestamp);
mLastHwVSync[disp] =
char tag[16];
snprintf(tag, sizeof(tag), &HW_VSYNC_%1u&, disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
mEventHandler.onVSyncReceived(disp, timestamp);
二、FrameBuffer工作原理
我们先来看下loadFbHalModule函数,hw_get_module是HAl框架中装载HAL模块的函数
int HWComposer::loadFbHalModule()
hw_module_t const*
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err != 0) {
ALOGE(&%s module not found&, GRALLOC_HARDWARE_MODULE_ID);
return framebuffer_open(module, &mFbDev);
我们再来看看framebuffer_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 就是fb0
#define GRALLOC_HARDWARE_FB0 &fb0&
Gralloc模块在实际设备中有硬件厂商提供。我们来看下这个open函数
static int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
int status = -EINVAL;
if (!strncmp(name, GRALLOC_HARDWARE_GPU0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))
status = alloc_device_open(module, name, device);//处理gpu的
else if (!strncmp(name, GRALLOC_HARDWARE_FB0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))
status = framebuffer_device_open(module, name, device);
我们来看framebuffer_device_open函数,如果不支持framebuffer直接退出了(现在很多设备都开始不支持了)。如果支持framebuffer的话先是调用了init_frame_buffer函数来获取设备信息,通过mmap分配一块共享内存,然后设置FrameBuffer的操作函数等。
int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
int status = -EINVAL;
log_fbpost =
char property[PROPERTY_VALUE_MAX];
if(property_get(&debug.gralloc.fbpost&, property, &0&) & 0) {
if(atoi(property) == 1) {
log_fbpost =
ALOGI(&enable fbpost log!&);
alloc_device_t* gralloc_
#if DISABLE_FRAMEBUFFER_HAL == 1 //不支持FrameBuffer
AERR(&Framebuffer HAL not support/disabled %s&,
#ifdef MALI_DISPLAY_VERSION
&with MALI display enable&);
return -ENODEV;
status = gralloc_open(module, &gralloc_device);
if (status & 0)
private_module_t* m = (private_module_t*)
status = init_frame_buffer(m);
framebuffer_device_t *dev =
reinterpret_cast&framebuffer_device_t*& (malloc(sizeof(framebuffer_device_t)));
/* if either or both of init_frame_buffer() and malloc failed */
if ((status & 0) || (!dev))
gralloc_close(gralloc_device);
(!dev) ? (void)(status = -ENOMEM) : free(dev);
memset(dev, 0, sizeof(*dev));
//设置framebuffer的操作函数
dev-&common.tag = HARDWARE_DEVICE_TAG;
dev-&common.version = 0;
dev-&common.module = const_cast(module);
dev-&common.close = fb_
dev-&setSwapInterval = fb_set_swap_
dev-&post = fb_
dev-&enableScreen = fb_enable_
dev-&setUpdateRect = 0;
dev-&compositionComplete = &compositionC
int stride = m-&finfo.line_length / (m-&info.bits_per_pixel && 3);
const_cast(dev-&flags) = 0;
const_cast(dev-&width) = m-&info.
const_cast(dev-&height) = m-&info.
const_cast(dev-&stride) =
const_cast(dev-&format) = m-&fbF
const_cast(dev-&xdpi) = m-&
const_cast(dev-&ydpi) = m-&
const_cast(dev-&fps) = m-&
const_cast(dev-&minSwapInterval) = 0;
const_cast(dev-&maxSwapInterval) = 1;
const_cast(dev-&numFramebuffers) = m-&numB
*device = &dev-&
AINF(&%s line %d format %d numBuffers %d&,__FUNCTION__,__LINE__, dev-&format, m-&numBuffers);
//init dynamic lcd fps adjustment
dyn_fps_init(m);
#if GRALLOC_VSYNC_NEEDED == 1
gralloc_vsync_enable(dev);//支持vsync
gralloc_close(gralloc_device);
}&/framebuffer_device_t*&
init_frame_buffer函数主要调用了init_frame_buffer_locked函数
static int init_frame_buffer(struct private_module_t* module)
pthread_mutex_lock(&module-&lock);
int err = init_frame_buffer_locked(module);
pthread_mutex_unlock(&module-&lock);
我们来看看init_frame_buffer_locked函数,先打开设备列表中的一个设备即可,然后通过ioctl获取设备信息,把设备信息放到module中,后面通过mmap分配一块共享内存。
int init_frame_buffer_locked(struct private_module_t* module)
if (module-&framebuffer)
return 0; // Nothing to do, already initialized
char const * const device_template[] =//设备列表
&/dev/graphics/fb%u&,
&/dev/fb%u&,
int fd = -1;
int i = 0;
char name[64];
while ((fd == -1) && device_template[i])//只要打开一个设备就好了
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
if (fd & 0)
struct fb_fix_
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
struct fb_var_
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
if(info.bits_per_pixel == 32)
* Explicitly request 8/8/8
info.bits_per_pixel = 32;
info.red.offset
info.red.length
info.green.offset
info.green.length
info.blue.offset
info.blue.length
info.transp.offset
info.transp.length
* Explicitly request 5/6/5
info.bits_per_pixel = 16;
info.red.offset
info.red.length
info.green.offset
info.green.length
info.blue.offset
info.blue.length
info.transp.offset
info.transp.length
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)
info.yres_virtual = info.
flags &= ~PAGE_FLIP;
AWAR( &FBIOPUT_VSCREENINFO failed, page flipping not supported fd: %d&, fd );
if (info.yres_virtual & info.yres * 2)
// we need at least 2 for page-flipping
info.yres_virtual = info.
flags &= ~PAGE_FLIP;
AWAR( &page flipping not supported (yres_virtual=%d, requested=%d)&, info.yres_virtual, info.yres*2 );
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
int refreshRate = 0;
if ( info.pixclock & 0 )
refreshRate = 0000LLU /
uint64_t( info.upper_margin + info.lower_margin + info.yres + info.hsync_len )
* ( info.left_margin
+ info.right_margin + info.xres + info.vsync_len )
* info.pixclock
AWAR( &fbdev pixclock is zero for fd: %d&, fd );
if (refreshRate == 0)
refreshRate = 60*1000;
if (int(info.width) &= 0 || int(info.height) &= 0)
// the driver doesn't return that information
// default to 320 dpi
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
property_get(&ro.sf.lcd_density&, value, &320&);
lcd_density = atoi(value);
info.width
= ((info.xres * 25.4f) / (float)lcd_density + 0.5f);
info.height = ((info.yres * 25.4f) / (float)lcd_density + 0.5f);
float xdpi = (info.xres * 25.4f) / info.
float ydpi = (info.yres * 25.4f) / info.
= refreshRate / 1000.0f;
AINF(&leadcore fb using (fd=%d)\n&
= %d px\n&
= %d px\n&
&xres_virtual = %d px\n&
&yres_virtual = %d px\n&
= %2u:%u\n&
= %2u:%u\n&
= %2u:%u\n&,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length);
AINF(&width
= %d mm (%f dpi)\n&
= %d mm (%f dpi)\n&
&refresh rate = %.2f Hz\n&,
info.width,
info.height, ydpi,
if (0 == strncmp(finfo.id, &CLCD FB&, 7))
module-&dpy_type = MALI_DPY_TYPE_CLCD;
else if (0 == strncmp(finfo.id, &ARM Mali HDLCD&, 14))
module-&dpy_type = MALI_DPY_TYPE_HDLCD;
module-&dpy_type = MALI_DPY_TYPE_UNKNOWN;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
if (finfo.smem_len &= 0)
if( info.bits_per_pixel == 32 &&
info.red.offset == 16 &&
info.red.length == 8 &&
info.green.offset == 8 &&
info.green.length == 8 &&
info.blue.offset == 0 &&
info.blue.length == 8)
module-&fbFormat = HAL_PIXEL_FORMAT_BGRA_8888;
if( info.bits_per_pixel == 32 &&
info.red.offset == 0 &&
info.red.length == 8 &&
info.green.offset == 8 &&
info.green.length == 8 &&
info.blue.offset == 16 &&
info.blue.length == 8)
module-&fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;
if( info.bits_per_pixel == 16 &&
info.red.offset == 0 &&
info.red.length == 5 &&
info.green.offset == 5 &&
info.green.length == 6 &&
info.blue.offset == 11 &&
info.blue.length == 5)
module-&fbFormat = HAL_PIXEL_FORMAT_RGB_565;
module-&flags =//设置信息
module-&info =
module-&finfo =
module-&xdpi =
module-&ydpi =
module-&fps =
module-&swapInterval = 1;
* map the framebuffer
size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual);
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//mmap分配一块共享内存
if (vaddr == MAP_FAILED)
AERR( &Error mapping the framebuffer (%s)&, strerror(errno) );
//fix black screen between uboot logo and bootanimation
//memset(vaddr, 0, fbSize);
// Create a &fake& buffer object for the entire frame buffer memory, and store it in the module
module-&framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, GRALLOC_USAGE_HW_FB, fbSize, vaddr,
0, dup(fd), 0, 0);
module-&numBuffers = info.yres_virtual / info.
module-&bufferMask = 0;
最后我们再来看看framebuffer的操作函数fb_post,这个函数根据PRIV_FLAGS_FRAMEBUFFER来判断Framebuffer是否支持多缓冲,如果不支持方法很简单,直接把buffer中的数据复制到Framebuffer中就可以了。
Filp是指使用ioctl的FBIOPUT_VSCREENINFO参数设置当前显示的buffer。通过将显示区域指向Framebuffer中的新的数据帧,能非常迅速地完成buffer的切换。单缓冲模式下数据复制到缓冲区还需要一定时间,会加重闪烁感,通过Filp的方式切换缓冲区就不存在这个问题了。
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
if (private_handle_t::validate(buffer) & 0)
return -EINVAL;
private_handle_t const* hnd = reinterpret_cast(buffer);
private_module_t* m = reinterpret_cast(dev-&common.module);
if (m-&currentBuffer)
m-&base.unlock(&m-&base, m-&currentBuffer);
m-&currentBuffer = 0;
struct timeval tv1, tv2;
if (hnd-&flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) //framebuffer是否支持多缓冲区(flip)
m-&base.lock(&m-&base, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
0, 0, m-&info.xres, m-&info.yres, NULL);
const size_t offset = (uintptr_t)hnd-&base - (uintptr_t)m-&framebuffer-&
m-&info.activate = FB_ACTIVATE_VBL;
m-&info.yoffset = offset / m-&finfo.line_
up_fps(m);
gettimeofday(&tv1, NULL);
if (ioctl(m-&framebuffer-&fd, FBIOPUT_VSCREENINFO, &m-&info) == -1)
AERR( &FBIOPUT_VSCREENINFO failed for fd: %d&, m-&framebuffer-&fd );
m-&base.unlock(&m-&base, buffer);
#if GRALLOC_VSYNC_NEEDED
if ( 0 != gralloc_wait_for_vsync(dev) )
AERR( &Gralloc wait for vsync failed for fd: %d&, m-&framebuffer-&fd );
m-&base.unlock(&m-&base, buffer);
gettimeofday(&tv2, NULL);
if((int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000 & 50)
ALOGI(&%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d&,__FUNCTION__,__LINE__,
(int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000,
systemTime(CLOCK_MONOTONIC)/1000000,
(int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime,
gettid());
ALOGD_IF(log_fbpost, &%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d&,__FUNCTION__,__LINE__,
(int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000,
systemTime(CLOCK_MONOTONIC)/1000000,
(int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime,
gettid());
lasttime = (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000;
postcount++;
if(postcount == 1000)
ALOGI(&%s line %d avgframerate = %2f&,__FUNCTION__,__LINE__,
(float)postcount*1000.0/(lasttime - timecount));
postcount = 0;
timecount =
m-&currentBuffer =
} else {//不支持多缓冲(flip)
void* buffer_
m-&base.lock(&m-&base, m-&framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m-&info.xres, m-&info.yres, &fb_vaddr);
m-&base.lock(&m-&base, buffer, GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m-&info.xres, m-&info.yres, &buffer_vaddr);
// If buffer's alignment match framebuffer alignment we can do a direct copy.
// If not we must fallback to do an aligned copy of each line.
if ( hnd-&byte_stride == (int)m-&finfo.line_length )
memcpy(fb_vaddr, buffer_vaddr, m-&finfo.line_length * m-&info.yres);
uintptr_t fb_offset = 0;
uintptr_t buffer_offset = 0;
for (i = 0; i & m-&info. i++)
memcpy((void *)((uintptr_t)fb_vaddr + fb_offset),
(void *)((uintptr_t)buffer_vaddr + buffer_offset),
m-&finfo.line_length);
fb_offset += m-&finfo.line_
buffer_offset += hnd-&byte_
m-&base.unlock(&m-&base, buffer);
m-&base.unlock(&m-&base, m-&framebuffer);
三、分配图像缓冲区的内存
之前的博客在GraphicBufferAllocator的alloc方法是调用了mAllocDev的alloc,而这个mAllocDev也是Gralloc模块,最后会调用如下方法。
int gralloc_alloc(struct alloc_device_t* dev,
int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
/* TODO: Redirect to specific allocator according to usage. */
if (usage & GRALLOC_USAGE_HW_FB) {
/* Dispatch to framebuffer allocator. */
rel = gralloc_alloc_framebuffer(dev,
w, h, format, usage, pHandle, pStride);
rel = gc_gralloc_alloc(dev, w, h, format, usage, pHandle, pStride);
gralloc_alloc函数会根据usage中的标志是否有GRALLOC_USAGE_HW_FB来决定是从硬件缓冲中分配缓冲区还是从普通内存分配缓冲区。我们先看看从内存中分配缓冲区的。
如果不支持framebuffer,只能从普通内存中分配缓冲区。gc_gralloc_alloc函数是从普通内存中分配缓冲区,主要使用了匿名共享内存的方法。最后pHandle装了共享内存的fd。
另外从硬件缓冲区分配内存是调用了gralloc_alloc_framebuffer方法,这个函数主要调用了gralloc_alloc_framebuffer_locked方法
static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev, size_t size, int usage, buffer_handle_t* pHandle, int* stride, int* byte_stride)
private_module_t* m = reinterpret_cast(dev-&common.module);
// allocate the framebuffer
if (m-&framebuffer == NULL)//如果为空
// initialize the framebuffer, the framebuffer is mapped once and forever.
int err = init_frame_buffer_locked(m);//分配一大块内存
if (err & 0)
const uint32_t bufferMask = m-&bufferM
const uint32_t numBuffers = m-&numB
/* framebufferSize is used for allocating the handle to the framebuffer and refers
to the size of the actual framebuffer.
* alignedFramebufferSize is used for allocating a possible internal buffer and
thus need to consider internal alignment requirements. */
const size_t framebufferSize = m-&finfo.line_length * m-&info.
const size_t alignedFramebufferSize = GRALLOC_ALIGN(m-&finfo.line_length, 64) * m-&info.
*stride = m-&info.
if (numBuffers == 1)//如果是单缓冲,使用普通内存分配
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
AWAR( &fallback to single buffering. Virtual Y-res too small %d&, m-&info.yres );
*byte_stride = GRALLOC_ALIGN(m-&finfo.line_length, 64);
return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle);
if (bufferMask &= ((1LU&framebuffer-&
// find a free slot
for (uint32_t i=0 ; ibufferMask |= (1LU&framebuffer-&fd),
(framebufferVaddr - (uintptr_t)m-&framebuffer-&base), 0);
* Perform allocator specific actions. If these fail we fall back to a regular buffer
* which will be memcpy'ed to the main screen when fb_post is called.
if (alloc_backend_alloc_framebuffer(m, hnd) == -1)
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
AERR( &Fallback to single buffering. Unable to map framebuffer memory to handle:%p&, hnd );
*byte_stride = GRALLOC_ALIGN(m-&finfo.line_length, 64);
return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle);
*pHandle =
*byte_stride = m-&finfo.line_
这个函数如果第一次调用会调用init_frame_buffer_locked来从Framebuffer设备上分配一大块共享内存,内存的大小是屏幕尺寸的整数倍。numBuffers是内存的块数,如果只有一块代表是单缓冲,单缓冲调用分配普通内存的函数(单内存只能分配普通内存也很好理解,因为framebuffer的内存要用于显示。重新分配的话只能就分配普通内存了)。多缓冲的话使用Framebuffer的内存。但是Framebuffer的缓冲区块数也是有限的,因此函数要找一块空闲的缓冲区。如果缓冲区分配完了,返回错误值-ENOMEM。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'}

我要回帖

更多关于 xposed模块大全6.0 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信