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

Commit 00d3a28a authored by Orion Hodson's avatar Orion Hodson Committed by Android (Google) Code Review
Browse files

Merge "Retire android::nio_{get,release}Buffer"

parents 395a639d b0461ebb
Loading
Loading
Loading
Loading
+18 −40
Original line number Original line Diff line number Diff line
@@ -18,51 +18,29 @@


#include "core_jni_helpers.h"
#include "core_jni_helpers.h"


namespace {
namespace android {


void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) {
AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit)
    assert(array);
        : fEnv(env), fCommit(commit) {
    jint position;
    jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer);
    jint limit;
    jint elementSizeShift;
    jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
    if (pointer != 0L) {
    if (pointer != 0L) {
        *array = nullptr;
        // Buffer is backed by a direct buffer.
        *elements = nullptr;
        fArray = nullptr;
        pointer += position << elementSizeShift;
        fElements = nullptr;
        return reinterpret_cast<void*>(pointer);
        fPointer = reinterpret_cast<void*>(pointer);
    } else {
        // Buffer is backed by a managed array.
        jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer);
        fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer);
        fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr);
        fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset);
    }
    }
    jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer);
    *array = jniGetNioBufferBaseArray(_env, buffer);
    *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
    return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset);
}
}


void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) {
AutoBufferPointer::~AutoBufferPointer() {
    _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT);
}

}  // namespace

void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
    void* elements;
    return getPointer(_env, buffer, array, &elements);
}

void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
    releasePointer(_env, array, data, commit);
}

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

android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) {
    fEnv = env;
    fCommit = commit;
    fPointer = getPointer(env, nioBuffer, &fArray, &fElements);
}

android::AutoBufferPointer::~AutoBufferPointer() {
    if (nullptr != fArray) {
    if (nullptr != fArray) {
        releasePointer(fEnv, fArray, fElements, fCommit);
        fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT);
    }
    }
}
}

}  // namespace android
+42 −35
Original line number Original line Diff line number Diff line
@@ -22,51 +22,58 @@
namespace android {
namespace android {


/**
/**
 * Given an nio.Buffer, return a pointer to it, beginning at its current
 * Class providing scoped access to the memory backing a java.nio.Buffer instance.
 * position. The returned pointer is only valid for the current JNI stack-frame.
 * For performance, it does not create any global references, so the getPointer
 * (and releasePointer if array is returned non-null) must be done in the
 * same JNI stack-frame.
 *
 *
 * @param env   The current JNI env
 * Instances of this class should only be allocated on the stack as heap allocation is not
 * @param buffer    The nio.Buffer object
 * supported.
 * @param array     REQUIRED. Output. If on return it is set to non-null, then
 *
 *                  nio_releasePointer must be called with the array
 * Instances of this class do not create any global references for performance reasons.
 *                  and the returned pointer when the caller is through with it.
 *                  If on return it is set to null, do not call
 *                  nio_releasePointer.
 * @return The pointer to the memory in the buffer object
 */
 */
void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array);
class AutoBufferPointer final {

public:
/**
    /** Constructor for an AutoBufferPointer instance.
 * Call this if android_nio_getPointer returned non-null in its array parameter.
 * Pass that array and the returned pointer when you are done accessing the
 * pointer. If called (i.e. array is non-null), it must be called in the same
 * JNI stack-frame as getPointer
     *
     *
     * @param env          The current JNI env
     * @param env          The current JNI env
 * @param buffer    The array returned from android_nio_getPointer (!= null)
     * @param nioBuffer    Instance of a java.nio.Buffer whose memory will be accessed.
 * @param pointer   The pointer returned by android_nio_getPointer
     * @param commit       JNI_TRUE if the underlying memory will be updated and should be
 * @param commit    JNI_FALSE if the pointer was just read, and JNI_TRUE if
     *                     copied back to the managed heap. JNI_FALSE if the data will
 *                  the pointer was written to.
     *                     not be modified or the modifications may be discarded.
     *
     * The commit parameter is only applicable if the buffer is backed by a managed heap
     * array and the runtime had to provide a copy of the data rather than the original data.
     */
     */
void nio_releasePointer(JNIEnv *env, jarray array, void *pointer,
                                jboolean commit);

class AutoBufferPointer {
public:
    AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit);
    AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit);

