summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hoisie <hoisie@google.com>2023-12-29 07:11:44 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-12-29 07:11:44 +0000
commitee03ecfce775d72496014250a3933eb3c0a4f085 (patch)
treeb2ff35fde002a8d10399e8b2ba922b61a6ba3d89
parentc2ce75657e2bacbdcc2def0acb272ae096b08ad3 (diff)
parent747730a64a02c9e83b7a2a3ebe1836b35ca495f4 (diff)
downloadbase-ee03ecfce775d72496014250a3933eb3c0a4f085.tar.gz
Merge "Enable BitmapFactory.nativeDecodeFileDescriptor on Windows" into android12-hostruntime-dev
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp42
-rw-r--r--libs/hwui/jni/Utils.cpp10
-rw-r--r--libs/hwui/jni/Utils.h28
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);
/**