This is a follow-up to another question I asked: Android -- get MEID from JNI
I am trying to get the ID of a phone in Android. I have some JNI code and a simple test app to call the JNI code. Here is working Java code from my simple test app:
TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String id = tm.getDeviceId();
The string id
is set to the phone ID value that I want. But I need to get it from JNI, and just using the above code and passing the ID value in is not an acceptable solution. (This is to make some JNI code somewhat tamper-proof and I shouldn't trust the Java layer to send a correct ID value.)
Here is the JNI code that I have written, with error handling removed so it is easier to follow. It works until the indicated line, and then the whole app crashes.
// "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);
I think the problem is that obj
isn't the right thing to pass, but if so I have no idea what is the right thing. Isn't obj
that gets passed to the JNI function the same thing as this
in the Java code?
EDIT: Okay, we have figured out that if we add an extra argument of type jobject
to the JNI function, and explicitly pass a copy of this
in that argument, and then pass that to CallObjectMethod()
(the one that crashes in the above code), everything works. We get our TelephonyManager
instance and we can query the Phone ID value.
Using a logging macro, I logged the obj
pointer and the passed-in this
pointer. They are similar numbers (addresses close to each other) but not identical. So I think obj
is some sort of object reference from inside the Java VM... it is not actually the same as this
.
In a JNI function, the first two arguments are JNIEnv *env
and jobject obj
. What is that second one for? What can I do with it? Is there any way I can use it to call getSystemService
or will I have to pass an extra argument and pass in this
?