之前在调试flash 11在ICS上的使用效果时(这个版本使用的是surfaceView,市场上下的,基本上都是用nativeWindow了),发现一个bug,bug的现象如图1所示(访问http://www.qiaqiafood.com,页面主体是一个flash):


图1:错误的图片


图2:正常的图片

Webpage加载时,没有问题,但当将网页上下拖动后,就出现如图1所示的黑色区域,且图像显示的层叠关系也不正常。

该问题则追踪过程不细说,也花了好久。对这个问题:

1.通过dump framebuffer的数据:

$adb shell cat/dev/graphics/fb0 > framebuffer.bin
查看结果,framebuffer中确实是花的,和屏幕上表现的一致,这不意外

2.接上hierarchyviewer,分析framebuffer,却发现这是好的

3.通过screencap -p /sdcard/screenshot.png 发现也是好的


有现象和重现方法,接下来分析原因了。

从现象上看,这个问题是与画图,也就是surfaceFlinger有关的。查看surfaceFlinger的状态:

#dumpsys SurfaceFlinger

重点关注下BrowserActivity:

+ Layer 0x95cc0(com.android.browser/com.android.browser.BrowserActivity)     z=    21025, pos=(0,0),size=(1024, 600), isOpaque=0, needsDithering=0, invalidate=0, alpha=0xff,flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]     client=0x918a8, identity=40     format= 1, activeBuffer=[1024x 600:1024, 1], transform-hint=0x00, queued-frames=0           mBufferCount=2, mSynchronousMode=1, default-size=[1024x600],mPixelFormat=1, mTexName=3           current: {crop=[0,0,-1,-1], transform=0x00, current=1}           next   : {crop=[0,0,-1,-1],transform=0x00, FIFO(0)={}}            [00] state=FREE    ,crop=[0,0,-1,-1], transform=0x00, timestamp=16875976105982, 0x919b0 [1024x600:1024,  1]           >[01] state=QUEUED  ,crop=[0,0,-1,-1], transform=0x00, timestamp=16877388086666, 0x8b6a0 [1024x600:1024,  1] Region transparentRegion (this=0x95e60, count=1)   [  0, 211, 1014, 715] Region transparentRegionScreen (this=0x95cf4, count=1)   [  0, 211, 1014, 715]  RegionvisibleRegionScreen (this=0x95cd0, count=2)   [  0,   0, 1024, 211]   [1014, 211, 1024, 552] 
仔细分析输出内容,可以发现一个问题:browser的区域是有一个透明区域:

[ 0,211, 1014, 715]

这个区域把整个activity(对应的surface),划分为两个可见区域:

[ 0, 0, 1024, 211]

[1014, 211, 1024, 552]

Scroll一下browser的页面,再查看BrowserActivity的状态,两次一样,这个透明区域的位置坐标竟然没有随着scroll跟着改变

顺着surfaceView的创建和render过程,发现问题了:

Android将surfaceView(一般的Game, video及browserplugin会使用的一种view)在其layout的区域,会设成transparent(也就是挖洞), 但是其设置只是在attachWindow的时候做的。这样造成的问题是:transparent的区域是固定的,当一个页面scroll的时候,不会更新这个transparent区域的boundary,最终给hwComposer合成的boundary,和scroll之后,surface的内容对不上,造成hwcomposer合错

知道问题后,解决方法也可以知道了。

常规做法:让每次layout的遍历viewHierarchy时都做transparent的重置, 但这个影响面太大且较复杂(还没找到可行的修改方法)

workaround做法:给hwComposer的composer区域,不考虑transparent区域即可 (目前测试,还没看到会造成系统有什么不好的的影响),让它把surface的区域全部拿去计算(理论上效率可能有影响,但没观测出来影响)

修改方法,注释掉[email protected]中对visibleRegionScreen的赋值:

   hwcl->visibleRegionScreen.rects =           reinterpret_cast<hwc_rect_t const *>(                   visibleRegionScreen.getArray(                           &hwcl->visibleRegionScreen.numRects)); 
至于hierarchyviewer和screencap得到的screenshot为何是好的呢?这里可以看看screenshot的实现(在surfaceFlinger中),这个screenshot和framebuffer的合成还不是一回事,screenshot没有用到hwcomposer,只是通过openGL将各个layer直接draw到FBO中,这里就没有挖洞的区域了,实际计算的区域和workaround后差不太多了。

另外还有两个问题:

1. 在scroll 窗口和初次加载flash(会比网页慢), flash内容盖住navigation bar的问题, 如图

图3:surfaceView overlap BrowserActivity

2. 网页Scroll的时候,flash内容的scroll和browser内容不同步的问题,不同步的区域会留有黑框。

覆盖的问题,由于surfaceView默认是放在browser的surface前面的,这个无解,要解只能将surfaceView放在borwser的后面(前面说过,由于surface有实现挖洞(transparent)的功能,实际上放在后面也是可以解决的)


而不同步的问题,参看今年的google IO关于webview的介绍,这个在surfaceView上应该是无解了,Google的解决方法,是使用Hardware Accelerated,通过clipLayer/mediaLayer的方式 (openGL的纹理贴图)。相信webview插件往后都不会用surfaceView实现了吧。

不过近期,我在某超大型跨国公司的同事,也碰到类似问题,现象几乎一样,也是跨进程使用Surface引起的这个问题。查看Android的release更新,4.0,4.1和4.2都没有修复这个问题

更多相关文章

  1. windows下cygwin使用ndkr8编译ffmpeg
  2. Android(安卓)之 悬浮窗
  3. Android实现背景图自适应不失真(下)
  4. Android(安卓)— 之内容提供器(Content Provider)
  5. Android(安卓)Studio Analyze APK 一直显示 Parsing Manifest解
  6. Android控件之SlidingDrawer(滑动式抽屉)详解与实例
  7. Android实现手机游戏隐藏虚拟按键
  8. 怎么在android实现通过浏览器点击链接打开apk
  9. android 事件总线 -- Otto(四) HandlerFinder、DeadEvent

随机推荐

  1. Android EventBus框架入门
  2. android 自学日记(三) ---Intent
  3. Android和js进行交互
  4. Android内核开发:为什么刷机后系统第一次
  5. 深入理解android之IPC机制与Binder框架
  6. 【Android】handler类分析研究
  7. Android异步操作总结
  8. Android(安卓)国际化(i18n)
  9. Android线程池使用
  10. Android(安卓)8.0系统源码分析--Zygote启