I've been struggling with this for a while, and although I have found many having similar problems, their fixes don't seem to work for me. Perhaps I am misunderstanding something though, regarding of where the shared library files go after installing an APK.
Setup: Android, using a build.gradle file, and CMakeLists.txt since I want to run some C++ code using JNI. I followed the tutorial basically from https://developer.android.com/studio/projects/add-native-code, along with other pieces here and there from other websites.
My C++ code works correctly (it only returns a number). The APK generated can be unzipped, and I see all the .so files under the lib directory. Inside /lib there are four directories, each one for a different arquitecture, including my target (ARM). However, when I install the APK and try to run my C++ code portion, it returns an unsatisfiedlinkerror with the message saying "We looked for your .so file on nativeDirs under /system/lib and /vendor/lib, but we didn't find it)."
Now, if I instead push the .so file from the unzipped APK, into the location they mention, everything will run correctly (so at least my code is compiled correctly). Am I misunderstanding something? I was also reading that it appears that the .so files are not extracted from the APK anymore, but still, it's not finding it. I actually can't find the .so file in the system at all, but again, if I extract the APK it will be there.
My CMakeLists.txt simply have the parameters based on: https://developer.android.com/studio/projects/configure-cmake
cmake_minimum_required(VERSION 3.4.1)
add_library(native SHARED
nativeCode.cpp)
target_link_libraries(native
android
log)
I'm loading my library as:
static {
System.loadLibrary("native");
}
My questions are:
First of all, where should the .so files exist in my device after installing the APK.
Should I specify in any way the location of where the .so files should be under CMakeLists.txt?
If I need to specify a path for the app to look for the .so files, where should this be?
Thank you for your help!
i'm answering your question one by one...
QUESTION : First of all, where should the .so files exist in my device after installing the APK ?
Starting From Android M, it supports uncompressed native libraries in APKs, which allows the platform to read the native libraries directly from the APK without having to extract them.It have the flag android:extractNativeLibs which is default false. This is why you don't see them in the "data/data/packagename/lib/" directory if you're testing on a device on Android M or later.
Ultimately for testing purpose you can use android:extractNativeLibs="true" in Application tag of AndroidManifest.xml, to see in "data/data/packagename/lib/" folder.
<application
android:extractNativeLibs="true">
...
</application>
QUESTION: Should I specify in any way the location of where the .so files should be under CMakeLists.txt?
Considering your nativecode.cpp in rootPath/app/src/main/cpp/nativecode.cpp, and your CMakeList.txt under roothPath/app , your CmakeList.txt add_library should be like below,
add_library( # Sets the name of the library.
nativecode
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/nativecode.cpp)
If you notice, i added relative path and i don't know about case Sensitive. please try with smallcase.
I noticed, you mentioned your lib name as "nativeCode" , but in Code you taken only (System.loadLibrary("native")), it should be nativeCode. make sure the name matches for your library.
Add path of your CMakeList.txt in build.gradle (App Level)
android{
...
externalNativeBuild {
cmake {
path "CMakeLists.txt" //consider this CMakeLists.txt inside rootPath/app/CMakeLists.txt
}
}
QUESTION : If I need to specify a path for the app to look for the .so files, where should this be?
If you follow above steps it will work, You no need to specify which is modern and easy way., but if you wish manually i'm sure it bit complex compared to above(atleast for me)
First you have to create .so files from your .cpp file. (for that,we can do with Android.mk and Application.mk)
Then, you can add following line in build.gradle app level.
android{
...
...
sourceSets {
main {
jniLibs.srcDir 'jniLibs' //consider this jniLibs folder under rootPath\app\src\main\jniLibs
}
}
}
Then, you have to add *.so files in rootPath/app/jniLibs/**/*.so.
You have to generate *.so files for all supported ARM like, ("x86", "x86_64", "armeabi", "armeabi-v7a", "arm64-v8a")
then your folder path something like ,
rootPath\app\src\main\jniLibs\arm64-v8a\libnativecode.so,
rootPath\app\src\main\jniLibs\arm64-v7a\libnativecode.so
and so on...
Hope, these clear your issues and your doubts aswell 🤞.
Related
So I am trying to load a native library from a resource contained in the resources of the JAR. I'm using some code to select the correct .dll file based on the current platform. (my platform is Windows 10 on amd64) It then extracts the code to a temporary file and passes the absolute path to System.load(String). (Code of Natives.java (Utility)). I am calling this from a static { } block in the class supposed to load its own natives. When calling a test main(String[]) method in that class to test the loading of the libraries, it extracts the correct .dll file and attempts to load it, then it crashed and exits with -1073741819, I have searched for this exit code on Google but I can't seem to find any information on this, not even outside of Java.
With breakpoints I was able to conclude that it happens somewhere in System.load, because before that call everything works, and after it has stopped so its never reached.
All resources, including the C++ source code, Python build system I made to build it, the built .dll files (under src/main/resources) and the code for the loading and utility class can be found here: GitHub
Edit: I have used the Microsoft dumpbin /EXPORTS tool on it, this is the result: Imgur
Minimal Reproducible Example
To reproduce this you really only need to:
1: Copy the Natives.java file provided above (Code of Natives.java (Utility)) into your source directory
2: Copy the built DLL matching your system (32 or 64 bit) from here into a directory natives under your resource folder
And 3: Create a simple main file with the code:
public static void main(String[] args) {
Natives.loadNativeFromResource(Main.class, "j8mathexpr_native");
}
Your project structure should now look something like this:
src
- main
- java
- Main.java
- Natives.java
- resources
- natives
- j8mathexpr_native-xx-win.dll
In this previous question, I was trying to rework some Matlab code and figure out a package called javaplex to be compatible with Octave; it uses Java, but is tooled for Matlab, hence that issue. Now in an interval of time, I was busy/running simulations, and hadn't gotten around to a final step - actually using the package, with most all of the difficulties worked out. It turns out that another step exists: I need to convert an Octave array to a Java array (although I'm not sure why this issue didn't come up in Matlab).
To do so, I have turned to this script, in which the comments indicate that when using it, it
Assumes the JIDT [Java Information Dynamics Toolkit] jar is already on the java classpath - you will get a java classpath error if this is not the case.
So I go to the JIDT GitHub page and download this package. Now I am not a very avid user of java, so I believe I am failing to see something fairly straightforward: I am not sure where the "JIDT jar" is that is referenced in the above block quote! I can't find such a particular jar file to put in Octave's java classpath. In this tutorial for JIDT, they say you need the "infodynamics.jar" file in the classpath (page 9). I'm not sure what jar file I should be looking for, and where. Any help understanding the nature, name and location of this jar file (within the infodynamics toolkit folder) would be appreciated!
As an inevitable follow-up question, because this will come up upon resolving this issue, I would like to clarify the following procedure is how to add a jar file to the Octave (static) java classpath (following this answer here, I wasn't sure if I was implementing correctly):
I create a file called "javaclasspath.txt" inside of the directory I use in Octave.
I enter the name of files as follows: "./path/to/your-file.jar"
I suppose my main issue here is where do I start the path (all the way back with "C:/..."?), and do I put this "javaclasspath.txt" file in the directory folder I will be using most of the time in Octave?
Edit: I cannot find "infodynamics.jar" as shown here:
The JIDT jar is named infodynamics.jar and it is located in the root of the downloads infodynamics-dist-1.4.zip file.
I am loading the JNI libraries using System.loadLibrary("xyz") and it works fine. But the thing is, when using java.lang.System.load() to load a library, an attacker can replace or modify the original file with a malicious one if the full path of the dynamic library is specified in a world readable location (such as the SDCard). This can result in the loading of untrusted content into the Dalvik VM.
So this can be fixed using fully qualified path to the target library. For some reason I am not able to get succeed in providing fully qualified path.
Below are the things I tried but no luck.
System.load ("xyz")
System.load ("/src/main/jni/lib/xyz")
System.load ("/system/lib/xyz")
Can someone please suggest where I am going wrong.
You need to set the 'jniLibs.srcDirs' in the gradle file.
Something like:
main {
...
jniLibs.srcDirs 'lib'
}
I have the same problem with you.
When load a lib in java.library.path(located in /data/data/com.xxx.yyy/lib/[abi]), System.loadLibrary is OK.
But when load a lib from a absolute path, we should use System.load. For example:
System.load("/data/data/com.xxx.yyy/files/xxx/libxyz.so")
I tried to use some native library and received some Exception with underlying exception UnsatisfiedLinkError:
java.lang.UnsatisfiedLinkError: Couldn't load viblast: findLibrary returned null
I am using Android Studio + gradle.
It looks like android can't find the native library in APK file.
My projects tree:
I tried to put them in "jniLibs" directory, but it doesn't helped me. I think I forget to write something in gradle files, but I can't figure out what.
Create Folder "jniLibs" inside your "src/main/" and put all your .so files inside "src/main/jniLibs" folder. In your screenshot I can't find "jniLibs".
Please follow below steps :
Add the path of your NDK in the local.properties file, located to
the root directory of your project.
add these lines to your app build.grade files :
sourceSets {
main {
jni.srcDirs = ["libs"]
}
}
Remove old .so files from your app.
Go to the directory src/jni directory of your app project and run the command :
PATH_TO_YOUR_NDK/ndk-build
The project is compiling and your get your lib (.so) under the directory libs of your modules.
5.the libraries into your main app should be like below structure.
Please for reference visit this link..!!
Thanks..!!
I'm trying to use R to hook the Java code from the GSRad project. The GSRad Java code is available online and comes as a One-Jar project jar (I was not familiar with One-Jar until today). I can run the One-Jar file just dandy using the following command (after unzipping the file from the above link):
java -jar gsrad_sample.jar
When I pop open the gsrad_sample.jar file I see a jar titled clima_GSRAD-1.0.0.jar in the /lib/ directory which contains the class files I want to hook with R. I've pulled out the jar of my affection and tried the following, to no avail:
library(rJava)
.jinit()
.jaddClassPath( "/home/jal/Documents/DSSAT/gsrad/clima_GSRAD-1.0.0.jar" )
.jnew( "cra/clima/gsrad/GSRBristowCampbellStrategy" )
Any tips on how I might hook the classes inside the clima_GSRAD-1.0.0.jar? I'm flummoxed.
EDIT
The GSRad site requires registration which is annoying. The full zip file which contains the Doxygen documentation for the Java package as well as the One-Jar jar file is available here and if you pop that open the jar that has the classes I want to hook is this one.
Let me preface my answer by saying that I'm no expert in Java / rJava, so apologies if this isn't 100% correct. I hope it's a step in the right direction though.
Start by unzipping gsrad_sample.jar to C:/gsrad (or adjust your paths based on where you unzip it). Then add all the contents of C:/gsrad/lib to your class path:
library(rJava)
.jinit()
.jaddClassPath(dir( "C:/gsrad/lib", full.names=TRUE ))
.jclassPath()
.jnew( "cra/clima/gsrad/GSRBristowCampbellStrategy" )