SlideShare a Scribd company logo
Android NDK & JNI
Использование Java Native Interface (JNI) и
кросплатформенных C/C++ реализаций в Java (Android)
Sergey Komlach
GDG Kremenchuk, StickyPassword
Skype: s.komlach
sergey.komlach@stickypassword.com
● Что такое JNI/NDK? Быстродействие, много готовых либ, платформозависимость, не-
"Write once, run anywhere" (WORA), аналогия с Reflection, используемые типы и вызовы
● Настройка окружения (NDK x 2), отладка, поддержка и тестирование всех платформ
● Пример простейшей реализации Java → C.
● Вызов из С++ метода Java как колбека (Java interface)
● Особенности выполнения кода (BlackBerry10 (mktime()), IntelAtom, х64), tmpdir(), флаги
оптимизации, порезаный Bionic и прочие либы в Андроид, удаление SO-шек на Sony при
апдейте
Рассмотрим….
Wiki: Java Native Interface (JNI) — стандартный механизм для запуска кода, под управлением
виртуальной машины Java (JVM), который написан на языках С/С++ или Ассемблера, и
скомпонован в виде динамических библиотек, позволяет не использовать статическое
связывание. Это даёт возможность вызова функции С/С++ из программы на Java, и наоборот.
Более ранние интерфейсы, в отличие от JNI, не удовлетворяли условию двоичной
совместимости.
Wiki: В 2009 году в дополнение к ADT был опубликован Android Native Development Kit (NDK) —
пакет инструментариев и библиотек, позволяющий реализовать часть приложения на языке
С/С++. NDK рекомендуется использовать для разработки участков кода, критичных к скорости.
Реально же наиболее частое применение:
Работа с OpenGL ES
Использование кросс-платформенных игровых движков, например Cocos2Dx
Использование уже написанного на C/C++ кода (а его ох как дофига написано!). Часто, это
работа с мультимедиа, например FFMPEG, libpng или наукоемкие вещи типа openCV
«Обход» «бутылочного горлышка» в программе (UP! «тяжелых» процессов)
Кроссплатформенное (повторное) использование кода
JNI/NDK
Работа с NDK на порядок усложняет разработку.
- Разработчик должен понимать Java (само собой)
- С/С++ (особенно внимание на память, указатели, треды/семафоры и т.д)
- команды и принципы работы JVM (очень пригодится если вы уже работали с Reflection)
Class cls = sample1.getClass();
try {
cls.getDeclaredMethod("print", String.class).invoke(sample1, "sample class");
cls.getDeclaredMethod("print", String.class).invoke(sample1, "test string");
cls.getDeclaredMethod("print", null).invoke(sample2, null);
cls.getDeclaredMethod("print", null).invoke(sample3, null);
} catch (Exception e) {}
- Нужно учитывать большое количество ограничений JNI в Android (порезаные библиотека,
размеры типов, «пустышки» реализаций)
- Сложная настройка среды и особенно отладка
Таким образом, работа с NDK чаще всего представляем из себя процесс (часто — мучительный)
сборки некой библиотеки и написиние оберток (wrappers) на нативные методы. В тоже время,
сейчас есть возможность ваять приложение практически без использования Java, используя
NativeActivity (API 9 и выше).
package com.example;
public class NativeTest{
static {
System.loadLibrary("nativetest"); // libs/armeabi-v7a/libnativetest.so
}
public native boolean testMethod(int arg);
}
JNIEXPORT jboolean JNICALL Java_com_example_NativeTest_testMethod
(JNIEnv *env, jobject caller, jint arg);
JNIEXPORT — необходимый для JNI модификатор. Типы данных с префиксом «j»: jdouble,
jobject, jstring etc — это «отражения» объектов и типов Java в C/C++.
Именование
jstring JAVA_JNI_This_1Is_1Native_00024Wrapper_00024_000408_000413_000397(...)
Дело в том, что _1 это аналог нижнего подчёркивания.
_00024 это символ $, то есть может как разделитель внутреннего класса использоваться.
_00408, 0xxxx, это код в юникоде.
В итоге получается:
class JNI {
static class This_Is_Native {
static class Wrapper$ {
static String Юникод(...)
}
Именование, часть 2
Java JNI JNI array Code Array Code
boolean jboolean jbooleanArray Z [Z
byte jbyte jbyteArray B [B
char jchar jcharArray C [C
double jdouble jdoubleArray D [D
float jfloat jfloatArray F [F
int jint jintArray I [I
long jlong jlongArray J [J
short jshort jshortArray S [S
Object/Class/
String
jobject/jclass/
jstring
jobjectArray/-/- L/L/L [L/[L/[L
void void - V -
Внутренности JNI в Android
● Устаналивается APK
● Если внутри находятся SO-файлы (аналог DLL) они копируются в
/data/data/apppackage/app_lib/*.so
● При первом обращении к классу, использующему нативные библиотеки, последние
загружаются через System.load(«name»)
● Библиотека «живет» пока не будет завершено приложение
Как работает взаимодействие
между Java и Native
● Качаем NDK. При чем если хотим все платформы, то нужно NDK x32 (для arm6, arm7a, x86
& mips) и NDK x64 (arm8, x86_64 & mips_64 и все х32)
● Устанавливаем окружение
(путь к папке NDK)
● «цепляем» в IDE
С чего начинается NDK
javah создает файлы заголовков и исходники C из Java класса.
Эти файлы обеспечивают связь, которая позволит взаимодействовать вашему Java и C коду
javah -classpath bin/classes -jni -d jni com.my.javaclass
javah
Application.mk
APP_PLATFORM := android-9
APP_STL := stlport_static
APP_ABI := all32
APP_CPPFLAGS += -std=c++11
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_FEATURES += rtti # Enable exceptions in Android.mk
LOCAL_CPP_FEATURES += exceptions # Enable exceptions in Android.mk
LOCAL_LDLIBS := -llog -lz
LOCAL_MODULE := nativeTest
LOCAL_CFLAGS := -DANDROID -O3 -pipe
LOCAL_CXXFLAGS := -DANDROID -O3 -pipe
LOCAL_SRC_FILES :=com_test.cpp
Android.mk & Application.mk
Использование Java Native Interface (JNI) и кросплатформенных C/C++ реализаций в Java/Android
- Логгирование
__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- StackTrace в LogCat
Dalvik:
F/libc (17861): invalid address or address of corrupt block 0x7f51ce50 passed to dlfree
F/libc (17861): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 29266 (Thread-9488)
ART:
A/art(21149): sart/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal
start byte 0xa3
….
A/art(21149): sart/runtime/check_jni.cc:65] native: #07 pc 000bfaad /system/lib/libart.so (art::CheckJNI::NewStringUTF
(_JNIEnv*, char const*)+44)
A/art(21149): sart/runtime/check_jni.cc:65] native: #08 pc 00008fbb /data/app/com.stickypassword.android-
1/lib/arm/libSPCAgent.so (setValue(_jobject*, int, long, char*, char*)+202)
A/art(21149): sart/runtime/check_jni.cc:65] native: #09 pc 00009ac7 /data/app/com.stickypassword.android-
1/lib/arm/libSPCAgent.so (Java_com_spc_SPCManager_GetAuthCredentialsV2+82)
Отладка
GDB (GNU Debugger) — переносимый отладчик проекта GNU, который работает на многих UNIX-
подобных системах и умеет производить отладку многих языков программирования, включая
Си, C++, Free Pascal, FreeBASIC, Ada и Фортран. GDB — свободное программное обеспечение,
распространяемое по лицензии GPL.
GDB
package com.example.testsimplycall;
public class NativeTest {
static {
try{
// == Runtime.getRuntime().loadLibrary("testSimplyCall");
System.loadLibrary("testSimplyCall");
} catch (UnsatisfiedLinkError err){
//need catch exception
err.printStackTrace();
}
}
public native void testMePlz(String msg);
}
project/jni/com_example_testsimplycall_NativeTest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef _Included_com_example_testsimplycall_NativeTest
#define _Included_com_example_testsimplycall_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_example_testsimplycall_NativeTest_testMePlz(JNIEnv *env,jobject jobj, jstring msg);
#ifdef __cplusplus
}
#endif
#endif
project/jni/com_example_testsimplycall_NativeTest.cpp
#include <def.h>
#include <jni.h>
#include "com_example_testsimplycall_NativeTest.h"
JNIEXPORT void JNICALL Java_com_example_testsimplycall_NativeTest_testMePlz(JNIEnv *env,
jobject jobj, jstring msg){
jboolean isCopy;
const char * Str;
Str = env->GetStringUTFChars(msg, &isCopy);
LOGI("string = "%s"",Str);
}
package com.example.testcallback;
import android.util.Log;
public interface NativeCallback {
public void print(String str);
}
public class NativeTest {
static {
try{
System.loadLibrary("testCallback");
} catch (UnsatisfiedLinkError err){
err.printStackTrace();
}
}
public NativeCallback nativecallback = new NativeCallback(){
@Override
public void print(String str) {
Log.d("JAVA_CALLBACK", str);
}};
public native void testMePlz(String msg);
public native void SetListener(NativeCallback javacallback);
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef _Included_com_example_testcallback_NativeTest
#define _Included_com_example_testcallback_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_testMePlz(JNIEnv *env,
jobject jobj, jstring msg);
JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_SetListener(
JNIEnv *env, jobject jobj, jobject callback);
#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "com_example_testcallback_NativeTest.h"
jobject javaCallback;
JavaVM* mJVM;
/* Reference to Java-object*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
mJVM = jvm;
return JNI_VERSION_1_2;
}
JNIEnv* getJniEnv() {
JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_2;
attachArgs.name = ">>>NativeThread__Any";
attachArgs.group = NULL;
JNIEnv* env;
if (mJVM->AttachCurrentThread(&env, &attachArgs) != JNI_OK) {
env = NULL;
}
return env;
}
void printToLogcat(const char* msg) {
JNIEnv* pEnv = getJniEnv();
jclass javaClass = pEnv->GetObjectClass(javaCallback);
if (javaClass != NULL) {
jmethodID javaMethodID = pEnv->GetMethodID(javaClass, "print","(Ljava/lang/String;)V");
jstring logmsg = pEnv->NewStringUTF(msg);
if (logmsg != NULL) {
pEnv->CallVoidMethod(javaCallback, javaMethodID, logmsg);
pEnv->DeleteLocalRef(logmsg);
logmsg = NULL;
}
pEnv->DeleteLocalRef(javaClass);
javaClass = NULL;
}
}
JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_SetListener(
JNIEnv *env, jobject jobj, jobject callback) {
if(javaCallback)
env->DeleteGlobalRef(javaCallback);
javaCallback = env->NewGlobalRef(callback);
}
JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_testMePlz(JNIEnv *env,jobject jobj, jstring msg){
jboolean isCopy;
const char * Str;
Str = env->GetStringUTFChars(msg, &isCopy);
printToLogcat(Str);
}
● Blackberry10 (mktime)
● ARM & Intel
● NDK X32 & х64
● Android L & 5.0 (копирование массивов)
● tmpdir()/tmpfile()
● флаги оптимизации ( -03,-Ofast, -SSE etc)
● порезаный Bionic и прочие либы в Андроид
● *.so на Sony
● Проблема 01.01.2037
Грабли
Android NDK & JNI
Использование Java Native Interface (JNI) и
кросплатформенных C/C++ реализаций в Java (Android)
Q/A
Sergey Komlach
GDG Kremenchuk, StickyPassword
Skype: s.komlach
sergey.komlach@stickypassword.com

More Related Content

PPTX
New Android NDK & JNI
PDF
Дмитрий Юницкий. «Android NDK или как я перестал бояться и полюбил нативную р...
PDF
C++ STL & Qt. Занятие 10.
PDF
C++ STL & Qt. Занятие 03.
PDF
C++ STL & Qt. Занятие 11.
PDF
C++ STL & Qt. Занятие 09.
PPTX
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
PDF
C++ STL & Qt. Занятие 04.
New Android NDK & JNI
Дмитрий Юницкий. «Android NDK или как я перестал бояться и полюбил нативную р...
C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 09.
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
C++ STL & Qt. Занятие 04.

What's hot (20)

PDF
Разница в подходах анализа кода компилятором и выделенным инструментом
PDF
C++ STL & Qt. Занятие 08.
PDF
C++ STL & Qt. Занятие 05.
PPTX
Bytecode
PDF
C++ весна 2014 лекция 5
PDF
C++ STL & Qt. Занятие 01.
PPTX
PDF
C++ STL & Qt. Занятие 06.
PDF
C++ STL & Qt. Занятие 02.
PDF
Память в Java. Garbage Collector
PDF
Шишки, набитые за 15 лет использования акторов в C++
PDF
C++ осень 2013 лекция 4
PDF
C++ осень 2013 лекция 9
PPTX
Современный статический анализ кода: что умеет он, чего не умели линтеры
PDF
C++ осень 2013 лекция 7
PDF
C++ refelection and cats
PPTX
Александр Фокин, Рефлексия в C++
PPTX
Зачем нужна Scala?
PPTX
SAST и Application Security: как бороться с уязвимостями в коде
ODP
Java: вчера, сегодня, завтра
Разница в подходах анализа кода компилятором и выделенным инструментом
C++ STL & Qt. Занятие 08.
C++ STL & Qt. Занятие 05.
Bytecode
C++ весна 2014 лекция 5
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 06.
C++ STL & Qt. Занятие 02.
Память в Java. Garbage Collector
Шишки, набитые за 15 лет использования акторов в C++
C++ осень 2013 лекция 4
C++ осень 2013 лекция 9
Современный статический анализ кода: что умеет он, чего не умели линтеры
C++ осень 2013 лекция 7
C++ refelection and cats
Александр Фокин, Рефлексия в C++
Зачем нужна Scala?
SAST и Application Security: как бороться с уязвимостями в коде
Java: вчера, сегодня, завтра
Ad

Similar to Использование Java Native Interface (JNI) и кросплатформенных C/C++ реализаций в Java/Android (20)

PPTX
Dz Java Hi Load 0.4
PDF
Распределённое нагрузочное тестирование на Java
ODP
Java 9 - кратко о новом
PDF
IT-инфраструктура. FAQ для разработчика
PPTX
JavaScript-модули "из прошлого в будущее"
PDF
Леонид Васильев "Python в инфраструктуре поиска"
PPT
Node.js (RichClient)
ODP
Java 9 - Back to the Future
PDF
От Make к Ansible
PDF
Lift, play, akka, rails part1
PDF
REPL в Node.js: улучшаем быт разработчик
PDF
Opensource на .NET
PDF
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
PDF
Frontend: Путешествие в мир модульных загрузчиков
PDF
Разговор про Java 9. Extended version
PPT
Ввведение в java
PPT
Введение в язык программирования «Java»
PPTX
Node.js введение в технологию, КПИ #ITmeetingKPI
PDF
Компьютерная графика. Введение в Processing
Dz Java Hi Load 0.4
Распределённое нагрузочное тестирование на Java
Java 9 - кратко о новом
IT-инфраструктура. FAQ для разработчика
JavaScript-модули "из прошлого в будущее"
Леонид Васильев "Python в инфраструктуре поиска"
Node.js (RichClient)
Java 9 - Back to the Future
От Make к Ansible
Lift, play, akka, rails part1
REPL в Node.js: улучшаем быт разработчик
Opensource на .NET
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Frontend: Путешествие в мир модульных загрузчиков
Разговор про Java 9. Extended version
Ввведение в java
Введение в язык программирования «Java»
Node.js введение в технологию, КПИ #ITmeetingKPI
Компьютерная графика. Введение в Processing
Ad

More from Stfalcon Meetups (20)

PDF
Conversion centered design 3
PDF
Discovery phase
PPTX
Stfalcon QA Meetup 31.01.2020
PPTX
Stfalcon QA Meetup 31.01.2020
PDF
Stfalcon PM Meetup 21.11
PDF
Stfalcon PM Meetup 21.11
PDF
Design of the_future_30_05_2019
PPTX
2 5404811386729530203
PDF
Team evolution
PDF
Mobile&Privacy
PDF
Global sales - a few insights
PDF
How to build your own startup
PDF
Первая и последняя встреча с клиентом
PPTX
Парнерство нидерланды
ODP
Риси гарного менеджера
PPTX
Между заказчиком и разработчиком
PPTX
Cv vs resume
PPTX
PPTX
майстер-клас “Управління ризиками”
PPTX
Kubernetes: від знайомства до використання у CI/CD
Conversion centered design 3
Discovery phase
Stfalcon QA Meetup 31.01.2020
Stfalcon QA Meetup 31.01.2020
Stfalcon PM Meetup 21.11
Stfalcon PM Meetup 21.11
Design of the_future_30_05_2019
2 5404811386729530203
Team evolution
Mobile&Privacy
Global sales - a few insights
How to build your own startup
Первая и последняя встреча с клиентом
Парнерство нидерланды
Риси гарного менеджера
Между заказчиком и разработчиком
Cv vs resume
майстер-клас “Управління ризиками”
Kubernetes: від знайомства до використання у CI/CD

Использование Java Native Interface (JNI) и кросплатформенных C/C++ реализаций в Java/Android

  • 1. Android NDK & JNI Использование Java Native Interface (JNI) и кросплатформенных C/C++ реализаций в Java (Android) Sergey Komlach GDG Kremenchuk, StickyPassword Skype: s.komlach sergey.komlach@stickypassword.com
  • 2. ● Что такое JNI/NDK? Быстродействие, много готовых либ, платформозависимость, не- "Write once, run anywhere" (WORA), аналогия с Reflection, используемые типы и вызовы ● Настройка окружения (NDK x 2), отладка, поддержка и тестирование всех платформ ● Пример простейшей реализации Java → C. ● Вызов из С++ метода Java как колбека (Java interface) ● Особенности выполнения кода (BlackBerry10 (mktime()), IntelAtom, х64), tmpdir(), флаги оптимизации, порезаный Bionic и прочие либы в Андроид, удаление SO-шек на Sony при апдейте Рассмотрим….
  • 3. Wiki: Java Native Interface (JNI) — стандартный механизм для запуска кода, под управлением виртуальной машины Java (JVM), который написан на языках С/С++ или Ассемблера, и скомпонован в виде динамических библиотек, позволяет не использовать статическое связывание. Это даёт возможность вызова функции С/С++ из программы на Java, и наоборот. Более ранние интерфейсы, в отличие от JNI, не удовлетворяли условию двоичной совместимости. Wiki: В 2009 году в дополнение к ADT был опубликован Android Native Development Kit (NDK) — пакет инструментариев и библиотек, позволяющий реализовать часть приложения на языке С/С++. NDK рекомендуется использовать для разработки участков кода, критичных к скорости. Реально же наиболее частое применение: Работа с OpenGL ES Использование кросс-платформенных игровых движков, например Cocos2Dx Использование уже написанного на C/C++ кода (а его ох как дофига написано!). Часто, это работа с мультимедиа, например FFMPEG, libpng или наукоемкие вещи типа openCV «Обход» «бутылочного горлышка» в программе (UP! «тяжелых» процессов) Кроссплатформенное (повторное) использование кода JNI/NDK
  • 4. Работа с NDK на порядок усложняет разработку. - Разработчик должен понимать Java (само собой) - С/С++ (особенно внимание на память, указатели, треды/семафоры и т.д) - команды и принципы работы JVM (очень пригодится если вы уже работали с Reflection) Class cls = sample1.getClass(); try { cls.getDeclaredMethod("print", String.class).invoke(sample1, "sample class"); cls.getDeclaredMethod("print", String.class).invoke(sample1, "test string"); cls.getDeclaredMethod("print", null).invoke(sample2, null); cls.getDeclaredMethod("print", null).invoke(sample3, null); } catch (Exception e) {} - Нужно учитывать большое количество ограничений JNI в Android (порезаные библиотека, размеры типов, «пустышки» реализаций) - Сложная настройка среды и особенно отладка Таким образом, работа с NDK чаще всего представляем из себя процесс (часто — мучительный) сборки некой библиотеки и написиние оберток (wrappers) на нативные методы. В тоже время, сейчас есть возможность ваять приложение практически без использования Java, используя NativeActivity (API 9 и выше).
  • 5. package com.example; public class NativeTest{ static { System.loadLibrary("nativetest"); // libs/armeabi-v7a/libnativetest.so } public native boolean testMethod(int arg); } JNIEXPORT jboolean JNICALL Java_com_example_NativeTest_testMethod (JNIEnv *env, jobject caller, jint arg); JNIEXPORT — необходимый для JNI модификатор. Типы данных с префиксом «j»: jdouble, jobject, jstring etc — это «отражения» объектов и типов Java в C/C++. Именование
  • 6. jstring JAVA_JNI_This_1Is_1Native_00024Wrapper_00024_000408_000413_000397(...) Дело в том, что _1 это аналог нижнего подчёркивания. _00024 это символ $, то есть может как разделитель внутреннего класса использоваться. _00408, 0xxxx, это код в юникоде. В итоге получается: class JNI { static class This_Is_Native { static class Wrapper$ { static String Юникод(...) } Именование, часть 2
  • 7. Java JNI JNI array Code Array Code boolean jboolean jbooleanArray Z [Z byte jbyte jbyteArray B [B char jchar jcharArray C [C double jdouble jdoubleArray D [D float jfloat jfloatArray F [F int jint jintArray I [I long jlong jlongArray J [J short jshort jshortArray S [S Object/Class/ String jobject/jclass/ jstring jobjectArray/-/- L/L/L [L/[L/[L void void - V -
  • 9. ● Устаналивается APK ● Если внутри находятся SO-файлы (аналог DLL) они копируются в /data/data/apppackage/app_lib/*.so ● При первом обращении к классу, использующему нативные библиотеки, последние загружаются через System.load(«name») ● Библиотека «живет» пока не будет завершено приложение Как работает взаимодействие между Java и Native
  • 10. ● Качаем NDK. При чем если хотим все платформы, то нужно NDK x32 (для arm6, arm7a, x86 & mips) и NDK x64 (arm8, x86_64 & mips_64 и все х32) ● Устанавливаем окружение (путь к папке NDK) ● «цепляем» в IDE С чего начинается NDK
  • 11. javah создает файлы заголовков и исходники C из Java класса. Эти файлы обеспечивают связь, которая позволит взаимодействовать вашему Java и C коду javah -classpath bin/classes -jni -d jni com.my.javaclass javah
  • 12. Application.mk APP_PLATFORM := android-9 APP_STL := stlport_static APP_ABI := all32 APP_CPPFLAGS += -std=c++11 Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CPP_FEATURES += rtti # Enable exceptions in Android.mk LOCAL_CPP_FEATURES += exceptions # Enable exceptions in Android.mk LOCAL_LDLIBS := -llog -lz LOCAL_MODULE := nativeTest LOCAL_CFLAGS := -DANDROID -O3 -pipe LOCAL_CXXFLAGS := -DANDROID -O3 -pipe LOCAL_SRC_FILES :=com_test.cpp Android.mk & Application.mk
  • 14. - Логгирование __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) - StackTrace в LogCat Dalvik: F/libc (17861): invalid address or address of corrupt block 0x7f51ce50 passed to dlfree F/libc (17861): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 29266 (Thread-9488) ART: A/art(21149): sart/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xa3 …. A/art(21149): sart/runtime/check_jni.cc:65] native: #07 pc 000bfaad /system/lib/libart.so (art::CheckJNI::NewStringUTF (_JNIEnv*, char const*)+44) A/art(21149): sart/runtime/check_jni.cc:65] native: #08 pc 00008fbb /data/app/com.stickypassword.android- 1/lib/arm/libSPCAgent.so (setValue(_jobject*, int, long, char*, char*)+202) A/art(21149): sart/runtime/check_jni.cc:65] native: #09 pc 00009ac7 /data/app/com.stickypassword.android- 1/lib/arm/libSPCAgent.so (Java_com_spc_SPCManager_GetAuthCredentialsV2+82) Отладка
  • 15. GDB (GNU Debugger) — переносимый отладчик проекта GNU, который работает на многих UNIX- подобных системах и умеет производить отладку многих языков программирования, включая Си, C++, Free Pascal, FreeBASIC, Ada и Фортран. GDB — свободное программное обеспечение, распространяемое по лицензии GPL. GDB
  • 16. package com.example.testsimplycall; public class NativeTest { static { try{ // == Runtime.getRuntime().loadLibrary("testSimplyCall"); System.loadLibrary("testSimplyCall"); } catch (UnsatisfiedLinkError err){ //need catch exception err.printStackTrace(); } } public native void testMePlz(String msg); }
  • 17. project/jni/com_example_testsimplycall_NativeTest.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #ifndef _Included_com_example_testsimplycall_NativeTest #define _Included_com_example_testsimplycall_NativeTest #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_com_example_testsimplycall_NativeTest_testMePlz(JNIEnv *env,jobject jobj, jstring msg); #ifdef __cplusplus } #endif #endif project/jni/com_example_testsimplycall_NativeTest.cpp #include <def.h> #include <jni.h> #include "com_example_testsimplycall_NativeTest.h" JNIEXPORT void JNICALL Java_com_example_testsimplycall_NativeTest_testMePlz(JNIEnv *env, jobject jobj, jstring msg){ jboolean isCopy; const char * Str; Str = env->GetStringUTFChars(msg, &isCopy); LOGI("string = "%s"",Str); }
  • 18. package com.example.testcallback; import android.util.Log; public interface NativeCallback { public void print(String str); } public class NativeTest { static { try{ System.loadLibrary("testCallback"); } catch (UnsatisfiedLinkError err){ err.printStackTrace(); } } public NativeCallback nativecallback = new NativeCallback(){ @Override public void print(String str) { Log.d("JAVA_CALLBACK", str); }}; public native void testMePlz(String msg); public native void SetListener(NativeCallback javacallback); }
  • 19. /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #ifndef _Included_com_example_testcallback_NativeTest #define _Included_com_example_testcallback_NativeTest #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_testMePlz(JNIEnv *env, jobject jobj, jstring msg); JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_SetListener( JNIEnv *env, jobject jobj, jobject callback); #ifdef __cplusplus } #endif #endif
  • 20. #include <jni.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "com_example_testcallback_NativeTest.h" jobject javaCallback; JavaVM* mJVM; /* Reference to Java-object*/ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { mJVM = jvm; return JNI_VERSION_1_2; } JNIEnv* getJniEnv() { JavaVMAttachArgs attachArgs; attachArgs.version = JNI_VERSION_1_2; attachArgs.name = ">>>NativeThread__Any"; attachArgs.group = NULL; JNIEnv* env; if (mJVM->AttachCurrentThread(&env, &attachArgs) != JNI_OK) { env = NULL; } return env; }
  • 21. void printToLogcat(const char* msg) { JNIEnv* pEnv = getJniEnv(); jclass javaClass = pEnv->GetObjectClass(javaCallback); if (javaClass != NULL) { jmethodID javaMethodID = pEnv->GetMethodID(javaClass, "print","(Ljava/lang/String;)V"); jstring logmsg = pEnv->NewStringUTF(msg); if (logmsg != NULL) { pEnv->CallVoidMethod(javaCallback, javaMethodID, logmsg); pEnv->DeleteLocalRef(logmsg); logmsg = NULL; } pEnv->DeleteLocalRef(javaClass); javaClass = NULL; } } JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_SetListener( JNIEnv *env, jobject jobj, jobject callback) { if(javaCallback) env->DeleteGlobalRef(javaCallback); javaCallback = env->NewGlobalRef(callback); } JNIEXPORT void JNICALL Java_com_example_testcallback_NativeTest_testMePlz(JNIEnv *env,jobject jobj, jstring msg){ jboolean isCopy; const char * Str; Str = env->GetStringUTFChars(msg, &isCopy); printToLogcat(Str); }
  • 22. ● Blackberry10 (mktime) ● ARM & Intel ● NDK X32 & х64 ● Android L & 5.0 (копирование массивов) ● tmpdir()/tmpfile() ● флаги оптимизации ( -03,-Ofast, -SSE etc) ● порезаный Bionic и прочие либы в Андроид ● *.so на Sony ● Проблема 01.01.2037 Грабли
  • 23. Android NDK & JNI Использование Java Native Interface (JNI) и кросплатформенных C/C++ реализаций в Java (Android) Q/A Sergey Komlach GDG Kremenchuk, StickyPassword Skype: s.komlach sergey.komlach@stickypassword.com