    /** Destructor for an AutoBufferPointer instance.
     *
     * Releases critical managed heap array pointer if acquired.
     */
    ~AutoBufferPointer();
    ~AutoBufferPointer();


    /**
     * Returns a pointer to the current position of the buffer provided to the constructor.  This
     * pointer is only valid whilst the AutoBufferPointer instance remains in scope.
     */
    void* pointer() const { return fPointer; }
    void* pointer() const { return fPointer; }


private:
private:
    JNIEnv* fEnv;
    JNIEnv* const fEnv;
    void*   fPointer;   // pointer to current buffer position.
    void* fPointer;   // Pointer to current buffer position when constructed.
    void*   fElements;  // pointer to array element 0 (may be directly in fArray or a copy).
    void* fElements;  // Pointer to array element 0 (null if buffer is direct, may be
    jarray  fArray;     // pointer to array on managed heap.
                      // within fArray or point to a copy of the array).
    jboolean fCommit;   // commit data to source if required (when fElements is a copy of fArray).
    jarray fArray;    // Pointer to array on managed heap.
    const jboolean fCommit;  // Flag to commit data to source (when fElements is a copy of fArray).

    // Unsupported constructors and operators.
    AutoBufferPointer() = delete;
    AutoBufferPointer(AutoBufferPointer&) = delete;
    AutoBufferPointer& operator=(AutoBufferPointer&) = delete;
    static void* operator new(std::size_t);
    static void* operator new[](std::size_t);
    static void* operator new(std::size_t, void*);
    static void* operator new[](std::size_t, void*);
    static void operator delete(void*, std::size_t);
    static void operator delete[](void*, std::size_t);
};
};


}   /* namespace android */
}   /* namespace android */
+165 −6
Original line number Original line Diff line number Diff line
@@ -23,6 +23,8 @@ import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
import junit.framework.TestCase;


import java.nio.ByteBuffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;


public class BitmapTest extends TestCase {
public class BitmapTest extends TestCase {


@@ -266,10 +268,11 @@ public class BitmapTest extends TestCase {
    }
    }


    @SmallTest
    @SmallTest
    public void testCopyWithDirectBuffer() {
    public void testCopyWithDirectByteBuffer() {
        // Initialize Bitmap
        // Initialize Bitmap
        final int width = 2;
        final int width = 2;
        final int height = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);


@@ -277,7 +280,8 @@ public class BitmapTest extends TestCase {
        // of bitmap.
        // of bitmap.
        final int pad = 1;
        final int pad = 1;
        final byte padValue = 0x5a;
        final byte padValue = 0x5a;
        final int bufferSize = pad + width * height * 2 + pad;
        final int bytesPerElement = 1;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
        ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);


        // Write padding
        // Write padding
@@ -287,7 +291,8 @@ public class BitmapTest extends TestCase {
        // Copy bitmap
        // Copy bitmap
        directBuffer.position(pad);
        directBuffer.position(pad);
        bm1.copyPixelsToBuffer(directBuffer);
        bm1.copyPixelsToBuffer(directBuffer);
        assertEquals(directBuffer.position(), pad + width * height * 2);
        assertEquals(directBuffer.position(),
                     pad + width * height * bytesPerPixel / bytesPerElement);


        // Check padding
        // Check padding
        assertEquals(directBuffer.get(0), padValue);
        assertEquals(directBuffer.get(0), padValue);
@@ -301,10 +306,89 @@ public class BitmapTest extends TestCase {
    }
    }


    @SmallTest
    @SmallTest
    public void testCopyWithHeapBuffer() {
    public void testCopyWithDirectShortBuffer() {
        // Initialize Bitmap
        // Initialize Bitmap
        final int width = 2;
        final int width = 2;
        final int height = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);

        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
        // of bitmap.
        final int pad = 1;
        final short padValue = 0x55aa;
        final int bytesPerElement = 2;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        ShortBuffer directBuffer =
                ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer();

        // Write padding
        directBuffer.put(0, padValue);
        directBuffer.put(directBuffer.limit() - 1, padValue);

        // Copy bitmap
        directBuffer.position(pad);
        bm1.copyPixelsToBuffer(directBuffer);
        assertEquals(directBuffer.position(),
                     pad + width * height * bytesPerPixel / bytesPerElement);

        // Check padding
        assertEquals(directBuffer.get(0), padValue);
        assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue);

        // Create bitmap from heap buffer and check match.
        directBuffer.position(pad);
        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm2.copyPixelsFromBuffer(directBuffer);
        assertTrue(bm2.sameAs(bm1));
    }

