简体   繁体   English

使用Android NDK从.so文件调用Native函数

[英]Using Android NDK to call Native functions from .so file

I found instructions for how to link and use c/c++ code in Android by utilizing the NDK. 我找到了如何使用NDK在Android中链接和使用c / c ++代码的说明。 What I'm wondering is how different this process is when you have a .so from a third party? 我想知道当你有来自第三方的.so时这个过程有多么不同?

Calling System.loadLibrary() seems to load the library properly, but whenever I try to call the method I need, I get an UnsatisfiedLinkError. 调用System.loadLibrary()似乎正确加载库,但每当我尝试调用我需要的方法时,我得到一个UnsatisfiedLinkError。

The function prototype is declared according to the details provided by the third party who compiled the .so file. 根据编译.so文件的第三方提供的详细信息声明函数原型。 Is there any way that I can decompile the file effectively to at least check that the prototype is correct? 有没有办法可以有效地反编译文件,至少检查原型是否正确?

Is the link process for a precompiled .so library somehow different? 预编译的.so库的链接过程是否有所不同? Maybe I'm missing some steps which cause the link error. 也许我错过了导致链接错误的一些步骤。

EDIT: 编辑:

I wish I could post code but I can only write from my phone. 我希望我可以发布代码,但我只能用手机写。 My Android.mk file is set as you would expect, with a reference to the .so file and the $(PREBUILT_SHARED_LIBRARY) specification. 我的Android.mk文件是按照您的预期设置的,引用了.so文件和$(PREBUILT_SHARED_LIBRARY)规范。

All my code does is load the library and declare the function prototype with the native keyword. 我的所有代码都是加载库并使用native关键字声明函数原型。 When I try calling the function I get a link error. 当我尝试调用该函数时,我收到链接错误。

What I'm wondering is how different this process is when you have a .so from a third party? 我想知道当你有来自第三方的.so时这个过程有多么不同?

Here's what one of my projects look like. 这是我的一个项目的样子。 The project produces libprng.so . 该项目产生libprng.so It uses Crypto++ for the underlying PRNG (it also samples the sensors to reseed the PRNG before returning bytes in GetBytes ). 它使用Crypto ++作为底层PRNG(它还在传输GetBytes字节之前对传感器进行采样以重新种植PRNG)。

The Crypto++ library is located in /usr/local/cryptopp/android-ARCH , where ARCH is armeabi , armeabi-v7a , x86 or mips . Crypto ++库位于/usr/local/cryptopp/android-ARCH ,其中ARCHarmeabiarmeabi-v7ax86mips

My shared object and the Crypto++ shared object each depend on STLport. 我的共享对象和Crypto ++共享对象都依赖于STLport。 Because multiple modules depend upon STLport, we must use the shared object version of STLport (ie, libstlport_shared.so ). 因为多个模块依赖于STLport,所以我们必须使用STLport的共享对象版本(即libstlport_shared.so )。

Here's what the Java class file looks like: 这是Java类文件的样子:

public class PRNG {

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

Application.mk Application.mk

APP_ABI   := armeabi x86 mips armeabi-v7a

Android.mk 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)

First you need your methods prototypes to match the ones the lib was designed for, but usually also the packagename and class name have to match as well. 首先,您需要使用您的方法原型来匹配lib设计的原型,但通常包名和类名也必须匹配。

You can get what symbols are declared inside your .so file using readelf from binutils: 您可以使用binutils中的readelf获取.so文件中声明的符号:

readelf -s libYourLib.so

The symbols to look for are starting with Java_ followed by the package name, then the class name, finally the method name, with . 要查找的符号以Java_开头,后跟包名,然后是类名,最后是方法名,用. replaced by _ . 取而代之的是_

Instead of using readelf, you can also use this app I've developed: https://play.google.com/store/apps/details?id=com.xh.nativelibsmonitor.app 您也可以使用我开发的这个应用程序而不是使用readelf: https//play.google.com/store/apps/details? id = com.xh.nativelibsmonitor.app

Sometimes there is only a JNI_OnLoad method declared instead of Java_* methods. 有时只声明了JNI_OnLoad方法而不是Java_*方法。 In that case you can't get the information you need straight away from the declared symbols. 在这种情况下,您无法直接从声明的符号中获取所需的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM