diff options
author | Michael Hoisie <hoisie@google.com> | 2023-12-29 07:11:44 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-12-29 07:11:44 +0000 |
commit | ee03ecfce775d72496014250a3933eb3c0a4f085 (patch) | |
tree | b2ff35fde002a8d10399e8b2ba922b61a6ba3d89 | |
parent | c2ce75657e2bacbdcc2def0acb272ae096b08ad3 (diff) | |
parent | 747730a64a02c9e83b7a2a3ebe1836b35ca495f4 (diff) | |
download | base-ee03ecfce775d72496014250a3933eb3c0a4f085.tar.gz |
Merge "Enable BitmapFactory.nativeDecodeFileDescriptor on Windows" into android12-hostruntime-dev
-rw-r--r-- | libs/hwui/jni/BitmapFactory.cpp | 42 | ||||
-rw-r--r-- | libs/hwui/jni/Utils.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/jni/Utils.h | 28 |
3 files changed, 76 insertions, 4 deletions
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp index 46cbdacf5ed1..dca865d2971c 100644 --- a/libs/hwui/jni/BitmapFactory.cpp +++ b/libs/hwui/jni/BitmapFactory.cpp @@ -26,6 +26,10 @@ #include <stdio.h> #include <sys/stat.h> +#ifdef _WIN32 +#include <windows.h> +#endif + jfieldID gOptions_justBoundsFieldID; jfieldID gOptions_sampleSizeFieldID; jfieldID gOptions_configFieldID; @@ -523,10 +527,32 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA return bitmap; } +// Gets the 'handle' field from a FileDescriptor object. This field is only +// populated in Windows. +static jlong jniGetHandleFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) { + jclass fileDescriptorClass = android::FindClassOrDie(env, "java/io/FileDescriptor"); + jfieldID handleField = android::GetFieldIDOrDie(env, fileDescriptorClass, "handle", "J"); + return env->GetLongField(fileDescriptor, handleField); +} + static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor, jobject padding, jobject bitmapFactoryOptions, jlong inBitmapHandle, jlong colorSpaceHandle) { -#ifdef _WIN32 // LayoutLib for Windows does not support F_DUPFD_CLOEXEC - return nullObjectReturn("Not supported on Windows"); +#ifdef _WIN32 + HANDLE fileHandle = (HANDLE)jniGetHandleFromFileDescriptor(env, fileDescriptor); + + // Restore the handle's offset on existing this function. + AutoHandleSeek autoRestore(fileHandle); + + // Duplicate the file handle + HANDLE duplicateHandle; + if (!DuplicateHandle(GetCurrentProcess(), fileHandle, GetCurrentProcess(), &duplicateHandle, 0, + FALSE, DUPLICATE_SAME_ACCESS)) { + return nullObjectReturn("DuplicateHandle failed"); + } + + int dupDescriptor = _open_osfhandle((intptr_t)duplicateHandle, _O_RDONLY); + FILE* file = _fdopen(dupDescriptor, "r"); + bool noOffset = SetFilePointer(fileHandle, 0, NULL, FILE_CURRENT) == 0; #else NPE_CHECK_RETURN_ZERO(env, fileDescriptor); @@ -550,6 +576,10 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0); FILE* file = fdopen(dupDescriptor, "r"); + + bool noOffset = ::lseek(descriptor, 0, SEEK_CUR) == 0; +#endif + if (file == NULL) { // cleanup the duplicated descriptor since it will not be closed when the // file is cleaned up (fclose). @@ -560,7 +590,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file)); // If there is no offset for the file descriptor, we use SkFILEStream directly. - if (::lseek(descriptor, 0, SEEK_CUR) == 0) { + if (noOffset) { assert(isSeekable(dupDescriptor)); return doDecode(env, std::move(fileStream), padding, bitmapFactoryOptions, inBitmapHandle, colorSpaceHandle); @@ -574,7 +604,6 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, inBitmapHandle, colorSpaceHandle); -#endif } static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, @@ -596,8 +625,13 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, } static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) { +#ifdef _WIN32 + HANDLE handle = (HANDLE)jniGetHandleFromFileDescriptor(env, fileDescriptor); + return isSeekable(handle); +#else jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE; +#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/jni/Utils.cpp b/libs/hwui/jni/Utils.cpp index ac2f5b77d23a..2f8a9e68dfbc 100644 --- a/libs/hwui/jni/Utils.cpp +++ b/libs/hwui/jni/Utils.cpp @@ -20,6 +20,10 @@ #include <log/log.h> +#ifdef _WIN32 +#include <windows.h> +#endif + using namespace android; AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset) @@ -152,6 +156,12 @@ bool android::isSeekable(int descriptor) { return ::lseek64(descriptor, 0, SEEK_CUR) != -1; } +#ifdef _WIN32 +bool android::isSeekable(HANDLE handle) { + return SetFilePointer(handle, 0, NULL, FILE_CURRENT) != INVALID_SET_FILE_POINTER; +} +#endif + JNIEnv* android::get_env_or_die(JavaVM* jvm) { JNIEnv* env; if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { diff --git a/libs/hwui/jni/Utils.h b/libs/hwui/jni/Utils.h index 6cdf44d85a5a..8291dd71fdad 100644 --- a/libs/hwui/jni/Utils.h +++ b/libs/hwui/jni/Utils.h @@ -22,6 +22,10 @@ #include <jni.h> #include <androidfw/Asset.h> +#ifdef _WIN32 +#include <windows.h> +#endif + namespace android { class AssetStreamAdaptor : public SkStreamRewindable { @@ -69,12 +73,36 @@ private: off64_t fCurr; }; +#ifdef _WIN32 +/** Restore the HANDLE offset in the destructor. Windows version of + * AutoFDSeek. */ +class AutoHandleSeek { +public: + explicit AutoHandleSeek(HANDLE handle) : hFile(handle) { + fCurr = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + } + ~AutoHandleSeek() { + if (fCurr >= 0) { + SetFilePointer(hFile, fCurr, NULL, FILE_BEGIN); + } + } + +private: + HANDLE hFile; + off64_t fCurr; +}; +#endif + jobject nullObjectReturn(const char msg[]); /** Check if the file descriptor is seekable. */ bool isSeekable(int descriptor); +#ifdef _WIN32 +bool isSeekable(HANDLE handle); +#endif + JNIEnv* get_env_or_die(JavaVM* jvm); /** |