How to link crypto shared library in Android JNI - android

I am writing a wrapper to use some functions of crypto.
I build crypto lib from openssl-android with Android-NDK. Now i have the libcrypto.so that i need, but i donĀ“t know how to link it with my wrapper.
My project tree is like this
(proj root)
|
|->(src)
|->(src)-> com.package
|->(src)-> com.package->NativeCipher.java
|
|->(jni)
|->(jni)->Android.mk
|->(jni)->NativeCipher.c
NativeCipher.java
public class NativeCipher {
static {
System.loadLibrary("crypto");
System.loadLibrary("NativeCipher");
}
public static native byte[] AESEncrypt(byte[] in, byte[] key);
}
NativeCipher.c
#include <string.h>
#include <jni.h>
#include <aes.h>
jbyteArray Java_com_package_NativeCipher_AESEncrypt(JNIEnv* env, jobject this, jbyteArray in, jbyteArray key)
{
// All my code here
}
I need to use the functions of #include that crypto provides.
However, i don't know what to do with the .so files that NDK generates and how to make the Android.mk file to build.
Thanks in advance, i tried to be as specific as posible.

Native libraries go to the libs/armeabi or libs/armeabi-v7a of your Android project. You might want to rename the OpenSSL library though, because the system already has a libcrypto.so. As for your own JNI wrapper, just take the shared library sample from the NDK and modify to use your own files.

Related

Android - use generated C files with JNI

