Pass WRITE usage flag to the mapper if ImageReader was created with a
WRITE usage flag.

Since some producers rely on these buffers being unchanged (eg. for
partial rendering), this feature should be used with caution. A warning
to this effect was added in the Javadoc.

Bug: 162287616
Test: built emulator, confirmed no SIGSEGV anymore (b/162287616 fixed).
Change-Id: Ia1f8b8754b0d6ae75a2af33147645e744d593d82
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 87c3bb9..5dc6f75 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -198,7 +198,10 @@
      *   {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
      * </tr>
      * </table>
-     * Using other combinations may result in {@link IllegalArgumentException}.
+     * Using other combinations may result in {@link IllegalArgumentException}. Additionally,
+     * specifying {@link HardwareBuffer#USAGE_CPU_WRITE_RARELY} or
+     * {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} and writing to the ImageReader's buffers
+     * might break assumptions made by some producers, and should be used with caution.
      * </p>
      * <p>
      * If the {@link ImageReader} is used as an output target for a {@link
@@ -255,6 +258,7 @@
         mWidth = width;
         mHeight = height;
         mFormat = format;
+        mUsage = usage;
         mMaxImages = maxImages;
 
         if (width < 1 || height < 1) {
@@ -768,6 +772,7 @@
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
+    private final long mUsage;
     private final int mMaxImages;
     private final int mNumPlanes;
     private final Surface mSurface;
@@ -909,7 +914,8 @@
             throwISEIfImageIsInvalid();
 
             if (mPlanes == null) {
-                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
+                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat,
+                        ImageReader.this.mUsage);
             }
             // Shallow copy is fine.
             return mPlanes.clone();
@@ -1038,7 +1044,7 @@
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
-                int readerFormat);
+                int readerFormat, long readerUsage);
         private synchronized native int nativeGetWidth();
         private synchronized native int nativeGetHeight();
         private synchronized native int nativeGetFormat(int readerFormat);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0a02156..bd2a0eaa7 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -675,7 +675,8 @@
     return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
 }
 
-static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
+static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image,
+        uint64_t ndkReaderUsage) {
     ALOGV("%s", __FUNCTION__);
     BufferItem* buffer = Image_getBufferItem(env, thiz);
     if (buffer == NULL) {
@@ -684,8 +685,16 @@
         return;
     }
 
-    status_t res = lockImageFromBuffer(buffer,
-            GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
+    uint32_t lockUsage;
+    if ((ndkReaderUsage & (AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY
+            | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)) != 0) {
+        lockUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+    } else {
+        lockUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+    }
+
+    status_t res = lockImageFromBuffer(buffer, lockUsage, buffer->mFence->dup(), image);
+
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                 "lock buffer failed for format 0x%x",
@@ -721,7 +730,7 @@
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
-        int numPlanes, int readerFormat)
+        int numPlanes, int readerFormat, uint64_t ndkReaderUsage)
 {
     ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
     int rowStride = 0;
@@ -754,7 +763,7 @@
     }
 
     LockedImage lockedImg = LockedImage();
-    Image_getLockedImage(env, thiz, &lockedImg);
+    Image_getLockedImage(env, thiz, &lockedImg, ndkReaderUsage);
     if (env->ExceptionCheck()) {
         return NULL;
     }
@@ -839,7 +848,7 @@
 };
 
 static const JNINativeMethod gImageMethods[] = {
-    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+    {"nativeCreatePlanes",      "(IIJ)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                              (void*)Image_createSurfacePlanes },
     {"nativeGetWidth",          "()I",                       (void*)Image_getWidth },
     {"nativeGetHeight",         "()I",                       (void*)Image_getHeight },