2015-04-26 1 views
12


Je suis en train d'écrire une application Android qui traite une image du C (NDK r10d) natif. Le code fonctionnait bien jusqu'à la récente introduction de l'ART qui est plus stricte avec JNI. Donc, le code fonctionne bien avec Dalvik (par exemple sur les appareils pré-Lolipop) mais ii crée un SIGENV sur les téléphones les plus récents.
Je reçois maintenant l'erreur:Android (ART) crash avec erreur JNI DETECTED ERROR IN APPLICATION: jarray est une table de référence indirecte invalide ou une référence invalide

04-26 16:18:34.169: E/art(21443): 0xb4a2dd00 SpaceTypeMallocSpace begin=0x12c00000,end=0x12e01000,limit=0x32c00000,size=2MB,capacity=192MB,non_growth_limit_capacity=512MB,name="main rosalloc space"] 
04-26 16:18:34.170: E/art(21443): 0xb4ae5640 allocspace main rosalloc space live-bitmap 3[begin=0x12c00000,end=0x32c00000] 
04-26 16:18:34.170: E/art(21443): 0xb4ae5660 allocspace main rosalloc space mark-bitmap 3[begin=0x12c00000,end=0x32c00000] 
04-26 16:18:34.170: E/art(21443): 0xb4874120 SpaceTypeImageSpace begin=0x6f5ab000,end=0x6ff21e58,size=9MB,name="/data/dalvik-cache/arm/[email protected]@boot.art"] 
04-26 16:18:34.170: E/art(21443): 0xb4875220 imagespace /data/dalvik-cache/arm/[email protected]@boot.art live-bitmap 0[begin=0x6f5ab000,end=0x6ff21f00] 
04-26 16:18:34.170: E/art(21443): 0xb4875220 imagespace /data/dalvik-cache/arm/[email protected]@boot.art live-bitmap 0[begin=0x6f5ab000,end=0x6ff21f00] 
04-26 16:18:34.170: E/art(21443): 0xb49d9dd0 SpaceTypeZygoteSpace begin=0x72f09000,end=0x740c7000,size=17MB,name="Zygote space"] 
04-26 16:18:34.170: E/art(21443): 0xb4875440 allocspace zygote/non moving space live-bitmap 0[begin=0x72f09000,end=0x740c7000] 
04-26 16:18:34.170: E/art(21443): 0xb4875460 allocspace zygote/non moving space mark-bitmap 0[begin=0x72f09000,end=0x740c7000] 
04-26 16:18:34.170: E/art(21443): 0xb4a2dc80 SpaceTypeMallocSpace begin=0x740c7000,end=0x740d6000,limit=0x76f09000,size=60KB,capacity=46MB,non_growth_limit_capacity=46MB,name="non moving space"] 
04-26 16:18:34.170: E/art(21443): 0xb4ae5460 allocspace non moving space live-bitmap 4[begin=0x740c7000,end=0x76f09000] 
04-26 16:18:34.170: E/art(21443): 0xb4ae53c0 allocspace non moving space mark-bitmap 4[begin=0x740c7000,end=0x76f09000] 
04-26 16:18:34.170: E/art(21443): 0xb486d340 large object space:GcRetentionPolicyAlwaysCollect 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: jarray is an invalid stack indirect reference table or invalid reference: 0x740c9268 (0xdead4321) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65]  in call to GetByteArrayElements 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65]  from boolean com.googlecode.leptonica.android.Pix.nativeGetData(int, byte[]) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] "main" prio=5 tid=1 Runnable 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | group="main" sCount=0 dsCount=0 obj=0x72f09000 self=0xb4827800 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | sysTid=21443 nice=0 cgrp=default sched=0/0 handle=0xb6f6abec 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | state=R schedstat=(427402282 63106827 397) utm=28 stm=14 core=3 HZ=100 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | stack=0xbe5e3000-0xbe5e5000 stackSize=8MB 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | held mutexes= "mutator lock"(shared held) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #00 pc 00004e64 /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #01 pc 00003665 /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #02 pc 00256429 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+84) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #03 pc 00238fe7 /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+158) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #04 pc 000b191b /system/lib/libart.so (art::JniAbort(char const*, char const*)+610) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #05 pc 000b2055 /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #06 pc 000b4455 /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+480) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #07 pc 000bee03 /system/lib/libart.so (art::CheckJNI::GetByteArrayElements(_JNIEnv*, _jbyteArray*, unsigned char*)+62) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #08 pc 00239478 /data/app/com.bill2bin.core.lib.demo-1/lib/arm/liblept.so (_JNIEnv::GetByteArrayElements(_jbyteArray*, unsigned char*)+48) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #09 pc 0023992c /data/app/com.bill2bin.core.lib.demo-1/lib/arm/liblept.so (Java_com_googlecode_leptonica_android_Pix_nativeGetData+540) 
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #10 pc 0008d3b5 /data/dalvik-cache/arm/[email protected]@[email protected]@classes.dex (Java_com_googlecode_leptonica_android_Pix_nativeGetData__I_3B+104) 
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.googlecode.leptonica.android.Pix.nativeGetData(Native method) 
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.googlecode.leptonica.android.Pix.getData(Pix.java:94) 
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.bill2bin.core.lib.demo.VideoPipeDebug.testDoJNIDebug(VideoPipeDebug.java:449) 
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.bill2bin.core.lib.demo.CameraActivity.runTest1(CameraActivity.java:133) 

