Don't emulate posix read, do mmap instead

This commit is contained in:
tarsin committed 2022-07-22 00:13:53 +08:00
1 parent ac3662a469
commit 3026b16d70
3 files changed
+53 -129

No files matched your search

@@ -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);
@@ -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);
}
}
+22 -51
View File
@@ -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();
}