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

Commit 8c9d8f2a authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Ensure that PostProcess Canvas is released

Bug: 63909536
Bug: 63908092
Test: CtsGraphicsTestCases (ImageDecoderTest)

Refactor a method for calling postProcess from ImageDecoder. This will
be shared with the animated drawable (TODO). Call
PostProcess.postProcess in Java inside a try block to ensure that the
Canvas is released. Otherwise, a client could hold on to a pointer to
Canvas and keep using it, even though we have removed its backing.

In addition, share code for calling nDecodeBitmap.

Change-Id: I81ce2befce91ac1e27c78ad059c4b173a2c7e679
parent 21acc10b
Loading
Loading
Loading
Loading
+23 −21
Original line number Original line Diff line number Diff line
@@ -43,11 +43,11 @@ static jclass gIncomplete_class;
static jclass    gCorrupt_class;
static jclass    gCorrupt_class;
static jclass    gCanvas_class;
static jclass    gCanvas_class;
static jmethodID gImageDecoder_constructorMethodID;
static jmethodID gImageDecoder_constructorMethodID;
static jmethodID gImageDecoder_postProcessMethodID;
static jmethodID gPoint_constructorMethodID;
static jmethodID gPoint_constructorMethodID;
static jmethodID gIncomplete_constructorMethodID;
static jmethodID gIncomplete_constructorMethodID;
static jmethodID gCorrupt_constructorMethodID;
static jmethodID gCorrupt_constructorMethodID;
static jmethodID gCallback_onPartialImageMethodID;
static jmethodID gCallback_onPartialImageMethodID;
static jmethodID gPostProcess_postProcessMethodID;
static jmethodID gCanvas_constructorMethodID;
static jmethodID gCanvas_constructorMethodID;
static jmethodID gCanvas_releaseMethodID;
static jmethodID gCanvas_releaseMethodID;


@@ -176,6 +176,24 @@ static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jby
    return native_create(env, std::move(stream));
    return native_create(env, std::move(stream));
}
}


static jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder,
                                  std::unique_ptr<Canvas> canvas, int width, int height) {
    jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
                                     reinterpret_cast<jlong>(canvas.get()));
    if (!jcanvas) {
        doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
        return ImageDecoder::kUnknown;
    }

    // jcanvas now owns canvas.
    canvas.release();

    return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID,
                              jcanvas, width, height);
}

// Note: jpostProcess points to an ImageDecoder object if it has a PostProcess object, and nullptr
// otherwise.
static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                          jobject jcallback, jobject jpostProcess,
                                          jobject jcallback, jobject jpostProcess,
                                          jint desiredWidth, jint desiredHeight, jobject jsubset,
                                          jint desiredWidth, jint desiredHeight, jobject jsubset,
