3

これは私が尋ねた別の質問のフォローアップです:Android-JNIからMEIDを取得します

Androidで携帯電話のIDを取得しようとしています。いくつかの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が、もしそうなら、私は何が正しいかわからない。それがJNI関数に渡されるのは、Javaコードobjの場合と同じではありませんか?this

編集:さて、JNI関数に型の引数を追加し、その引数jobjectのコピーを明示的に渡しthisてから、それをCallObjectMethod()(上記のコードでクラッシュする引数)に渡すと、すべてが機能することがわかりました。 。インスタンスを取得しTelephonyManager、電話ID値を照会できます。

ロギングマクロを使用して、objポインターと渡されたポインターをログに記録しましたthis。それらは類似した番号(互いに近いアドレス)ですが、同一ではありません。objしたがって、JavaVM内からのある種のオブジェクト参照だと思います...実際には。と同じではありませんthis

JNI関数では、最初の2つの引数はとJNIEnv *envですjobject obj。その2番目のものは何のためですか?私はそれで何ができますか?それを使用して呼び出す方法はありますか、それともgetSystemService追加の引数を渡して渡す必要がありthisますか?

4

3 に答える 3

2

この問題はJavaの継承に関連しているようです。Javaでは、実際にはのインスタンスではありませんがthis.getSystemService()、呼び出すことができ、機能します。JNI呼び出しを行うと、呼び出しは単に失敗します。thisContext

したがって、私たちの解決策は、Androidアプリに.getApplicationContext()実際に独自のクラスの一部としてメソッド関数を追加させることでした。これにより、実際が呼び出されgetSystemService()、結果が返されます。

コードは変更されませんでした:まだ呼び出しています

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

しかし.getSystemService()、JNI関数を呼び出しているクラスにメソッドがある場合、これは機能します。したがって、envJNI呼び出しの引数は、this同じではありません(の値をthisポインターとして出力し、出力しましたenv。これらは同じではありませんが、確実に関連しています)。

于 2012-09-17T20:53:31.387 に答える
0

オブジェクトでスーパークラスメソッドを呼び出す場合はCallNonvirtualObjectMethod() 、JNIでオーバーライドされたメソッドを呼び出す方法を使用する必要があります

于 2015-02-03T09:58:43.067 に答える
0

これを試してください...それは動作します...「コンテキスト」はJavaから来ました:)

jclass ctx = env->FindClass("android/content/Context");
jfieldID fid = env->GetStaticFieldID(ctx,"TELEPHONY_SERVICE","Ljava/lang/String;");
jstring str = (jstring) env->GetStaticObjectField(ctx, fid);
jmethodID mid = env->GetMethodID(ctx, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
jobject tm = env->CallObjectMethod(context, mid, str);

jclass ctx_tm = env->FindClass("android/telephony/TelephonyManager");
jmethodID mid_tm = env->GetMethodID(ctx_tm,"getDeviceId","()Ljava/lang/String;");
jstring str_tm = (jstring) env->CallObjectMethod(tm, mid_tm);

strReturn = env->GetStringUTFChars(str_tm, 0);
于 2020-01-06T05:35:44.883 に答える