Read static files through NDK

9,136 views
Skip to first unread message

Mike Gassman

unread,
Nov 7, 2009, 10:02:59 PM11/7/09
to android-ndk
Hey I was working on a simple 3d mesh loader (which will hopefully
evolve into a game engine) and I ran into an issue.

I already have lots of code in C written to parse file formats for 3d
models, which I have no problem compiling and running on the android.

Only problem is... I can't seem to find a way to get the files on to
the Android device so I am able to read the data in. I would prefer
some way to package these files into the apk so they can be installed
with the package. I would like to be able to access these files
without having to go through the java functions, which basically
"unmangle" the files that the apk would generate if you put them into
the assets or rsc directories.

What would be the best way to package these files, and be able to read
them from native code?

fadden

unread,
Nov 8, 2009, 4:21:22 PM11/8/09
to android-ndk
On Nov 7, 7:02 pm, Mike Gassman <mikeispretty...@gmail.com> wrote:
> Only problem is... I can't seem to find a way to get the files on to
> the Android device so I am able to read the data in.  I would prefer
> some way to package these files into the apk so they can be installed
> with the package.  I would like to be able to access these files
> without having to go through the java functions, which basically
> "unmangle" the files that the apk would generate if you put them into
> the assets or rsc directories.

If you don't want to call into Java at all, you can provide your own
"unzip" function and unpack the files directly from the APK yourself.
(See e.g. frameworks/base/libs/utils/ZipFileRO.cpp .)

Not sure what "unmangle" means here.

Ash

unread,
Nov 18, 2009, 7:45:17 AM11/18/09
to android-ndk
Hi!!

I have a similar requirement where I want to put a read-write flat
file (configuration file/properties file) inside the APK. After the
installation the file is required for reading the initial
configuration settings to run the service (no GUI) first time. And
later it will be modified by external applications like file-explorer
or other GUI applications.

"unzip" function seems to be quite complicated, is there any other
simpler alternative or example/sample??

Thanks in advance
Ash

Dianne Hackborn

unread,
Nov 18, 2009, 5:51:44 PM11/18/09
to andro...@googlegroups.com
Get the file descriptor with the Java APIs on Resources of AssetManager and hand that to your native code, such as:

http://developer.android.com/reference/android/content/res/AssetManager.html#openFd(java.lang.String)

Note that for those to work you need to make sure your data is stored uncompressed.  If you don't want to do that, you could use the higher-level APIs that return an InputStream and perform calls on it from your JNI code to read the data.

--

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.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=.





--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails.  All such questions should be posted on public forums, where I and others can see and answer them.

Belveder

unread,
Nov 19, 2009, 1:32:01 PM11/19/09
to android-ndk
I've two questions to this before I start trying it.

First, if I simply put a file into res/raw, how can I make sure it is
not compressed? Or did you just mean that the text file is available
as-is anyway as soon as I access it through AssetManager, and as long
as I do not compress it myself somehow?

Secondly, AssetManager just allows the reading of files. However, I
also need writing files (at least during developing and debugging). I
already read two books about android, but still I haven't found full
insight on how to write raw files. The simplest way seams to be using
the sdcard for writing data, but that's hopefully not the end of the
story; could you point me to some starting point for writing files?

Regards

On Nov 18, 11:51 pm, Dianne Hackborn <hack...@android.com> wrote:
> Get the file descriptor with the Java APIs on Resources of AssetManager and
> hand that to your native code, such as:
>
> http://developer.android.com/reference/android/content/res/AssetManag...)
> hack...@android.com

Dianne Hackborn

unread,
Nov 19, 2009, 3:36:41 PM11/19/09
to andro...@googlegroups.com
On Thu, Nov 19, 2009 at 10:32 AM, Belveder <clemen...@gmail.com> wrote:
First, if I simply put a file into res/raw, how can I make sure it is
not compressed? Or did you just mean that the text file is available
as-is anyway as soon as I access it through AssetManager, and as long
as I do not compress it myself somehow?

Either use an extension that isn't compressed (such as .zip or .png), or use the command line option on aapt to tell it not to compress whatever extension you are using.
 
