Вызов собственных функций перенесенной библиотеки - PullRequest
5 голосов
/ 05 мая 2011

Я следовал этому руководству о том, как портировать библиотеку LAME с Android NDK.http://blog.libertadtech.com/2011/02/porting-lame-encoder-to-android-arm.html

Все работало нормально, я получил файл libmp3lame.so.

Теперь для первого теста я хотел вызвать простую функцию:

 void get_lame_version(char *strbuf, size_t buflen, const char *prefix);

Iнаписал обертку для библиотеки LAME:

package de.goddchen.android.youtubeconverter;

public class LameWrapper {

public static native void get_1lame_1version(char[] buf, int len,
        char[] prefix);
}

И я называю это так:

public class MainActivity extends Activity {

static {
    System.loadLibrary("mp3lame");
}

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        char[] buffer = new char[100];
        LameWrapper.get_1lame_1version(buffer, 100, "".toCharArray());
        ((TextView) findViewById(R.id.text)).setText(buffer.toString());
    }

}

Но я получаю следующую ошибку:

05-05 10:36:11.973: DEBUG/dalvikvm(199): Trying to load lib /data/data/de.goddchen.android.youtubeconverter/lib/libmp3lame.so 0x43757f78
05-05 10:36:12.053: DEBUG/dalvikvm(199): Added shared lib /data/data/de.goddchen.android.youtubeconverter/lib/libmp3lame.so 0x43757f78
05-05 10:36:12.123: DEBUG/dalvikvm(199): No JNI_OnLoad found in /data/data/de.goddchen.android.youtubeconverter/lib/libmp3lame.so 0x43757f78
05-05 10:36:12.573: DEBUG/dalvikvm(199): +++ not scanning '/system/lib/libwebcore.so' for 'get_1lame_1version' (wrong CL)
05-05 10:36:12.693: DEBUG/dalvikvm(199): +++ not scanning '/system/lib/libexif.so' for 'get_1lame_1version' (wrong CL)
05-05 10:36:12.693: DEBUG/dalvikvm(199): +++ not scanning '/system/lib/libFFTEm.so' for 'get_1lame_1version' (wrong CL)
05-05 10:36:12.703: DEBUG/dalvikvm(199): +++ not scanning '/system/lib/libmedia_jni.so' for 'get_1lame_1version' (wrong CL)
05-05 10:36:12.703: DEBUG/dalvikvm(199): +++ not scanning '/system/lib/libsrec_jni.so' for 'get_1lame_1version' (wrong CL)
05-05 10:36:12.703: WARN/dalvikvm(199): No implementation found for native Lde/goddchen/android/youtubeconverter/LameWrapper;.get_1lame_1version ([CI[C)V
05-05 10:36:12.703: DEBUG/AndroidRuntime(199): Shutting down VM
05-05 10:36:12.753: INFO/ActivityManager(52): Start proc com.android.alarmclock for broadcast com.android.alarmclock/.AlarmInitReceiver: pid=213 uid=10017 gids={}
05-05 10:36:12.773: WARN/dalvikvm(199): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
05-05 10:36:12.783: ERROR/AndroidRuntime(199): Uncaught handler: thread main exiting due to uncaught exception
05-05 10:36:12.883: ERROR/AndroidRuntime(199): java.lang.UnsatisfiedLinkError: get_1lame_1version
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at de.goddchen.android.youtubeconverter.LameWrapper.get_1lame_1version(Native Method)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at de.goddchen.android.youtubeconverter.MainActivity.onCreate(MainActivity.java:19)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.ActivityThread.access$2100(ActivityThread.java:116)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.os.Looper.loop(Looper.java:123)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at android.app.ActivityThread.main(ActivityThread.java:4203)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at java.lang.reflect.Method.invokeNative(Native Method)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at java.lang.reflect.Method.invoke(Method.java:521)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
05-05 10:36:12.883: ERROR/AndroidRuntime(199):     at dalvik.system.NativeStart.main(Native Method)

Может кто-нибудь, пожалуйста, укажите мне правильный способ вызова функций libmp3lame.so?

1 Ответ

5 голосов
/ 10 мая 2011

К сожалению, вы не можете просто вызвать любую старую функцию C из Java. Вы должны использовать функцию с «искаженным» именем или использовать механизм JNI_OnLoad. В любом случае виртуальная машина Dalvik добавит дополнительные аргументы к вызову функции, которых обычная функция lame get_version_number не ожидает.

Этот пример использования JNI объясняет искажение имени. Для вашего Java-класса вам понадобится функция с этим прототипом:

void Java_de_goddchen_android_youtubeconverter_LameWrapper_get_11lame_11version
  (JNIEnv *, jclass, jcharArray, jint, jcharArray);

Аргументы JNIEnv и jclass являются частью вызывающего интерфейса. Не забудьте указать extern "C", если вы используете C ++. Инструмент javah создаст правильный файл заголовка для вас.

Если бы я делал это, я бы, вероятно, написал функции-оболочки JNI C для нужных вызовов lame. В этом конкретном случае вместо использования char * с аргументом длины и передачи пустого char * в качестве последнего аргумента я бы создал более простой интерфейс Java to C, который только что возвратил Java String. Итак, в Java:

package de.goddchen.android.youtubeconverter;

public class LameWrapper {
    public static native String getVersion();
}

Затем в C, который вызывает реальный хромой API:

JNIEXPORT jstring JNICALL Java_de_goddchen_android_youtubeconverter_LameWrapper_getVersion
  (JNIEnv * env, jclass c)
{
    char buffer[80];
    get_lame_version(buffer, sizeof(buffer) - 1, "");
    return (*env)->NewStringUTF(env, buffer));
}

Жизненный цикл созданной здесь новой строки затем контролируется на стороне Java / Dalvik.

...