From 4381eb8c3dc1555e0fbd315dad9bd370412df011 Mon Sep 17 00:00:00 2001 From: tarsin Date: Fri, 22 Jul 2022 09:52:35 +0800 Subject: [PATCH] Fuck off the buffer --- .../gallery/ArchiveGalleryProvider.java | 5 +- .../java/com/hippo/ehviewer/gallery/Pipe.java | 144 +++--------------- .../java/com/hippo/UriArchiveAccessor.java | 13 +- native/src/main/jni/archive.c | 29 +--- 4 files changed, 33 insertions(+), 158 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 b6a13c803..7d4ca66f3 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java @@ -204,7 +204,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { continue; } - Pipe pipe = new Pipe(4096 * 16); + Pipe pipe = new Pipe(); synchronized (streams) { if (streams.get(index) != null) { @@ -214,7 +214,8 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { streams.notify(); } - archiveAccessor.extractTargetIndexToOutputStream(index, pipe.getOutputStream()); + archiveAccessor.extracttoOutputStream(index, pipe.getOutputFd()); + pipe.closeOutputFd(); } } } diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/Pipe.java b/app/src/main/java/com/hippo/ehviewer/gallery/Pipe.java index f591ada86..1b9d275e9 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/Pipe.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/Pipe.java @@ -16,141 +16,37 @@ package com.hippo.ehviewer.gallery; -import androidx.annotation.NonNull; +import android.os.ParcelFileDescriptor; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; class Pipe { - - private final int capacity; - private final byte[] buffer; - - private int head = 0; - private int tail = 0; - private boolean full = false; - - private boolean inClosed = false; - private boolean outClosed = false; - - private final InputStream inputStream = new InputStream() { - @Override - public int read() throws IOException { - synchronized (Pipe.this) { - byte[] bytes = new byte[1]; - if (read(bytes, 0, 1) != -1) { - return bytes[0]; - } else { - return -1; - } - } + private ParcelFileDescriptor[] fd; + { + try { + fd = ParcelFileDescriptor.createPipe(); + } catch (IOException e) { + e.printStackTrace(); } - - @Override - public int read(@NonNull byte[] b, int off, int len) throws IOException { - synchronized (Pipe.this) { - for (; ; ) { - if (inClosed) { - throw new IOException("The InputStream is closed"); - } - if (len == 0) { - return 0; - } - - if (head == tail && !full) { - if (outClosed) { - // No bytes available and the OutputStream is closed. So it's the end. - return -1; - } else { - // Wait for OutputStream write bytes - try { - Pipe.this.wait(); - } catch (InterruptedException e) { - throw new IOException("The thread interrupted", e); - } - } - } else { - int read = Math.min(len, (head < tail ? tail : capacity) - head); - System.arraycopy(buffer, head, b, off, read); - head += read; - if (head == capacity) { - head = 0; - } - full = false; - Pipe.this.notifyAll(); - return read; - } - } - } - } - - @Override - public void close() { - synchronized (Pipe.this) { - inClosed = true; - Pipe.this.notifyAll(); - } - } - }; - - private final OutputStream outputStream = new OutputStream() { - @Override - public void write(int b) throws IOException { - synchronized (Pipe.this) { - byte[] bytes = new byte[]{(byte) b}; - write(bytes, 0, 1); - } - } - - @Override - public void write(@NonNull byte[] b, int off, int len) throws IOException { - synchronized (Pipe.this) { - while (len != 0) { - if (head == tail && full) { - // The buffer is full, wait for InputStream read bytes - try { - Pipe.this.wait(); - } catch (InterruptedException e) { - throw new IOException("The thread interrupted", e); - } - } else { - int write = Math.min(len, (head <= tail ? capacity : head) - tail); - System.arraycopy(b, off, buffer, tail, write); - off += write; - len -= write; - tail += write; - if (tail == capacity) { - tail = 0; - } - if (head == tail) { - full = true; - } - Pipe.this.notifyAll(); - } - } - } - } - - @Override - public void close() { - synchronized (Pipe.this) { - outClosed = true; - Pipe.this.notifyAll(); - } - } - }; - - Pipe(int capacity) { - this.capacity = capacity; - this.buffer = new byte[capacity]; } + private final InputStream inputStream = new FileInputStream(fd[0].getFileDescriptor()); + InputStream getInputStream() { return inputStream; } - OutputStream getOutputStream() { - return outputStream; + int getOutputFd() { + return fd[1].getFd(); + } + + void closeOutputFd() { + try { + fd[1].close(); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/native/src/main/java/com/hippo/UriArchiveAccessor.java b/native/src/main/java/com/hippo/UriArchiveAccessor.java index 1a89eb7b0..0c8d72b70 100644 --- a/native/src/main/java/com/hippo/UriArchiveAccessor.java +++ b/native/src/main/java/com/hippo/UriArchiveAccessor.java @@ -21,15 +21,10 @@ package com.hippo; import android.content.Context; import android.net.Uri; import android.os.ParcelFileDescriptor; -import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; -import java.io.Closeable; import java.io.FileDescriptor; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; public class UriArchiveAccessor { ParcelFileDescriptor pfd; @@ -50,20 +45,16 @@ public class UriArchiveAccessor { return openArchive(archiveAddr, pfd.getStatSize()); } - public void extractTargetIndexToOutputStream(int index, OutputStream os) { - extracttoOutputStream(index, os); - } - private native int openArchive(long addr, long size); - private native void extracttoOutputStream(int index, OutputStream os); + public native void extracttoOutputStream(int index, int fd); private native void closeArchive(); public void close() throws Exception { closeArchive(); Os.munmap(archiveAddr, pfd.getStatSize()); - pfd.close(); Os.close(fd); + pfd.close(); } } diff --git a/native/src/main/jni/archive.c b/native/src/main/jni/archive.c index effe4afe5..b81467125 100644 --- a/native/src/main/jni/archive.c +++ b/native/src/main/jni/archive.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #define LOG_TAG "libarchive_wrapper" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG ,__VA_ARGS__) @@ -40,7 +42,7 @@ static jbyteArray jbr; static int cur_index = 0; // Current entry we haven't read any data from it yet static struct archive* arc; -static jlong archiveAddr = 0; +static void* archiveAddr = 0; static jlong archiveSize = 0; static void JNI_prepare_environment(JNIEnv* jniEnv) @@ -86,8 +88,9 @@ static void archive_create() { JNIEXPORT jint JNICALL Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong addr, jlong size) { - archiveAddr = addr; + archiveAddr = (void *) addr; archiveSize = size; + madvise(archiveAddr, archiveSize, MADV_SEQUENTIAL | MADV_WILLNEED); JNI_prepare_environment(_); archive_create(); long r = archive_read_open_memory(arc, (const void *) archiveAddr, archiveSize); @@ -105,7 +108,7 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add } JNIEXPORT void JNICALL -Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, jint index, jobject os) { +Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, jint index, jint fd) { struct archive_entry *entry; size_t size; int ret; @@ -116,12 +119,9 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, archive_read_close(arc); archive_read_free(arc); archive_create(); - archive_read_open_memory(arc, (const void *) archiveAddr, archiveSize); + archive_read_open_memory(arc, archiveAddr, archiveSize); cur_index = 0; } - jmethodID writeID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "write", "([B)V"); - jmethodID flushID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "flush", "()V"); - jmethodID closeID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, os), "close", "()V"); while (archive_read_next_header(arc, &entry) == ARCHIVE_OK) { if (!filename_is_playable_file(archive_entry_pathname(entry))) continue; @@ -134,24 +134,11 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, LOGE("%s%s", "Archive read failed:", archive_error_string(arc)); break; } - 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; - } - } + write(fd, buff, size); } break; } } - (*env)->CallVoidMethod(env, os, flushID); - (*env)->CallVoidMethod(env, os, closeID); } JNIEXPORT void JNICALL