Secondly, AssetManager just allows the reading of files. However, I
also need writing files (at least during developing and debugging). I
already read two books about android, but still I haven't found full
insight on how to write raw files. The simplest way seams to be using
the sdcard for writing data, but that's hopefully not the end of the
story; could you point me to some starting point for writing files?

This has nothing to do with asset manager.  The documentation has lots of information about storage; you can start here:

http://developer.android.com/guide/topics/data/data-storage.html

--
Dianne Hackborn
Android framework engineer
hac...@android.com

Ash

unread,
Nov 20, 2009, 7:32:50 AM11/20/09
to android-ndk
Hi!!

I tried using the AssetManager, after putting my text file
"myProp.prop" under asset in eclipse, and I verified it from the apk
that it exists in the apk, but when I try to call openFd
("myProp.prop"), I get the following exception

11-20 16:57:51.127: WARN/System.err(722):
java.io.FileNotFoundException: This file can not be opened as a file
descriptor; it is probably compressed
11-20 16:57:51.137: WARN/System.err(722): at
android.content.res.AssetManager.openAssetFd(Native Method)
11-20 16:57:51.167: WARN/System.err(722): at
android.content.res.AssetManager.openFd(AssetManager.java:316)

I tried changing the extension to .zip but it did not help.
Am I missing something?? What could be the problem?

Thanks in advance
Ash




On Nov 20, 1:36 am, Dianne Hackborn <hack...@android.com> wrote:
> On Thu, Nov 19, 2009 at 10:32 AM, Belveder <clemens.a...@gmail.com> wrote:
> > First, if I simply put a file into res/raw, how can I make sure it is
> > not compressed? Or did you just mean that the text file is available
> > as-is anyway as soon as I access it through AssetManager, and as long
> > as I do not compress it myself somehow?
>
> Either use an extension that isn't compressed (such as .zip or .png), or use
> the command line option on aapt to tell it not to compress whatever
> extension you are using.
>
> > Secondly, AssetManager just allows the reading of files. However, I
> > also need writing files (at least during developing and debugging). I
> > already read two books about android, but still I haven't found full
> > insight on how to write raw files. The simplest way seams to be using
> > the sdcard for writing data, but that's hopefully not the end of the
> > story; could you point me to some starting point for writing files?
>
> This has nothing to do with asset manager.  The documentation has lots of
> information about storage; you can start here:
>
> http://developer.android.com/guide/topics/data/data-storage.html
>
> --
> Dianne Hackborn
> Android framework engineer
> hack...@android.com

Dianne Hackborn

unread,
Nov 20, 2009, 3:19:42 PM11/20/09
to andro...@googlegroups.com
Try using this option with aapt to make your file extension not compressed:

-0  specifies an additional extension for which such files will not
       be stored compressed in the .apk.  An empty string means to not
       compress any files at all.

(Thats a zero, not the letter oh).

--

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=.



--
Dianne Hackborn
Android framework engineer

Ash

unread,
Nov 21, 2009, 5:55:11 AM11/21/09
to android-ndk
Well I tried changing the extension to .png and it worked.

BTW, I am using eclipse(ADT Plugin/SDK) for generating the APK, do I
need to configure eclipse for specifing this option(aapt -0) or I need
to generate the APK from command line/console, if so how to package
the other content??

Thanks in advance
Ash
> > android-ndk...@googlegroups.com<android-ndk%2Bunsubscribe@googlegr­oups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/android-ndk?hl=.
>
> --
> Dianne Hackborn
> Android framework engineer
> hack...@android.com
>
> Note: please don't send private questions to me, as I don't have time to
> provide private support, and so won't reply to such e-mails.  All such
> questions should be posted on public forums, where I and others can see and
> answer them.- Hide quoted text -
>
> - Show quoted text -

Steve

unread,
Nov 21, 2009, 9:55:15 AM11/21/09
to android-ndk
I have been wanting to do the same thing, so far I have got as far as:

1. Packing all my files in to a single data file.
2. Rename file to .mp3 to avoid it getting compressed
3. Put it in the raw folder (so it gets automatically added to
package)
4. Get the file descriptor, offset and length for the file
5. Passed above via the JNI to my C code
6. Got the OS file descriptor from the Java File Descriptor object.
7. Used fdopen to open the OS file handle, then can fseek to start of
data etc.

Some questions I have (I post on this thread as I believe they are
related) are:

a. If I make my single data file too big it fails to run on emulator,
e.g. 20MB will be too big, 10MB is okay, from doing some Google
searches it sounds like the asset is copied on to the heap, so there
is a limit - to me this sounds a bit bonkers, as I don't really want
my assets stored on the heap, I am happy for them to stay in what ever
the normal storage is, so I can read them in to memory on demand. Is
this whole storing on the heap stuff true? If so is there a way to
stop this happening? I do not want to have to write an installer to
pull data files from the internet when my game is run, I want to
package up everything as a single file - in my mind this seems like
the obvious/standard way people would want to run their applications,
but maybe I just am not thinking with the right mindset? If there is a
limit to the size of the assets that can be in a package, are there
any hints on what this limit is? I appreciate Android can run on all
sorts of devices to there may not be a definite limit, but I am
interested in targeting mobile phones, so would the majority of phones
be okay with a 10MB package for example?

b. I have read I need to make sure I close my file descriptors, could
I just check what I need to do for this? Is it just the case of
calling fclose from the C side? Or do I need to do something from the
Java side too? I don't explicitly open any files on the Java side, but
I do request a file descriptor, so I wasn't sure if the act of doing
that opened the file at the OS level and is waiting for me to close it
etc.

Many thanks, and sorry for the long post!

Steve

Keith

unread,
Nov 24, 2009, 12:05:43 AM11/24/09
to android-ndk

Thank you Dianne and others for this info.
I was able to read in my static data file after I renamed it to png.
I find this to be a rather odd practice, and would prefer to add the
-0 option to aapt, so I can maintain the proper file ext.
Where do I put this aapt -0 option? I searched google, eclipse, and
the make file, and I cant find the aapt options.

Thanks!

Keith

Clapfoot

unread,
Nov 28, 2009, 9:48:32 AM11/28/09
to android-ndk
How exactly do you get the native OS file descriptor from the Java
FileDescriptor object? From the Java documentation the FileDescriptor
class doesn't seem to have any public fields for the native fd. I read
that there is an int field called "fd" that exists and you can get
that via a GetIntField call, but I tried this and got the following
error: "Ljava/lang/NoSuchFieldError;: fd".

fadden

unread,
Nov 30, 2009, 3:26:13 PM11/30/09
to android-ndk
On Nov 28, 6:48 am, Clapfoot <markus...@gmail.com> wrote:
> How exactly do you get the native OS file descriptor from the Java
> FileDescriptor object? From the Java documentation the FileDescriptor
> class doesn't seem to have any public fields for the native fd. I read
> that there is an int field called "fd" that exists and you can get
> that via a GetIntField call, but I tried this and got the following
> error: "Ljava/lang/NoSuchFieldError;: fd".

This is not part of the public API, and relying on its existence will
likely cause your program to break in the future.

If you look in FileDescriptor.java, however, you will see that it's
actually called "descriptor".

Further, if you look in dalvik/libnativehelper/include/nativehelper/
JNIHelp.h, you can find a helper function called
jniGetFDFromFileDescriptor().

Again, don't use these, on pain of having a broken app.

Bytes

unread,
Dec 8, 2009, 2:16:31 AM12/8/09
to android-ndk
Hi,

But what about writing to these files ?



On Nov 9, 2:21 am, fadden <fad...@android.com> wrote:

Bytes

unread,
Dec 8, 2009, 3:20:08 AM12/8/09
to android-ndk
I want to avoid JNI....

So what is the best way to read and write from native code.

How to bundle the configuration files in to APK.

(See e.g. frameworks/base/libs/utils/ZipFileRO.cpp .)

- This unzip also to read from APK without involving JNI.. but writing
can't be possible right ?

Here the approach I'm thinking....

1. I need a config file (myconfig.cfg) when application boot up, and
it should be bundle up along with APK

Sol: Keep the file in res/raw or assets and use AssetManager to open
the file for reading.

2. On configuration change

Copy myconfig.cfg to another file myconfig-write.cfg with in
Applicaiton private directory and open it for writing... and pass the
FD to native code.

Quesiton: How to map FD returned by Java used in native code, as there
is no clear information in above replies ?



Is there any other best way , please give me some pointers.

regards
-Bytes
> > Not sure what "unmangle" means here.- Hide quoted text -

Chun-Kai Hwang

unread,
Dec 9, 2009, 8:58:52 PM12/9/09
to andro...@googlegroups.com
On Tue, Dec 8, 2009 at 4:20 PM, Bytes <toyven...@gmail.com> wrote:
I want to avoid JNI....

So what is the best way to read and write from native code.

How to bundle the configuration files in to APK.

(See e.g. frameworks/base/libs/utils/ZipFileRO.cpp .)

- This unzip also to read from APK without involving JNI.. but writing
can't be possible right ?

Here the approach I'm thinking....

1. I need a config file (myconfig.cfg) when application boot up, and
it should be bundle up along with APK

Sol: Keep the file in res/raw or assets and use AssetManager to open
the file for reading.

2. On configuration change

   Copy myconfig.cfg to another file myconfig-write.cfg with in
Applicaiton private directory and open it for writing... and pass the
FD to native code.
 
why not open the file by native codes?

Quesiton: How to map FD returned by Java used in native code, as there
is no clear information in above replies ?



Is there any other best way , please give me some pointers.

regards
-Bytes



On Dec 8, 12:16 pm, Bytes <toyvenu.t...@gmail.com> wrote:
> Hi,
>
> But what about writing to these files ?
>
> On Nov 9, 2:21 am, fadden <fad...@android.com> wrote:
>
>
>
> > On Nov 7, 7:02 pm, Mike Gassman <mikeispretty...@gmail.com> wrote:
>
> > > Only problem is... I can't seem to find a way to get the files on to
> > > the Android device so I am able to read the data in.  I would prefer
> > > some way to package these files into the apk so they can be installed
> > > with the package.  I would like to be able to access these files
> > > without having to go through the java functions, which basically
> > > "unmangle" the files that the apk would generate if you put them into
> > > the assets or rsc directories.
>
> > If you don't want to call into Java at all, you can provide your own
> > "unzip" function and unpack the files directly from the APK yourself.
> > (See e.g. frameworks/base/libs/utils/ZipFileRO.cpp .)
>
> > Not sure what "unmangle" means here.- Hide quoted text -
>
> - Show quoted text -

--

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.



Keith

unread,
Dec 18, 2009, 2:09:42 PM12/18/09
to android-ndk
If you want to READ a file that you package with your app, this will
work:
Dianne explained this rather breifly. I will expand.


1) Put the target file in the assets folder of you project.
You MUST rename the file so it has a .png extension, to fool the aapt
into not compressing it.
OR
You can tell aapt to not compress the file using the -0 command line
argument. But, I can not figure out how to specify that command line
argument using Eclipse. If anyone know how to do so, PLEASE rely.

2) On the Java Side you need to get three things:
a) Proper path to the apk file so you can open it on the native side.
b & c) The offset and length of the file you wish to read.

So, pass that string with the Path, and the two ints across the jni to
your native code.

3) On the native side, open the .apk file using fopen, and the path
that you passed in.
Do a fseek using the offset that you passed in to get to the proper
place in the apk bucket of bits.
Read the bytes from the file, using the length of the file that you
passed in.


Here is the Javacode to get the path, offset, and length:


// Get the path
String apkFilePath = null;
ApplicationInfo appInfo = null;
PackageManager packMgmr = mActivity.getPackageManager();
try
{
appInfo = packMgmr.getApplicationInfo
( "com.abc.YourPackageName", 0 );
apkFilePath = appInfo.sourceDir;
}
catch( NameNotFoundException e){
}

// Get the offset and length for the file: theUrl, that is in your
assets folder

AssetManager assetManager = mActivity.getAssets();
try {

// HACK till I figure out the aapt -0 options to not compress files
//String hackedUrl = theUrl.substring(0, theUrl.length()-3 ) + "png";

AssetFileDescriptor assFD = assetManager.openFd( hackedUrl );
if( assFD != null ) {
long offset = assFD.getStartOffset();
long fileSize = assFD.getLength();
assFD.close();
}
}
catch( IOException e) {}

Again. openFd will return NULL if your file has an extension other
than .png, or mp3...

Jeremiah Sellars

unread,
Dec 18, 2009, 4:54:52 PM12/18/09
to android-ndk
@Keith... I figured (as you probably did) that it be in the builders
section of the project properties, but the Android Package Builder
script can't be edited.

Reading all the way above to Dianne wrote:
"Get the file descriptor with the Java APIs on Resources of
AssetManager and
hand that to your native code, such as:

http://developer.android.com/reference/android/content/res/AssetManag...)

Note that for those to work you need to make sure your data is stored
uncompressed. If you don't want to do that, you could use the higher-
level
APIs that return an InputStream and perform calls on it from your JNI
code
to read the data. "

Where I'm confused is in the native code, what JNIEnv* function would
need to be called to on either the AssetManager object or the
InputStream and what exactly would it return... an opened FILE
pointer?

If this is one of those RTFM question on general JNI usage... please
let me know and I'll hit the books harder.

Thanks,
Jeremiah

On Dec 18, 11:09 am, Keith <keithrvic...@gmail.com> wrote:
> If you want to READ afilethat you package with your app, this will


> work:
> Dianne explained this rather breifly.  I will expand.
>

> 1) Put the targetfilein the assets folder of you project.
> You MUST rename thefileso it has a .png extension, to fool the aapt


> into not compressing it.
> OR

> You can tell aapt to not compress thefileusing the -0 command line


> argument.  But, I can not figure out how to specify that command line
> argument using Eclipse.  If anyone know how to do so, PLEASE rely.
>
> 2) On the Java Side you need to get three things:

> a) Proper path to the apkfileso you can open it on the native side.
> b & c) The offset and length of thefileyou wish to read.


>
> So, pass that string with the Path, and the two ints across the jni to
> your native code.
>

> 3) On the native side, open the .apkfileusing fopen, and the path


> that you passed in.
> Do a fseek using the offset that you passed in to get to the proper
> place in the apk bucket of bits.

> Read the bytes from thefile, using the length of thefilethat you


> passed in.
>
> Here is the Javacode to get the path, offset, and length:
>
> // Get the path
>         String apkFilePath = null;
>         ApplicationInfo appInfo = null;
>         PackageManager packMgmr = mActivity.getPackageManager();
>         try
>         {
>                 appInfo = packMgmr.getApplicationInfo
> ( "com.abc.YourPackageName", 0 );
>                 apkFilePath = appInfo.sourceDir;
>         }
>         catch( NameNotFoundException e){
>         }
>

> // Get the offset and length for thefile: theUrl, that is in your


> assets folder
>
>                 AssetManager assetManager = mActivity.getAssets();
>                 try {
>
>         // HACK till I figure out the aapt -0 options to not compress files
>         //String hackedUrl = theUrl.substring(0, theUrl.length()-3 ) + "png";
>
>                 AssetFileDescriptor assFD = assetManager.openFd( hackedUrl );
>                 if( assFD != null ) {
>                         long offset = assFD.getStartOffset();
>                         long fileSize = assFD.getLength();
>                         assFD.close();
>                         }
>                 }
>         catch( IOException e) {}
>

> Again.  openFd will return NULL if yourfilehas an extension other

Keith

unread,
Dec 18, 2009, 9:47:33 PM12/18/09
to android-ndk
Yes, I saw that too. But, it just does not seem feasable to pass an
open File descriptor from Java across the JNI, and read the bits on
the naitve side. Has anyone got that to work?
Reply all
Reply to author
Forward
0 new messages