How to add vendor shared lib to android ndk app - android

I have added a library under Android aosp vendor folder and successfully created shared lib (lets say, libmyvendor.so) files. And verified that .so files are created under both system/lib and system/lib64. Flashed on a device and working fine here.
To debug my ndk application, I have copied .so files into Android's path sdk/ndk/{versionNumber}/platforms/android-28/arch-x86/usr/lib. Also in archx86_64/usr/lib64 folder. Did invalidate and restart Android Studio. Now I'm trying to find or add libmyvendor library in my ndk application using cmake function
find_library(mVendor libmyvendor)
Tried myvendor instead of libmyvendor. In both cases, cmake couldn't find it.
Then tried copying libmyvendor.so files into ndk application (under jniLibs/x86/ and x86_64/ ). Compiled but app crash at runtime saying
UnSatifiedLinkError: dlopen failed library 'libcrypto.so' not found
Where libcrypto.so is needed as a dependent to libmyvendor project. And I'm stuck here.
As per my assumption, libmyvendor is part of system libs. NDK should be capable of finding it using find_library(), just like we find liblog.so. But it cannot find. Did I miss or mess anything?

Related

LibC++_shared is Present in APK but Not Found When Loading Libraries During Execution?

I'm working on an Android project with a pre-compiled .so file for OpenCV. The original distribution I used as my base (courtesy of QuickBird Studios) contains 2 .so files: libopencv_java4 and libc++_shared. The two .so files are taken from a .aar library which I had to unpack in order to address a known, long-standing issue in the OpenCV Android implementation. These two SOs are stored in the same folder in my project tree, as seen here. The other ABIs share identical structure to arm64-v8a.
When compiling the APK with Intellij IDEA (v2022.1.3), the APK analyzer shows that both .so files have been packaged in to lib/{ABI}, as can be seen here (in this case, the ABI is arm64-v8a). So far, so good.
However, when I go to load the OpenCV library (which calls upon libc++_shared), I receive the following error:
W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found: needed by {omitted}/base.apk/lib/arm64-v8a/libopencv_java4.so in namespace classloader-namespace
I've attempted building the APK without including libstdc++_shared, under the pretense that Gradle claims to be able to include the C++ shared libraries automatically. This failed with the same error message as above, with no libc++_shared.so in the APK.
I've also attempted to create a dummy native C++ file, in order to get libc++_shared added via CMake during the Gradle build process. This also failed with the above error. I did not think to check the APK during this attempt.
In a previous iteration of this project (before I discovered the bug in the OpenCV Android implementation), I was able to compile and run without issue by including the .aar file as an external library.
Between each of the above attempts, I've performed a full Gradle cache invalidation to make sure I'm not keeping broken files from previous tries.
I'm completely flummoxed. Did I break something when I unpacked the .aar to fix the bug? How can I get Android to acknowledge what's inside the APK?
I had the same issue after upgrading the Gradle plugin. the nonsense disappear after I also upgrade the Gradle build tool.
dependencies {
//after upgrad from 3.5.1 the link error disappear
classpath "com.android.tools.build:gradle:3.5.4"
...
}

Where does an Android app search for shared .so files to load?

To make this a little more complicated I'm loading a native library I've compiled with ndk and cmake into Unity which will be deployed on Android. This was all working fine until I wanted to link another shared library to the library I was building. Now my library fails to load and I believe it is because it can't find the new shared library. I can say that the new shared library works on its own because I'm using it in another NDK project.
I see that Unity copies the new .so library over to the apps install directory and puts it along with my original library in a /data/appname/lib/arm64 directory. I have also tried installing the library in /system/lib64 but no luck. I have compiled my library without the new shared library and it works, and then only modified cmake to add it back in and my library will no longer load. I have also objdump'd it to make sure it is x64 as well as exported the symbols in case it was corrupted. So I'm wondering, is there a way to find out where my library file is looking?
This is how I include the new shared library in my CmakeList.txt
add_library(libusb SHARED IMPORTED)
set_target_properties(libusb PROPERTIES IMPORTED_LOCATION D:/projects/arm64-v8a/libusb1.0.so)
where D:\projects\arm64-v8a is the location of the library file on my build machine. I wonder if this is screwing things up. But I use the same syntax in my Android studio Cmake project and I can access the library but I'm sure that's different somehow. Any help is always appreciated.
Thank you
The imported library may have its own dependencies, which must also be copied to your APK (or AAR). To check this, run objdump -p libusb1.so | findstr "NEEDED".
It will look in the lib/[platform-abi] directory of your app. But there is a list of steps for using prebuilt libraries:
https://developer.android.com/ndk/guides/prebuilts
Have you checked those?

