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

Commit 775873a6 authored by Richard Uhler's avatar Richard Uhler
Browse files

Use NativeAllocationRegistry for Paint, Canvas, and Bitmap

Bug: 23130675
Change-Id: I3fbd84ba417ac63df75f87ee2c56e3e7f3c9eb46
parent 58647664
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1257,6 +1257,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_os_Binder),
    REG_JNI(register_android_os_Parcel),
    REG_JNI(register_android_nio_utils),
    REG_JNI(register_android_graphics_Canvas),
    REG_JNI(register_android_graphics_Graphics),
    REG_JNI(register_android_view_DisplayEventReceiver),
    REG_JNI(register_android_view_RenderNode),
@@ -1289,7 +1290,6 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_graphics_BitmapRegionDecoder),
    REG_JNI(register_android_graphics_Camera),
    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
    REG_JNI(register_android_graphics_Canvas),
    REG_JNI(register_android_graphics_CanvasProperty),
    REG_JNI(register_android_graphics_ColorFilter),
    REG_JNI(register_android_graphics_DrawFilter),
+6 −3
Original line number Diff line number Diff line
@@ -774,11 +774,14 @@ static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
    return ret;
}

static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmap(bitmapHandle);
static void Bitmap_destruct(Bitmap* bitmap) {
    bitmap->detachFromJava();
}

static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
}

static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmap(bitmapHandle);
    bitmap->freePixels();
