Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d9da135 authored by Derek Sollenberger's avatar Derek Sollenberger Committed by Android (Google) Code Review
Browse files

Merge "Update AndroidPixelRef to prevent VM from cleaning up memory prematurely." into lmp-mr1-dev

parents c9660bdf f29d5a5b
Loading
Loading
Loading
Loading
+13 −14
Original line number Diff line number Diff line
@@ -558,7 +558,7 @@ class GLES20Canvas extends HardwareCanvas {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    }

@@ -567,32 +567,31 @@ class GLES20Canvas extends HardwareCanvas {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    }

    private static native void nDrawPatch(long renderer, long bitmap, byte[] buffer, long chunk,
    private static native void nDrawPatch(long renderer, long bitmap, long chunk,
            float left, float top, float right, float bottom, long paint);

    @Override
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
        throwIfCannotDraw(bitmap);
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
            float left, float top, long paint);
    private static native void nDrawBitmap(long renderer, long bitmap, float left,
            float top, long paint);

    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        throwIfCannotDraw(bitmap);
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
                matrix.native_instance, nativePaint);
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
    private static native void nDrawBitmap(long renderer, long bitmap,
            long matrix, long paint);

    @Override
@@ -612,7 +611,7 @@ class GLES20Canvas extends HardwareCanvas {
            bottom = src.bottom;
        }

        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    }

@@ -633,11 +632,11 @@ class GLES20Canvas extends HardwareCanvas {
            bottom = src.bottom;
        }

        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
    private static native void nDrawBitmap(long renderer, long bitmap,
            float srcLeft, float srcTop, float srcRight, float srcBottom,
            float left, float top, float right, float bottom, long paint);

@@ -698,11 +697,11 @@ class GLES20Canvas extends HardwareCanvas {
        }

        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, meshWidth, meshHeight,
                verts, vertOffset, colors, colorOffset, nativePaint);
    }

    private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
    private static native void nDrawBitmapMesh(long renderer, long bitmap,
            int meshWidth, int meshHeight, float[] verts, int vertOffset,
            int[] colors, int colorOffset, long paint);

+5 −101
Original line number Diff line number Diff line
@@ -492,19 +492,15 @@ AndroidPixelRef::AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* sto
        SkMallocPixelRef(info, storage, rowBytes, ctable, (storageObj == NULL)),
        fWrappedPixelRef(NULL) {
    SkASSERT(storage);
    SkASSERT(storageObj);
    SkASSERT(env);

    if (env->GetJavaVM(&fVM) != JNI_OK) {
        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
        sk_throw();
    }
    fStorageObj = storageObj;
    fHasGlobalRef = false;
    fGlobalRefCnt = 0;

    // If storageObj is NULL, the memory was NOT allocated on the Java heap
    fOnJavaHeap = (storageObj != NULL);

    fStorageObj = (jbyteArray) env->NewGlobalRef(storageObj);
}

AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info,
@@ -516,91 +512,18 @@ AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImage
    SkASSERT(fWrappedPixelRef);
    SkSafeRef(fWrappedPixelRef);

    // don't need to initialize these, as all the relevant logic delegates to the wrapped ref
    // don't need to initialize this, as all the relevant logic delegates to the wrapped ref
    fStorageObj = NULL;
    fHasGlobalRef = false;
    fGlobalRefCnt = 0;
    fOnJavaHeap = false;
}

AndroidPixelRef::~AndroidPixelRef() {
    if (fWrappedPixelRef) {
        SkSafeUnref(fWrappedPixelRef);
    } else if (fOnJavaHeap) {
        JNIEnv* env = vm2env(fVM);

        if (fStorageObj && fHasGlobalRef) {
            env->DeleteGlobalRef(fStorageObj);
        }
        fStorageObj = NULL;
    }
}
jbyteArray AndroidPixelRef::getStorageObj() {
    if (fWrappedPixelRef) {
        return fWrappedPixelRef->fStorageObj;
    }
    return fStorageObj;
}

void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) {
    if (fWrappedPixelRef) {
        // delegate java obj management to the wrapped ref
        fWrappedPixelRef->setLocalJNIRef(arr);
    } else if (!fHasGlobalRef) {
        fStorageObj = arr;
    }
}

