I currently developing app for Android that provides various audio settings. I use android system prepared by someone else, and it provides (I see in source and compiled files) some methods that could be useful for me. For example there are (kernel/drivers/audio/audio.c) some methods to change bands (for equalizer). In compiled system there is audio_setting.so file in some audio dir on kernel. Is there a possibility to use this methods (library) in my application NDK? I don't want to compile my app with whole system, rather to dynamically add this lib.
edit:
It was simplier than I thought. I used:
void *some_lib;
bundlewrapper = dlopen("some/path/some_lib.so", RTLD_LAZY);
if ( some_lib!= NULL ) {
LOGV("Loaded lib\n");
// use methods from lib
}
Sure, you can use any code on the system.
Obviously if it is non-JNI code you'll have to call it from your own JNI code or wrapper.
In your Android.mk file you will need to add the extra lib in LOCAL_LDLIBS
Related
We are working on an Android and iOS (but we want to just get Android working for now) application that needs to rely on some native drivers (.so, .a and some .ini files). The company providing those drivers also provides a Xamarin project to showcase how the drivers are used. They seem to be storing those driver and other files as assets (.ini files under Assets/Files and .so files under Assets/lib/arm64-v8a and Assets/lib/armeabi-v7a respectively) and extracting the former using the following code:
void ExtractAssets()
{
var assets = ApplicationContext.Assets;
var paths = assets.List("Files");
foreach (var path in paths)
{
// Read the compressed file and extract
string readPath = Path.Combine("Files", path);
byte[] buffer = new byte[32000];
int bytesRead = 0;
using (var inStream = assets.Open(readPath))
using (var outStream = ApplicationContext.OpenFileOutput(path, Android.Content.FileCreationMode.Private))
{
do
{
bytesRead = inStream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
outStream.Write(buffer, 0, bytesRead);
}
}
while (bytesRead > 0);
}
System.Diagnostics.Debug.WriteLine(string.Format("Extracted '{0}' to '{1}'", readPath, path));
}
}
Since Xamarin is becoming obsolete and MAUI is the next big thing, we decided to build our project on that. My colleague and I have spent the entire afternoon on a sample project and we still do not manage to simply load a libhello-jni.so file (we use this one) at runtime to call a stringFromJNI(). We tried:
Using an Android Native Binding project — we never really got what that's about and how mappings are supposed to work
Trying to include the libhello-jni.so file as an asset and load it using JavaNative.LoadLibrary("hello-jni"); and this had various unsuccessful results, it either did not find the library at all or it was complaining about the lib being built for x86 time processor instead of x64.
Can anyone please help us with some sample code allowing us to just simply bind a native .so file in a MAUI project, or at least provide us with a good guide? Thank you and sorry for the long post.
Not sure if this is exactly what you are going for or not, but we use bindings to a C library that we develop for various platforms, including Android. The way to correctly place native libraries into the final APK is via the EmbeddedNativeLibrary type in .csproj as demonstrated here. This will include your native library alongside the other native libraries that the toolchain is going to create (like the .NET runtime, garbage collection native lib, etc).
One thing changed in .NET 6, however. This affects us as an SDK distributor, because we need to include all necessary files inside of Nuget packages, so it may not affect you. In Xamarin, when you embed native libraries, the native libraries are literally stitched into your assembly and no further files are needed. In .NET 6, now they are all placed into a separate .aar file which also needs to be available when building the final application.
If you do everything correctly, you will see your native library inside of the APK in the lib/<arch> directory. Our native library is not JNI, and thus we use P/Invoke so we don't need a LoadLibrary call but I am reasonably certain that the call should succeed with the libraries in this directory.
I have an Android native library (C++ code base) called:
libserverapp.so
And I cannot get the Android build to find it:
"DllNotFoundException: serverapp"
I am using an internal build system, but when I parse the output of the build process, I can see many calls of the form:
android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-g++.exe -march=armv7-a
After building my Android app, I inspect the resulting APK (renaming to .zip and extracting), and can see my library file here:
lib/armeabi-v7a/libserverapp.so
I can confirm that "ARMv7" is the target architecture in the Android Player settings, and I access the library, in C#, via:
[DllImport("serverapp", CallingConvention = CallingConvention.Cdecl)]
private static extern void run_sim(StringBuilder matchInput, StringBuilder results, int randomSeed);
I have built a Windows DLL of the C++ code, to use in the Editor, and everything works great. However, when I move to Android, the .so cannot be found. The import settings for libserverapp.so are:
Platform: Android; CPU: ARMv7; Path: Assets/Plugins/Android/libserverapp.so; Type: Native
Given that the final APK includes the .so where I expect it to be (lib/armeabi-v7a/), I assume my Unity settings are correct? Also, I am not using IL2CPP for the Android build.
Finally, when I do an object dump of the library file (using arm-linux-androideabi-objdump.exe), the file format of the library file is "elf32-littlearm".
I feel that the issue here is simply finding the .so, not the functionality within it. Any ideas on what's going on here?
Thanks!
I ended up solving the problem. I mentioned that was using an internal build system. Well, there seems to be a bug in it. I ported things over to official Android NDK makefiles, and then it "just worked". So in this case, the library could be found, but its contents weren't valid.
I downloaded an APK from Play Store that contains native code binaries. In the APK file there is an lib/x86 folder that supposedly contains a library file containing native procedures, normally a .so extension. Since the code is in x86, is it possible to write a Java program to invoke the library on the desktop? Even if you dont have the source code for that library. The NDK function just has to accept parameters and return a value. For example, can we write
class AppNativeLoader
{
public static native void generateRand(int seed);
static
{
System.loadLibrary( "AndroidNDKLib" );
}
}
public class WCallTest
{
public static void main( String[ ] args )
{
long seed = System.currentTimeMillis();
if(args.length > 0) {
seed = Long.valueOf(args[0]);
}
long rand = AppNativeLoader.generateRand(seed);
System.out.println(rand);
}
}
NOTE: This is just an example. The actual environment differs. Using JRE 7 on RHEL, I extracted the x86 .so and placed it in the same directory as the .class file. I still get an UnSatisfiedLinkerError. Anything amiss? Assuming there are no callbacks and the function doesn't utilize and Android APIs, is this possible?
EDIT: I opened the lib in IDA Pro and I saw the following dependencies
.plt:0000B100 ; Needed Library 'liblog.so'
.plt:0000B100 ; Needed Library 'libz.so'
.plt:0000B100 ; Needed Library 'libc.so'
.plt:0000B100 ; Needed Library 'libm.so'
.plt:0000B100 ; Needed Library 'libstdc++.so'
.plt:0000B100 ; Needed Library 'libdl.so'
These should be available in my desktop environment, no?
Not all Linux environments are identical (even crossing distribution boundaries is not guaranteed to work). NDK binaries are built against Bionic and a handful of other Android specific libraries, whereas your RedHat system uses glibc and a bunch of other things available from the RedHat repositories.
tl;dr you can't run Android binaries on desktop Linux.
You can try downloading the needed shared libraries from here (make sure to choose the correct API version, and an architecture matching the architecture of the NDK shared library, to find out which shared libraries you need you can simply use ldd).
Then, to easily access the methods exposed by the shared lib, you can decompile the java code of the app using jadx, and then write your own code around the JNI classes.
Then, to compile your java code, you can use any version of the JDK.
Then, to execute it, you'll have to use a version of JRE matching the architecture of the NDK shared library (in your case, you'll have to download the 32-bit JRE).
However, this is not guaranteed to work: I am currently getting segfaults in the NDK shared library I'm trying to use on my PC, and since most NDK binaries are stripped, debugging is going to be a nightmare.
I am attempting to build an Android app that makes use of boost serialization. I have built the library against NDK r8d using arm 4.7's g++. When I go to compile my native code into a library using ndk-build, however, I get "undefined reference to 'mbtowc'" and "undefined reference to 'wctomb'" when the compiler attempts to link some code from Archive headers in boost.
I cannot seem to get a clear answer as to whether the NDK supports these functions.
Although it implements the functions, the CrystaX NDK is not an option as it has known crashes when using it with Boost, according to the Boost mailing list.
So, if the NDK does implement these functions somehow, why is NDK-build unable to link against them? I can find reference to them in cstdlib within the NDK, and I believe there may be a flag I need to set, but I'm not sure how or where to do so.
If there is no implementation of them, does anyone have any advice on how I can write them myself? I know roughly what mbtowc and its complement are supposed to do, but without much experience writing low-level C, and without much knowledge of Android / ARM architecture, I could really use some advice on doing so.
#ifdef ANDROID
int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); }
int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); }
#endif
Findings! Yes, boost has options to build it without requiring wchar support by adding preprocessor definitions to the boost build scripts. Boost still crashes when built using them at the line of code where I attempt to serialize an object to file. (the crash is a generic segfault at 0x00000000, and I was unable to gain any useful information).
So, I haven't bothered writing wctomb or its inverse. I shouldn't need to, is the answer to my question, although in the end the answer to the question doesn't matter.
To further clarify: don't bother doing what I've been trying to do. If you have been using Boost's serialization library and want your code to run on android ndk r8d or earlier, just give up. Write a serializer yourself, because there is no useful information to be found on how to make Serialization work. Hopefully a future release of the ndk fixes this problem, but for now I have no choice but to just rewrite everything.
I had the same problem. I was creating an android port for code that uses boost::serialization.
My code failed to compile because of missing implementation of mbtowc / wctomb (mb: multi-byte (char), wc: (wide-char)'
Implementation of these functions will probably be tricky cause as far as I know the wide-char for android is a single byte char instead of a true wide character..
However when I compiled boost with -DBOOST_NO_STD_WSTRING the link errors disappeared and I could use boost::archive::text_iarchive & boost::archive::text_oarchive on android.
I am now serializing STL containers of numerics and std::strings without a problem.
I compiled boost for android following the advice on this link: http://www.codexperiments.com/android/2011/05/tips-tricks-building-boost-with-ndk-r5/
I am using boost-1.55_0 and NDK r9c.
I added the following <compileflags>-DBOOST_NO_STD_WSTRING to the build command so it would build serialization library without wide character support.
Getting "system.entrypointnotfoundexception: loadlibrary" While trying to use SevenZipLib.dll to uncompress the .7z file containing media contents/file in the Android evn.
Context:
-The whole program is written in c# as a MONO Android Project. No Build/Deployment Error/warnings.
While running the apk, its throwing "system.entrypointnotfoundexception: loadlibrary".
-Also tested the same code as windows project (not mono) - uncompressing in the windows evn.
Assumptions for the issue:
7zip internally might be using COM components & Mono frame work is not supporting.
Question:
Has anyone come across similar issue? Please suggest some alternative dll/framework which can be used by my apk for uncompressing the .7z file.
Assuming that SevenZipLib.dll is the SevenZipLib Library on CodePlex, the problem is SevenZipLib\SevelZipLib\SevenZipArchive.cs:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeLibraryHandle LoadLibrary(
[MarshalAs(UnmanagedType.LPTStr)] string lpFileName);
The project contains numerous P/Invokes into kernel32.dll (LoadLibrary(), GetProcAddress(), FreeLibrary()), ole32.dll (PropVariantClear()), oleaut32.dll (SafeArrayCreateVector()), and more.
In short, this library is intimately tied to Windows, and isn't going to work on a non-Windows platform in any meaningful fashion, not without a lot of work.
If you need 7z support in a Mono for Android application, you'll need to look into a different library. It looks like the 7-zip SDK includes C# source for reading LZMA files that doesn't rely on P/Invoke, so perhaps that would work?