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.
Related
Context
I work on an app for Android which should analyse in real time the camera input.
I chose Qt to develop the user interface, for portability reasons (the app may evolve to support other platforms than Android).
For image processing, my colleague is working on it using TensorFlow.
So I want to know how could I use TensorFlow for Android in Qt ?
What I've done :
Downloaded tensorflow the nightly precompiled version (#453) from http://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild as suggered at https://www.tensorflow.org/versions/master/mobile/linking_libs#android (option 2)
Put the files in my qt project android/libs folder
Modified my *.pro file to add :
the given *.jar file with : DISTFILES += android_v453/libandroid_tensorflow_inference_java.jar
the given *.so file with : ANDROID_EXTRA_LIBS = $$PWD/android/libs/armeabi-v7a/libtensorflow_inference.so
But for now I'm confused. How should I call it in my Qt App ?
Note : I just noticed that TensorFlow Android interface is aimed only at inference, so no training would be available. (source)
Well, I think I figured it out !
The QAndroidJniEnvironment & QAndroidJniObject classes from Qt AndroidExtras seems to do all the big work.
Sample instanciation code:
QAndroidJniObject graph ("org/tensorflow/Graph");
QAndroidJniObject inferenceInterface("org/tensorflow/contrib/android/TensorFlowInferenceInterface", "(Lorg/tensorflow/Graph;)V", graph.object());
I know this works because tensorflow now logs data to the Qt console.
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 tried to use CryptoObfuscator to obfuscate my Android app, but it doesn't generate all the pdb files.
My Xamarin.Forms solution has 11 projects, 7 of them should be obfuscated. I disabled most CryptoObfuscator features just to test it. My .obproj file contains these settings for all dlls:
<Assembly Load="true" Path=".\bin\Release\RoyalMobileApps.XF.dll" XapEntryName="" KeyFilePath="" KeyFileContainsPublicKeyOnly="False" CertFilePath="" TimeStampURL="" Rfc3161TimestampURL="False" SHA256SigningAlgorithm="False" Embed="True" AddExceptionReporting="False" PfxPassword="" PfxPasswordCert="" IsWinRTAssembly="False">
<ObfuscationSettings EncryptStrings="True" EncryptMethods="False" EncryptConstants="False" SuppressReflector="False" ReduceMetaData="False" ObfuscationDisposition="1" FlowObfuscation="2" CodeMasking="0" SuppressILDASM="True" SuppressReflection="False" CombineResources="True" EncryptResources="True" CompressResources="True" MarkAsSealed="False" EnableTamperDetection="False" EnableAntiDebugging="False" SymbolRenaming="True" HideExternalCalls="False" HideInternalCalls="False" GeneratePdbFile="True" ObfuscatePdbFileNames="True" IncludeLocalVariablesInPdbFile="False" Encrypt="False" Compress="False" MSBuild="False" ObfuscatedNamespace="A" RetainNamespace="False" ModuleInitializationMethod="" LicensingMerge="False" RemoveConstants="False" ProcessSatelliteAssemblies="True">
<Watermarks Watermark0="" Watermark1="" Watermark2="" Watermark3="" Watermark4="" Watermark5="" Watermark6="" Watermark7="" Watermark8="" Watermark9="" />
</ObfuscationSettings>
</Assembly>
As you can see I set GeneratePdbFile="True" for all 7 projects. I integrated co.exe in my build process and it claims to have run successfully. It generates 7 dlls but only 6 pdbs. The pdb file for my main PCL project which I pasted above is missing and therefore Xamarins linker fails and I cannot build an apk.
How can I get CryptoObfuscator to create all pdbs? Or can I generate the apk without them?
Unfortunately the CryptoObfuscator support did not respond to my emails and I couldn't find anybody else with a similar problem.
I got it working by disabling the Pdbs at all. I switched to release mode and opened up the properties of each project which should be obfuscated. In Build / Advanced you can set the Debug Info to None.
In Crypto Obfuscator I disabled Output Settings / Generate New Pdb File For Assembly.
Then nothing created Pdb files. I got warnings when building the solution, but they can be ignored.
This answer should actually be credited to #JonDouglas, but he wrote only a comment.
Unfortunately I had to disable Rename Symbols too. But this was the main reason why I wanted to use Crypto Obfuscator. Because I couldn't get the Name Protection in ConfuserEx running. So as it doesn't work in either tool and Crypto Obfuscators support still didn't answer my email I'm back to ConfuserEx. This is free and it cannot be deobfuscated with de4dot.
is there someone who has experience with pyqtdeploy and adding external modules? I am currently using pyqtdeploy (version 1.2) together with PyQt 5.5.1 to write an application that can be deployed to an Android device. Without any external modules, the freezing with pyqtdeploy works pretty well. However, I am not really sure how I can add external modules (not pure Python ones) to my application.
In particular, I want to add the external module pycrypto. Therefore, I downloaded the pycrypto sourcecode, compiled it with the Android toolchain (from the Android NDK) and now I have a bunch of *.py and *.so files. How can I add them to my application?
My initial attempt was to add the *.py and the *.so files (so basically the whole pycrypto module) to the "Other Packages" tab in pyqtdeploy.
But now, when I import something pycrypto related in my application (from Crypto.Cipher import AES) i get the following error message:
File: ":/Crypto/Cipher/_AES.py", line 20 in __bootstrap__
TypeError: 'NoneType' object is not callable
The _AES.py file where the error is thrown, looks like this:
def __bootstrap__():
global __bootstrap__, __loader__, __file__
import sys, pkgutil, imp
__file__ = pkgutil.get_data(__name__,'_AES.cpython-34m.so')
__loader__ = None; del __bootstrap__, __loader__
imp.load_dynamic(__name__,__file__)
__bootstrap__()
At first I thought, that the *.so filename was just wrong and therefore, I got the NoneType Error, so I changed the filename in _AES.py to something other like 'test.so'. Surprisingly, now, I get a different error message than before:
File ":/pkgutil.py" line 629, in get_data
ImportError: qrcimporter: error opening file :/Crypto/Cipher/test.so
Ok, so the filename should be fine, right? But why do i get the 'NoneType` error message? What am I doing wrong? Is this the right way to accomplish this?
Any help is highly appreciated. I am pretty sure, that i'm only one small step away from getting this thing to work, but I can't figure out what i'm doing wrong.
Thanks!
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?