Android system app in c/c++? - android

I'm experimenting with a rooted Android tablet. I need to run some system applications in C/C++ that can run as native apps with/without using the NDK. This would work like existing command line applications such as toolbox as a native ARM Linux executable.
Is that a possibility?

Yes, you can. And you can do it using the NDK which you make things easier to you , cross-compiling to all platforms supported by Android (ARM variants and x86). You just need to do like you would do to create a shared library for native Java methods. Just make sure you change the makefile to use BUILD_EXECUTABLE instead of BUILD_SHARED_LIBRARY to create an executable. Of course you won't need the APK folder structure, just the "jni" folder.
Tutorial
Create the project folders:
mkdir project_folder
cd project_folder/jni
NDK_PROJECT_PATH=<path to>/project_folder
Create the Android.mk makefile in the jni folder
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := teste
LOCAL_SRC_FILES := teste.c
include $(BUILD_EXECUTABLE)
Create also your source code in the jni. In this case, you can see from above makefile, it is teste.c:
#include <stdio.h>
int main (){
puts("Hello World");
return 0;
}
Now go up to your project folder and run ndk-build from there:
# ~/Downloads/android-ndk-r8b/ndk-build
Compile thumb : teste <= teste.c
Executable : teste
Install : teste => libs/armeabi/teste
Although it is output to a lib folder it is a executable, as you can inspect with file
#file libs/armeabi/teste
libs/armeabi/teste: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped

Yes, it's possible. When you download the NDK you get a set of tools (compiler, linker, etc.), headers and libraries. It's not significantly different from other cross compilation environments.

