From d172a0cff8b7b3a4332d5992a87c5e3ab1784174 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 10 Sep 2020 14:57:11 -0400 Subject: 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. Merged-In: I8d8e520f43a7ef0d7e4534ef165d8c7e4d2a0b55 Change-Id: I8d8e520f43a7ef0d7e4534ef165d8c7e4d2a0b55 --- graphics/java/android/graphics/ImageDecoder.java | 6 +++--- libs/hwui/jni/ImageDecoder.cpp | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index c8f065ad094c..71744eff8a56 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -308,7 +308,7 @@ public final class ImageDecoder implements AutoCloseable { ImageDecoder decoder = null; try { - decoder = nCreate(fd, preferAnimation, source); + decoder = nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, preferAnimation, source); } finally { if (decoder == null) { IoUtils.closeQuietly(stream); @@ -356,7 +356,7 @@ public final class ImageDecoder implements AutoCloseable { try { try { Os.lseek(fd, offset, SEEK_SET); - decoder = nCreate(fd, preferAnimation, source); + decoder = nCreate(fd, assetFd.getDeclaredLength(), preferAnimation, source); } catch (ErrnoException e) { decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source); } @@ -1995,7 +1995,7 @@ public final class ImageDecoder implements AutoCloseable { private static native ImageDecoder nCreate(InputStream is, byte[] storage, boolean preferAnimation, Source src) throws IOException; // The fd must be seekable. - private static native ImageDecoder nCreate(FileDescriptor fd, + private static native ImageDecoder nCreate(FileDescriptor fd, long length, boolean preferAnimation, Source src) throws IOException; @NonNull private static native Bitmap nDecodeBitmap(long nativePtr, diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp index 41d939bd6373..c8c3d3d5b078 100644 --- a/libs/hwui/jni/ImageDecoder.cpp +++ b/libs/hwui/jni/ImageDecoder.cpp @@ -152,7 +152,7 @@ static jobject native_create(JNIEnv* env, std::unique_ptr stream, } 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 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/, nullptr, source); } - std::unique_ptr fileStream(new SkFILEStream(file)); + std::unique_ptr 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 } @@ -494,7 +501,7 @@ static const JNINativeMethod gImageDecoderMethods[] = { { "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 }, -- cgit v1.2.3-59-g8ed1b