SlideShare une entreprise Scribd logo
1  sur  23
Télécharger pour lire hors ligne
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
- Логгирование
__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

Contenu connexe

Tendances

C++ весна 2014 лекция 5
C++ весна 2014 лекция 5C++ весна 2014 лекция 5
C++ весна 2014 лекция 5
Technopark
 
C++ осень 2013 лекция 4
C++ осень 2013 лекция 4C++ осень 2013 лекция 4
C++ осень 2013 лекция 4
Technopark
 
C++ осень 2013 лекция 9
C++ осень 2013 лекция 9C++ осень 2013 лекция 9
C++ осень 2013 лекция 9
Technopark
 
C++ осень 2013 лекция 7
C++ осень 2013 лекция 7C++ осень 2013 лекция 7
C++ осень 2013 лекция 7
Technopark
 

Tendances (20)

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

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

Dz Java Hi Load 0.4
Dz Java Hi Load 0.4Dz Java Hi Load 0.4
Dz Java Hi Load 0.4
HighLoad2009
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1
Eduard Antsupov
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Mikhail Kurnosov
 

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

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

Plus de Stfalcon Meetups

Kubernetes: від знайомства до використання у CI/CD
Kubernetes: від знайомства до використання у CI/CDKubernetes: від знайомства до використання у CI/CD
Kubernetes: від знайомства до використання у CI/CD
Stfalcon Meetups
 

Plus de Stfalcon Meetups (20)

Conversion centered design 3
Conversion centered design 3Conversion centered design 3
Conversion centered design 3
 
Discovery phase
Discovery phaseDiscovery phase
Discovery phase
 
Stfalcon QA Meetup 31.01.2020
Stfalcon QA Meetup 31.01.2020Stfalcon QA Meetup 31.01.2020
Stfalcon QA Meetup 31.01.2020
 
Stfalcon QA Meetup 31.01.2020
Stfalcon QA Meetup 31.01.2020Stfalcon QA Meetup 31.01.2020
Stfalcon QA Meetup 31.01.2020
 
Stfalcon PM Meetup 21.11
Stfalcon PM Meetup 21.11Stfalcon PM Meetup 21.11
Stfalcon PM Meetup 21.11
 
Stfalcon PM Meetup 21.11
Stfalcon PM Meetup 21.11Stfalcon PM Meetup 21.11
Stfalcon PM Meetup 21.11
 
Design of the_future_30_05_2019
Design of the_future_30_05_2019Design of the_future_30_05_2019
Design of the_future_30_05_2019
 
2 5404811386729530203
2 54048113867295302032 5404811386729530203
2 5404811386729530203
 
Team evolution
Team evolutionTeam evolution
Team evolution
 
Mobile&Privacy
Mobile&PrivacyMobile&Privacy
Mobile&Privacy
 
Global sales - a few insights
Global sales - a few insightsGlobal sales - a few insights
Global sales - a few insights
 
How to build your own startup
How to build your own startupHow to build your own startup
How to build your own startup
 
Первая и последняя встреча с клиентом
Первая и последняя встреча с клиентом Первая и последняя встреча с клиентом
Первая и последняя встреча с клиентом
 
Парнерство нидерланды
Парнерство нидерландыПарнерство нидерланды
Парнерство нидерланды
 
Риси гарного менеджера
Риси гарного менеджераРиси гарного менеджера
Риси гарного менеджера
 
Между заказчиком и разработчиком
Между заказчиком и разработчикомМежду заказчиком и разработчиком
Между заказчиком и разработчиком
 
Cv vs resume
Cv vs resumeCv vs resume
Cv vs resume
 
Vue.js
Vue.jsVue.js
Vue.js
 
майстер-клас “Управління ризиками”
майстер-клас “Управління ризиками”майстер-клас “Управління ризиками”
майстер-клас “Управління ризиками”
 
Kubernetes: від знайомства до використання у CI/CD
Kubernetes: від знайомства до використання у CI/CDKubernetes: від знайомства до використання у CI/CD
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
  • 13.
  • 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