The NDK comes with a cross compiler and enough of a freestanding programming environment (includes and libs) to port simple C/C++ applications to run as native Android binaries. Check out the docs/STANDALONE-TOOLCHAIN.html file in the NDK for documentation. (It's available online at kandroid.com.)

I believe that the NDK does not have access to enough system services to write a complete app. You'll still have to write the scaffolding of the app in Java, but you can write plenty of native libraries for the Java to call.

Related

Native library not found on android build?

I am getting this error: unable to lookup library path for, native render plugin support disabled when I run my app on android. I think I am building the shared libraries incorrectly.
I am looking to build the source files from this repo. I'll say my build process and perhaps someone can spot a step I'm missing or doing incorrect.
Following this guide, I came up with this:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libhydrogen
LOCAL_SRC_FILES := ..\hydrogen.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_PLATFORM := android-16
APP_OPTIM := release
APP_MODULES := libhydrogen
Next I:
Placed these files in the jni folder.
Called ndk-build.
Copied the .so files from the \libs folder and placed them in their respective folders in Unity (i.e. Hydrogen\Plugins\Android\arm64-v8a).
Made sure their platforms and CPU architectures were correct.
Built my app.
Here is the c# wrapper I am using.
Calling Hydrogen.Library.Initialize(); is then giving me this error.
Here is the full logcat related to this error.
And in the case my build process manages to be correct, and the .so files are fine; what else might cause this to happen?
Edit: I am trying to build for armeabi-v7a and `x86. Here are the .so file details, maybe there is something there that is not right? I am unfamiliar with c and since I haven't heard of anyone building this library for android, I wonder: could there be anything within the c source file that is incompatible with the NDK build process?
Native libraries are loaded by the native linker of the system, in your case, the linux dynamic linker: ld.so (it changes names sometimes, so I used that name, as you can check the man page in the documentation with that name).
For that to happen, in general, you need to provide a LD_LIBRARY_PATH environment variable to the java virtual machine, so it can effectively dlopen(3) it.
Think how different can be your development system to your target one.... and you'll easily get to that.
It was a bug with Unity! For some reason when switching the project's target platform some of my files would get corrupted. Strangely, it only seems to happen in this one project, but in any case the (temporary) solution is to re-import the plugin folder whenever I switch platforms.

How to integrate OpenCV into Qt Creator Android project

I use Qt Creator to compile an Android application. I needed to integrate OpenCV into it, and it took me half a day to configure it properly, so I want to document the steps I took here, in case somebody else ever has to do it.
Edit: For OpenCV 4.x see the answers below. My answer was tested on OpenCV 2.4 only.
Original answer:
First, I downloaded OpenCV-2.4.10-android-sdk, and put into my project directory. It contains static libraries, and link order matters for static libraries for GCC. So you need to order them just so. This is how my .pro file looked in the end ($$_PRO_FILE_PWD_ refers to the project directory):
INCLUDEPATH += "$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/jni/include"
android {
LIBS += \
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/3rdparty/libs/armeabi-v7a"\
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/libs/armeabi-v7a"\
-llibtiff\
-llibjpeg\
-llibjasper\
-llibpng\
-lIlmImf\
-ltbb\
-lopencv_core\
-lopencv_androidcamera\
-lopencv_flann\
-lopencv_imgproc\
-lopencv_highgui\
-lopencv_features2d\
-lopencv_calib3d\
-lopencv_ml\
-lopencv_objdetect\
-lopencv_video\
-lopencv_contrib\
-lopencv_photo\
-lopencv_java\
-lopencv_legacy\
-lopencv_ocl\
-lopencv_stitching\
-lopencv_superres\
-lopencv_ts\
-lopencv_videostab
ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android
}
After that the project will compile but it will fail to run with the error
E/AndroidRuntime(11873): java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1891]: 176 could not load needed library 'libopencv_java.so' for 'libMyProject.so' (load_library[1093]: Library 'libopencv_java.so' not found)
To overcome this, you need to add libopencv_java.so to your APK, and then manually load it from QtActivity.java. That's what the ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android line at the end was for. Now you need to place libopencv_java.so here:
project_root/android/libs/armeabi-v7a/libopencv_java.so
project_root/android/src/org/qtproject/qt5/android/bindings/QtActivity.java
You can get QtActivity.java from the Android target build directory, in my case the full path was c:\Workspace\build-MyProject-Android_for_armeabi_v7a_GCC_4_9_Qt_5_4_0-Debug\android-build\src\org\qtproject\qt5\android\bindings\QtActivity.java, and just copy it.
Then you find those lines in it:
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
And load libopencv_java.so before them, so they become:
// This is needed for OpenCV!!!
System.loadLibrary("opencv_java");
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
Note that you pass opencv_java to System.loadLibrary(), even though the file is libopencv_java.so.
Edit: I forgot to mention, but I already had installed OpenCV Manager on my phone when trying to run one of the samples that come with OpenCV-2.4.10-android-sdk, so I don't know if it's needed or not. In any event, keep it in mind, if it fail even after my steps, you might need to download OpenCV Manager (it's available on the Google Store).
Edit 2: I'm using adt-bundle-windows-x86-20140702, android-ndk-r10d, OpenCV-2.4.10-android-sdk, Qt Creator 3.3.0, and my build target is "Android for armeabi-v7a (GCC 4.9, Qt 5.4.0)".
Edit 3: From Daniel Saner's comment:
In OpenCV 3.x, opencv_java has been renamed to opencv_java3. Also, while I didn't look into the specific changes that might have effected this, the workaround regarding that library in the final step seems to no longer be necessary. The app compiles and runs without the ANDROID_PACKAGE_SOURCE_DIR line
Edit 4: #myk's comment:
Worked for me with OpenCV 3.2. To workaround the build issues with carotene finish the LIBS+ section with: -lopencv_videostab\ -ltegra_hal\ – myk 2 hours ago
For OpenCV 4, sashoalm's approach did not work for me until I adapted it:
Download the Android-Pack and unzip it somewhere. We'll create a qmake-variable OPENCV_ANDROID which points to that directory later.
Add the following snippet to your *.pro-file:
android {
contains(ANDROID_TARGET_ARCH,arm64-v8a) {
isEmpty(OPENCV_ANDROID) {
error("Let OPENCV_ANDROID point to the opencv-android-sdk, recommended: v4.0")
}
INCLUDEPATH += "$$OPENCV_ANDROID/sdk/native/jni/include"
LIBS += \
-L"$$OPENCV_ANDROID/sdk/native/libs/arm64-v8a" \
-L"$$OPENCV_ANDROID/sdk/native/3rdparty/libs/arm64-v8a" \
-llibtiff \
-llibjpeg-turbo \
-llibjasper \
-llibpng \
-lIlmImf \
-ltbb \
-lopencv_java4 \
ANDROID_EXTRA_LIBS = $$OPENCV_ANDROID/sdk/native/libs/arm64-v8a/libopencv_java4.so
} else {
error("Unsupported architecture: $$ANDROID_TARGET_ARCH")
}
}
This will work for the arm64-v8a only. If you happen to build for another architecture (apparently 32-Bit is still the default for Qt#Android), you must change the .../libs/arm64-v8a part of the paths (occurs 3 times) and the same to match your actual target-architecture (the contains(...)-part in the second line of the snippet).
Tell qmake where to find the SDK. Add the following to qmake-call: "OPENCV_ANDROID=/path/to/OpenCV-android-sdk".
e.g., this looks like qmake example.pro "OPENCV_ANDROID=/home/user/OpenCV-android-sdk" from command line.
when you use QtCreator, add "OPENCV_ANDROID=..." to the "Additional arguments"-field. You can find it after enabling the Project-Mode in the Build-section of the android-kit. Expand the qmake-field under Build Steps
Starting from Android android-ndk-r18b, with Qt Creator 4.9.x kits, I could not use the openCV-4.1.1 pre-compiled shared libraries (.so) with Qt Android ABI armeabi-v7a target and ABI arm64-v8a, as Opencv standard is based on GCC, While the NDK-r18b removed gcc and uses clang compiler. ( I am getting
Fatal signal 11 (SIGSEGV), code 1
On initialize calling android_getCpuFeatures() when the application starts)
Thus, openCV shared libs must be compiled from sources for clang in order to be used with Qt Android kits.
This reference Compiling OpenCV on Android from C++ (Without OpenCVManager) was of real help. I would leave a reference here as well for a simple procedure I used under windows 10, to get opencv compiled with NDK 18 (clang) for Qt Android:
Downloaded openCV source code
Downloaded openCV contrib source for selected openCV version
Used cmake for windows
in the unzipped opencv source folder, created a new build folder.
MinGW from Qt installation can generally be used for building, So I used Qt 5.11.x (MinGW 5.3.0 32 bit) command line tool from Qt menu.
from command line, in new build folder, I could generate cmake configuration :
C:\opencv-4.1.1\build> "C:\program files\cmake\bin\cmake" .. -G"MinGW Makefiles"
-DBUILD_SHARED_LIBS=ON
-DANDROID_STL=c++_shared
-DANDROID_ABI="armeabi-v7a with NEON"
-DANDROID_NATIVE_API_LEVEL=23
-DANDROID_TOOLCHAIN=clang
-DCMAKE_TOOLCHAIN_FILE=D:\Qt\android-ndk-r18b\build\cmake\android.toolchain.cmake
-DANDROID_NDK=D:\Qt\android-ndk-r18b
-DANDROID_SDK=C:\Users\moham\AppData\Local\Android\sdk
-DCMAKE_BUILD_TYPE=Debug
-DBUILD_ANDROID_PROJECTS=OFF
-DWITH_OPENCL=ON -DWITH_TBB=ON -DENABLE_NEON=ON
-DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF
-DBUILD_FAT_JAVA_LIB=OFF
Then , C:\opencv-4.1.1\build>\mingw32-make -jx and C:\opencv-4.1.1\build>\mingw32-make install
the result libs can be picked from opencv-4.1.1\build\install folder
Link in Qt Android project:
android {
#opencv
OPENCVLIBS = $$PWD/../opencv-4.1.1\build\install/sdk/native
INCLUDEPATH = $$OPENCVLIBS/jni/include
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
# might need libs to be copied into app's library folder and loaded on start-up, in case android ships older libs??!
ANDROID_EXTRA_LIBS = \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_core.so \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_imgproc.so \
$$OPENCVLIBS/libs/armeabi-v7a/libtbb.so
LIBS += -L"$$OPENCVLIBS/libs/armeabi-v7a"\
-lopencv_core -lopencv_imgproc -ltbb
}
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
}
Also, copy the libs to ANDROID_PACKAGE_SOURCE_DIR
Note: If detailed control over cmake configuration is needed, cmake windows gui can be used, while not a must and not tested. AmMIN's procedure is helpful for cmake tool, remember to add flag for shared Android STL.

How to add dynamic c++ library to Android source?

I need to add my native library to Android source for others applications can use it (call functions from this library in their code). I need to use library like embed without adding it to every project in that I want use it. But i can't find information about this.
Please give me information how to do this. Sorry
As far as I understand, what you are trying to do is to run c/c++ code on Android. Am I right?
To be able to do that, you should use Android NDK to build your native library, and then load it into java code.
You need to follow 4 simple steps to run native code on android, after installing ndk:
1) Create Java "wrapper" for your native code - for. eg. create class named MyNatives which will hold method declared with native keyword. This tells the compiler, that implementation of this method is done in native library. Create static initializer, which will load the library. eg:
public class MyNatives {
static {
System.loadLibrary("hello-jni");
}
public void native nativeMethod(int x);
}
2) Compile the code, and run tool called javah for your native class (there are some plugins for eclipsee which will do that for you, eg. sequoyah)
cd <your project path>
mkdir jni
javah -d jni -classpath bin/classes com.example.MyNatives
This will generate header in jni directory (all native code in android project should be inside this direcotry)
3) Add implementation of your method from generated header
4) Create makefile for android build system and build library. Makefile should be named Android.mk. It makes use of some specific variables and macros, for more info please see NDK documentation, eg:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# your library name
LOCAL_MODULE := hello-jni
# all source files
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
to buld library just call ndk-build from project root directory
For more info, please see Android NDK documentation. Hope it helped a little.

Linking cross-platform library to native android application

The problem:
I have a native Android application that is compiled for x86 and arm, armv7a.
The app also links to a pre-shared library.
That pre-shared library is also compiled for x86, arm, and armv7a. So there are 3 lib.so files.
What must I do in the Android.mk/Application.mk to link to the appropriate *.so file given the architecture it is being compiled for?
That is, when the build system is compiling for arm, it should link to the libs/armeabi/lib.so.
Likewise, when the Build system is compiling for x86, it should use the libs/x86/lib.so file.
I believe the alternative might be a more complex build script but I'm shooting for the simple solution first, if it exists.
Thanks!
The answer
Unfortunately my query skills were not very good and shortly after posting, I found the question and answer already on SO:
How can i Link prebuilt shared Library to Android NDK project?
To summarize:
Prebuilt shared libraries, compiled for different platforms, should all be named the same and go under the jni/${ARCH}/ directory.
That is, the structure should appear as so:
jni/x86/libtest.so
jni/armeabi/libtest.so
jni/armeabi-v7a/libtest.so
You should use the $(TARGET_ARCH_ABI) flag, for example:
include $(CLEAR_VARS)
LOCAL_MODULE := mylib-prebuilt
LOCAL_SRC_FILES := ../path_to_prebuilt_folder/libs/$(TARGET_ARCH_ABI)/libmylib.so
include $(PREBUILT_SHARED_LIBRARY)

Android NDK code analysis not using defined variables

I think this problem started when upgrading to the Juno Eclipse. I believe the C/C++ build environment was probably upgraded as well at the same time. The NDK was not upgraded.
We have a large mass of C code that compiles under several platforms. We are using the crystax-ndk (r6) to compile our C++ code. To know when we are compiling for Android, we have defined the following in the Android.mk
LOCAL_CFLAGS := -DANDROID_NDK \
-DDISABLE_IMPORTGL \
...
Then in some files we will include different headers depending upon the platform
#ifdef ANDROID_NDK
...
Our code compiles just fine and seems to run fine. However, when opening certain files the C/C++ code analyzer will find many errors. This appears to be because the analyzer doesn't know about the ANDROID_NDK defined variable.
Any idea why the code analyzer is not using the same #defines as the compiler? The code is almost uneditable with all the bogus errors the analyzer is reporting.
I saw you're comment about the analyzer you were refering to.
Eclipse CDT (C/C++ Development Toolkit) does not support parsing Android.mk yet neither does the NDK plugin add that functionality at the time of writing this.
Possible (ugly/annoying) workaround: Set up a header file setting the defines you are missing and include that header file to all files.
Use LOCAL_CPPFLAGS for C++ files and LOCAL_CFLAGS for C files in your Android.mk

Categories

Resources