Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't access AAssetManager in native code passed from Java in WallpaperService

I'm trying to access the the assets in native code from a custom WallpaperService. The native code compiles and works but trying to get the AAssetManager reference from the AssetManager object passed to the native function always returns NULL.

Is it something to do with the fact that I am using a Service rather than an Activity that results in the AAssetManager reference being NULL? In the Java source the AssetManager being passed to the native function is valid and is not null.

To test this I used them CubeLiveWallpaper demo from the samples provided and targeting API level 10. Here is the relevant code added to the CubeWallpaper1 class in order to access the native functionality:

static {
    System.loadLibrary("renderer");
}

private static native void load(AssetManager mgr);

@Override
public void onCreate() {
    super.onCreate();

    AssetManager mgr = getResources().getAssets();
    load(mgr);
}

Here is the JNI code I'm using to try and acquire a valid AAssetManager reference:

#include <jni.h>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

#define TAG "CubeWallpaper1.c"

void
Java_com_example_android_livecubes_cube1_CubeWallpaper1_load(JNIEnv *env,
                                                             jobject assetManager) {

    AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
    if (mgr == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "CubeWallpaper1.c", "error loading asset   maanger");
    } else {
        __android_log_print(ANDROID_LOG_VERBOSE, "CubeWallpaper1.c", "loaded asset  manager");
    }

}

This has been replicated on a couple of devices but most testing has been done on a HTC Desire running 2.3.7.

like image 368
cshaw Avatar asked Jun 08 '12 00:06

cshaw


1 Answers

Read the comments inside asset_manager_jni.h: "Note that the caller is responsible for obtaining and holding a VM reference to the jobject to prevent its being garbage collected while the native object is in use."

In Java, you are passing an object (mgr) that may be freed by the garbage collector once the native callback is called. To prevent this, you could, for example, create the mgr variable as a private attribute in your class and then pass it through the load method, such as this:

private static native void load(AssetManager mgr);

private AssetManager mgr;

@Override
public void onCreate() {
  super.onCreate();

  mgr = getResources().getAssets();
  load(mgr);
}

Also, I think you must replace your native C++ callback with:

void Java_com_example_android_livecubes_cube1_CubeWallpaper1_load
     (JNIEnv *env, jobject obj, jobject assetManager) 
like image 187
Dani Avatar answered Nov 14 '22 22:11

Dani