Cannot load prebuilt OpenSSL library in Android project - android

I'm trying to link the OpenSSL .so prebuilt files so I can use it in my native C files. In my project, I've created native_hello.c file and it works fine, the C code runs, but when I'm trying to
System.loadLibrary("crypto");
System.loadLibrary("ssl");
in my java code to load the OpenSSL .so files, the app crashes with error
java.lang.UnsatisfiedLinkError: dlopen failed: library "libcrypto.so" not found
I went ahead and decompiled my source apk file, and sure enough there were no libcrypto.so or libssl.so files in lib folder.
I'm using CMake for linking native files:
CMakeLists.txt
cmake_minimum_required(VERSION 3.6.0)
set(distribution_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/main)
add_library(lib_crypto SHARED IMPORTED)
set_target_properties(lib_crypto PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/jniLibs/${ANDROID_ABI}/lib/libcrypto.so)
# add the open ssl lib
add_library(lib_ssl SHARED IMPORTED)
set_target_properties(lib_ssl PROPERTIES IMPORTED_LOCATION ${distribution_DIR}/jniLibs/${ANDROID_ABI}/lib/libssl.so)
add_library(native-test SHARED
${distribution_DIR}/jni/native_hello.c)
target_include_directories(native-test PRIVATE ${distribution_DIR}/jniLibs/${ANDROID_ABI}/include)
target_link_libraries(native-test
lib_crypto
lib_ssl)
In related questions one of the solutions is to use sourceSets in build.gradle but with the following code snippet the .so files are still missing:
sourceSets {
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
I think that the problem is pretty easy, but I could not figure out how to solve it. Any help would be appreciated

Turned out that structure of my jniLibs was something like:
arm64-v8a
include
...
lib
libcrypto.so
libssl.so
x86
include
...
lib
...
opposed to:
arm64-v8a
include
...
libcrypto.so
libssl.so
x86
include
...
...
Which solves initial problem.

Related

What does cpp, jni, jniLibs directories, and android.mk and CMake.txt do in Android

When configuring a project to add C and C++ in an Android project a few things come up in a project's directory tree.
There's the cpp, jniLibs, and the jni directories.
There are also android.mk and CMakeLists.txt files.
What are the purposes \ what should be included in the cpp, jniLibs, and the jni directories?
Do android.mk and CMakeLists.txt work interchangeably?
Thank you all in advance.
cpp is a directory where you put your cpp code.
jniLibs is an optional directory, can be added if you need to include some external libs (.so files).
CMakeLists.txt is a configuration file for CMake, which is a build tool for c++ code.
android.mk is a configuration file used to build cpp code, similar to GNU makefile. No longer used now, replaced by CMake tool. You should use CMake now instead of android.mk, but you can still used if you want.
CMakeLists.txt is a replacement of the old way android.mk

How to add prebuilt *.so libraries in android studio?

I am trying to integrate the Hyperledger indy SDK. However, when running my code I get the error
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: dlopen failed: library "libgnustl_shared.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
I am trying to follow the documentation provided in the project repo. I tried using the sample project on this blog .
I was able to build the *.so libraries under a linux virtual machine, the copied the built files in my android studio project on windows.
I added the files inside my project's jniLibs forlder for each architecture.
Added the code to load the library inside my mainActivity
static{
System.loadLibrary("indy");
}
Tried creating a CMake file
cmake_minimum_required(VERSION 3.4.1)
add_library(indy SHARED IMPORTED)
include_directories(src/main/jniLibs/${ANDROID_ABI}/include)
My gradle file includes:
android{
defaultconfig{
...
ndk{
moduleName "indy"
abiFilters 'armeabi-v7a'
}
}
...
sourceSets {
main {
jniLibs.srcDir 'src/main/jniLibs'
}
}
externalNativeBuild {
cmake {
path file('../CMakeLists.txt')
}
}
}
Still, keep on getting the same error when I launch the app.
I am aware that the bash script that builds the libraries on linux uses the android-ndk-r16b-linux-x86_64 tools so I tried downgrading my ndk in android studio to use the same version but had no luck.
The output of the build script is
include/
indy_anoncreds.h
indy_core.h
...
lib/
libindy.a
libindy.so
libindy_shared.so
How can I use this libraries in my android studio project?
The issue is mainly related to the nature of libraries. Libraries are dynamic in Android and needs to be linked at runtime.
libindy.so depends on stl, openssl, libsodium and libzmq.
You will find libgnustl_shared.so in NDK.
All the other needed prebuilt libraries are also available here.
What you need to do is make sure these libraries are present in the jniLibs folder and load these in order libraries before libindy.
System.loadLibrary("libgnustl_shared");
.
.
System.loadLibrary("indy");
Alternate approach:
There is a subproject in Indy where we are using libindy as dependency and we try to create a one fat dynamic library which has all the dependencies.
Link
If you follow the steps like vcx you dont have to have all the defendant l libraries in jniLibs as they will be already part of final .so file
The command which make one fat dynamic library with all the symbols and dependencies is this (from the link pasted above)
${LIBVCX}/target/${CROSS_COMPILE}/release/libvcx.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libz.so \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libm.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/liblog.so \
${LIBINDY_DIR}/libindy.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so \
${OPENSSL_DIR}/lib/libssl.a \
${OPENSSL_DIR}/lib/libcrypto.a \
${SODIUM_LIB_DIR}/libsodium.a \
${LIBZMQ_LIB_DIR}/libzmq.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so -Wl,--no-whole-archive -z muldefs

java.lang.UnsatisfiedLinkError: dlopen failed: library "/Users/..." not found

I want to add another lib into android-ndk hello-libs example.
In CMakeLists.txt, I add:
# this is from the hello-libs sample code
add_library(lib_gperf SHARED IMPORTED)
set_target_properties(lib_gperf PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/gperf/lib/${ANDROID_ABI}/libgperf.so)
########## I add this after the sample code: ###########
add_library(lib_py SHARED IMPORTED)
set_target_properties(lib_py PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/gperf/lib/${ANDROID_ABI}/libpython.so)
And this:
target_link_libraries(
hello-libs
android
lib_gperf
#### this line ######
lib_py
log)
And copy libpython.so in the directory where libgperf.so located:
Also copy the python headers into the include directory:
When I click the run button:
java.lang.UnsatisfiedLinkError: dlopen failed: library "/Users/finn/Downloads/hello-libs/app/src/main/cpp/../../../../distribution/gperf/lib/arm64-v8a/libpython.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
at com.example.hellolibs.MainActivity.<clinit>(MainActivity.java:36)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2747)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:173)
at android.app.ActivityThread.main(ActivityThread.java:6698)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
The path exists in my computer, but why the apk use my computer path, but not the android device path?
And I use the Android device file explorer, the lib is in the directory:
Then how can I make the apk use the right path?
Or I miss something to add?
I encounter the exact same issue and I discovered that when the .so file is built, the library link for the python library is wrong while the link for gperf library is ok.
Link error for python library
Both libraries are imported with the exact same method in the cmake so it doesn't make sense.
I friend of mine told me it is a bug from ninja and they provided me a "turn-around" solution. You have to import the python library as if it was an Android-NDK provided one (like Android or Log).
The library should be put in the NDK libraries, which should be located at <NDK PATH>/toolchains/llvm/prebuilt/<OS_related_folder>/sysroot/usr/lib/<ABI targeted>/<minSdkVersion/
Where:
- NDK path is the location of your NDK folder.
- OS_related_folder is the os_named folder (in my case windows-x86_64).
- ABI targeted is the ABI to which your library is compiled for (arm-linux-androideabi, aarch64-linux-android, etc).
- minSdkVersion is the number of your min SDK version of your project.
This information was found from CMakeCache.txt, in the folder `\app.cxx\cmake\debug\\'. When using find_library for log, the path of the library is shown
Change CMakeLists.txt to only provide library include, and directly link the library by it's name (python2.7 for libpython2.7.so)
cmake_minimum_required(VERSION 3.4.1)
add_library( native-lib SHARED native-lib.cpp)
include_directories( ${CMAKE_CURRENT_LIST_DIR}/../../../libs/python/include/ )
find_library( log-lib log ) # Optional
target_link_libraries( native-lib python2.7 ${log-lib} )
Since the python library isn't natively provided by Android, you will need to pack it to the APK by changing the jnLibs folders (see documentation)
Following these steps should fix the issue
Resulting library link in .so file
Obviously, this is not a good solution. I hope my answer will draw more attention on this issue and somebody will provide a real solution to avoid such tweaks
Assume path /Users/finn/Downloads/hello-libs/app/src/main/cpp/../../../../distribution/gperf/lib is correct, then you can configure your JNI libs like below:
sourceSets {
release {
jniLibs.srcDirs += ["/Users/finn/Downloads/hello-libs/app/src/main/cpp/../../../../distribution/gperf/lib"]
}
debug {
jniLibs.srcDirs += ["/Users/finn/Downloads/hello-libs/app/src/main/cpp/../../../../distribution/gperf/lib"]
}
}
Try to change /Users/finn/Downloads/hello-libs/app/src/main/cpp/../../../../distribution/gperf/lib if it is not your correct path to the jni libs.

Adding sub directory in cmake not working

I'm trying to add another cmake project which has CMakeLists.txt file as a compilation dependency which i can use in another .cpp file.
Location of project which i want to add: Users/brainfreak/Downloads/assimp-master/
Location of main project: /Users/brainfreak/AndroidStudioProjects/ModelShow/app/src/main/cpp/hellojni.cpp
This is used as a native code in a Android Studio project. I followed the tutorial in https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script under "Include other CMake projects"
This is the main CMakeLists.txt that i came up with:
/Users/brainfreak/AndroidStudioProjects/ModelShow/app/src/main/cpp/CMakeLists.txt
cmake_minimum_required( VERSION 2.6 )
add_library(model-lib SHARED hellojni.cpp)
set (src_dir Users/brainfreak/Downloads/assimp-master/)
set (output_dir Users/brainfreak/Downloads/assimp-master/output)
file(MAKE_DIRECTORY ${output_dir})
add_subdirectory(${src_dir} ${output_dir})
add_library(assimp STATIC IMPORTED)
set_target_properties( assimp PROPERTIES IMPORTED_LOCATION
${output_dir}/${ANDROID_ABI}/assimp)
include_directories(${src_dir}/include)
target_link_libraries(model-lib assimp)
The error i always get:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process /Users/brainfreak/Android/sdk/cmake/3.6.3155560/bin/cmake with arguments {--build /Users/brainfreak/AndroidStudioProjects/ModelShow/app/.externalNativeBuild/cmake/debug/x86 --target model-lib}
ninja: error: 'Users/brainfreak/Downloads/assimp-master/output/x86/assimp', needed by '/Users/brainfreak/AndroidStudioProjects/ModelShow/app/build/intermediates/cmake/debug/obj/x86/libmodel-lib.so', missing and no known rule to make it
I don't know what file to place under "${output_dir}/${ANDROID_ABI}/" for the script to find. Can you tell where i'm going wrong?
Assuming that you got one of the latest releases from https://github.com/assimp and followed the instructions (note that this was tested with NDK r14, available for download from https://developer.android.com/ndk/downloads/older_releases), you have produced file libassimp.so inside project "Code" folder. Make sure that you build the x86 version of the library.
Copy this file to /Users/brainfreak/Downloads/assimp-master/output/x86/, and prepare your CMakeLists.txt:
cmake_minimum_required( VERSION 2.6 )
add_library(model-lib SHARED hellojni.cpp)
set (src_dir /Users/brainfreak/Downloads/assimp-master/)
set (output_dir /Users/brainfreak/Downloads/assimp-master/output)
file(MAKE_DIRECTORY ${output_dir})
add_subdirectory(${src_dir} ${output_dir})
add_library(assimp STATIC IMPORTED)
set_target_properties( assimp PROPERTIES IMPORTED_LOCATION
${output_dir}/${ANDROID_ABI}/libassimp.so)
include_directories(${src_dir}/include)
target_link_libraries(model-lib assimp)
Note that the file that your script was missing slash (/) before Users which could cause the confusion.
Don't forget to set abiFilters in your app/build.gradle:
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'x86'
}

Android : link prebuilt shared library (.so) within jar file in NDK

I've a static java library compiled as a jar file.
This jar loads a .so library using System.loadLibrary.
Then another Android application project links statically the jar file.
Everything is compiled using an Android.mk file in the NDK...how can I make the shared native library being included and correctly loaded from my final application (and "seen" from the jar code)?
Ok I solved the problem by using these instructions in Android.mk:
$(shell cp $(wildcard $(LOCAL_PATH)/libs/armeabi/*.so) $(TARGET_OUT_INTERMEDIATE_LIBRARIES))
LOCAL_JNI_SHARED_LIBRARIES:= libMyLib
just before
include $(BUILD_PACKAGE)

Categories

Resources