這是一個後續的另一個問題,我問:Android -- get MEID from JNI的Android NDK崩潰CallObjectMethod調用getSystemService
我試圖讓手機的ID在Android系統。我有一些JNI代碼和一個簡單的測試應用程序來調用JNI代碼。這裏是我的簡單的測試應用工作的Java代碼:
TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String id = tm.getDeviceId();
字符串id
設置爲我想要的手機ID值。但是我需要從JNI中獲取它,只是使用上面的代碼並將ID值傳入是不可接受的解決方案。 (這是爲了讓一些JNI代碼有點防篡改,並且我不應該相信Java層發送正確的ID值。)
這是我寫的JNI代碼,它的錯誤處理已被刪除更容易遵循。它一直運行到指定的行,然後整個應用程序崩潰。
// "env" and "obj" are passed to a JNI function and are used unmodified in this code
// JNIEnv *env, jobject obj
jclass cls_context = NULL;
jclass cls_tm = NULL;
jobject tm = NULL;
jmethodID mid;
jfieldID fid;
jstring jstr;
jsize len_jstr;
cls_context = (*env)->FindClass(env, "android/content/Context");
fid = (*env)->GetStaticFieldID(env, cls_context, "TELEPHONY_SERVICE",
"Ljava/lang/String;");
jstr = (*env)->GetStaticObjectField(env, cls_context, fid);
mid = (*env)->GetMethodID(env, cls_context, "getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
tm = (*env)->CallObjectMethod(env, obj, mid, jstr); // THIS LINE CRASHES
cls_tm = (*env)->FindClass(env, "android/telephony/TelephonyManager");
mid = (*env)->GetMethodID(env, cls_tm, "getDeviceId",
"()Ljava/lang/String;");
jstr = (*env)->CallObjectMethod(env, tm, mid);
len_jstr = (*env)->GetStringUTFLength(env, jstr);
(*env)->GetStringUTFRegion(env, jstr, 0, len_jstr, buf_devid);
我認爲這個問題是obj
是不是通過正確的事情,但如果是這樣,我不知道什麼是正確的事情。是不是obj
得到數據傳遞給JNI函數同樣的事情,在Java代碼中this
?
編輯:好的,我們已經計算出,如果我們增加jobject
類型的額外參數JNI函數,並明確傳遞的this
在爭論一個副本,然後傳遞到CallObjectMethod()
(在崩潰的一個上面的代碼),一切正常。我們得到我們的TelephonyManager
實例,我們可以查詢電話ID值。
使用記錄宏,我記錄了obj
指針和傳入的this
指針。它們是相似的數字(地址彼此接近)但不完全相同。所以我覺得obj
是某種來自Java VM內部對象引用的......它實際上不是一樣this
。
在JNI函數中,前兩個參數是JNIEnv *env
和jobject obj
。第二個是什麼?我能用它做什麼?有什麼辦法,我可以用它打電話getSystemService
否則我將不得不通過一個額外的參數,並通過在this
?
那你有沒有調試?首先打印出LogCat的所有變量值(爲此使用'_android_log_print()'),查看是否所有的類和方法ID都是有效的。機會是,錯誤在實際的方法調用之前。 –
據我所知,如果返回值不是NULL,那麼返回值是有效的;並且沒有返回值是NULL。我的代碼在每一步之後都會記錄,並以'%p'格式打印每個指針;這些數字看起來似乎合理。 (當我刪除這裏發佈的錯誤檢查代碼時,我也刪除了日誌代碼。) – steveha