2012-06-15 20 views
7

OK, więc mam kod natywny poniżej. Próbuję zwrócić z niego tablicę FilePermissionInfo, wypełnioną niektórymi danymi zwracanymi przez stat(). Problemem jest to, że pojawia się następujący błąd podczas NewObject nazywa się po raz pierwszy:Nieprawidłowe odwołanie pośrednie na wywołanie NewObject

06-15: 20: 25: 17.621: W/dalvikvm (2287): Nieprawidłowy odniesienie pośrednie 0x40005820 w decodeIndirectRef 06-15 20: 25: 17,621: E/dalvikvm (2287): VM przerywanie

to dziwne, ponieważ jedynym celem odniesienia mam jest JClass (dla FilePermissionInfo) i włączyć go do globalnej odniesienia.

Kod jest:

JNIEXPORT jobjectArray JNICALL 
Java_com_mn_rootscape_utils_NativeMethods_getFilesPermissions(JNIEnv* env, jobject thizz, jobjectArray filePathsArray) 
{ 
jobjectArray result; 
int size = (*env)->GetArrayLength(env, filePathsArray); 
jboolean isCopy; 

jclass filePermInfoCls = (*env)->FindClass(env, kFilePermissionInfoPath); 
if(!filePermInfoCls) 
{ 
    LOGE("getFilesPermissions: failed to get class reference."); 
    return NULL; 
} 

gFilePermInfoClass = (jclass)(*env)->NewGlobalRef(env, filePermInfoCls); 
LOGI("got gFilePermInfoClass"); 

jmethodID filePermInfoClsConstructor = (*env)->GetMethodID(env, gFilePermInfoClass, "<init>", kFilePermInfoConstructorSig); 
if(!filePermInfoClsConstructor) 
{ 
    LOGE("getFilesPermissions: failed to get method reference."); 
    return NULL; 
} 

struct stat sb; 

LOGI("starting..."); 
result = (jobjectArray)(*env)->NewObjectArray(env, size, gFilePermInfoClass, NULL); 
for(int i = 0; i != size; ++i) 
{ 
    jstring string = (jstring) (*env)->GetObjectArrayElement(env, filePathsArray, i); 
const char *rawString = (*env)->GetStringUTFChars(env, string, &isCopy);  

    if(stat(rawString, &sb) == -1) 
    { 
     LOGE("stat error for: %s", rawString); 
    } 

    LOGI("%ld %ld %ld %ld %ld %ld %ld %ld", sb.st_dev, sb.st_mode, sb.st_nlink, sb.st_uid, sb.st_gid, sb.st_atime, sb.st_mtime, sb.st_ctime); 

    jobject permInfo = (*env)->NewObject(env, 
          gFilePermInfoClass, 
          filePermInfoClsConstructor, 
          (long)sb.st_dev, 
          (long)sb.st_mode, 
          (long)sb.st_nlink, 
          (long)sb.st_uid, 
          (long)sb.st_gid, 
          (long)sb.st_atime, 
          (long)sb.st_mtime, 
          (long)sb.st_ctime, 
          "", 
          "", 
          1, 
          ""); 

    LOGI("xxx1"); 
    (*env)->SetObjectArrayElement(env, result, i, permInfo); 
    LOGI("xxx2"); 
    (*env)->ReleaseStringUTFChars(env, string, rawString); 
    LOGI("xxx3"); 
} 

(*env)->DeleteLocalRef(env, filePermInfoCls); 

return result; 

}

Konstruktor klasy podpis i ścieżka Java są:

const char* kFilePermissionInfoPath = "com/mn/rootscape/utils/FilePermissionInfo"; 
const char* kFilePermInfoConstructorSig = "(JJJJJJJJLjava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V"; 

Należy pamiętać, że jeśli zadzwonię NewObject na domyślnego konstruktora to działa w porządku.

+0

Mam nadzieję, że to nie jest błąd w NDK (v8). Próbowałem różnych podejść i to jest bardzo dziwne, że działa z domyślnym konstruktorem (np. "() V". Ostatecznie mogę użyć setterów w tej klasie, aby ustawić wartości, ale nie chciałbym wywoływać zbyt wiele metod nad granicą JNI –

Odpowiedz

13

OK, znalazłem. To był problem z parametrami jstring. Okazuje się, że nie można przekazać pustych ciągów znaków (lub nawet NULL w tej sprawie) jako jstring. Zamiast tego użyłem (*env)->NewStringUTF(env, NULL) do utworzenia NULL jstring.

Wydaje się działać OK.


Ponieważ to pytanie wygenerowało dość dużą aktywność, zamieszczam poniżej ostateczne rozwiązanie. Zauważ, że zmienna nullString jest zwalniane pod koniec jego zakresu (lub po zakończeniu pracy):

 jstring nullString = (*env)->NewStringUTF(env, NULL); 
... 
     jobject permInfo = (*env)->NewObject(env, 
           gFilePermInfoClass, 
           filePermInfoClsConstructor, 
           (jbyte)permsOwner, 
           (jbyte)permsGroup, 
           (jbyte)permsOthers, 
           (jlong)sb.st_uid, 
           (jlong)sb.st_gid, 
           (jlong)sb.st_atime, 
           (jlong)sb.st_mtime, 
           (jlong)sb.st_ctime, 
           nullString, 
           nullString, 
           (jboolean)1, 
           nullString); 
... 
     (*env)->DeleteLocalRef(env, nullString); 
+2

Czy masz na myśli zastąpienie argumentów "", "," w '(* env) -> NewObject (...)' wywołanie funkcji w 'jstring myNullString = (* env) -> NewStringUTF (env, NULL) "następnie przekazać myNullString jako argumenty? –

+1

@ m-ric: Tak, to jest poprawne –

+0

Nie jestem pewien, czy to jest nadal problem z pustymi jstrings, jak pierwotnie stwierdzono. został uruchomiony w tym wydaniu, ale udało się go naprawić przy użyciu czegoś takiego: std: string empty (""); jstring myemptyString = (* env) -> NewStringUTF (empty.c_str()); Zauważ, że testowałem z Androidem 4.3: –