Le code que je lance en Java est:

/** 
    * Return the raw bytes of the native PIX object. You can reconstruct the 
    * Pix from this data using createFromPix(). 
    * 
    * @return a copy of this PIX object's raw data 
    */ 
    public byte[] getData() { 
     int size = nativeGetDataSize(mNativePix); 
     // Size is usually quite big since I work on pictures (1Mo-300Ko) 
     byte[] buffer = new byte[size]; 

     if (!nativeGetData(mNativePix, buffer)) { 
      throw new RuntimeException("native getData failed"); 
     } 

     return buffer; 
    } 

    private static native boolean nativeGetData(long nativePix, byte[] data); 

Le code natif correspondant est:

jboolean Java_com_googlecode_leptonica_android_Pix_nativeGetData(JNIEnv *env, 
     jclass clazz, jlong nativePix, jbyteArray data) { 
    PIX *pix = (PIX *) nativePix; 

    jbyte *data_buffer = env->GetByteArrayElements(data, NULL); 

    l_uint8 *byte_buffer = (l_uint8 *) data_buffer; 

    size_t size = 4 * pixGetWpl(pix) * pixGetHeight(pix); 
    memcpy(byte_buffer, pixGetData(pix), size); 

    env->ReleaseByteArrayElements(data, data_buffer, 0); 

    return JNI_TRUE; 
} 

Il semble que GetByteArrayElements est la source de l'erreur, mais la référence JNIEnv et le jbyteArray sont fournis par Android et je ne stocke pas ni ne les modifie. Depuis le tableau tampon est toujours alloué dans le même fil Java, je ne vois pas comment il peut être corrompu ... Je suis assez perplexe :)
Quelle peut être la source de ce problème?
Le tas est-il trop petit? Ou est-ce un problème d'ART (j'en doute vraiment ...)?
Merci pour votre aide!

+2

Veuillez vérifier la taille retournée par 'nativeGetDataSize()', et que 'env-> GetArrayLength()' retourne la même chose. Ne prétendant pas résoudre ce problème, je suggère toujours d'allouer le tableau en code natif, en se débarrassant de la moitié des appels JNI avec tous les frais généraux impliqués. –

+1

Malheureusement, cela confirme que la référence de jbyteArray est corrompue: l'appel de 'env-> GetArrayLength()' déclenche maintenant la même erreur. Je vais essayer demain l'allocation à partir du code natif. Merci! – Stef

+1

Fonctionne comme un charme! Merci! – Stef

Répondre

4

Suivant les conseils de Alex Cohn J'ai fait le travail de code suivant:
JAVA

public byte[] getData() { 
     byte[] buffer = nativeGetData(mNativePix); 

     if (buffer == null) { 
      throw new RuntimeException("native getData failed"); 
     } 
     return buffer; 
    } 
    private static native byte[] nativeGetData(long nativePix); 


natif

jbyteArray Java_com_googlecode_leptonica_android_Pix_nativeGetData(
     JNIEnv *env, jclass clazz, jlong nativePix) { 
    PIX *pix = (PIX *) nativePix; 
    // Get the size 
    size_t size = 4 * pixGetWpl(pix) * pixGetHeight(pix); 

    jbyteArray result = env->NewByteArray(size); 
    if (result == NULL) { 
     LOGE("Cannot allocate JNI Byte Array"); 

     return NULL; /* out of memory error thrown */ 
    } 
    // move from the Pix to the java structure 
    env->SetByteArrayRegion(result, 0, size,(jbyte*)pixGetData(pix)); 
    return result; 
} 


Merci!

1

Cela signifie qu'il est valide pour la durée de la méthode native actuelle dans le thread en cours. Même si l'objet lui-même continue à exister après le retour de la méthode native, la référence n'est pas valide. Essayez de remplacer ceci dans votre déclaration jclass/jarray.

jclass localClass = env->FindClass("MyClass"); 
jclass globalClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass)); 

Référez JNI Tips

+0

Désolé, je ne suis pas sûr de comprendre. Le jarray est alloué dans la partie java, dans un thread, puis donné au JNI. J'ai oublié de mentionner que l'appelant de la fonction java que j'ai cité est synchronisé. Ensuite, le jarray est utilisé seulement pendant l'exécution de la fonction JNI, donc la référence locale devrait être bien ici, non? Néanmoins, j'ai aussi essayé de créer une référence globale à partir du jarray mais cela ne change pas la situation. – Stef