Calling function from .so file created in android in linux C++ code - android

I have .so file which I take from apk. With command nm -D libnative-lib.so I took list of functions. I need to call function named Java_com_example_nativelib_utils_Constants_getStringFromJNI . I wrote the code below:
#include <stddef.h>
#include <dlfcn.h>
#include <stdio.h>
int init_library() {
void* hdl = dlopen("./libnative-lib.so", RTLD_LAZY);
if(hdl == 0)
return 0;
else return 1;
}
int main() {
printf("%s\n", (init_library() ? "OK": "ERROR"));
}
and make file:
all: exe
exe: main.c
gcc main.c -fPIC -ldl -o main
but result of program is always "ERROR". I tried libnative-lib.so from x86 and armeabi-v7a architectures (others not present). How to load library and call function from it? C++ or C do not care.

It is not possible to use android .so files in non-android project. similar question is here

Related

Why is it tough to find a dummy .so file online?

I need a dummy .so file in order to call it's functions in android. The dummy .so file could be anything from doing addition, subtraction, etc.
When searched online, All I find is "What is .so file?", "How to integrate .so file in android". Can anyone please share a dummy .so file for doing addition?
It's my first shared library, and it was quie easy to do. I've applied this toutorial.
Here is my code:
lib.h
#pragma once
int sum(const int a, const int b);
lib.cpp
#include "lib.h"
int sum(const int a, const int b)
{
return a+b;
}
main.cpp
#include "lib.h"
#include <iostream>
int main()
{
std::cout << sum(10, 20) << std::endl;
return 0;
}
and with theese commands i've vreated one:
# generating simple library
c++ -c -Wall -Werror -fPIC lib.cpp
# making it shared
c++ -shared -o libsum.so lib.o
Now you will have shared library, for making this program work i have to do 2 additional commands:
# create executable
g++ -L. main.cpp -l:libsum.so -o main
# if you try to run this command it will fail
./main
# so i've set ld path, but in the link above there are alternative solutions to that
export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
# now it should work, in my case output is: 30
./main

Simple android binary crashing with zlib

I made a simple android executable with CMake that links with the native zlib on the ndk. Everything compiles correctly, but when calling deflateInit I get a segmentation fault.
Here is the code:
main.cpp
#include <iostream>
#include <zlib.h>
int main()
{
z_stream strm;
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
std::cout << "it works!" << std::endl;
}
And the corresponding CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(zlib-on-android)
add_executable(main main.cpp)
find_package(ZLIB REQUIRED)
set_target_properties(main
PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(main PUBLIC ZLIB::ZLIB)
I then compile with the following command:
cmake -H. -Bbuild -DCMAKE_SYSTEM_NAME=Android -DCMAKE_ANDROID_NDK=~/android-ndk-r17b -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_SYSTEM_VERSION=16 -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang
Everything works fine. Then I do the following:
cd build
adb push main /data/local/tmp/.
adb shell
shell#device:/ $ cd /data/local/tmp
shell#device:/ $ ./main
[1] + Stopped (signal) ./main
Does anyone know the reason? I am having a lot of trouble trying to hook up gdb with this executable. Since the same code works on my Macosx, I cannot understand why it does not work on android.
EDIT
For some reason the same code crashes on Macosx (the one that worked was a similar code). This is the error: bus error ./main
Well, turns out that setting z_stream to zero fixes the problem.
#include <iostream>
#include <zlib.h>
#include <cstdlib>
int main()
{
z_stream strm;
std::memset(&strm, 0, sizeof(z_stream));
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
std::cout << "it works!" << std::endl;
}

Use a shared library with Android NDK

I have a C++ project compiled in a shared library. I need to use that library (.so file) in Android with the NDK.
The idea is that someone else would compile the C++ project and give me the .so file, so that I don't have to compile it on my computer.
I need to reference the .so file in my Android.mk file, and all the solutions I tried did not work. That's where I'm stuck.
So:
is it possible to do what I described without creating one shared library per platform?
how can I reference my .so library in my Android.mk? All the solutions I tried did not work.
To reproduce everything from scratch, I did these steps:
1°) Create a HelloWorld C++ project:
Test.h:
#include <iostream>
class Test {
public:
Test();
~Test();
static std::string getTest();
};
Test.cpp:
#include "Test.h"
std::string Test::getTest()
{
return "Hey!!\n";
}
2°) Create the shared library:
g++ -Wall -shared -fPIC -o libTest.so Test.cpp
This gaves me a libTest.so file, which I can use on a C++ project. Now I want to use it on an Android project.
3°) Create a basic empty Android project:
package: com.so.test
name: CppTest
4°) Create a "Test.java" file next to the MainActivity.java file containing:
package com.so.test;
public class Test {
static {
System.loadLibrary("hellondk");
}
public native String getMessage();
}
5°) Open a terminal and:
cd /path/to/my/android/project/app/src/main/java
javac com/so/test/Test.java
javah com.so.test.Test
This creates the "com_so_test_Test.h" file.
cd /path/to/my/android/project
mkdir jni
mv app/src/main/java/com_so_test_Test.h jni
touch jni/com_so_test_Test.cpp
6°) Add the following code in "com_so_test_Test.cpp" file:
#include <jni.h>
#include <stdio.h>
#include "com_so_test_Test.h"
#include "Test.hpp"
JNIEXPORT jstring JNICALL Java_com_so_test_Test_getMessage(JNIEnv* env, jobject ob)
{
return env->NewStringUTF(Test::getTest().c_str());
}
7°) Copy "Test.h" and "libTest.so" files created on steps 1 & 2 into "jni" folder
8°) Create an "Android.mk" file in the "jni" folder containing:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellondk
LOCAL_SRC_FILES := com_so_test_Test.cpp
include $(BUILD_SHARED_LIBRARY)
9°) Create an "Application.mk" file in the "jni" folder containing:
APP_STL := stlport_static
10°) Back in the terminal, run:
/path/to/your/ndk/ndk-build
And that's the step where I'm stuck. I need to reference the libTest.so file in the Android.mk, but all the solutions I tried did not work. Any idea?
EDIT: here is the error I get:
[arm64-v8a] Compile++ : hellondk <= com_so_test_Test.cpp
[arm64-v8a] SharedLibrary : libhellondk.so
./obj/local/arm64-v8a/objs/hellondk/com_so_test_Test.o: In function `Java_com_so_test_Test_getMessage':
/Users/timsandra/Desktop/CppTest/jni/com_so_test_Test.cpp:8: undefined reference to `Test::getTest()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [obj/local/arm64-v8a/libhellondk.so] Error 1