void AndroidPixelRef::globalRef(void* localref) {
    if (fWrappedPixelRef) {
        // delegate java obj management to the wrapped ref
        fWrappedPixelRef->globalRef(localref);

        // Note: we only ref and unref the wrapped AndroidPixelRef so that
        // bitmap->pixelRef()->globalRef() and globalUnref() can be used in a pair, even if
        // the bitmap has its underlying AndroidPixelRef swapped out/wrapped
        return;
    }
    if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
        JNIEnv *env = vm2env(fVM);

        // If JNI ref was passed, it is always used
        if (localref) fStorageObj = (jbyteArray) localref;

        if (fStorageObj == NULL) {
            SkDebugf("No valid local ref to create a JNI global ref\n");
            sk_throw();
        }
        if (fHasGlobalRef) {
            // This should never happen
            SkDebugf("Already holding a JNI global ref");
            sk_throw();
        }

        fStorageObj = (jbyteArray) env->NewGlobalRef(fStorageObj);
        // TODO: Check for failure here
        fHasGlobalRef = true;
    }
    ref();
}

void AndroidPixelRef::globalUnref() {
    if (fWrappedPixelRef) {
        // delegate java obj management to the wrapped ref
        fWrappedPixelRef->globalUnref();
        return;
    }
    if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
    } else {
        SkASSERT(fStorageObj);
        JNIEnv* env = vm2env(fVM);
        if (!fHasGlobalRef) {
            SkDebugf("We don't have a global ref!");
            sk_throw();
        }
        env->DeleteGlobalRef(fStorageObj);
        fStorageObj = NULL;
        fHasGlobalRef = false;
    }
    unref();
}

