ImageDecoder: Use AssetFileDescriptor's length

Bug: 166069819
Test: ImageDecoderTest (cts)

The contained asset may only be a subset of the AssetFileDescriptor.
SkWebpCodec reads the entire stream into a contiguous block of memory.
(This is because libwebp does not provide a streaming API for creating
its demuxer.) If the AssetFileDescriptor contains data after the webp
file, this wastes memory. In some cases, there may be a *lot* of data
after the webp file, so this can use too much memory, particularly on
low memory devices.

Change-Id: I8d8e520f43a7ef0d7e4534ef165d8c7e4d2a0b55
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 1f4fd23..da91d46 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -152,7 +152,7 @@
 }
 
 static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
-        jobject fileDescriptor, jboolean preferAnimation, jobject source) {
+        jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
 #ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
     return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
 #else
@@ -172,7 +172,14 @@
                                nullptr, source);
     }
 
-    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
+    std::unique_ptr<SkFILEStream> fileStream;
+    if (length == -1) {
+        // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
+        // so SkFILEStream will figure out the size of the file on its own.
+        fileStream.reset(new SkFILEStream(file));
+    } else {
+        fileStream.reset(new SkFILEStream(file, length));
+    }
     return native_create(env, std::move(fileStream), source, preferAnimation);
 #endif
 }
@@ -493,7 +500,7 @@
     { "nCreate",        "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
     { "nCreate",        "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
-    { "nCreate",        "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+    { "nCreate",        "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
     { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },