Don't emulate posix read, do mmap instead
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in new issue
Block a user