@@ -399,23 +417,9 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong


    if (jpostProcess) {
    if (jpostProcess) {
        std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
        std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
        jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
                                         reinterpret_cast<jlong>(canvas.get()));
        if (!jcanvas) {
            doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
            return nullptr;
        }
        // jcanvas will now own canvas.
        canvas.release();


        jint pixelFormat = env->CallIntMethod(jpostProcess, gPostProcess_postProcessMethodID,
        jint pixelFormat = postProcessAndRelease(env, jpostProcess, std::move(canvas),
                                              jcanvas, bm.width(), bm.height());
                                                 bm.width(), bm.height());
        if (env->ExceptionCheck()) {
            return nullptr;
        }

        // The Canvas objects are no longer needed, and will not remain valid.
        env->CallVoidMethod(jcanvas, gCanvas_releaseMethodID);
        if (env->ExceptionCheck()) {
        if (env->ExceptionCheck()) {
            return nullptr;
            return nullptr;
        }
        }
@@ -511,7 +515,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {
    { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
    { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
    { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
    { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
    { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
    { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnPartialImageListener;Landroid/graphics/PostProcess;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnPartialImageListener;Landroid/graphics/ImageDecoder;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
                                                                 (void*) ImageDecoder_nDecodeBitmap },
                                                                 (void*) ImageDecoder_nDecodeBitmap },
    { "nGetSampledSize","(JI)Landroid/graphics/Point;",          (void*) ImageDecoder_nGetSampledSize },
    { "nGetSampledSize","(JI)Landroid/graphics/Point;",          (void*) ImageDecoder_nGetSampledSize },
    { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
    { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
@@ -522,6 +526,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {
int register_android_graphics_ImageDecoder(JNIEnv* env) {
int register_android_graphics_ImageDecoder(JNIEnv* env) {
    gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
    gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JII)V");
    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JII)V");
    gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;II)I");


    gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
    gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
    gPoint_constructorMethodID = GetMethodIDOrDie(env, gPoint_class, "<init>", "(II)V");
    gPoint_constructorMethodID = GetMethodIDOrDie(env, gPoint_class, "<init>", "(II)V");
@@ -535,9 +540,6 @@ int register_android_graphics_ImageDecoder(JNIEnv* env) {
    jclass callback_class = FindClassOrDie(env, "android/graphics/ImageDecoder$OnPartialImageListener");
    jclass callback_class = FindClassOrDie(env, "android/graphics/ImageDecoder$OnPartialImageListener");
    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, callback_class, "onPartialImage", "(Ljava/io/IOException;)Z");
    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, callback_class, "onPartialImage", "(Ljava/io/IOException;)Z");


    jclass postProcess_class = FindClassOrDie(env, "android/graphics/PostProcess");
    gPostProcess_postProcessMethodID = GetMethodIDOrDie(env, postProcess_class, "postProcess", "(Landroid/graphics/Canvas;II)I");

    gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
    gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
    gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
    gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
    gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
    gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
+27 −27
Original line number Original line Diff line number Diff line
@@ -677,6 +677,18 @@ public final class ImageDecoder implements AutoCloseable {
        }
        }
    }
    }


    private Bitmap decodeBitmap() throws IOException {
        checkState();
        // nDecodeBitmap calls postProcessAndRelease only if mPostProcess
        // exists.
        ImageDecoder postProcessPtr = mPostProcess == null ? null : this;
        return nDecodeBitmap(mNativePtr, mOnPartialImageListener,
                postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
                mMutable, mAllocator, mRequireUnpremultiplied,
                mPreferRamOverQuality, mAsAlphaMask);

    }

    /**
    /**
     *  Create a {@link Drawable} from a {@code Source}.
     *  Create a {@link Drawable} from a {@code Source}.
     *
     *
@@ -702,8 +714,6 @@ public final class ImageDecoder implements AutoCloseable {
                }
                }
            }
            }


            decoder.checkState();

            if (decoder.mRequireUnpremultiplied) {
            if (decoder.mRequireUnpremultiplied) {
                // Though this could be supported (ignored) for opaque images,
                // Though this could be supported (ignored) for opaque images,
                // it seems better to always report this error.
                // it seems better to always report this error.
@@ -716,17 +726,7 @@ public final class ImageDecoder implements AutoCloseable {
                                                "Drawable!");
                                                "Drawable!");
            }
            }


            Bitmap bm = nDecodeBitmap(decoder.mNativePtr,
            Bitmap bm = decoder.decodeBitmap();
                                      decoder.mOnPartialImageListener,
                                      decoder.mPostProcess,
                                      decoder.mDesiredWidth,
                                      decoder.mDesiredHeight,
                                      decoder.mCropRect,
                                      false,    // mMutable
                                      decoder.mAllocator,
                                      false,    // mRequireUnpremultiplied
                                      decoder.mPreferRamOverQuality,
                                      decoder.mAsAlphaMask);
            Resources res = src.getResources();
            Resources res = src.getResources();
            if (res == null) {
            if (res == null) {
                bm.setDensity(Bitmap.DENSITY_NONE);
                bm.setDensity(Bitmap.DENSITY_NONE);
@@ -781,19 +781,7 @@ public final class ImageDecoder implements AutoCloseable {
                }
                }
            }
            }


            decoder.checkState();
            return decoder.decodeBitmap();

            return nDecodeBitmap(decoder.mNativePtr,
                                 decoder.mOnPartialImageListener,
                                 decoder.mPostProcess,
                                 decoder.mDesiredWidth,
                                 decoder.mDesiredHeight,
                                 decoder.mCropRect,
                                 decoder.mMutable,
                                 decoder.mAllocator,
                                 decoder.mRequireUnpremultiplied,
                                 decoder.mPreferRamOverQuality,
                                 decoder.mAsAlphaMask);
        }
        }
    }
    }


@@ -809,6 +797,18 @@ public final class ImageDecoder implements AutoCloseable {
        return decodeBitmap(src, null);
        return decodeBitmap(src, null);
    }
    }


    /**
     * Private method called by JNI.
     */
    @SuppressWarnings("unused")
    private int postProcessAndRelease(@NonNull Canvas canvas, int width, int height) {
        try {
            return mPostProcess.postProcess(canvas, width, height);
        } finally {
            canvas.release();
        }
    }

    private static native ImageDecoder nCreate(long asset) throws IOException;
    private static native ImageDecoder nCreate(long asset) throws IOException;
    private static native ImageDecoder nCreate(ByteBuffer buffer,
    private static native ImageDecoder nCreate(ByteBuffer buffer,
                                               int position,
                                               int position,
@@ -820,7 +820,7 @@ public final class ImageDecoder implements AutoCloseable {
    @NonNull
    @NonNull
    private static native Bitmap nDecodeBitmap(long nativePtr,
    private static native Bitmap nDecodeBitmap(long nativePtr,
            OnPartialImageListener listener,
            OnPartialImageListener listener,
            PostProcess postProcess,
            @Nullable ImageDecoder decoder,     // Only used if mPostProcess != null
            int width, int height,
            int width, int height,
            Rect cropRect, boolean mutable,
            Rect cropRect, boolean mutable,
            int allocator, boolean requireUnpremul,
            int allocator, boolean requireUnpremul,