2015-04-26 16 views
12


Sto scrivendo un'applicazione Android che elabora un'immagine dal C nativo (NDK r10d). Il codice funzionava bene fino alla recente introduzione ART che è più severa con JNI. Quindi il codice funziona perfettamente con Dalvik (ad esempio sui dispositivi pre-Lolipop) ma ii crea un SIGENV sui telefoni più recenti.
io ora ottenere l'errore:Arresto Android (ART) con errore JNI RILEVATO ERRORE NELL'APPLICAZIONE: jarray è una tabella di riferimento indiretta di stack non valida o riferimento non valido

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) 

Il codice corro in Java è:

/** 
    * 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); 

Il codice nativo corrispondente è:

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; 
} 

Sembra che GetByteArrayElements è la fonte dell'errore, ma il riferimento JNIEnv e il jbyteArray sono forniti da Android e non li memorizzo né li memorizzo. Poiché l'array buffer è sempre allocato nello stesso thread Java, non vedo come possa essere danneggiato ... Sono abbastanza perplesso :)
Quale può essere la fonte di questo problema?
L'heap è troppo piccolo? O è un problema di ARTE (ne dubito davvero ...)?
Grazie per il tuo aiuto!

+2

Controllare la dimensione restituita da 'nativeGetDataSize()' e che 'env-> GetArrayLength()' restituisce effettivamente lo stesso valore. Non pretendo di risolvere questo problema, suggerirei comunque di allocare l'array nel codice nativo, eliminando la metà delle chiamate JNI con tutti gli overhead coinvolti. –

+1

Sfortunatamente, ciò conferma che il riferimento di jbyteArray è corrotto: la chiamata a 'env-> GetArrayLength()' sta ora generando lo stesso errore. Proverò domani l'allocazione all'interno del codice nativo. Grazie! – Stef

+1

Funziona come un fascino! Grazie! – Stef

risposta

4

Seguendo il consiglio di Alex Cohn s' ho fatto i seguenti lavori di codice:
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); 


Native

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; 
} 


Grazie!

1

Ciò significa che è valido per la durata del metodo nativo corrente nel thread corrente. Anche se l'oggetto stesso continua a vivere dopo la restituzione del metodo nativo, il riferimento non è valido.

Provare a sostituire questo nella dichiarazione jclass/jarray.

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

consultare JNI Tips

+0

Scusa, non sono sicuro di capire. Il jarray è allocato nella parte java, in un thread, quindi dato al JNI. Ho dimenticato di menzionare che il chiamante della funzione java che ho citato è sincronizzato. Quindi, il jarray viene usato solo durante l'esecuzione della funzione JNI, quindi il riferimento locale dovrebbe andare bene qui, no? Tuttavia, ho anche provato a creare un riferimento globale dal jarray ma questo non sta cambiando la situazione. – Stef