diff options
| author | 2019-09-11 12:33:00 -0400 | |
|---|---|---|
| committer | 2019-09-16 16:29:58 -0400 | |
| commit | a7ec12f7efc032211e54aa1ce28c698413f02b8d (patch) | |
| tree | da3ec860c6f4c2d898785540be5da747f563099b | |
| parent | 081deafca597c61d4e7e73083ff685e64034c9cc (diff) | |
Fix AnimatedImageDrawables using ByteBuffers
Bug: 140715166
Test: I56dc6e9865c2701746c95ea584bcc70fe4d62a6c
AnimatedImageDrawable, when created from a ByteBuffer, needs to get a
pointer to the JNI interface in order to read the ByteBuffer (or
byte[]). But the AnimatedImageThread is not attached to the JVM. Attach
it as necessary.
Change-Id: I51b69b5b70f8c5865d5e5ed065e42267fa556202
| -rw-r--r-- | core/jni/android/graphics/ByteBufferStreamAdaptor.cpp | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp index 173818b13837..d443fd8cdf14 100644 --- a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp +++ b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp @@ -1,6 +1,7 @@ #include "ByteBufferStreamAdaptor.h" #include "core_jni_helpers.h" #include "Utils.h" +#include <jni.h> #include <SkStream.h> @@ -9,6 +10,24 @@ using namespace android; static jmethodID gByteBuffer_getMethodID; static jmethodID gByteBuffer_setPositionMethodID; +/** + * Helper method for accessing the JNI interface pointer. + * + * Image decoding (which this supports) is started on a thread that is already + * attached to the Java VM. But an AnimatedImageDrawable continues decoding on + * the AnimatedImageThread, which is not attached. This will attach if + * necessary. + */ +static JNIEnv* requireEnv(JavaVM* jvm) { + JNIEnv* env; + if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + if (jvm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } + return env; +} + class ByteBufferStream : public SkStreamAsset { private: ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length, @@ -46,7 +65,7 @@ public: } ~ByteBufferStream() override { - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); env->DeleteGlobalRef(mByteBuffer); env->DeleteGlobalRef(mStorage); } @@ -63,7 +82,7 @@ public: return this->setPosition(mPosition + size) ? size : 0; } - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); size_t bytesRead = 0; do { const size_t requested = (size > kStorageSize) ? kStorageSize : size; @@ -146,7 +165,7 @@ private: // Range has already been checked by the caller. bool setPosition(size_t newPosition) { - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); env->CallObjectMethod(mByteBuffer, gByteBuffer_setPositionMethodID, newPosition + mInitialPosition); if (env->ExceptionCheck()) { @@ -185,7 +204,7 @@ public: } ~ByteArrayStream() override { - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); env->DeleteGlobalRef(mByteArray); } @@ -197,7 +216,7 @@ public: return 0; } - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); if (buffer) { env->GetByteArrayRegion(mByteArray, mPosition + mOffset, size, reinterpret_cast<jbyte*>(buffer)); |