2012-08-24 56 views
3

這是一個後續的另一個問題,我問: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 *envjobject obj。第二個是什麼?我能用它做什麼?有什麼辦法,我可以用它打電話getSystemService否則我將不得不通過一個額外的參數,並通過在this

+0

那你有沒有調試?首先打印出LogCat的所有變量值(爲此使用'_android_log_print()'),查看是否所有的類和方法ID都是有效的。機會是,錯誤在實際的方法調用之前。 –

+0

據我所知,如果返回值不是NULL,那麼返回值是有效的;並且沒有返回值是NULL。我的代碼在每一步之後都會記錄,並以'%p'格式打印每個指針;這些數字看起來似乎合理。 (當我刪除這裏發佈的錯誤檢查代碼時,我也刪除了日誌代碼。) – steveha

回答

1

這個問題似乎涉及到Java繼承:在Java中,你可以調用this.getSystemService()和它的作品,即使this是不實際的Context一個實例。當你進行JNI調用時,調用就會失敗。

所以我們的解決方案是讓我們的Android應用程序實際上是增加一個.getApplicationContext()方法函數作爲自己的階級的一部分。這又調用實際的getSystemService()並返回結果。

的代碼並沒有改變:我們仍然呼籲

mid = (*env)->GetMethodID(env, cls_context, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); 

,但現在它的工作原理,當有在呼籲我們的JNI函數的類.getSystemService()方法。所以,env參數在JNI調用確實代表this(它不相同......我打印爲指針的this值,並打印env,和他們是不一樣的,但他們肯定是相關的)。

+0

我有同樣的問題,我在應用程序及其工作中使用此代碼,但是當我在庫模塊中使用它時,出現異常。請在Android中向我展示一個簡單的.getApplicationContext()以傳遞此異常。 – sma6871