2

Java 側に接続するために android_native_app_glue ファイルと共に、NativeActivity を使用するプロジェクトに取り組んでいます。Java を介していくつかの非 NDK クラスにアクセスする必要があり、C から Java への呼び出しを行う方法を理解しましたが、逆に問題があります。Java から CI への呼び出しで "No implementation found for etc..." が表示される場合、この種の呼び出しのほとんどの落とし穴を確認し、すべてが正しいと信じています。これがActivityクラスです。

package com.JNITest;

import android.app.NativeActivity;
import android.util.Log;

public class JniNativeActivity extends NativeActivity
{
    private static String TAG = "JniNativeActivity";

    public static native void nativeJniCall();

    public JniNativeActivity()
    {
        super();
        Log.v(TAG, "Creating JniNativeActivity");
    }

    public void testCall()
    {
        Log.v(TAG, "Calling native");
        nativeJniCall();
    }
}

これはグルー コードを使用する NativeActivity であるため、呼び出される JNI_OnLoad はありません。エントリ ポイントは android_main です (グルー コードは独自のスレッドで実行するように設定されています)。

void android_main(struct android_app* state)
{
    test_call(state->activity);
    etc...
}

...

void test_call(ANativeActivity *activity)
{
    JNIEnv *jni;

    activity->vm->AttachCurrentThread(&jni, NULL);

    jclass activityClass=jni->GetObjectClass(activity->clazz);
    jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");

    jni->CallVoidMethod(activity->clazz, testCallId);
}

extern "C"
{
    JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall(JNIEnv *, jclass)
    {
        LOGI("nativeJniCall");
    }
}

logcat から

...
waiting for debugger to settle...
waiting for debugger to settle...
debugger has settled (1388)
Creating JniNativeActivity
Creating: 0xb420b100
Config: mcc=0 mnc=0 lang=en cnt=US orien=2 touch=3 dens=576 keys=2 nav=1 keysHid=1 navHid=0 sdk=22 size=2 long=1 modetype=1 modenight=1
Start: 0xb420b100
removeObsoleteFile: deleting file=161_task.xml
Calling native
No implementation found for void com.JNITest.JniNativeActivity.nativeJniCall() (tried Java_com_JNITest_JniNativeActivity_nativeJniCall and Java_com_JNITest_JniNativeActivity_nativeJniCall__)
activityState=10
Resume: 0xb420b100
activityState=11
Adding window Window{2b21e24c u0 com.JNITest/com.JNITest.JniNativeActivity} at 2 of 8 (before Window{3238fdec u0 Starting com.JNITest})
InputQueueCreated: 0xb420b100 -- 0xb420b880
APP_CMD_INPUT_CHANGED
Attaching input queue to looper
NativeWindowCreated: 0xb420b100 -- 0xb417ae08
APP_CMD_INIT_WINDOW
Waiting for host to establish connection
WindowFocusChanged: 0xb420b100 -- 1
Accepting new connection from local client
Accepted new client connection: PID = 3945, fd = 39
Requesting connection from host
Sending initiation request to host
Accepting new connection from host service
Accepted new host connection: fd = 40
Connecting local socket 39 to host socket 40
HostConnection::get() New Host Connection established 0xb4272e50, tid 3976
Displayed com.JNITest/.JniNativeActivity: +5s618ms

何かが実行されるという事実は、ライブラリがロードされていることを意味し、ログにもあります

...
=thread-created,id="9",group-id="i1"[New Thread 3958]
=thread-created,id="10",group-id="i1"[New Thread 3959]
=thread-created,id="11",group-id="i1"[New Thread 3960]
Loaded 'D:\projects\JNITest\JNITest\JNITest.Android.NativeActivity\x86\Debug\libJNITest.so'
=thread-created,id="12",group-id="i1"[New Thread 3976]
[Switching to Thread 3976]
=thread-created,id="13",group-id="i1"[New Thread 3975]
Loaded 'gralloc.donatello.so'
...

その名前をjavahで確認しました

extern "C" {
#endif
/*
 * Class:     com_JNITest_JniNativeActivity
 * Method:    nativeJniCall
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif

ライブラリexternsもチェックしましたが、関数はそこにあります

...
         U glRotatef
         U glShadeModel
         U glTranslatef
         U glVertexPointer
         U glViewport
00007004 D indices
00004b70 T Java_com_JNITest_JniNativeActivity_nativeJniCall
         U malloc
         U memcpy
         U memset
         U pipe
...

別のプロジェクトでこの問題が発生し、テスト アプリ (上記のコードの元) を作成したため、ランダムで一意の構成の問題ではありません。私はこれについて少し途方に暮れています.NativeActivityとグルーコード(おそらくスレッド)に問題があると思いますが、それを回避する方法がわかりません. どんな助けでも大歓迎です。

4

1 に答える 1

2

さて、私は問題を見つけました。この場合、System.loadlibrary がグルー コードで使用されていないため、標準のルックアップ メカニズムが機能しないようです。RegisterNatives を手動で呼び出す必要があります (有効な JNIEnv から)。したがって、この場合、次のことを行う必要があります。

void nativeJniCall(JNIEnv *, jclass)
{
    LOGV("nativeJniCall");
}

void android_main(struct android_app* state)
{
    test_call(state->activity);
    etc...
}

...

void test_call(ANativeActivity *activity)
{
    JNIEnv *jni;

    activity->vm->AttachCurrentThread(&jni, NULL);

    jclass activityClass=jni->GetObjectClass(activity->clazz);
    jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");

    JNINativeMethod methodTable[]=
    {
        {"nativeJniCall", "()V", (void *)nativeJniCall}
    };

    int methodTableSize=sizeof(methodTable)/sizeof(methodTable[0]);

    jni->RegisterNatives(activityClass, methodTable, methodTableSize);

    jni->CallVoidMethod(activity->clazz, testCallId);
}

本番環境では、すべての jclass/jmethoidID をキャッシュし (NewGlobalRef/DeleteGlobalRef を使用することを忘れないでください)、ネイティブ関数をクラスに 1 回だけ登録しますが、これは例として役立ちます。他の誰かの時間を節約できることを願っています。

于 2015-10-03T04:59:10.320 に答える