Сергій Комлач
— Android розробник в Sticky Password (Чехія).
— Головні напрямки роботи — біометрична ідентифікація, кібер-безпека, кросс-платформенні рішення.
— Досвід у сфері розробки під Мобайл понад 8 років.
— Переможець Opera Mobile Store Awards.
— Спікер та учасник: Lviv Mobile Development Day, UAMobile, Frameworks Day Android, Code'n'Coffee Khmelnitsky, Google DevFest UA.
— Засновник та лідер Google Developers Group Kremenchuk.
3. Что такое JNI/NDK? Быстродействие, много готовых либ, платформозависимость, не-
"Write once, run anywhere" (WORA), аналогия с Reflection, используемые типы и
вызовы
Настройка окружения (NDK x 2), отладка, поддержка и тестирование всех платформ
Особенности выполнения кода (BlackBerry10 (mktime()), IntelAtom, х64), tmpdir(), флаги
оптимизации, порезаный Bionic и прочие либы в Андроид, удаление SO-шек на Sony
при апдейте
Рассмотрим….
4. Wiki: Java Native Interface (JNI) — стандартный механизм для запуска кода, под
управлением виртуальной машины Java (JVM), который написан на языках С/С++ или
Ассемблера, и скомпонован в виде динамических библиотек, позволяет не
использовать статическое связывание. Это даёт возможность вызова функции С/С++
из программы на Java, и наоборот. Более ранние интерфейсы, в отличие от JNI, не
удовлетворяли условию двоичной совместимости.
Wiki: В 2009 году в дополнение к ADT был опубликован Android Native Development Kit
(NDK) — пакет инструментариев и библиотек, позволяющий реализовать часть
приложения на языке С/С++. NDK рекомендуется использовать для разработки
участков кода, критичных к скорости.
JNI/NDK
5. Реально же наиболее частое применение:
Работа с OpenGL ES
Использование кросс-платформенных игровых движков, например Cocos2Dx
Использование уже написанного на C/C++ кода (а его ох как дофига написано!). Часто,
это работа с мультимедиа, например FFMPEG, libpng или наукоемкие вещи типа openCV
«Обход» «бутылочного горлышка» в программе (UP! «тяжелых» процессов)
Кроссплатформенное (повторное) использование кода
JNI/NDK
6. Работа с 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 и выше).
7. 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++.
Именование
8. 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
9. 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 -
12. Устаналивается APK
Если внутри находятся SO-файлы (аналог DLL) они копируются в
/data/data/apppackage/app_lib/*.so
При первом обращении к классу, использующему нативные библиотеки, последние
загружаются через System.load(«name»)
Библиотека «живет» пока не будет завершено приложение
Как работает взаимодействие
между Java и Native
13. Качаем NDK. Если вам нужна поддержка только 32-битных архитектур, то нужно NDK
x32 (для arm6, arm7a, x86 & mips), иначе можно исполользовать NDK x64 (arm8,
x86_64 & mips_64 и все х32)
Устанавливаем окружение (путь к папке NDK) «цепляем» в IDE
Альтернативные компиляторы: GCC, Clang, MinGW
Альтернатива - Crysta X NDK (https://www.crystax.net/ru/android/ndk ) (wide chars, C
localizations, full math, C++11/C++14, Boost, Object-C/C++ etc.)
Android* NDK for Intel® Architecture
Выбираем STL
С чего начинается NDK
14. javah создает файлы заголовков и исходники C из Java класса.
Эти файлы обеспечивают связь, которая позволит взаимодействовать вашему Java и C
коду
javah -classpath bin/classes -jni -d jni com.my.javaclass
javah
17. Now: Like a pro (see
NDKSamples)
Gradle/Android Studio
ndk {
moduleName = 'sanangeles'
CFlags.addAll(['-DANDROID_NDK', '-DDISABLE_IMPORTGL'])
CFlags.addAll(['-Wall', '-Werror'])
ldLibs.addAll(['android', 'log', 'dl', 'GLESv1_CM'])
abiFilters.addAll(['armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'])
}
18. Migrating from Traditional
Android Gradle Plugin
A typical Android Studio project may have a directory structure as follows. File that needs to be change is highlighted in red:
There are some significant changes in the DSL between the new plugin and the traditional one.
.
├── app/
│ ├── app.iml
│ ├── build.gradle
│ └── src/
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew*
├── gradlew.bat
├── local.properties
├── MyApplication.iml
└── settings.gradle
21. Standart Template Library
libstdc++(default) The default minimal system C++ runtime library. N/A
gabi++_static The GAbi++ runtime (static). C++ Exceptions and RTTI
gabi++_shared The GAbi++ runtime (shared). C++ Exceptions and RTTI
stlport_static The STLport runtime (static). C++ Exceptions and RTTI; Standard Library
stlport_shared The STLport runtime (shared). C++ Exceptions and RTTI; Standard Library
gnustl_static The GNU STL (static). C++ Exceptions and RTTI; Standard Library
gnustl_shared The GNU STL (shared). C++ Exceptions and RTTI; Standard Library
c++_static The LLVM libc++ runtime (static). C++ Exceptions and RTTI; Standard Library
c++_shared The LLVM libc++ runtime (shared). C++ Exceptions and RTTI; Standard Library
22. @echo off
echo Build
set ROOT=%CD%
echo %%ROOT%% = %ROOT%
del build.log 2>nul
call D:androidandroid-ndkndk-build.cmd clean
call D:androidandroid-ndkndk-build.cmd >>build.log 2>&1
pause
Сборка из командной строки
23.
24. - Логгирование
__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)
Отладка
25. - GDB (GNU Debugger) — переносимый отладчик проекта GNU, который работает на
многих UNIX-подобных системах и умеет производить отладку многих языков
программирования, включая Си, C++, Free Pascal, FreeBASIC, Ada и Фортран. GDB
— свободное программное обеспечение, распространяемое по лицензии GPL.
- NVIDIA Debug Manager for Android NDK https://developer.nvidia.com/nvidia-
debug-manager-android-ndk
- CoffeeCatch (https://github.com/xroche/coffeecatch) - небольшая библиотека для
перехвата POSIX сигналов и имитирующая работу try{} catch(){} из Java
COFFEE_TRY() {
recurse_madness(42);
*fault = 0;
} COFFEE_CATCH() {
const char*const message = coffeecatch_get_message();
snprintf(string_buffer, sizeof(string_buffer), "%s", message);
*fault = 1;
} COFFEE_END();
GDB & CoffeCatch
26. http://forum.xda-developers.com/showthread.php?t=2754997
- Optimized for speed yet more all instructions - ARM and THUMB (-O3)
- Optimized for speed also parts which are compiled with Clang (-O3)
- Turned off all debugging code (lack of -g)
- Eliminated redundant loads that come after stores to the same memory location, both partial and full redundancies (-fgcse-las)
- Ran a store motion pass after global common subexpression elimination. This pass attempts to move stores out of loops (-fgcse-sm)
- Performed interprocedural pointer analysis and interprocedural modification and reference analysis (-fipa-pta)
- Performed induction variable optimizations (strength reduction, induction variable merging and induction variable elimination) on trees (-fivopts)
- Didn't keep the frame pointer in a register for functions that don't need one. This avoids the instructions to save, set up and restore frame pointers; it
also makes an extra register available in many functions (-fomit-frame-pointer)
- Attempted to avoid false dependencies in scheduled code by making use of registers left over after register allocation. This optimization most benefits
processors with lots of registers (-frename-registers)
Flags
28. Blackberry10 и mktime
Android 5 (копирование массивов)
tmpdir()/tmpfile()
флаги оптимизации ( -03,-Ofast, -SSE etc)
порезаный Bionic и прочие либы в Андроид
*.so на Sony
Проблема 01.01.2037
TTF
Грабли