C++11 std::async in Android NDK does not work

I have tried to get following sample code working to know whether asynchronous programming is working in Android NDK. Though NDK has the STL <future> which gets recognized as a header, the std::async is not getting recognized are not getting recognized. The code I tried to use was the following:
#include <future>
#include <iostream>
struct Foo
{
Foo() : data(0) {}
void sum(int i) { data +=i;}
int data;
};
int main()
{
Foo foo;
auto f = std::async(&Foo::sum, &foo, 42);
f.get();
std::cout << foo.data << "\n";
}
Also all the include paths have been set to the specified folder under Properties->Paths and Symbols
Errors
Description Resource Path Location Type
invalid use of incomplete type 'std::__async_sfinae_helper<void (Foo::*)(int), void (Foo::*)(int), Foo*, int>::type {aka struct std::future<void>}' Sample.cpp /Project12/jni line 50 C/C++ Problem
Description Resource Path Location Type
declaration of 'std::__async_sfinae_helper<void (Foo::*)(int), void (Foo::*)(int), Foo*, int>::type {aka struct std::future<void>}' Project12 line 111, external location: D:\android-ndk-r8e-windows-x86_64\android-ndk-r8e\sources\cxx-stl\gnu-libstdc++\4.6\include\future C/C++ Problem
Curently Android NDK does not incorporate all of the C++11 features. Clang 3.3 compiler from NDK r9b is C++11-feature complete, however, STL and stdlib on Android are not.
To use the most recent C++11 feature set in Android use Clang 3.3 compiler from Android NDK r9b. Put this line into your Application.mk file:
NDK_TOOLCHAIN_VERSION := clang
Also, add -std=c++11 switch to the LOCAL_CPPFLAGS variable:
LOCAL_CPPFLAGS += -std=c++11

Android: Error While Generating .so file

I'm new to Android and am trying to create a simple SDK+NDK concept. I followed the below steps:
Download NDK
Extract zip file
Create new android project.
Create new folder jni under project.
Define UI as needed.
Create a java file to call all the native methods. Declare all those methods with "native" prefix. Have static block to load library using system.loadLibrary("").
Create corresponding header file using javah -jni filename
Move the generated filename.h file to jni folder.
Write c file that includes the .h file and implements the methods in .h file and saved it.
Create mk file,with following content:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    :=
LOCAL_SRC_FILES := .c
include $(BUILD_SHARED_LIBRARY)
Go to the project folder in command prompt
Give <ndkfolder>/ndk-build
.so file will be generated
But I got stuck in the "12" point with the following error:
**"Compile thumb : com_cts_c2dmclient_NativeLib <= com_cts_c2dmclient_NativeLib.c
jni/com_cts_c2dmclient_NativeLib.c:3:40: fatal error: com_cts_c2dmclient_NativeL
ib: No such file or directory
compilation terminated.
make: *** [obj/local/armeabi/objs/com_cts_c2dmclient_NativeLib/com_cts_c2dmclien
t_NativeLib.o] Error 1**
Note: The .h file is created successfully.
My com_exampleservice_NativeLib.c file
#include "stdio.h"
#include "malloc.h"
#include <com_exampleservice_NativeLib.h>
JNIEXPORT jint JNICALL Java_com_exampleservice_NativeLib_loop
(JNIEnv * env,jobject obj,jint v1, jint v2){
int loop;
unsigned long int *array;
if(v2 == 0){
array = (unsigned long int *)malloc(v1 * sizeof(unsigned long int));}
else if(v2 == 1)
{
array = realloc(array,sizeof(array)+v1);
}
else{
}
array[0] = 1;
array[1] = 1;
for (loop = 2; loop < v1; loop++) {
array[loop] = array[loop - 1] + array[loop - 2];
}
for (loop = 0; loop < v1; loop++) {
}
if(v2 == 2)
{
free(array);
}
return 0;
}
Your Android.mk file does not look good in your question.
Make sure that the com_exampleservice_NativeLib.h file does exist in your jni directory near your c file.
It may be necessary to add directories to the include path, like
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
Note that this $(LOCAL_C_INCLUDES) must be a list of absolute paths, not like $(LOCAL_SRC_FILES) which is $(LOCAL_PATH)-based.
Another note is that in your com_exampleservice_NativeLib.c file the use of #include directive ornamenation is not correct. It should go
#include <stdio.h>
#include <malloc.h>
#include "com_exampleservice_NativeLib.h"
See What is the difference between #include <filename> and #include "filename"? for detailed explanation.
I've just been using the NDK for the 1st time as well.
I used SWIG to avoid having to write the Java JNI code manually
I found this tutorial useful:

Categories

Resources