2015-04-26 13 views
12

Ich schreibe eine Android-Anwendung, die ein Bild aus dem nativen C (NDK r10d) verarbeitet. Der Code funktionierte bis zur kürzlichen ART-Einführung, die bei JNI strenger ist. Der Code funktioniert also gut mit Dalvik (z. B. auf Pre-Lolipop-Geräten), aber er erzeugt auf den neuesten Telefonen ein SIGENV.
ich jetzt den Fehler:Android (ART) Absturz mit Fehler JNI DETECTED FEHLER IN DER ANWENDUNG: jarray ist eine ungültige Stack indirekten Referenztabelle oder ungültiger Verweis

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) 

Der Code, den ich in Java ist:

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

Die entsprechenden nativen Code ist:

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

Es scheint, dass GetByteArrayElements die Quelle Der JNIEnv-Verweis und das JbyteArray werden von Android zur Verfügung gestellt und ich kann sie weder speichern noch ändern. Da das Puffer-Array immer im selben Java-Thread zugeordnet ist, sehe ich nicht, wie es beschädigt werden kann ... Ich bin ziemlich verwirrt :)
Was kann die Ursache für dieses Problem sein?
Ist der Heap zu klein? Oder ist es ein ART-Thema (ich bezweifle es wirklich ...)?
Danke für Ihre Hilfe!

+2

Überprüfen Sie bitte die von 'nativeGetDataSize()' zurückgegebene Größe, und das 'env-> GetArrayLength()' gibt das gleiche zurück. Da ich nicht behaupte, dieses Problem zu lösen, würde ich immer noch vorschlagen, das Array in nativem Code zuzuordnen und die Hälfte der JNI-Aufrufe mit allen damit verbundenen Kosten loszuwerden. –

+1

Leider bestätigt dies, dass die Referenz des jbyteArray beschädigt ist: Der Aufruf von 'env-> GetArrayLength()' triggert jetzt den gleichen Fehler. Ich werde morgen die Zuordnung aus dem nativen Code heraus versuchen. Danke! – Stef

+1

Funktioniert wie ein Charme! Vielen Dank! – Stef

Antwort

4

Nach Alex Cohn ‚s Rat, den ich den folgenden Code Arbeit gemacht:
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); 


Mutter

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


Danke!

1

Dies bedeutet, dass es für die Dauer der aktuellen systemeigenen Methode im aktuellen Thread gültig ist. Selbst wenn das Objekt selbst weiterlebt, nachdem die native Methode zurückgegeben wurde, ist die Referenz nicht gültig.

Versuchen Sie, dies in Ihrem jclass/jarray declare zu ersetzen.

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

Siehe JNI Tips

+0

Entschuldigung, ich bin mir nicht sicher zu verstehen. Das jarray wird im Java-Teil in einem Thread zugewiesen und dann dem JNI übergeben. Ich habe vergessen zu erwähnen, dass der Aufrufer der Java-Funktion, die ich zitiert habe, synchronisiert ist. Dann wird das Jarray nur während der Ausführung der JNI-Funktion verwendet, daher sollte die lokale Referenz hier in Ordnung sein, nicht? Trotzdem habe ich versucht, eine globale Referenz aus dem Jarray zu erstellen, aber das ändert nichts an der Situation. – Stef