定位Canvas: trying to use a recycled bitmap android.graphics.Bitmap@299c9ae7

来源:互联网 发布:windows下的串口编程 编辑:程序博客网 时间:2024/06/05 20:05

在工作中碰到这样一个问题,描述为:设置计时器,等待计时器时间到按Home退出,重启手机后,解锁时SystemUI报错。(实际和计时器毫无关系,插入USB重启后就会报错)
查看LOG如下:

AndroidRuntime: Shutting down VMAndroidRuntime: FATAL EXCEPTION: mainAndroidRuntime: Process: com.android.systemui, PID: 1224java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@299c9ae7    at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1282)    at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:599)    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:538)    at android.view.View.getDrawableRenderNode(View.java:15766)    at android.view.View.drawBackground(View.java:15712)    at android.view.View.draw(View.java:15479)    at android.widget.FrameLayout.draw(FrameLayout.java:658)    at android.view.View.updateDisplayListIfDirty(View.java:14384)    at android.view.View.getDisplayList(View.java:14413)    at android.view.View.draw(View.java:15204)    at android.view.ViewGroup.drawChild(ViewGroup.java:3532)    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3325)    at android.view.View.draw(View.java:15507)    at android.widget.FrameLayout.draw(FrameLayout.java:658)    at android.view.View.updateDisplayListIfDirty(View.java:14384)    at android.view.View.getDisplayList(View.java:14413)    at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:279)    at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:285)    at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:335)    at android.view.ViewRootImpl.draw(ViewRootImpl.java:2939)    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2753)    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2367)    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1292)    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6598)    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:800)    at android.view.Choreographer.doCallbacks(Choreographer.java:603)    at android.view.Choreographer.doFrame(Choreographer.java:572)    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:786)    at android.os.Handler.handleCallback(Handler.java:815)    at android.os.Handler.dispatchMessage(Handler.java:104)    at android.os.Looper.loop(Looper.java:194)    at android.app.ActivityThread.main(ActivityThread.java:5666)    at java.lang.reflect.Method.invoke(Native Method)    at java.lang.reflect.Method.invoke(Method.java:372)    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

以上LOG中仅仅能够看到是使用了已经回收的图片,但是图片在哪使用,在哪回收无法从LOG中获取,而且现象是偶现。即使再次复现也是同样的LOG,无法追究到根本原因。网上也有很多关于类似问题的帖子,大多数都是自己开发的应用,清楚的知道手动调用recycle()的位置,或者去除或者采用其他方式。针对这个问题,问题就在于不知到系统哪里回收了图片。
1. 经过不断的尝试排除,最终基本找到了问题的必现路径。
2. 咨询其他员工,添加打印栈的信息。

在frameworks/base/graphics/java/android/graphics/Bitmap.java中public void recycle() {    /**增加以下LOG,打印出被回收图片的hash值*/    Log.d("BitmapTAG", "Object tried to call recycle,this="+this));    /**增加以下方法,打印栈信息*/    Thread.dumpStack();    if (!mRecycled && mFinalizer.mNativeBitmap != 0) {        if (nativeRecycle(mFinalizer.mNativeBitmap)) {         // return value indicates whether native pixel object was actually recycled.         // false indicates that it is still in use at the native level and these         // objects should not be collected now. They will be collected later when the         // Bitmap itself is collected.         mBuffer = null;         mNinePatchChunk = null;        }        mRecycled = true;    }}

因为问题必现,所以很容易抓取加入信息后的报错LOG。
通过过滤发现,被回收的LOG有很多,如下:

BitmapTAG: Object tried to call recycle,this=android.graphics.Bitmap@30b0ce56BitmapTAG: Object tried to call recycle,this=android.graphics.Bitmap@299c9ae7BitmapTAG: Object tried to call recycle,this=android.graphics.Bitmap@2b8b32adBitmapTAG: Object tried to call recycle,this=android.graphics.Bitmap@2e708e18.......

还有很多,不过只需要@299c9ae7这一个就好。
过滤tag为BitmapTAG|System.err的LOG发现了 299c9ae7

D/BitmapTAG(1224): Object tried to call recycle,this=android.graphics.Bitmap@299c9ae7W/System.err(1224): java.lang.Throwable: stack dumpW/System.err(1224): at java.lang.Thread.dumpStack(Thread.java:490)W/System.err(1224): at android.graphics.Bitmap.recycle(Bitmap.java:309)W/System.err(1224): at com.android.systemui.ImageWallpaper$DrawableEngine.trimMemory(ImageWallpaper.java:165)W/System.err(1224): at com.android.systemui.ImageWallpaper.onTrimMemory(ImageWallpaper.java:94)W/System.err(1224): at android.app.ActivityThread.handleTrimMemory(ActivityThread.java:4573)W/System.err(1224): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1666)W/System.err(1224): at android.os.Handler.dispatchMessage(Handler.java:111)W/System.err(1224): at android.os.Looper.loop(Looper.java:194)W/System.err(1224): at android.app.ActivityThread.main(ActivityThread.java:5666)W/System.err(1224): at java.lang.reflect.Method.invoke(Native Method)W/System.err(1224): at java.lang.reflect.Method.invoke(Method.java:372)W/System.err(1224): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)W/System.err(1224): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

可以看出是ImageWallpaper.java:的94行调用了recycle()

 public void trimMemory(int level) {     if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW &&             mBackground != null) {         if (DEBUG) {             Log.d(TAG, "trimMemory");         }         mBackground.recycle();         mBackground = null;         mBackgroundWidth = -1;         mBackgroundHeight = -1;         mWallpaperManager.forgetLoadedWallpaper();     } }

找到对应的代码注释掉即可。

0 0
原创粉丝点击