@@ -1357,7 +1360,7 @@ static const JNINativeMethod gBitmapMethods[] = {
        (void*)Bitmap_copy },
    {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
        (void*)Bitmap_copyAshmem },
    {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
    {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
    {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
+7 −4
Original line number Diff line number Diff line
@@ -76,9 +76,12 @@ namespace PaintGlue {
        AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
    };

    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
        Paint* obj = reinterpret_cast<Paint*>(objHandle);
        delete obj;
    static void deletePaint(Paint* paint) {
        delete paint;
    }

    static jlong getNativeFinalizer(JNIEnv*, jobject) {
        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint));
    }

    static jlong init(JNIEnv* env, jobject) {
@@ -863,7 +866,7 @@ namespace PaintGlue {
}; // namespace PaintGlue

static const JNINativeMethod methods[] = {
    {"nFinalizer", "(J)V", (void*) PaintGlue::finalizer},
    {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
    {"nInit","()J", (void*) PaintGlue::init},
    {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},

+7 −3
Original line number Diff line number Diff line
@@ -37,8 +37,12 @@ static Canvas* get_canvas(jlong canvasHandle) {
    return reinterpret_cast<Canvas*>(canvasHandle);
}

static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
    delete get_canvas(canvasHandle);
static void delete_canvas(Canvas* canvas) {
    delete canvas;
}

static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
}

// Native wrapper constructor used by Canvas(Bitmap)
@@ -710,7 +714,7 @@ static void freeTextLayoutCaches(JNIEnv* env, jobject) {
}; // namespace CanvasJNI

static const JNINativeMethod gMethods[] = {
    {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
    {"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
    {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
    {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
    {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
+40 −68
Original line number Diff line number Diff line
@@ -25,14 +25,14 @@ import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;

import dalvik.system.VMRuntime;

import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import libcore.util.NativeAllocationRegistry;

public final class Bitmap implements Parcelable {
    private static final String TAG = "Bitmap";

@@ -44,6 +44,10 @@ public final class Bitmap implements Parcelable {
     */
    public static final int DENSITY_NONE = 0;

    // Estimated size of the Bitmap native allocation, not including
    // pixel data.
    private static final long NATIVE_ALLOCATION_SIZE = 32;

    /**
     * Backing buffer for the Bitmap.
     */
@@ -51,7 +55,6 @@ public final class Bitmap implements Parcelable {

    // Convenience for JNI access
    private final long mNativePtr;
    private final BitmapFinalizer mFinalizer;

    private final boolean mIsMutable;

@@ -125,9 +128,13 @@ public final class Bitmap implements Parcelable {
        }

        mNativePtr = nativeBitmap;
        mFinalizer = new BitmapFinalizer(nativeBitmap);
        int nativeAllocationByteCount = (buffer == null ? getByteCount() : 0);
        mFinalizer.setNativeAllocationByteCount(nativeAllocationByteCount);
        long nativeSize = NATIVE_ALLOCATION_SIZE;
        if (buffer == null) {
            nativeSize += getByteCount();
        }
        NativeAllocationRegistry registry = new NativeAllocationRegistry(
            nativeGetNativeFinalizer(), nativeSize);
        registry.registerNativeAllocation(this, nativeBitmap);
    }

    /**
@@ -253,7 +260,7 @@ public final class Bitmap implements Parcelable {
            throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
        }

        nativeReconfigure(mFinalizer.mNativeBitmap, width, height, config.nativeInt,
        nativeReconfigure(mNativePtr, width, height, config.nativeInt,
                mBuffer.length, mRequestPremultiplied);
        mWidth = width;
        mHeight = height;
@@ -330,8 +337,8 @@ public final class Bitmap implements Parcelable {
     * there are no more references to this bitmap.
     */
    public void recycle() {
        if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
            if (nativeRecycle(mFinalizer.mNativeBitmap)) {
        if (!mRecycled && mNativePtr != 0) {
            if (nativeRecycle(mNativePtr)) {
                // 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
@@ -364,7 +371,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called getGenerationId() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return nativeGenerationId(mFinalizer.mNativeBitmap);
        return nativeGenerationId(mNativePtr);
    }

    /**
@@ -520,7 +527,7 @@ public final class Bitmap implements Parcelable {
            throw new RuntimeException("Buffer not large enough for pixels");
        }

        nativeCopyPixelsToBuffer(mFinalizer.mNativeBitmap, dst);
        nativeCopyPixelsToBuffer(mNativePtr, dst);

        // now update the buffer's position
        int position = dst.position();
@@ -560,7 +567,7 @@ public final class Bitmap implements Parcelable {
            throw new RuntimeException("Buffer not large enough for pixels");
        }

        nativeCopyPixelsFromBuffer(mFinalizer.mNativeBitmap, src);
        nativeCopyPixelsFromBuffer(mNativePtr, src);

        // now update the buffer's position
        int position = src.position();
@@ -582,7 +589,7 @@ public final class Bitmap implements Parcelable {
     */
    public Bitmap copy(Config config, boolean isMutable) {
        checkRecycled("Can't copy a recycled bitmap");
        Bitmap b = nativeCopy(mFinalizer.mNativeBitmap, config.nativeInt, isMutable);
        Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
        if (b != null) {
            b.setPremultiplied(mRequestPremultiplied);
            b.mDensity = mDensity;
@@ -598,7 +605,7 @@ public final class Bitmap implements Parcelable {
     */
    public Bitmap createAshmemBitmap() {
        checkRecycled("Can't copy a recycled bitmap");
        Bitmap b = nativeCopyAshmem(mFinalizer.mNativeBitmap);
        Bitmap b = nativeCopyAshmem(mNativePtr);
        if (b != null) {
            b.setPremultiplied(mRequestPremultiplied);
            b.mDensity = mDensity;
@@ -859,7 +866,7 @@ public final class Bitmap implements Parcelable {
        }
        bm.setHasAlpha(hasAlpha);
        if (config == Config.ARGB_8888 && !hasAlpha) {
            nativeErase(bm.mFinalizer.mNativeBitmap, 0xff000000);
            nativeErase(bm.mNativePtr, 0xff000000);
        }
        // No need to initialize the bitmap to zeroes with other configs;
        // it is backed by a VM byte array which is by definition preinitialized
@@ -1049,7 +1056,7 @@ public final class Bitmap implements Parcelable {
            throw new IllegalArgumentException("quality must be 0..100");
        }
        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
        boolean result = nativeCompress(mFinalizer.mNativeBitmap, format.nativeInt,
        boolean result = nativeCompress(mNativePtr, format.nativeInt,
                quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        return result;
@@ -1093,7 +1100,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called isPremultiplied() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return nativeIsPremultiplied(mFinalizer.mNativeBitmap);
        return nativeIsPremultiplied(mNativePtr);
    }

    /**
@@ -1119,7 +1126,7 @@ public final class Bitmap implements Parcelable {
    public final void setPremultiplied(boolean premultiplied) {
        checkRecycled("setPremultiplied called on a recycled bitmap");
        mRequestPremultiplied = premultiplied;
        nativeSetPremultiplied(mFinalizer.mNativeBitmap, premultiplied);
        nativeSetPremultiplied(mNativePtr, premultiplied);
    }

    /** Returns the bitmap's width */
@@ -1220,7 +1227,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return nativeRowBytes(mFinalizer.mNativeBitmap);
        return nativeRowBytes(mNativePtr);
    }

    /**
@@ -1266,7 +1273,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called getConfig() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return Config.nativeToConfig(nativeConfig(mFinalizer.mNativeBitmap));
        return Config.nativeToConfig(nativeConfig(mNativePtr));
    }

    /** Returns true if the bitmap's config supports per-pixel alpha, and
@@ -1281,7 +1288,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return nativeHasAlpha(mFinalizer.mNativeBitmap);
        return nativeHasAlpha(mNativePtr);
    }

    /**
@@ -1296,7 +1303,7 @@ public final class Bitmap implements Parcelable {
     */
    public void setHasAlpha(boolean hasAlpha) {
        checkRecycled("setHasAlpha called on a recycled bitmap");
        nativeSetHasAlpha(mFinalizer.mNativeBitmap, hasAlpha, mRequestPremultiplied);
        nativeSetHasAlpha(mNativePtr, hasAlpha, mRequestPremultiplied);
    }

    /**
@@ -1320,7 +1327,7 @@ public final class Bitmap implements Parcelable {
        if (mRecycled) {
            Log.w(TAG, "Called hasMipMap() on a recycle()'d bitmap! This is undefined behavior!");
        }
        return nativeHasMipMap(mFinalizer.mNativeBitmap);
        return nativeHasMipMap(mNativePtr);
    }

    /**
@@ -1345,7 +1352,7 @@ public final class Bitmap implements Parcelable {
     */
    public final void setHasMipMap(boolean hasMipMap) {
        checkRecycled("setHasMipMap called on a recycled bitmap");
        nativeSetHasMipMap(mFinalizer.mNativeBitmap, hasMipMap);
        nativeSetHasMipMap(mNativePtr, hasMipMap);
    }

    /**
@@ -1358,7 +1365,7 @@ public final class Bitmap implements Parcelable {
        if (!isMutable()) {
            throw new IllegalStateException("cannot erase immutable bitmaps");
        }
        nativeErase(mFinalizer.mNativeBitmap, c);
        nativeErase(mNativePtr, c);
    }

    /**
@@ -1375,7 +1382,7 @@ public final class Bitmap implements Parcelable {
    public int getPixel(int x, int y) {
        checkRecycled("Can't call getPixel() on a recycled bitmap");
        checkPixelAccess(x, y);
        return nativeGetPixel(mFinalizer.mNativeBitmap, x, y);
        return nativeGetPixel(mNativePtr, x, y);
    }

    /**
@@ -1408,7 +1415,7 @@ public final class Bitmap implements Parcelable {
            return; // nothing to do
        }
        checkPixelsAccess(x, y, width, height, offset, stride, pixels);
        nativeGetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
        nativeGetPixels(mNativePtr, pixels, offset, stride,
                        x, y, width, height);
    }

@@ -1489,7 +1496,7 @@ public final class Bitmap implements Parcelable {
            throw new IllegalStateException();
        }
        checkPixelAccess(x, y);
        nativeSetPixel(mFinalizer.mNativeBitmap, x, y, color);
        nativeSetPixel(mNativePtr, x, y, color);
    }

    /**
@@ -1525,7 +1532,7 @@ public final class Bitmap implements Parcelable {
            return; // nothing to do
        }
        checkPixelsAccess(x, y, width, height, offset, stride, pixels);
        nativeSetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
        nativeSetPixels(mNativePtr, pixels, offset, stride,
                        x, y, width, height);
    }

@@ -1563,7 +1570,7 @@ public final class Bitmap implements Parcelable {
     */
    public void writeToParcel(Parcel p, int flags) {
        checkRecycled("Can't parcel a recycled bitmap");
        if (!nativeWriteToParcel(mFinalizer.mNativeBitmap, mIsMutable, mDensity, p)) {
        if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
            throw new RuntimeException("native writeToParcel failed");
        }
    }
@@ -1609,7 +1616,7 @@ public final class Bitmap implements Parcelable {
    public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
        checkRecycled("Can't extractAlpha on a recycled bitmap");
        long nativePaint = paint != null ? paint.getNativeInstance() : 0;
        Bitmap bm = nativeExtractAlpha(mFinalizer.mNativeBitmap, nativePaint, offsetXY);
        Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
        if (bm == null) {
            throw new RuntimeException("Failed to extractAlpha on Bitmap");
        }
@@ -1629,7 +1636,7 @@ public final class Bitmap implements Parcelable {
        if (other.isRecycled()) {
            throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
        }
        return nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap);
        return nativeSameAs(mNativePtr, other.mNativePtr);
    }

    /**
@@ -1660,41 +1667,6 @@ public final class Bitmap implements Parcelable {
        return nativeRefPixelRef(mNativePtr);
    }

    private static class BitmapFinalizer {
        private long mNativeBitmap;

        // Native memory allocated for the duration of the Bitmap,
        // if pixel data allocated into native memory, instead of java byte[]
        private int mNativeAllocationByteCount;

        BitmapFinalizer(long nativeBitmap) {
            mNativeBitmap = nativeBitmap;
        }

        public void setNativeAllocationByteCount(int nativeByteCount) {
            if (mNativeAllocationByteCount != 0) {
                VMRuntime.getRuntime().registerNativeFree(mNativeAllocationByteCount);
            }
            mNativeAllocationByteCount = nativeByteCount;
            if (mNativeAllocationByteCount != 0) {
                VMRuntime.getRuntime().registerNativeAllocation(mNativeAllocationByteCount);
            }
        }

        @Override
        public void finalize() {
            try {
                super.finalize();
            } catch (Throwable t) {
                // Ignore
            } finally {
                setNativeAllocationByteCount(0);
                nativeDestructor(mNativeBitmap);
                mNativeBitmap = 0;
            }
        }
    }

    //////////// native methods

    private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -1703,7 +1675,7 @@ public final class Bitmap implements Parcelable {
    private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                            boolean isMutable);
    private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
    private static native void nativeDestructor(long nativeBitmap);
    private static native long nativeGetNativeFinalizer();
    private static native boolean nativeRecycle(long nativeBitmap);
    private static native void nativeReconfigure(long nativeBitmap, int width, int height,
                                                 int config, int allocSize,
Loading