** Read using .apk:
I've found a way to open up the .apk file and read using the offset/
size of the resource.
1. get application .apk file name (in java)
- context.getPackagemanager().getPackageInfo();
2. get a FileDescriptor object (in java)
- context.getAssets().openFd("someresource.txt")... getLength()/
getOffset();
3. open file (in c/c++)
- fopen(appname); fseek(offset);
Using the above solution seems to be the most common approach.
Although it appears we are steered away from this approach.
Dianne Hackborn: (http://groups.google.com/group/android-ndk/
browse_thread/thread/842ca9d7d82995b0)
Assuming that the start offset and end offset are absolute positions
in your .apk is
not guaranteed to work in the future. (For example, what happens if
one day
we decide that when an app is installed we unpack its .apk into
individual
files?)
** Using FileDescriptors:
Dianne Hackborn:
Get the file descriptor with the Java APIs on Resources of
AssetManager and
hand that to your native code, such as:
-- but there is no clear way to get the FILE handle from a
FileDescriptor.
fadden:
Further, if you look in dalvik/libnativehelper/include/nativehelper/
JNIHelp.h, you can find a helper function called
jniGetFDFromFileDescriptor().
-- fadden found this, but we still 'shouldn't' use this
So is there a way to open a FILE from a FileDescriptor that's
officially supported?
** unzipping the .apk manually
I haven't found too much against this, except for i would rather not
litter my files around.
---------------------------------------
Java side:
RawAssetsDescriptor = mContext.getResources().openRawResourceFd
(R.raw.assets);
if (RawAssetsDescriptor != null)
{
fd = RawAssetsDescriptor.getFileDescriptor();
off = RawAssetsDescriptor.getStartOffset();
len = RawAssetsDescriptor.getLength();
nativeInit(dataDir, fd, off, len);
}
---------------------------------------
---------------------------------------
C side:
...nativeInit(JNIEnv * env, jclass envClass, jobject fd_sys, jlong
off, jlong len)
{
jclass fdClass = (*env)->FindClass(env, "java/io/FileDescriptor");
if (fdClass != NULL)
{
jclass fdClassRef = (jclass) (*env)->NewGlobalRef(env, fdClass);
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env,
fdClass, "descriptor", "I");
if (fdClassDescriptorFieldID != NULL && fd_sys != NULL)
{
jint fd = (*env)->GetIntField(env, fd_sys,
fdClassDescriptorFieldID);
int myfd = dup(fd);
FILE* myFile = fdopen(myfd, "rb");
if (myFile)
{
fseek(myFile, off, SEEK_SET);
... use your file
}
}
}
}
---------------------------------------
Not sure if it is officially supported code, but originally i found it
somewhere in smth like pinyin keyboard code.
And remember:
1. "assets" file must be uncompressed, overwise openRawResourceFd
returns null, choose .mp3 extention e.g.
2. your have to do it with every file or use your own "virtual"
filesystem.
Also looking forward for any suggestions.
--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.
Well, that and the fact that InputStream is just generally terrible.
"descriptor" is a package-private field inside FileDescriptor, and as
such isn't part of the API, is subject to change, etc. On the other
hand, FileDescriptor objects are much more useful if you can pry the
fd out of them.
One code note... this:
jclass fdClassRef = (jclass) (*env)->NewGlobalRef(env, fdClass);
looks like it's going to leak a global reference every time you call
nativeInit, which it looks like you do every time you open an asset
file. You only need to convert fdClass to a global reference if
you're planning to keep the class object reference around after
nativeInit returns (e.g. in a global). Once you've got the integer fd
you probably don't need to use the class ref again.
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env, fdClass,
"descriptor", "I");
As fadden mentions:
"descriptor" is a package-private field inside FileDescriptor, and as
such isn't part of the API, is subject to change, etc. On the other
hand, FileDescriptor objects are much more useful if you can pry the
fd out of them.
> > android-ndk...@googlegroups.com<android-ndk%2Bunsu...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/android-ndk?hl=en.
>
> --
> Dianne Hackborn
> Android framework engineer
Yes i know, it is just for fast code sample, if init is used more than
once than programmer should care about it :)
MappedByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0,
channel.size());
MappedByteBuffer is a direct buffer, so it can be accessed by native
code directly, without copying. I believe this technique will be
future-proof, because it uses only documented API, no dependence on
assets not being compressed etc.
Is this real? Or will Android just be copying the data during each of
my steps, resulting in even worse preformance?
Regards,
dev.dri
- get a request to load an uncompressed resource file from a native
function
- call back to Java to get file size from the resource's file
descriptor
- malloc required memory in native code
- create a direct byte buffer with NewDirectByteBuffer in native code
- pass this buffer back to Java to use for reading the resource file
- Java code then uses java.nio.channels.FileChannel to load the file:
AssetFileDescriptor.createInputStream().getChannel().read( passed
in ByteBuffer jobject passed in );
Three questions:
- Is this method efficient since the nio channel can just load
directly into the native buffer without doing any conversion or double
copying?
- Is the jobject returned from NewDirectByteBuffer a
java.nio.ByteBuffer that can be passed directly to the Java code or am
I missing a step?
- Is this method considered a safer, more future-supported method than
the fdopen & fseek method mentioned earlier?
So far it seems like the best method is using the following to get the
native FD and then passing that into fopen:
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env, fdClass,
"descriptor", "I");
However, we know that we can't rely on the field named "descriptor"
being there in the future since its a private field. That said, is
there a more definitive solution or is this currently the best way?
Thanks
On Mar 31, 5:23 pm, captainpikachu <natebamber...@gmail.com> wrote:
> I'm a little late to the discussion, but consider this method for
> loading an uncompressed resourcefileinto native memory:
>
> - get a request to load an uncompressed resourcefilefrom a native