I am trying to create an application using C files.
In fact, the C files were generated from matlab (~20 files, with .c and .h), and I didn't modify those files.
To use those files with JNI, I create an other C file which is using JNI : native-lib.c.
So the C files generated by matlab are used through native-lib.c (I used a tuto found on the web to write this file).
I have this architecture for the c files :
src/
-- jni/
---- native-lib.c
---- include/
-------- All the c files generated from matlab
And this is native-lib.c (that I simplify here):
#include <jni.h>
#include "include/function1.h"
JNIEXPORT jint JNICALL
My_project_function1(JNIEnv* env, jobject obj, Function1_Args args) {
int x = function1(args);
return x;
}
etc...
To build the C library I use this file : CMakeList.txt :
cmake_minimum_required(VERSION 3.4.1)
add_library(native-lib SHARED src/jni/native-lib.c)
include_directories(src/jni/include)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
But this file CMakeList.txt doesn't work ! All the files in the folder include/ are not included in the project (only native-lib.c is recognize).
So I want to include the files of the include/ folder WITHOUT modify them (without adding JNIEXPORT, JNICALL, etc...).
I almost never use C, and I know nothing about the C generation. So I don't know how to do, and I don't understand most of the answers found on the web :(
Is someone understand why CMakeList.txt doesn't work? Do you have a solution to solve my problem ?
Thanks !
I am not familiar with CMake, however, You probably want to either add the src/jni/include folder as a second library source and static link to native-lib, or add the contents of src/jni/include directly to the arguments of add_library(native-lib SHARED ...). Please note that include_directories are for #include paths and not for src locations.
Finally I found a solution to my problem :
It is very simple in fact :
cmake_minimum_required(VERSION 3.4.1)
file(GLOB sources_c
"src/jni/include/*.h"
"src/jni/include/*.c"
"src/jni/native-lib.c"
)
add_library(native-lib SHARED ${sources_c})
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
I just put all the C files in the variable sources_c with file(GLOB sources_c ...).
And, in CMakeList.txt, it seems that there is any distinction between pure C files and JNI-C files (C files with, JNIEXPORT, ect ...).
I hope it will help !

Android NDK cmake JNI static library

Because of security concerns I would like to link all libraries statically including my native library containing JNI_OnLoad function. I've read that it's possible to link JNI library statically (http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#library_version) but I fail to do it with Android Studio. Is it possible?
Here's what I have currently.
In Java code:
System.loadLibrary("testlibrary");
In cmake makefile:
add_library( testlibrary
STATIC
${mysources} )
target_link_libraries(testlibrary)
In C++ file:
extern "C" {
EXPORT
JNIEXPORT jint JNICALL JNI_OnLoad_testlibrary(JavaVM *vm, void *reserved) {
...
return JNI_VERSION_1_8;
}
When built with Android Studio application fails because it tries to find *.so library file:
java.lang.UnsatisfiedLinkError:
dalvik.system.PathClassLoader[DexPathList[[zip file
"/data/app/xxx-1/base.apk"],nativeLibraryDirectories=[/vendor/lib,
/system/lib]]] couldn't find "libtestlibrary.so"
System.loadLibrary("testlibrary");
This line tries to load libtestlibrary.so, and obviously it wasn't built and packed into APK, since library with this name is static one:
add_library( testlibrary
STATIC
${mysources} )
Here you've described target libtestlibrary.a, that is not loadable, and can only be linked against loadable .so. So to achieve desired result you should declare testlibrary as shared one, and then link it against another static libraries. As result you'll get one, monolitic shared library, that can be loaded into program address space. E.g
add_library(testlibrary SHARED ${mysources})
add_library(lib1 STATIC ${lib1_src})
add_library(lib2 STATIC ${lib2_src})
...
target_link_libraries(testlibrary lib1 lib2 ...)

undefined lame decode function

I'm trying to add MP3 read and write capabilities to my Android app. I'm using the lame4android app as a starting point. Encoding a file works for me, but I'm having a problem with the decode functions -- I'm getting undefined references to the decode functions.
Here are excerpts from my wrapper.c:
#include "libmp3lame/lame.h"
#include "jni.h"
lame_t lame;
jint Java_com_intonia_dandy_WavStream_initEncoder(JNIEnv *env,
jobject jobj,
jint in_num_channels,
jint in_samplerate)
{
lame = lame_init();
...
return lame_init_params(lame);
}
hip_t hip;
jint Java_com_intonia_dandy_WavStream_initDecoder(JNIEnv *env, jobject jobj)
{
hip = hip_decode_init();
return hip != 0;
}
And here are the declarations from lame.h:
lame_global_flags * CDECL lame_init(void);
typedef hip_global_flags *hip_t;
hip_t CDECL hip_decode_init(void);
I'm getting an error message:
C:/ACode/dandy/src/main/jni/./wrapper.c:62: undefined reference to `hip_decode_init`
I'm also getting undefined references to hip_decode and and hip_decode_exit. But lame_init, lame_init_params, lame_encode_buffer, and lame_encode_flush do not generate any errors. I get these errors using the command line to run ndk-build, and I get the same errors when I let Android Studio manage the compilation.
How are the lame_* functions different from the hip_decode_* functions? Should I be using the deprecated lame_decode_*?
EDIT: I'm looking at the output of the ndk-build command. The .c files are listed on the console as they are compiled. hip_decode_init is defined in jni/libmp3lame/mpglib_interface.c, but mpglib_interface is not getting compiled, even though it's listed in jni/Android.mk. Why not???
It turns out that the LAME library as distributed does not have decoding enabled. To get it working, I had to do the following:
Add #define HAVE_MPGLIB 1 to mpglib_interface.c
Copy all .c and .h files from the mpglib directory of the LAME distribution.
Edit Android.mk to include the .c files from mpglib.
EDIT: instead of modifying mpglib_interface.c to define HAVE_MPGLIB,
it's better to set compilation flags.
Working with Android Studio 2+, build.gradle should contain
android {
defaultConfig {
ndk {
moduleName "libmp3lame"
cFlags "-DSTDC_HEADERS -DHAVE_MPGLIB"
}
}
}
Or in Android.mk:
LOCAL_CFLAGS = -DSTDC_HEADERS -DHAVE_MPGLIB

NDK unable to deal with #include with relative paths?

I'm writing an Adroid app with some C++ code behind the UI using Eclipse + NDK (r8d). I have some code that I thought was fool proof but the compiler just gives me weird errors like "Invalid arguments" without specifics. Here is what my C++ code looks like:
#include <jni.h>
#include <string>
using namespace std;
#include "../../Evaluator.Engine/Evaluator.Engine.h"
Evaluator evaluator;
extern "C" {
JNIEXPORT jstring JNICALL Java_haskellevaluator_android_MainActivity_evaluateNative(JNIEnv *env, jobject, jstring jInput)
{
...
string sInput(L"Hello world");
string sResult = evaluator.evaluate(sInput);
jstring jResult = env->NewStringUTF(sResult.data());
return jResult;
}
}
Evaluator.Engine.h is nothing fancy, but just a declaration of the class Evaluator.
#include <string>
using namespace std;
class Evaluator
{
public:
string evaluate(string input);
};
However, the compiler complains:
Invalid arguments '
Candidates are:
? evaluate(?)
'
as if string is not defined. But if I put a copy of the header file under the same folder, the error goes away. This is a Windows box. I have tried using \ and escaped \\ as path separators and it didn't work.
Does this sound like a NDK (or whatever the preprocessor it uses) bug? I don't want to move the header file because it'll be shared by other projects. I also hate to keep 2 copies of the same file.
Any ideas? Thanks.
Sorry I don't have windows OS, but I've tried you code on a MacOS, but it doesn't work because of:
string sInput(L"Hello world");
Saying that wchar_t cannot be put on std::string. Is it possible to be the same problem ?

How to create dll using android

I am new to Android application development.I want develop a dll using android. Is it possible to develop and integrate to android app. Please tell me the solution. If it is possible please tell me the solution one by one.
As for me I once made a note for myself about NDK. Here it is:
Required applicaitions:
1. Eclipse
2. CDT+Sequoyah plug-ins
3. Android ADT
4. Android NDK
Configuration:
1. Install Eclipse, ADT, CDT and Sequoyah plug-ins
2. In the Eclipse -> Window -> Preferences -> Android -> Native Development put NDK location
Steps:
1. Create new Android Project
2. Create Java class for working with native libraries (NativeLibrary.java)
3. In the class NativeLibrary.java define interface for native methods
4. Right click on Project -> Android Tools -> Add Native Support. Define name of the library.
5. Build the project
6. Go to PROJECT_HOME/bin
7. Create C header file with the command javah -jni <packagename>.NativeLibrary
8. Move this file to PROJECT_HOME/jni folder
9. Implement methods from the header file in the generated cpp file. Do not forget to include the moved header in this file.
10. In java classes create new object of NativeLibrary class and call its methods.
11. Build project.
UPDATE: Step by step without plugins
Required applications - this is what you need to develop native applications. In my case I use Eclipse + Android ADT plugin + Android CDT plugin + Sequoyah plugin. You can install them using Eclipse - > Install new software
Then you should download Android NDK. Also you should export PATH to it.
For the configuration: you should define only path to your NDK in Eclipse -> Window -> Preferences -> Android -> Native Development
You are not obliged to use these plugins but it is easier to develop with them. However, Sequoyah contains errors (or it's sometimes not properly configured for my computer)
After that you can create new Android project. Then you can create java class that defines native methods. In my case this is NativeLibrary.java. Here it is:
package com.testpack.nativetest;
public class NativeLibrary {
public native static int add(int a, int b);
static {
System.loadLibrary("nativ");
}
}
After that build your Android project. After that go to your bin/classes (I don't know but before it was just bin directory) directory:
cd ~/programming/android/workspace/NativeTest/bin/classes
And run the following command:
javah -jni com.testpack.nativetest.NativeLibrary
This command should produce com_testpack_nativetest_NativeLibrary.h header in your bin/classes directory. It should look like:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_testpack_nativetest_NativeLibrary */
#ifndef _Included_com_testpack_nativetest_NativeLibrary
#define _Included_com_testpack_nativetest_NativeLibrary
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_testpack_nativetest_NativeLibrary
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_testpack_nativetest_NativeLibrary_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
Create jni directory in your project and Run the following command. It will move this header to jni directory.
mv com_testpack_nativetest_NativeLibrary.h ../../jni
After that in jni directory create .c file. In my case it is nativ.c, copy the definition of the function from .h file and generate code:
#include "com_testpack_nativetest_NativeLibrary.h"
JNIEXPORT jint JNICALL Java_com_testpack_nativetest_NativeLibrary_add
(JNIEnv *env, jclass obj, jint a, jint b) {
return a+b;
}
Then in jni directory you should create a make file Android.mk Here it is. Simply change the source (nativ.c) and the name of your library (nativ).
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativ
LOCAL_SRC_FILES := nativ.c
include $(BUILD_SHARED_LIBRARY)
Go to the PROJECT_HOME directory. In my case this is
cd ~/programming/android/workspace/NativeTest
and run ndk-build. That's all. After that you can test it in your activity:
package com.testpack.nativetest;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class NativeTestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("TEST:", "Result 5+4=" + NativeLibrary.add(5, 4));
}
}
With plugins it is a bit easier to develop. But I think you should test it by yourself how to do this.
You can check out the Android NDK, here http://developer.android.com/sdk/ndk/index.html.
The NDK can be used to create linux equvalent .so, of the windows .dll files.

Categories

Resources