【问题标题】:Using Android NDK to call Native functions from .so file使用 Android NDK 从 .so 文件调用 Native 函数
【发布时间】:2014-09-18 11:55:36
【问题描述】:

我找到了有关如何利用 NDK 在 Android 中链接和使用 c/c++ 代码的说明。我想知道的是,当您拥有来自第三方的 .so 时,此过程有何不同?

调用 System.loadLibrary() 似乎可以正确加载库,但每当我尝试调用所需的方法时,都会收到 UnsatisfiedLinkError。

函数原型根据编译.so文件的第三方提供的详细信息进行声明。有什么方法可以有效地反编译文件以至少检查原型是否正确?

预编译的 .so 库的链接过程是否有所不同?也许我遗漏了一些导致链接错误的步骤。

编辑:

我希望我可以发布代码,但我只能用手机写。我的 Android.mk 文件按照您的预期设置,并引用了 .so 文件和 $(PREBUILT_SHARED_LIBRARY) 规范。

我的代码所做的只是加载库并使用 native 关键字声明函数原型。当我尝试调用该函数时,出现链接错误。

【问题讨论】:

  • 第三方库是否打算与 JNI 一起使用?您不能通过 JNI 调用 任意 C++ 函数 - 只能调用特别命名的函数,例如 Java_packagename_classname_methodname()。如果是,您是否匹配 Java 端的类和包名称?该库可能不是为您的包和类构建的。
  • 我没有考虑类和包的命名。有人告诉我该类旨在与 JNI 一起使用,但我得到的只是函数原型和 .so 文件。

标签: java android c++ android-ndk


【解决方案1】:

我想知道的是,当您拥有来自第三方的 .so 时,此过程有何不同?

这是我的一个项目的样子。该项目产生libprng.so。它对底层 PRNG 使用 Crypto++(它还对传感器进行采样以在返回 GetBytes 中的字节之前重新植入 PRNG)。

Crypto++ 库位于/usr/local/cryptopp/android-ARCH,其中ARCHarmeabiarmeabi-v7ax86mips

我的共享对象和 Crypto++ 共享对象都依赖于 STLport。由于多个模块依赖于 STLport,我们必须使用 STLport 的共享对象版本(即libstlport_shared.so)。

Java 类文件如下所示:

public class PRNG {

    static {
        System.loadLibrary("stlport_shared");
        System.loadLibrary("cryptopp");
        System.loadLibrary("prng");
    }
    ...
}

Application.mk

APP_ABI   := armeabi x86 mips armeabi-v7a

Android.mk

LOCAL_PATH := $(call my-dir)

# NDK_DEBUG_IMPORTS := 1

#########################################################
# STLport library
include $(CLEAR_VARS)

STLPORT_INCL     := /opt/android-ndk-r9/sources/cxx-stl/stlport/stlport
STLPORT_LIB      := /opt/android-ndk-r9/sources/cxx-stl/stlport/libs/$(TARGET_ARCH_ABI)

LOCAL_MODULE := stlport_shared
LOCAL_SRC_FILES := $(STLPORT_LIB)/libstlport_shared.so

LOCAL_EXPORT_CPPFLAGS :=
LOCAL_EXPORT_C_INCLUDES := $(STLPORT_INCL)

include $(PREBUILT_SHARED_LIBRARY)

LOCAL_SHARED_LIBRARIES  := stlport_shared

#########################################################
# Crypto++ library
include $(CLEAR_VARS)

CRYPTOPP_INCL   := /usr/local/cryptopp/android-$(TARGET_ARCH_ABI)/include
CRYPTOPP_LIB    := /usr/local/cryptopp/android-$(TARGET_ARCH_ABI)/lib

LOCAL_MODULE       := cryptopp
LOCAL_SRC_FILES    := $(CRYPTOPP_LIB)/libcryptopp.so

LOCAL_EXPORT_CPPFLAGS := -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
LOCAL_EXPORT_C_INCLUDES := $(CRYPTOPP_INCL) $(CRYPTOPP_INCL)/cryptopp

include $(PREBUILT_SHARED_LIBRARY)

LOCAL_SHARED_LIBRARIES  := cryptopp

#########################################################
# PRNG library
include $(CLEAR_VARS)

APP_STL         := stlport_shared
APP_MODULES     := prng stlport_shared cryptopp

# My ass... LOCAL_EXPORT_C_INCLUDES is useless
LOCAL_C_INCLUDES   := $(STLPORT_INCL) $(CRYPTOPP_INCL)

LOCAL_CPP_FEATURES := rtti exceptions

LOCAL_CPP_FLAGS    := -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
LOCAL_CPP_FLAGS    += -Wl,--exclude-libs,ALL

LOCAL_LDLIBS            := -llog -landroid
LOCAL_SHARED_LIBRARIES  := cryptopp stlport_shared

LOCAL_MODULE    := prng
LOCAL_SRC_FILES := libprng.cpp

include $(BUILD_SHARED_LIBRARY)

【讨论】:

    【解决方案2】:

    首先,您需要您的方法原型与库的设计目标相匹配,但通常包名和类名也必须匹配。

    您可以使用 binutils 中的 readelf 获取 .so 文件中声明的符号:

    readelf -s libYourLib.so

    要查找的符号以 Java_ 开头,然后是包名,然后是类名,最后是方法名,其中 . 替换为 _

    除了使用readelf,你还可以使用我开发的这个应用程序:https://play.google.com/store/apps/details?id=com.xh.nativelibsmonitor.app

    有时只声明了JNI_OnLoad 方法而不是Java_* 方法。在这种情况下,您无法直接从声明的符号中获得所需的信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-07
      • 2015-03-02
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多