Packaging external .so files into Android .apk files using Gradle

Recently, I ported my existing Android project from an ancient Gradle version to Gradle 6.6 and Android Studio's Gradle plugin 4.0.1. This project uses an external native library (.so file) that gets used in the Java code via JNI. This .so library has a dependency on libc++_shared.so because it is written in C++.
I realized that if I just copy the .so file into the corresponding platform folder (arm64-v8a, armeabi-v7a, x86, x86_64) within the jniLibs Gradle packages it "properly" into my .apk file.
By "properly" I mean that it automatically adds libc++_shared.so, which my library has a dependency on, as well as my own library to the .apk file. In addition, if I additionally set jniDebuggable to true in the build.gradle file it will also add the gdbserver library which is required to be able to attach the native code debugger.
Now, this is exactly what I want. The problem is that I cannot find any documentation that describes this behavior. The best source I could find is this but it does not mention anything about dependencies being packaged automatically. So, I don't know whether that is an officially supported way of doing things.
I suspect that there is a part of Android's Gradle based build process that automatically analyzes the files in the jniLibs folder and acts accordingly. It would be great to know a bit more to be aware what is really going on.
Does anyone have a reference that confirms my above observations or know which Gradle task (or whatever) accomplishes this? It would also be good to know in which Android Gradle plugin version this behavior was introduced.
Edit:
This answer to another SO question led me to the Android source file https://android.googlesource.com/platform/tools/build/+/master/builder/src/main/java/com/android/builder/internal/packaging/Packager.java
which seems to be the code that packages the .so files and gdbserver into the .apk file. But I have no explanation why libc++_shared.so gets packaged as well.

APK: native libraries name issues related to version number (SO.X.Y)

Issue
Built APK looks wrong and prevents my application from loading its native library because it cannot find a dependency when calling dlopen(): dlopen failed: library "libboost_filesystem.so.1.68.0" not found.
jniLibs content
My jniLibs directory, for the target platform, contains the following files:
libboost_filesystem.so.1.68.0 is the "real" shared object.
libboost_filesystem.so is a symlink to libboost_filesystem.so.1.68.0
APK Content
After building, the APK contains a libboost_filesystem.so which now is the binary object (not a symlink).
It seems like Android build system followed the symlink, grabbed content of the "pointed-to" file, but used the name of the symlink instead.
I have tried to remove the symlink from the jniLibs folder, but doing that it seems that the xxx.so.VERSION files are then ignored.
Question
How can I embed my "full name" shared object into the jniLibs without the Android build system messing with it ?
No you can't. You should avoid versioning the so file. See https://stackoverflow.com/a/45058227/192373 for instructions.
It's also quite natural that Android does not support this technique, because your native libraries belong to your APK and no version conflict can occur.
Consider linking boost filesystem statically to avoid extra lookup.

Problem loading pre-built library via Android NDK

I am attempting to add a third-party library to my Android app. It utilizes a .jar file and a .so file. This is a pre-built .so file (i.e. not built specifically for the Android app) - which I know will provide me with plenty of problems down the road. I do NOT have access to the source files for the .jar or .so files!
I am attempting to dynamically load the library via a call to System.loadLibrary("foo");. Currently, when attempting to run the app, it crashes with the UnsatisfiedLinkError: Library foo not found. I have the .so file in both the libs/ and the libs/armeabi file in my project.
Am I chasing after a ghost here? I am trying to determine if what I'm after is even feasible. I have no native code that I'm referencing - all my function calls are to the .jar file that is, as I understand it, backed by the .so file. I have not run the Android.mk file as I'm not compiling anything - the .so file is already provided. I could really use some advice as to what direction to proceed from here.
It's possible that the base name given to System.loadLibrary() is expanding to a file (or path) name different than that of the actual prebuilt library. Logcat should show you exactly what it is trying to load. You could also use System.load() with a full path/file name instead of System.loadLibrary() - though you really should get it working with the later.
While I think it would generate a different error message, it's also possible that the .so is not android compatible - it must not only be for a compatible processor type and abi, but not depend on any dynamic libraries (such as a non-bionic libc) not installed on the device.

Categories

Resources