From 3026b16d70220a6776e58d98c595924e3e0dec81 Mon Sep 17 00:00:00 2001 From: tarsin Date: Fri, 22 Jul 2022 00:13:00 +0800 Subject: [PATCH] Don't emulate posix read, do mmap instead --- .../gallery/ArchiveGalleryProvider.java | 14 ++- .../java/com/hippo/UriArchiveAccessor.java | 95 ++++--------------- native/src/main/jni/archive.c | 73 +++++--------- 3 files changed, 53 insertions(+), 129 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java b/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java index 1274ab4aa..b6a13c803 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java @@ -56,7 +56,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { UriArchiveAccessor archiveAccessor1; try { archiveAccessor1 = new UriArchiveAccessor(context, uri); - } catch (FileNotFoundException e) { + } catch (Exception e) { archiveAccessor1 = null; e.printStackTrace(); } @@ -90,6 +90,11 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { decodeThread.interrupt(); decodeThread = null; } + try { + archiveAccessor.close(); + } catch (Exception e) { + e.printStackTrace(); + } } @Override @@ -161,7 +166,12 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { private class ArchiveTask implements Runnable { @Override public void run() { - size = archiveAccessor.open(); + try { + size = archiveAccessor.open(); + } catch (Exception e) { + e.printStackTrace(); + size = 0; + } if (size <= 0) { size = STATE_ERROR; error = GetText.getString(R.string.error_reading_failed); diff --git a/native/src/main/java/com/hippo/UriArchiveAccessor.java b/native/src/main/java/com/hippo/UriArchiveAccessor.java index 3bb38b3dc..1a89eb7b0 100644 --- a/native/src/main/java/com/hippo/UriArchiveAccessor.java +++ b/native/src/main/java/com/hippo/UriArchiveAccessor.java @@ -31,96 +31,39 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; -public class UriArchiveAccessor implements AutoCloseable { - public static int OPEN_OK = 1; - public static int OPEN_ERR = 2; - private final OsReadableFile osf; +public class UriArchiveAccessor { + ParcelFileDescriptor pfd; + FileDescriptor fd; + long archiveAddr; + Context ctx; + Uri uri; - public UriArchiveAccessor(Context ctx, Uri uri) throws FileNotFoundException { - osf = new OsReadableFile(ctx, uri); + public UriArchiveAccessor(Context ctx, Uri uri) { + this.ctx = ctx; + this.uri = uri; } - public int open() { - return openArchive(osf); + public int open() throws Exception { + pfd = ctx.getContentResolver().openFileDescriptor(uri, "r"); + fd = pfd.getFileDescriptor(); + archiveAddr = Os.mmap(0, pfd.getStatSize(), OsConstants.PROT_READ, OsConstants.MAP_PRIVATE, fd, 0); + return openArchive(archiveAddr, pfd.getStatSize()); } public void extractTargetIndexToOutputStream(int index, OutputStream os) { extracttoOutputStream(index, os); } - private native int openArchive(OsReadableFile osf); + private native int openArchive(long addr, long size); private native void extracttoOutputStream(int index, OutputStream os); private native void closeArchive(); - @Override - public void close() throws IOException { + public void close() throws Exception { closeArchive(); - osf.close(); - } - - static class OsReadableFile { - ParcelFileDescriptor pfd; - FileDescriptor fd; - - public OsReadableFile(Context ctx, Uri uri) throws FileNotFoundException { - pfd = ctx.getContentResolver().openFileDescriptor(uri, "r"); - fd = pfd.getFileDescriptor(); - } - - public int read(byte[] b, int off, int len) throws IOException, ErrnoException { - return Os.read(fd, b, off, len); - } - - public int read(byte[] b) throws IOException, ErrnoException { - return read(b, 0, b.length); - } - - public long length() throws IOException, ErrnoException { - return Os.fstat(fd).st_size; - } - - public long seek(long pos, int whence) throws IOException, ErrnoException { - try { - return Os.lseek(fd, pos, whence); - } catch (Exception e) { - e.printStackTrace(); - return -30; - } - } - - public void rewind() throws IOException, ErrnoException { - Os.lseek(fd, 0, OsConstants.SEEK_SET); - } - - public long skip(long n) throws IOException, ErrnoException { - long pos; - long len; - long newpos; - - if (n <= 0) { - return 0; - } - pos = Os.lseek(fd, 0L, OsConstants.SEEK_CUR); - len = length(); - newpos = pos + n; - if (newpos > len) { - newpos = len; - } - seek(newpos, OsConstants.SEEK_SET); - - /* return the actual number of bytes skipped */ - return newpos - pos; - } - - public void close() throws IOException { - pfd.close(); - try { - Os.close(fd); - } catch (ErrnoException e) { - throw new IOException("An ErrnoException occurs", e); - } - } + Os.munmap(archiveAddr, pfd.getStatSize()); + pfd.close(); + Os.close(fd); } } diff --git a/native/src/main/jni/archive.c b/native/src/main/jni/archive.c index f88c80e91..effe4afe5 100644 --- a/native/src/main/jni/archive.c +++ b/native/src/main/jni/archive.c @@ -35,34 +35,18 @@ #define BLOCK_SIZE 4096 * 16 static JNIEnv *env; -static jobject file; -static jmethodID readID; -static jmethodID seekID; -static jmethodID skipID; -static jmethodID rewindID; -static void* read_buffer; static jbyteArray jbr; static int cur_index = 0; // Current entry we haven't read any data from it yet static struct archive* arc; -static void JNI_prepare_environment(JNIEnv* jniEnv, jobject OsReadablefile) +static jlong archiveAddr = 0; +static jlong archiveSize = 0; + +static void JNI_prepare_environment(JNIEnv* jniEnv) { env = jniEnv; - file = (*env)->NewGlobalRef(env, OsReadablefile); - readID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, OsReadablefile), "read", "([B)I"); - seekID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, OsReadablefile), "seek", "(JI)J"); - skipID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, OsReadablefile), "skip", "(J)J"); - rewindID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, OsReadablefile), "rewind", "()V"); jbr = (*env)->NewGlobalRef(env, (*env)->NewByteArray(env, BLOCK_SIZE)); - read_buffer = malloc(BLOCK_SIZE); -} - -static void JNI_destroy_environment() -{ - (*env)->DeleteGlobalRef(env, file); - (*env)->DeleteGlobalRef(env, jbr); - free(read_buffer); } static int filename_is_playable_file(const char *name) { @@ -94,41 +78,19 @@ static long archive_list_all_entries() { return count; } -ssize_t ins_read(struct archive *a, void *client_data_ptr, const void **buff) { - int32_t r = (*env)->CallIntMethod(env, file, readID, jbr); - (*env)->GetByteArrayRegion(env, jbr, 0, r, read_buffer); - *buff = read_buffer; - return r; -} - -int ins_close(struct archive *a, void *client_data) { - (*env)->CallVoidMethod(env, file, rewindID); - return ARCHIVE_OK; -} - -la_int64_t ins_seek(struct archive *a, void *client_data, la_int64_t offset, int whence) { - jlong ret = (*env)->CallLongMethod(env, file, seekID, offset, whence); - return ret; -} - -la_int64_t ins_skip(struct archive *a, void *client_data, la_int64_t request) { - jlong ret = (*env)->CallLongMethod(env, file, skipID, request); - return ret; -} - static void archive_create() { arc = archive_read_new(); - archive_read_set_seek_callback(arc, ins_seek); - archive_read_set_skip_callback(arc, ins_skip); archive_read_support_format_all(arc); archive_read_support_filter_all(arc); } JNIEXPORT jint JNICALL -Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jobject osf) { - JNI_prepare_environment(_, osf); +Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong addr, jlong size) { + archiveAddr = addr; + archiveSize = size; + JNI_prepare_environment(_); archive_create(); - long r = archive_read_open(arc, arc, NULL, ins_read, ins_close); + long r = archive_read_open_memory(arc, (const void *) archiveAddr, archiveSize); if (r) { r = 0; LOGE("%s%s", "Archive open failed:", archive_error_string(arc)); @@ -154,7 +116,7 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, archive_read_close(arc); archive_read_free(arc); archive_create(); - archive_read_open(arc, arc, NULL, ins_read, ins_close); + archive_read_open_memory(arc, (const void *) archiveAddr, archiveSize); cur_index = 0; } jmethodID writeID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "write", "([B)V"); @@ -172,8 +134,18 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, LOGE("%s%s", "Archive read failed:", archive_error_string(arc)); break; } - (*env)->SetByteArrayRegion(env, jbr, 0, (int)size, buff); - (*env)->CallVoidMethod(env, os, writeID, jbr); + for (;;) { + if (size > BLOCK_SIZE) { + (*env)->SetByteArrayRegion(env, jbr, 0, BLOCK_SIZE, buff); + (*env)->CallVoidMethod(env, os, writeID, jbr); + buff += BLOCK_SIZE; + size -= BLOCK_SIZE; + } else { + (*env)->SetByteArrayRegion(env, jbr, 0, (int)size, buff); + (*env)->CallVoidMethod(env, os, writeID, jbr); + break; + } + } } break; } @@ -188,5 +160,4 @@ Java_com_hippo_UriArchiveAccessor_closeArchive(JNIEnv *jniEnv, jobject thiz) { archive_read_close(arc); archive_read_free(arc); } - JNI_destroy_environment(); } \ No newline at end of file