diff options
author | Patrick Dubroy <dubroy@google.com> | 2010-12-19 16:47:17 -0800 |
---|---|---|
committer | Patrick Dubroy <dubroy@google.com> | 2010-12-20 17:02:15 -0800 |
commit | f890fab5a6715548e520a6f010a3bfe7607ce56e (patch) | |
tree | 6c61a1b736399a9dde6b83f4978ad5ef36e18a95 | |
parent | 2a1cc5ac30efc05880a12a2114c09364fc38e032 (diff) | |
download | frameworks_base-f890fab5a6715548e520a6f010a3bfe7607ce56e.zip frameworks_base-f890fab5a6715548e520a6f010a3bfe7607ce56e.tar.gz frameworks_base-f890fab5a6715548e520a6f010a3bfe7607ce56e.tar.bz2 |
Ensure bitmaps aren't freed while referenced from a display list
Also removes the reference queue finalizers. They aren't necessary
anymore now that Bitmaps are allocated in the heap.
-rw-r--r-- | core/java/android/util/Finalizers.java | 127 | ||||
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 31 | ||||
-rw-r--r-- | core/java/android/view/GLES20DisplayList.java | 31 | ||||
-rw-r--r-- | core/java/android/view/GLES20RecordingCanvas.java | 273 | ||||
-rw-r--r-- | core/java/com/android/internal/os/RuntimeInit.java | 7 | ||||
-rw-r--r-- | graphics/java/android/graphics/BitmapShader.java | 3 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 8 | ||||
-rw-r--r-- | tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java | 3 |
8 files changed, 301 insertions, 182 deletions
diff --git a/core/java/android/util/Finalizers.java b/core/java/android/util/Finalizers.java deleted file mode 100644 index 671f2d4..0000000 --- a/core/java/android/util/Finalizers.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.lang.ref.PhantomReference; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; - -/** - * This class can be used to implement reliable finalizers. - * - * @hide - */ -public final class Finalizers { - private static final String LOG_TAG = "Finalizers"; - - private static final Object[] sLock = new Object[0]; - private static boolean sInit; - private static Reclaimer sReclaimer; - - /** - * Subclass of PhantomReference used to reclaim resources. - */ - public static abstract class ReclaimableReference<T> extends PhantomReference<T> { - public ReclaimableReference(T r, ReferenceQueue<Object> q) { - super(r, q); - } - - public abstract void reclaim(); - } - - /** - * Returns the queue used to reclaim ReclaimableReferences. - * - * @return A reference queue or null before initialization - */ - public static ReferenceQueue<Object> getQueue() { - synchronized (sLock) { - if (!sInit) { - return null; - } - if (!sReclaimer.isRunning()) { - sReclaimer = new Reclaimer(sReclaimer.mQueue); - sReclaimer.start(); - } - return sReclaimer.mQueue; - } - } - - /** - * Invoked by Zygote. Don't touch! - */ - public static void init() { - synchronized (sLock) { - if (!sInit && sReclaimer == null) { - sReclaimer = new Reclaimer(); - sReclaimer.start(); - sInit = true; - } - } - } - - private static class Reclaimer extends Thread { - ReferenceQueue<Object> mQueue; - - private volatile boolean mRunning = false; - - Reclaimer() { - this(new ReferenceQueue<Object>()); - } - - Reclaimer(ReferenceQueue<Object> queue) { - super("Reclaimer"); - setDaemon(true); - mQueue = queue; - } - - @Override - public void start() { - mRunning = true; - super.start(); - } - - boolean isRunning() { - return mRunning; - } - - @SuppressWarnings({"InfiniteLoopStatement"}) - @Override - public void run() { - try { - while (true) { - try { - cleanUp(mQueue.remove()); - } catch (InterruptedException e) { - // Ignore - } - } - } catch (Exception e) { - Log.e(LOG_TAG, "Reclaimer thread exiting: ", e); - } finally { - mRunning = false; - } - } - - private void cleanUp(Reference<?> reference) { - do { - reference.clear(); - ((ReclaimableReference<?>) reference).reclaim(); - } while ((reference = mQueue.poll()) != null); - } - } -} diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 773d734..f0bb40d 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -34,11 +34,6 @@ import android.text.GraphicsOperations; import android.text.SpannableString; import android.text.SpannedString; import android.text.TextUtils; -import android.util.Finalizers; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; /** * An implementation of Canvas on top of OpenGL ES 2.0. @@ -46,7 +41,11 @@ import java.util.Set; class GLES20Canvas extends HardwareCanvas { private final boolean mOpaque; private int mRenderer; - + + // The native renderer will be destroyed when this object dies. + // DO NOT overwrite this reference once it is set. + private CanvasFinalizer mFinalizer; + private int mWidth; private int mHeight; @@ -78,7 +77,7 @@ class GLES20Canvas extends HardwareCanvas { this(false, translucent); } - GLES20Canvas(boolean record, boolean translucent) { + protected GLES20Canvas(boolean record, boolean translucent) { mOpaque = !translucent; if (record) { @@ -90,7 +89,7 @@ class GLES20Canvas extends HardwareCanvas { if (mRenderer == 0) { throw new IllegalStateException("Could not create GLES20Canvas renderer"); } else { - new CanvasFinalizer(this); + mFinalizer = new CanvasFinalizer(mRenderer); } } @@ -99,22 +98,16 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDestroyRenderer(int renderer); - private static class CanvasFinalizer extends Finalizers.ReclaimableReference<GLES20Canvas> { - private static final Set<CanvasFinalizer> sFinalizers = Collections.synchronizedSet( - new HashSet<CanvasFinalizer>()); - - private int mRenderer; + private static class CanvasFinalizer { + final int mRenderer; - CanvasFinalizer(GLES20Canvas canvas) { - super(canvas, Finalizers.getQueue()); - mRenderer = canvas.mRenderer; - sFinalizers.add(this); + CanvasFinalizer(int renderer) { + mRenderer = renderer; } @Override - public void reclaim() { + protected void finalize() throws Throwable { nDestroyRenderer(mRenderer); - sFinalizers.remove(this); } } diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java index 11e6d30..adf08ea 100644 --- a/core/java/android/view/GLES20DisplayList.java +++ b/core/java/android/view/GLES20DisplayList.java @@ -16,12 +16,6 @@ package android.view; -import android.util.Finalizers; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - /** * An implementation of display list for OpenGL ES 2.0. */ @@ -33,13 +27,18 @@ class GLES20DisplayList extends DisplayList { int mNativeDisplayList; + // The native display list will be destroyed when this object dies. + // DO NOT overwrite this reference once it is set. + @SuppressWarnings("unused") + private DisplayListFinalizer mFinalizer; + @Override HardwareCanvas start() { if (mStarted) { throw new IllegalStateException("Recording has already started"); } - mCanvas = new GLES20Canvas(true, true); + mCanvas = new GLES20RecordingCanvas(true); mStarted = true; mRecorded = false; @@ -53,7 +52,7 @@ class GLES20DisplayList extends DisplayList { mRecorded = true; mNativeDisplayList = mCanvas.getDisplayList(); - new DisplayListFinalizer(this); + mFinalizer = new DisplayListFinalizer(mNativeDisplayList); } } @@ -62,22 +61,16 @@ class GLES20DisplayList extends DisplayList { return !mStarted && mRecorded; } - private static class DisplayListFinalizer extends Finalizers.ReclaimableReference<DisplayList> { - private static final Set<DisplayListFinalizer> sFinalizers = Collections.synchronizedSet( - new HashSet<DisplayListFinalizer>()); - - private int mNativeDisplayList; + private static class DisplayListFinalizer { + int mNativeDisplayList; - DisplayListFinalizer(GLES20DisplayList displayList) { - super(displayList, Finalizers.getQueue()); - mNativeDisplayList = displayList.mNativeDisplayList; - sFinalizers.add(this); + DisplayListFinalizer(int nativeDisplayList) { + mNativeDisplayList = nativeDisplayList; } @Override - public void reclaim() { + protected void finalize() throws Throwable { GLES20Canvas.destroyDisplayList(mNativeDisplayList); - sFinalizers.remove(this); } } } diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java new file mode 100644 index 0000000..bd14286 --- /dev/null +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; + +import java.util.HashSet; + +/** + * An implementation of a GL canvas that records drawing operations. + * This is intended for use with a DisplayList. This class keeps a list of all the Paint and + * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while + * the DisplayList is still holding a native reference to the memory. + */ +class GLES20RecordingCanvas extends GLES20Canvas { + // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long + // as the DisplayList is alive. + private HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>(); + + GLES20RecordingCanvas(boolean translucent) { + super(true, translucent); + } + + private void recordShaderBitmap(Paint paint) { + if (paint != null) { + final Shader shader = paint.getShader(); + if (shader instanceof BitmapShader) { + mBitmaps.add(((BitmapShader) shader).mBitmap); + } + } + } + + @Override + public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, + Paint paint) { + super.drawArc(oval, startAngle, sweepAngle, useCenter, paint); + } + + @Override + public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { + super.drawPatch(bitmap, chunks, dst, paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { + super.drawBitmap(bitmap, left, top, paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { + super.drawBitmap(bitmap, matrix, paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { + super.drawBitmap(bitmap, src, dst, paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { + super.drawBitmap(bitmap, src, dst, paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, + int height, boolean hasAlpha, Paint paint) { + super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, + int height, boolean hasAlpha, Paint paint) { + super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, + int vertOffset, int[] colors, int colorOffset, Paint paint) { + super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, + paint); + mBitmaps.add(bitmap); + // Shaders in the Paint are ignored when drawing a Bitmap + } + + @Override + public void drawCircle(float cx, float cy, float radius, Paint paint) { + super.drawCircle(cx, cy, radius, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { + super.drawLine(startX, startY, stopX, stopY, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawLines(float[] pts, int offset, int count, Paint paint) { + super.drawLines(pts, offset, count, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawLines(float[] pts, Paint paint) { + super.drawLines(pts, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawOval(RectF oval, Paint paint) { + super.drawOval(oval, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPaint(Paint paint) { + super.drawPaint(paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPath(Path path, Paint paint) { + super.drawPath(path, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPoint(float x, float y, Paint paint) { + super.drawPoint(x, y, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPoints(float[] pts, int offset, int count, Paint paint) { + super.drawPoints(pts, offset, count, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPoints(float[] pts, Paint paint) { + super.drawPoints(pts, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { + super.drawPosText(text, index, count, pos, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawPosText(String text, float[] pos, Paint paint) { + super.drawPosText(text, pos, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawRect(float left, float top, float right, float bottom, Paint paint) { + super.drawRect(left, top, right, bottom, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawRect(Rect r, Paint paint) { + super.drawRect(r, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawRect(RectF r, Paint paint) { + super.drawRect(r, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { + super.drawRoundRect(rect, rx, ry, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { + super.drawText(text, index, count, x, y, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { + super.drawText(text, start, end, x, y, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawText(String text, int start, int end, float x, float y, Paint paint) { + super.drawText(text, start, end, x, y, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawText(String text, float x, float y, Paint paint) { + super.drawText(text, x, y, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, + float vOffset, Paint paint) { + super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { + super.drawTextOnPath(text, path, hOffset, vOffset, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, + float x, float y, int dir, Paint paint) { + super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawTextRun(CharSequence text, int start, int end, int contextStart, + int contextEnd, float x, float y, int dir, Paint paint) { + super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint); + recordShaderBitmap(paint); + } + + @Override + public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, + float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, + int indexOffset, int indexCount, Paint paint) { + super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, + colorOffset, indices, indexOffset, indexCount, paint); + recordShaderBitmap(paint); + } +} diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 18e1b45..f58f261 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -24,7 +24,6 @@ import android.os.IBinder; import android.os.Process; import android.os.SystemProperties; import android.util.Config; -import android.util.Finalizers; import android.util.Log; import android.util.Slog; @@ -142,12 +141,6 @@ public class RuntimeInit { Debug.enableEmulatorTraceOutput(); } - /** - * Initialize the thread used to reclaim resources without - * going through finalizers. - */ - Finalizers.init(); - initialized = true; } diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 4ba679b..f74d0ef 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -23,9 +23,10 @@ package android.graphics; public class BitmapShader extends Shader { /** * Prevent garbage collection. + * @hide */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) - private final Bitmap mBitmap; + public final Bitmap mBitmap; /** * Call this to create a new shader that will draw with a bitmap. diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 1c93ea6..00de39b 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -60,9 +60,7 @@ void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) } void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) { - SkPixelRef* pixref = bitmapResource->pixelRef(); - if (pixref) pixref->globalRef(); - + bitmapResource->pixelRef()->safeRef(); bitmapResource->getColorTable()->safeRef(); incrementRefcount((void*)bitmapResource, kBitmap); } @@ -91,9 +89,7 @@ void ResourceCache::decrementRefcount(void* resource) { } void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { - SkPixelRef* pixref = bitmapResource->pixelRef(); - if (pixref) pixref->globalUnref(); - + bitmapResource->pixelRef()->safeUnref(); bitmapResource->getColorTable()->safeUnref(); decrementRefcount((void*)bitmapResource); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 9de6e8f..c30e8e4 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -32,7 +32,6 @@ import com.android.tools.layoutlib.create.OverrideMethod; import android.graphics.Bitmap; import android.graphics.Typeface_Delegate; import android.os.Looper; -import android.util.Finalizers; import java.lang.ref.SoftReference; import java.lang.reflect.Field; @@ -198,8 +197,6 @@ public final class Bridge extends LayoutBridge { Capability.ANIMATE); - Finalizers.init(); - BridgeAssetManager.initSystem(); // When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener |