Native Access to Asset files under NDK r5b | Android 2.3 | SDK r09

8,442 views
Skip to first unread message

jenosch

unread,
Feb 9, 2011, 4:03:06 PM2/9/11
to android-ndk
Hello,

--- Problem ---
I am trying to access a text file under my $projectPath/assets
directory through the native interface without touching Java code. I
am using the Android SDK r09, the NDK r5b, Cygwin 1.7.7 und Windows 7
64 bit, ADT 9.0.0 Plugin for Eclipse.

Why? I want to provide cross platform (Android, Windows, IPhone)
compatible means for loading (and writing) to xml and image files.
Therefore, I do only want to employ C / C++ and no Java code.

According to [1] "Applications can now access a native Asset Manager
API to retrieve application assets directly from native code without
needing to go through JNI"

After some investigation (see below) the question to getting access to
asset files boiled down to
"How do I get access to a valid AAssetManager pointer without passing
it down from Java via JNI?"

--- What I have tried ---
- I am aware of discussions for prior versions of the NDK: [2] and
[3].
--> According to [1] these workarounds of
* renaming files to e.g., .png do not prevent the files from getting
compressed and added to the .apk in ndk r5b and
* manually unzipping the .apk is to elaborate for me (for now) AND
should not be necessary anymore [1].

- I had a look at android-ndk-r5b/platforms/android-9/arch-arm/usr/
include/android/asset_manager.h
It provides methods for accessing assets once you have a valid
AAssetManager*
Unfortunately, it seems to provide NO methods for getting a valid
AAssetManager pointer.
There is no method like getAssets() in Java which returns an
AssetManager instance.

- I had a look at the android-ndk-r5b/samples/native-audio example
Here "asset_manager_jni.h" is used to get a valid AAssetManager*
through JNI
According to [1] this should not be necessary.

- In despair and similar to the native-audio example I modified the
android-ndk-r5b/samples/native-activity example (without getting an
AAssetManager* from Java!) to:
...
#include <android/asset_manager.h>
...

void android_main(struct android_app* state) {
...
AAssetManager* assetManager;
AAsset* asset = AAssetManager_open(assetManager, "test.txt",
AASSET_MODE_UNKNOWN);
if (asset == NULL) {
LOGW("COULD NOT OPEN ASSET");
}
// open asset as file descriptor
off_t start, length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);
if(fd < 0)
{
LOGW("COULD NOT OPEN FILE DESCRIPTOR");
}
AAsset_close(asset);
...

As expected the application crashed presumably due to the invlaid
AAssetManager pointer:
...
02-09 20:53:12.505: INFO/native-activity(778): android_main called
02-09 20:53:12.625: INFO/DEBUG(31): *** *** *** *** *** *** *** ***
*** *** *** *** *** *** *** ***
02-09 20:53:12.635: INFO/DEBUG(31): Build fingerprint: 'generic/sdk/
generic:2.3.1/GSI11/93351:eng/test-keys'
02-09 20:53:12.635: INFO/DEBUG(31): pid: 778, tid: 787 >>>
com.example.native_activity <<<
02-09 20:53:12.635: INFO/DEBUG(31): signal 11 (SIGSEGV), code 1
(SEGV_MAPERR), fault addr 00000004
...

I have no idea where to go from here.
Any useful comments (other than "use Java to get a valid AssetManager
instance") are welcomed.

Many thanks in advance,
Jens

--- References ---
[1] http://developer.android.com/sdk/android-2.3-highlights.html
[2] http://groups.google.com/group/android-ndk/browse_thread/thread/842ca9d7d82995b0
[3]
http://groups.google.com/group/android-ndk/browse_thread/thread/4e25a5dfd46f8fea/1269bcd10bdb066d?lnk=gst&q=apk+compressed#1269bcd10bdb066d

David Turner

unread,
Feb 9, 2011, 4:18:51 PM2/9/11
to andro...@googlegroups.com
On Wed, Feb 9, 2011 at 10:03 PM, jenosch <jens.g...@gmail.com> wrote:
Hello,

--- Problem ---
I am trying to access a text file under my $projectPath/assets
directory through the native interface without touching Java code. I
am using the Android SDK r09, the NDK r5b, Cygwin 1.7.7 und Windows 7
64 bit, ADT 9.0.0 Plugin for Eclipse.

Why? I want to provide cross platform (Android, Windows, IPhone)
compatible means for loading (and writing) to xml and image files.
Therefore, I do only want to employ C / C++ and no Java code.

According to [1]  "Applications can now access a native Asset Manager
API to retrieve application assets directly from native code without
needing to go through JNI"

After some investigation (see below) the question to getting access to
asset files boiled down to
"How do I get access to a valid AAssetManager pointer without passing
it down from Java via JNI?"


Look at the "assetManager" field of the ANativeActivity object handled to you by the system, it's right here! :-)

Hope this helps

- Digit
 

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


jenosch

unread,
Feb 10, 2011, 4:07:21 AM2/10/11
to android-ndk
Hello David,

that was it. All I had to do was:

void android_main(struct android_app* state) {
...
AAssetManager* assetManager = state->activity->assetManager;
...

Thank you.

Cheers,
Jens

On 9 Feb., 22:18, David Turner <di...@android.com> wrote:
> >http://groups.google.com/group/android-ndk/browse_thread/thread/842ca...
> > [3]
>
> >http://groups.google.com/group/android-ndk/browse_thread/thread/4e25a...

jenosch

unread,
Feb 11, 2011, 9:56:12 AM2/11/11
to android-ndk
Hello again,

now a different problem pops up. How can I reliably read files greater
than 1023 bytes?
When trying to read larger files than 1023 bytes, only the first 1023
bytes are read in.

I tested it the following way on an emulator with Android 2.3 and on
the Google Nexus S with Android 2.3.2.

I created a file test.txt
with

this is line number 1
this is line number 2
....
this is line number 100

The file has a size of 2.392 bytes.

The file is compressed into the .apk - I can decompress and read it
without problems.

When trying
/////
...
AAsset* asset = AAssetManager_open(_assetManager, "test.txt",
AASSET_MODE_UNKNOWN);
off_t bufferSize = AAsset_getLength(asset);
char* buffer = new char[bufferSize];
int numBytesRead = AAsset_read(asset, buffer, bufferSize);
int numBytesRemaining = AAsset_getRemainingLength(asset);

// alternatively
const char* buffer2 = static_cast<const
char*>(AAsset_getBuffer(asset));

LOGW(buffer);
LOGW(buffer2);

AAsset_close(asset);
...
/////
Only the first 1023 bytes are written out (up to line 43).
Interestingly enough,
numBytesRead shows me the correct file size (2392) and
numBytesRemaining is 0.


I also tested
off_t start;
off_t length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);

which gives me total weired results for start and length.
fd tells me, that the asset is compressed.
start is always -2092760185 (as it seems not to be initialized by
openFileDescriptor)
but length is either -2092687276, when I a call

off_t bufferSize = AAsset_getLength(asset);
char* buffer = new char[bufferSize];
int numBytesRead = AAsset_read(asset, buffer, bufferSize);

AFTERWARDS (not before)!
Or length = 1219007 if I do not call anything but AAsset_close(asset)
in the end.

What am I doing wrong?
So how can I read files greater than 1023 bytes?

Thanks in advance,
Jens

Rémi Chaignon

unread,
May 24, 2011, 6:38:36 PM5/24/11
to andro...@googlegroups.com
Hi Jens,
Did you find a good workaround for that?
I'm having the same issue.
Rémi.

Philippe Simons

unread,
May 24, 2011, 6:51:14 PM5/24/11
to andro...@googlegroups.com
I'm loading files bigger than 1023 bytes with no problems using the AAssetManager. (jpeg files and vorbis files)
I think the issue is with android_log which seems to be unable to output buffers bigger than 1024 bytes

--

Rémi Chaignon

unread,
May 24, 2011, 7:35:22 PM5/24/11
to andro...@googlegroups.com
I see, but I have a problem loading files, or more exactly using the buffer from the asset.
Are you using AAsset_getBuffer or another method?

Dianne Hackborn

unread,
May 24, 2011, 11:52:03 PM5/24/11
to andro...@googlegroups.com
I suggest not using getBuffer() for a compressed file.  It really only make sense for a file that isn't compressed, where this can give you a direct pointer to the mmapped data.

On Tue, May 24, 2011 at 4:35 PM, Rémi Chaignon <re...@occipital.com> wrote:
I see, but I have a problem loading files, or more exactly using the buffer from the asset.
Are you using AAsset_getBuffer or another method?

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



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

Rémi Chaignon

unread,
May 25, 2011, 12:23:03 AM5/25/11
to andro...@googlegroups.com
I am accessing my assets from the /assets folder, aren't those asset supposed to not be compressed?
What other method are you using? read()?

Gregory Ray

unread,
May 25, 2011, 12:28:55 AM5/25/11
to andro...@googlegroups.com
Remi,

Try renaming the file to something in the do not compress list just to see if it fixes your issue:


> static const char* kNoCompressExt[] = {
>     ".jpg", ".jpeg", ".png", ".gif",
>     ".wav", ".mp2", ".mp3", ".ogg", ".aac",
>     ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
>     ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
>     ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
>     ".amr", ".awb", ".wma", ".wmv"
>
> };

On Tue, May 24, 2011 at 9:23 PM, Rémi Chaignon <re...@occipital.com> wrote:
I am accessing my assets from the /assets folder, aren't those asset supposed to not be compressed?
What other method are you using? read()?

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



--
Gregory Ray
Co-founder, Seek Mobile Interactive, Inc.

---

This e-mail message, including any attachments, is for the sole use of the intended recipient(s) and may contain information that is confidential and protected by law from unauthorized disclosure. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply e-mail and destroy all copies of the original message.

Rémi Chaignon

unread,
May 25, 2011, 1:36:25 AM5/25/11
to andro...@googlegroups.com
I am trying to load .png files.
The crash happens when I try to use the buffer. The call to getBuffer() works fine, the pointer returned is valid, but when I try to access the bytes, it crashes after a while.
The thing is, it doesn't crash at the same point for every images I'm trying to load. I am trying to load 20+ .png files and only 5 don't make the app crash, they are the ones under 2kb except one which is 2.56kb (but I have other images between 2kb and 2.56kb and they do crash the app). I can't make sense of any of this...
Any suggestions?

This is the error:
INFO/DEBUG(17664): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr dc5ab024

Gregory Ray

unread,
May 25, 2011, 1:46:51 AM5/25/11
to andro...@googlegroups.com
I have had no problem loading pngs using the read command and libpng but never tried getBuffer, sounds like a bug.

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

Dianne Hackborn

unread,
May 25, 2011, 1:50:02 AM5/25/11
to andro...@googlegroups.com
getBuffer is used by basically everything in Android that loads resources.

Rémi Chaignon

unread,
May 25, 2011, 11:54:16 AM5/25/11
to andro...@googlegroups.com
Here is my code to load my images, am I doing something wrong? It crashes on glTexSubImage2D when it's trying to access the bytes. If I put a smaller value for width and height in the glTexSubImage2D call, it works, so it seems the buffer doesn't hold the full image.


bool AssetManager::loadImageIntoTexture(const char* _sImageFilename, GLsizei _iWidth, GLsizei _iHeight, GLuint& _uTextureId)
AAsset* assetImage = AAssetManager_open(m_pAssetManager, _sImageFilename, AASSET_MODE_UNKNOWN);
if(!assetImage)
{
LOGE("Couldn't open image!");
return false;
}

GLubyte* acImageBuffer = (GLubyte*)AAsset_getBuffer(assetImage);

// Get power of 2 texture size
GLsizei iWidthPow2 = pow(2, (int)ceil(log(_iWidth) / log(2)));
GLsizei iHeightPow2 = pow(2, (int)ceil(log(_iHeight) / log(2)));

// Set texture
glBindTexture(GL_TEXTURE_2D, _uTextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidthPow2, iHeightPow2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _iWidth, _iHeight, GL_RGBA, GL_UNSIGNED_BYTE, acImageBuffer);

AAsset_close(assetImage);
return true;
}

Futumsh

unread,
May 25, 2011, 12:32:46 PM5/25/11
to android-ndk
It looks like you're trying to pass the bytes of a .png file to
glTexSubImage2D, which is is expecting an array of 32 bit texels.

Rémi Chaignon

unread,
May 25, 2011, 3:17:41 PM5/25/11
to andro...@googlegroups.com
Yes that's wrong, disregard.
I thought my problem came from loading assets because loading my shaders was failing too. But I just figured out that it was because of a wrong character encoding and end-of-line format.
I got libpng running now and will add the missing part for loading my textures.
Sorry for wasting your time.
Reply all
Reply to author
Forward
0 new messages