    @SmallTest
    public void testCopyWithDirectIntBuffer() {
        // Initialize Bitmap
        final int width = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);

        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
        // of bitmap.
        final int pad = 1;
        final int padValue = 0x55aa5a5a;
        final int bytesPerElement = 4;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        IntBuffer directBuffer =
                ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer();

        // Write padding
        directBuffer.put(0, padValue);
        directBuffer.put(directBuffer.limit() - 1, padValue);

        // Copy bitmap
        directBuffer.position(pad);
        bm1.copyPixelsToBuffer(directBuffer);
        assertEquals(directBuffer.position(),
                     pad + width * height * bytesPerPixel / bytesPerElement);

        // Check padding
        assertEquals(directBuffer.get(0), padValue);
        assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue);

        // Create bitmap from heap buffer and check match.
        directBuffer.position(pad);
        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm2.copyPixelsFromBuffer(directBuffer);
        assertTrue(bm2.sameAs(bm1));
    }

    @SmallTest
    public void testCopyWithHeapByteBuffer() {
        // Initialize Bitmap
        final int width = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);


@@ -312,7 +396,8 @@ public class BitmapTest extends TestCase {
        // of bitmap.
        // of bitmap.
        final int pad = 1;
        final int pad = 1;
        final byte padValue = 0x5a;
        final byte padValue = 0x5a;
        final int bufferSize = pad + width * height * 2 + pad;
        final int bytesPerElement = 1;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);
        ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);


        // Write padding
        // Write padding
@@ -322,7 +407,81 @@ public class BitmapTest extends TestCase {
        // Copy bitmap
        // Copy bitmap
        heapBuffer.position(pad);
        heapBuffer.position(pad);
        bm1.copyPixelsToBuffer(heapBuffer);
        bm1.copyPixelsToBuffer(heapBuffer);
        assertEquals(heapBuffer.position(), pad + width * height * 2);
        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);

        // Check padding
        assertEquals(heapBuffer.get(0), padValue);
        assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue);

        // Create bitmap from heap buffer and check match.
        heapBuffer.position(pad);
        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm2.copyPixelsFromBuffer(heapBuffer);
        assertTrue(bm2.sameAs(bm1));
    }

    @SmallTest
    public void testCopyWithHeapShortBuffer() {
        // Initialize Bitmap
        final int width = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);

        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
        // of bitmap.
        final int pad = 1;
        final short padValue = 0x55aa;
        final int bytesPerElement = 2;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize);

        // Write padding
        heapBuffer.put(0, padValue);
        heapBuffer.put(heapBuffer.limit() - 1, padValue);

        // Copy bitmap
        heapBuffer.position(pad);
        bm1.copyPixelsToBuffer(heapBuffer);
        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);

        // Check padding
        assertEquals(heapBuffer.get(0), padValue);
        assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue);

        // Create bitmap from heap buffer and check match.
        heapBuffer.position(pad);
        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm2.copyPixelsFromBuffer(heapBuffer);
        assertTrue(bm2.sameAs(bm1));
    }

    @SmallTest
    public void testCopyWithHeapIntBuffer() {
        // Initialize Bitmap
        final int width = 2;
        final int height = 2;
        final int bytesPerPixel = 2;
        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);

        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
        // of bitmap.
        final int pad = 1;
        final int padValue = 0x55aa5a5a;
        final int bytesPerElement = 4;
        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
        IntBuffer heapBuffer = IntBuffer.allocate(bufferSize);

        // Write padding
        heapBuffer.put(0, padValue);
        heapBuffer.put(heapBuffer.limit() - 1, padValue);

        // Copy bitmap
        heapBuffer.position(pad);
        bm1.copyPixelsToBuffer(heapBuffer);
        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);


        // Check padding
        // Check padding
        assertEquals(heapBuffer.get(0), padValue);
        assertEquals(heapBuffer.get(0), padValue);