///////////////////////////////////////////////////////////////////////////////
@@ -657,25 +580,6 @@ bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {

////////////////////////////////////////////////////////////////////////////////

JavaHeapBitmapRef::JavaHeapBitmapRef(JNIEnv* env, SkBitmap* nativeBitmap, jbyteArray buffer) {
    fEnv = env;
    fNativeBitmap = nativeBitmap;
    fBuffer = buffer;

    // If the buffer is NULL, the backing memory wasn't allocated on the Java heap
    if (fBuffer) {
        ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(fBuffer);
    }
}

JavaHeapBitmapRef::~JavaHeapBitmapRef() {
    if (fBuffer) {
        ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(NULL);
    }
}

////////////////////////////////////////////////////////////////////////////////

static jclass make_globalref(JNIEnv* env, const char classname[])
{
    jclass c = env->FindClass(classname);
+0 −41
Original line number Diff line number Diff line
@@ -123,52 +123,11 @@ public:

    virtual ~AndroidPixelRef();

    jbyteArray getStorageObj();

    void setLocalJNIRef(jbyteArray arr);

    /** Used to hold a ref to the pixels when the Java bitmap may be collected.
     *  If specified, 'localref' is a valid JNI local reference to the byte array
     *  containing the pixel data.
     *
     *  'localref' may only be NULL if setLocalJNIRef() was already called with
     *  a JNI local ref that is still valid.
     */
    virtual void globalRef(void* localref=NULL);

    /** Release a ref that was acquired using globalRef(). */
    virtual void globalUnref();

private:
    AndroidPixelRef* const fWrappedPixelRef; // if set, delegate memory management calls to this

    JavaVM* fVM;
    bool fOnJavaHeap; // If true, the memory was allocated on the Java heap

    jbyteArray fStorageObj; // The Java byte[] object used as the bitmap backing store
    bool fHasGlobalRef; // If true, fStorageObj holds a JNI global ref

    mutable int32_t fGlobalRefCnt;
};

/** A helper class for accessing Java-heap-allocated bitmaps.
 *  This should be used when calling into a JNI method that retains a
 *  reference to the bitmap longer than the lifetime of the Java Bitmap.
 *
 *  After creating an instance of this class, a call to
 *  AndroidPixelRef::globalRef() will allocate a JNI global reference
 *  to the backing buffer object.
 */
class JavaHeapBitmapRef {
public:

    JavaHeapBitmapRef(JNIEnv *env, SkBitmap* nativeBitmap, jbyteArray buffer);
    ~JavaHeapBitmapRef();

private:
    JNIEnv* fEnv;
    SkBitmap* fNativeBitmap;
    jbyteArray fBuffer;
};

/** Allocator which allocates the backing buffer in the Java heap.
+11 −24
Original line number Diff line number Diff line
@@ -347,11 +347,8 @@ static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject clazz,
// ----------------------------------------------------------------------------

static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong bitmapPtr, jbyteArray buffer,
        jfloat left, jfloat top, jlong paintPtr) {
        jlong rendererPtr, jlong bitmapPtr, jfloat left, jfloat top, jlong paintPtr) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
    // This object allows the renderer to allocate a global JNI ref to the buffer object.
    JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);

    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
@@ -364,12 +361,10 @@ static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz,
}

static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong bitmapPtr, jbyteArray buffer,
        jlong rendererPtr, jlong bitmapPtr,
        float srcLeft, float srcTop, float srcRight, float srcBottom,
        float dstLeft, float dstTop, float dstRight, float dstBottom, jlong paintPtr) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
    // This object allows the renderer to allocate a global JNI ref to the buffer object.
    JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);

    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
@@ -378,11 +373,8 @@ static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz,
}

static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong bitmapPtr, jbyteArray buffer,
        jlong matrixPtr, jlong paintPtr) {
        jlong rendererPtr, jlong bitmapPtr, jlong matrixPtr, jlong paintPtr) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
    // This object allows the renderer to allocate a global JNI ref to the buffer object.
    JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);

    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
@@ -427,12 +419,9 @@ static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
}

static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong bitmapPtr, jbyteArray buffer,
        jint meshWidth, jint meshHeight, jfloatArray vertices, jint offset, jintArray colors,
        jint colorOffset, jlong paintPtr) {
        jlong rendererPtr, jlong bitmapPtr, jint meshWidth, jint meshHeight,
        jfloatArray vertices, jint offset, jintArray colors, jint colorOffset, jlong paintPtr) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
    // This object allows the renderer to allocate a global JNI ref to the buffer object.
    JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);

    jfloat* verticesArray = vertices ? env->GetFloatArrayElements(vertices, NULL) + offset : NULL;
    jint* colorsArray = colors ? env->GetIntArrayElements(colors, NULL) + colorOffset : NULL;
@@ -446,11 +435,9 @@ static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
}

static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong bitmapPtr, jbyteArray buffer, jlong patchPtr,
        jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
        float left, float top, float right, float bottom, jlong paintPtr) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
    // This object allows the renderer to allocate a global JNI ref to the buffer object.
    JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);

    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
@@ -914,14 +901,14 @@ static JNINativeMethod gMethods[] = {
    { "nGetMatrix",         "(JJ)V",           (void*) android_view_GLES20Canvas_getMatrix },
    { "nConcatMatrix",      "(JJ)V",           (void*) android_view_GLES20Canvas_concatMatrix },

    { "nDrawBitmap",        "(JJ[BFFJ)V",      (void*) android_view_GLES20Canvas_drawBitmap },
    { "nDrawBitmap",        "(JJ[BFFFFFFFFJ)V",(void*) android_view_GLES20Canvas_drawBitmapRect },
    { "nDrawBitmap",        "(JJ[BJJ)V",       (void*) android_view_GLES20Canvas_drawBitmapMatrix },
    { "nDrawBitmap",        "(JJFFJ)V",      (void*) android_view_GLES20Canvas_drawBitmap },
    { "nDrawBitmap",        "(JJFFFFFFFFJ)V",(void*) android_view_GLES20Canvas_drawBitmapRect },
    { "nDrawBitmap",        "(JJJJ)V",       (void*) android_view_GLES20Canvas_drawBitmapMatrix },
    { "nDrawBitmap",        "(J[IIIFFIIZJ)V",  (void*) android_view_GLES20Canvas_drawBitmapData },

    { "nDrawBitmapMesh",    "(JJ[BII[FI[IIJ)V",(void*) android_view_GLES20Canvas_drawBitmapMesh },
    { "nDrawBitmapMesh",    "(JJII[FI[IIJ)V",(void*) android_view_GLES20Canvas_drawBitmapMesh },

    { "nDrawPatch",         "(JJ[BJFFFFJ)V",   (void*) android_view_GLES20Canvas_drawPatch },
    { "nDrawPatch",         "(JJJFFFFJ)V",   (void*) android_view_GLES20Canvas_drawPatch },

    { "nDrawColor",         "(JII)V",          (void*) android_view_GLES20Canvas_drawColor },
    { "nDrawRect",          "(JFFFFJ)V",       (void*) android_view_GLES20Canvas_drawRect },
+1 −6
Original line number Diff line number Diff line
@@ -48,13 +48,8 @@ public final class Bitmap implements Parcelable {

    /**
     * Backing buffer for the Bitmap.
     * Made public for quick access from drawing methods -- do NOT modify
     * from outside this class
     *
     * @hide
     */
    @SuppressWarnings("UnusedDeclaration") // native code only
    public byte[] mBuffer;
    private byte[] mBuffer;

    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
    private final BitmapFinalizer mFinalizer;