I am using a shared library libToon-c.so in my android app.
When running this app via the Android Virtual Device (AVD), the shared library is loaded and running without any problems.
However when attempting to load the library on to a phone (Google Pixel) the following error is shown
E/linker: "/data/app/com.example.androidsharedlibscratch-a6Mv8edOnQ2q6HbbixecrQ==/lib/arm64/libToon-c.so": ignoring DT_PREINIT_ARRAY in shared library! E/haredlibscratc: No implementation found for long com.example.androidsharedlibscratch.Toon.createToon() (tried Java_com_example_androidsharedlibscratch_Toon_createToon and Java_com_example_androidsharedlibscratch_Toon_createToon__) D/AndroidRuntime: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.androidsharedlibscratch, PID: 18368
java.lang.UnsatisfiedLinkError: No implementation found for long com.example.androidsharedlibscratch.Toon.createToon() (tried Java_com_example_androidsharedlibscratch_Toon_createToon and Java_com_example_androidsharedlibscratch_Toon_createToon__)
at com.example.androidsharedlibscratch.Toon.createToon(Native Method)
at com.example.androidsharedlibscratch.Toon.<init>(Toon.java:44)
at com.example.androidsharedlibscratch.MainActivity.onCreate(MainActivity.java:41)
at android.app.Activity.performCreate(Activity.java:7144)
at android.app.Activity.performCreate(Activity.java:7135)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2931)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
The toonJni.h contains the following function definition
JNIEXPORT jlong JNICALL Java_com_example_androidsharedlibscratch_Toon_createToon
(JNIEnv *, jobject);
The corresponding toonJni.cpp file contains the following function implementation:
JNIEXPORT jlong JNICALL Java_com_example_androidsharedlibscratch_Toon_createToon(JNIEnv *env, jobject obj) {
...
return (reinterpret_cast<jlong>(toon));
}
This shared library has been compiled for Android using the following standalone toolchains:
arm64 platform using the aarch64-linux-android toolchain
x86 platform using the i686-linux-anrdoid toolchain
In order to include the library in the project the .so file has been put in the jniLibs folder as per below:
src/main/jniLibs/arm64-v8a (contains arm64 library)
src/main/jniLibs/x86 (contains x86 library)
The following code has been added to in the build.gradle to include the jni files:
sourceSets {
main {
jniLibs.srcDirs 'src/main/jniLibs'
}
}
The toonJni.h contains the extern c { ... } directive
The toonJni.h file is generated by using the following javac command
javac -h . Toon.java
The apk has been built, extracted and verified to contain the libToon-c.so file
The following commands have also been used verify that the libToon-c.so is in the app folder on the device (Google Pixel)
adb shell dumpsys package packages | grep androidsharedlibscratch
adb ls /data/app/com.example.androidsharedlibscratch-foqHDywOpE_dDPgTCtTttw==/lib/arm64
Below is the command and the results from the check for name mangling:
android-ndk-r21/build/toolchain/bin/aarch64-linux-android-nm android_studio_scratch/AndroidSharedLibScratch/app/src/main/jniLibs/arm64-v8a/libToon-c.so
000000000000d570 T Java_com_example_androidsharedlibscratch_Toon_createToon
Added the following JNI_OnLoad in the .cpp and .h files (below) as #Botje specified. The toonLib loaded successfully is not showing up in the android studio logcat (log level is set to verbose).
Definition in toonJni.h:
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
Implementation in toonJni.cpp:
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
__android_log_print(ANDROID_LOG_INFO, "toonlib", "toonlib loaded successfully");
return JNI_VERSION_1_6;
}
Related
I have updated OpenCV module dependencies from 3.4.3 to 4.1.1 and now I get the message
OpenCV Manager package was not found
Despite I have included all libopencv_java4.so native libraries.
With previous version (3.4.x) the package manager was required only if I omit to include native *.so libraries, but with this version (4.1.1) seems doesn't make any difference, asking for OpenCV Manager every time regardless.
I don't want that app depends on a separate OpenCV Manager. How could I fix this error?
The error log is:
OpenCV error: Cannot load info library for OpenCV
W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
W/System.err: at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
W/System.err: at java.lang.Runtime.loadLibrary0(Runtime.java:1007)
W/System.err: at java.lang.System.loadLibrary(System.java:1667)
W/System.err: at org.opencv.android.StaticHelper.loadLibrary(StaticHelper.java:64)
W/System.err: at org.opencv.android.StaticHelper.initOpenCVLibs(StaticHelper.java:95)
W/System.err: at org.opencv.android.StaticHelper.initOpenCV(StaticHelper.java:39)
W/System.err: at org.opencv.android.OpenCVLoader.initDebug(OpenCVLoader.java:107)
W/System.err: at com.mysite.myapp.OpenCVTestActivity.onResume(OpenCVTestActivity.java:144)
W/System.err: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1446)
W/System.err: at android.app.Activity.performResume(Activity.java:7939)
W/System.err: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4195)
W/System.err: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4237)
W/System.err: at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
W/System.err: at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
W/System.err: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:107)
W/System.err: at android.os.Looper.loop(Looper.java:214)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7356)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
EDIT
The problem isn't related to module configuration, but is caused by a crash of the OpenCV native library, that for some reason doesn't happen with previous 3.4.x version. After this error the re-initialization of OpenCV module fails triggering this error.
I created an Android C++/C project and I realized that to use openCV 4.1.1 we need to force using the CMAKE in the gradle. So if we create a dummy CMAKE and a dummy-lib, the library libc++_shared.so is added to the APK.
Then, first create a cpp folder with a CMakeLists.txt and dummy-lib.cpp files inside in the /app/src/main/ directory.
The CMakeLists.txt is a dummy file, inside put this:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
dummy-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
dummy-lib.cpp)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
target_link_libraries( # Specifies the target library.
dummy-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
In the dummy-lib.cpp add:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
whatever(
JNIEnv *env,
jobject /* this */){
std::string hello = "Hello";
return env->NewStringUTF(hello.c_str());
};
Then, in the gradle file of the app add:
android {
....
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_STL=c++_shared"
}
}
}
...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
So, Make the project and all is done!
If you analyze the generated APK, you can see the library libc++_shared.so inside!
Lastly, the sample Android Project.
I am using NDK support in my app and am loading library like this:
static {
System.loadLibrary("sensorgraph");
}
All the native methods in sensorgraph.cpp starts with package name and JNI Activity name, like:
Java_sensor_com_ms_android_knowursensor_controller_jni_SensorGraphJNI_init(JNIEnv *env, jclass type, jobject assetManager) {
(void)type;
AAssetManager *nativeAssetManager = AAssetManager_fromJava(env, assetManager);
gSensorGraph.init(nativeAssetManager);
}
I am getting ExceptionInInitializerError on running the app.
FATAL EXCEPTION: GLThread 1042
java.lang.ExceptionInInitializerError
at sensor.com.ms.android.knowursensor.ui.view.AccelGLSV$2.run(AccelGLSV.java:58)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1470)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load sensorgraph from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.ms.android.knowursensor-41.apk,libraryPath=/data/app-lib/com.ms.android.knowursensor-41]: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at sensor.com.ms.android.knowursensor.controller.jni.SensorGraphJNI.<clinit>(SensorGraphJNI.java:26)
at sensor.com.ms.android.knowursensor.ui.view.AccelGLSV$2.run(AccelGLSV.java:58)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1470)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
I have tried all answers from SO, however no solution is correct. Please help.
No proper shared library-----Your device is arm type,but you build x86 type shared library.
No proper function found-----You may try hello-jni in NDK sample folder first.
Failed to copy shared library when package is installing--------You can try KeepSafe/ReLinker
I am also using sqlCipher in my application. They use openssl for calculating PKDF2 and I have read somewhere that openssl implementation is very faster than java implementation to find PKDF2. So my question is:
Is this true that openssl can give me better performace on android?
Can I use openssl implementation used in sqlCipher?
If yes how can I use find PKDF2 using openssl?
If No then how can I use openssl to find PBKDF2WithHmacSHA1 in
android. I have searched over the net but didn't found any example.
Thanks Nick for your suggestion
I have tried your suggestion and I am able to call c function using JNI in my java class.
Now I have one problem. How should I include openssl (Or call PKCS5_PBKDF2_HMAC_SHA1 in my c code). Here is my code:
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define KEY_LEN 32
#define KEK_KEY_LEN 20
#define ITERATION 1
JNIEXPORT jstring JNICALL
Java_com_example_testjni_MainActivity_someFunction(JNIEnv * env, jobject obj) {
// return 3;
size_t i;
unsigned char *out;
const char pwd[] = "password";
unsigned char salt_value[] = {'s','a','l','t'};
out = (unsigned char *) malloc(sizeof(unsigned char) * KEK_KEY_LEN);
printf("pass: %s\n", pwd);
printf("ITERATION: %u\n", ITERATION);
printf("salt: "); for(i=0;i<sizeof(salt_value);i++) { printf("%02x", salt_value[i]); } printf("\n");
if( PKCS5_PBKDF2_HMAC_SHA1(pwd, strlen(pwd), salt_value, sizeof(salt_value), ITERATION, KEK_KEY_LEN, out) != 0 )
{
printf("out: "); for(i=0;i<KEK_KEY_LEN;i++) { printf("%02x", out[i]); } printf("\n");
}
else
{
fprintf(stderr, "PKCS5_PBKDF2_HMAC_SHA1 failed\n");
}
return "";
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := example
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := example.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
I am getting this error when I compile my c code using ndk-build:
C:/Users/Nauman/Downloads/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/p
rebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-
linux-androideabi/bin/ld.exe: ./obj/local/armeabi/objs/example/example.o: in fun
ction Java_com_example_testjni_MainActivity_someFunction:jni/example.c:25: error
: undefined reference to 'PKCS5_PBKDF2_HMAC_SHA1'
collect2: ld returned 1 exit status
make.exe: * [obj/local/armeabi/libexample.so] Error 1
EDIT
Here is the exception I get when loading libs:
07-22 10:04:26.083: E/AndroidRuntime(1952): FATAL EXCEPTION: Thread-156
07-22 10:04:26.083: E/AndroidRuntime(1952): java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.ebricks.cii-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.ebricks.cii-1, /system/lib]]]: findLibrary returned null
07-22 10:04:26.083: E/AndroidRuntime(1952): at java.lang.Runtime.loadLibrary(Runtime.java:355)
07-22 10:04:26.083: E/AndroidRuntime(1952): at java.lang.System.loadLibrary(System.java:525)
07-22 10:04:26.083: E/AndroidRuntime(1952): at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:112)
07-22 10:04:26.083: E/AndroidRuntime(1952): at net.sqlcipher.database.SQLiteDatabase.loadLibs(SQLiteDatabase.java:107)
SQLCipher for Android does statically link OpenSSL, so PKCS5_PBKDF2_HMAC_SHA1 is included within the precompiled binaries. However if all you need is a call PKCS5_PBKDF2_HMAC_SHA1 directly, libcrypto.so is generally distributed with all Android platforms, however the version is often different on many platforms. To access PKCS5_PBKDF2_HMAC_SHA1, you will need to write a JNI interop library with the Android NDK that links to libcrypto, along with a Java wrapper class to load your native library and make the call into JNI. As a reference, I statically link OpenSSL within SQLCipher for Android here.
I am trying to integrate the Android SerialPort API into my project, but I have some problems doing so.
Eclipse is not resolving all JNI and native related methods and fields.. This is the beginning of the SerialPort.c file of the Android
SerialPort API:
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "SerialPort.h"
#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
The fist define-statement works, but in the other two, eclipse is
marking ANDROID_LOG_DEBUG and ANDROID_LOG_ERROR with Symbol XXX
could not be resolved, as well as every call of a method of JNIEnv
*env inside the methods of the serial port.
But there are no errors on the JNIEXPORT or JNICALL statements.
Problem one occured when I was trying to solve this problem. I downloaded all files for library and copied them in the directories given on the website. But it seems that something went wrong with the JNI part and I was not able to call open() to get my serial device.
11-19 14:18:22.232: D/dalvikvm(17898): Trying to load lib /data/data/master.androidsirfparser/lib/libserial_port.so 0x416a8570
11-19 14:18:22.232: D/dalvikvm(17898): Added shared lib /data/data/master.androidsirfparser/lib/libserial_port.so 0x416a8570
11-19 14:18:22.232: D/dalvikvm(17898): No JNI_OnLoad found in /data/data/master.androidsirfparser/lib/libserial_port.so 0x416a8570, skipping init
11-19 14:18:22.232: W/dalvikvm(17898): No implementation found for native Lmaster/serial/SerialPort;.open (Ljava/lang/String;II)Ljava/io/FileDescriptor;
11-19 14:18:22.240: W/dalvikvm(17898): threadid=11: thread exiting with uncaught exception (group=0x40a471f8)
11-19 14:18:22.240: E/AndroidRuntime(17898): FATAL EXCEPTION: Thread-651
11-19 14:18:22.240: E/AndroidRuntime(17898): java.lang.UnsatisfiedLinkError: open
11-19 14:18:22.240: E/AndroidRuntime(17898): at master.serial.SerialPort.open(Native Method)
11-19 14:18:22.240: E/AndroidRuntime(17898): at master.serial.SerialPort.<init>(SerialPort.java:61)
11-19 14:18:22.240: E/AndroidRuntime(17898): at master.androidsirfparser.ReadThread.init(ReadThread.java:38)
11-19 14:18:22.240: E/AndroidRuntime(17898): at master.androidsirfparser.ReadThread.run(ReadThread.java:48)
I always get the "no implementation found"-message.
I have to solve problem one first, in order to work on problem two, because Eclipse does not allow me to start my project without solving the compilation error in the code.
I re-installed my java platform, eclipse IDE, added the android eclipse plugin and now it works. I have no clue why.
Android NDK, I used the following command to generate the jni header,
C:\eclipse_workspace\C_Google_FaceDetect\bin>javah -jni -verbose -classpath C:\Android_SDK\platforms\android-10;C:\eclipse_workspace\C_Google_FaceDetect\src;. -d C:\eclipse_workspace\C_Google_FaceDetect\jni c.google.facedetect.FaceDetect
The problem is
even though I set everything well, I'm getting the following error
No implementation found for native Lc/google/facedetect/FaceDetect;.decodeYUV([I[BII)V
threadid=1:thread exiting with uncaught exception (group=0x40018578)
FATAL EXCEPTION: main java.lang.UnsatisfiedLinkError: decodeYUV
I tried looking for what's wrong, and I found that in the c_google_facedetect_FaceDetect.h jni header file, I have a syntax error actually (even though it's generated)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> /* Header for class c_google_facedetect_FaceDetect */
#ifndef _Included_c_google_facedetect_FaceDetect
#define _Included_c_google_facedetect_FaceDetect
#ifdef __cplusplus extern "C" {
#endif
#undef c_google_facedetect_FaceDetect_CAMERA_WIDTH
#define c_google_facedetect_FaceDetect_CAMERA_WIDTH 480L
#undef c_google_facedetect_FaceDetect_CAMERA_HEIGHT
#define c_google_facedetect_FaceDetect_CAMERA_HEIGHT 320L
/*
* Class: c_google_facedetect_FaceDetect
* Method: decodeYUV
* Signature: ([I[BII)V
*/
JNIEXPORT void JNICALL Java_c_google_facedetect_FaceDetect_decodeYUV(JNIEnv *, jobject, jintArray, jbyteArray, jint, jint);
#ifdef __cplusplus }
#endif
#endif
The "JNIEXPORT void JNICALL ...." line has a syntax error, maybe that's what causing all the errors ?
My Android.mk file is as follows:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := face-detect
LOCAL_SRC_FILES := face-detect.c
include $(BUILD_SHARED_LIBRARY)
UPDATE
My one and only java file is called FaceDetect.java and includes the following code
public class FaceDetect extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback
{
static
{
Log.d("mytag", "before_lib");
System.loadLibrary("face-detect");
Log.d("mytag", "after_lib");
}
public static native void decodeYUV(int[] out, byte[] fg, int width, int height);
}
Also, Eclipse doesn't say what the syntax error is, it only underlines the JNIExport line and says syntax error
Another UPDATE to answer the question
I have indeed checked that the library is being loaded, here is the logcat
07-16 13:31:43.257: D/mytag(25188): before_lib
07-16 13:31:43.281: D/dalvikvm(25188): Trying to load lib /data/data/c.google.facedetect/lib/libface-detect.so 0x40517808
07-16 13:31:43.281: D/dalvikvm(25188): Added shared lib /data/data/c.google.facedetect/lib/libface-detect.so 0x40517808
07-16 13:31:43.281: D/dalvikvm(25188): No JNI_OnLoad found in /data/data/c.google.facedetect/lib/libface-detect.so 0x40517808, skipping init
07-16 13:31:43.281: D/mytag(25188): after_lib
There is no syntax error. Check that you are loading your native library and that it has loaded successfuly.