Разработка приложений для android на С++. Юрий Береза, shturmann
DESCRIPTION
Юрий Береза, ShturmannОкончил факультет приборостроения Московской государственной академии приборостроения и информатики. В 2004 году пришел на работу в отдел мобильных разработок компании «Макцентр». Занимался разработкой под огромное число мобильных платформ: Windows Mobile, Symbian, Android, Embedded linux и iOS. В данный момент работает руководителем группы в компании «Контент Мастер», где занимается разработкой автомобильной навигации Shturmann.Тема докладаРазработка приложений для Android на С++.ТезисыПлатформа Android становится популярнее с каждым годом. Несмотря на то, что основным языком разработки приложений для Android является Java, часто для написания кросс-платформенных приложений или при использовании сторонних библиотек программистам приходится использовать С или С++. К сожалению, разработка на С++ для платформы Android описана довольно скупо, и зачастую приходится тратить много времени на поиск нужной информации. В докладе будут представлены ответы на основные вопросы по всему циклу разработки: как писать С++ код, который будет работать на Android, как его отлаживать и находить ошибки во время падения приложений, есть ли возможность профилировать код и где искать дополнительную информацию по этим вопросам.TRANSCRIPT
Разработка приложений для Android на C++
Берёза ЮрийпрограммистShturmann
YaC, Москва, 19 сентября 2011 года1
С чего начать
• Linux
• Java
• Eclipse
• C++
• GCC
• GDB
• Android SDK
2
3
4
Что такое NDK?http://developer.android.com/sdk/ndk/index.html
• Заголовочные файлы и библиотеки
•GCC компилятор
• Система сборки приложений
•Набор дополнительных утилит
5
Создание проекта
•Запустить Eclipse•Указать в настройках путь к SDK•Запустить мастер создания Android приложения
6
Sequoyah Android Native Code Supporthttp://www.eclipse.org/sequoyah/
7
Добавляем поддержку NDK
8
Application.mk
APP_MODULES := YaCAPP_CFLAGS := -DDEBUG -D__ANDROID__APP_OPTIM := debugAPP_STL := gnustl_staticAPP_ABI := armeabi armeabi-v7a
9
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := YaCLOCAL_CFLAGS := -I$(LOCAL_PATH)/incLOCAL_SRC_FILES := YaC.cppLOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Android.mk
10
Поддержка расширенных инструкций NEON
http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html
Anroid.mk
ifeq ($TARGET_ARCH_ABI), armeabi-v7a)! LOCAL_ARM_NEON := true! LOCAL_ARM_MODE := armendif
11
Или
#include <cpu-features.h>
void do_something(){ if ((android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && (android_getCpuFeatures() & ANDROID_CPU_FETURE_NEON)) { do_something_with_neon(); }}
12
JNI. Java
package com.shturmann.yac;
public class YaCActivity { private native void doSomething(); static { System.loadLibrary("YaC"); }}
13
JNI. Java
package com.shturmann.yac;
public class YaCActivity { private native void doSomething(); static { System.loadLibrary("YaC"); }}
14
JNI. Java
package com.shturmann.yac;
public class YaCActivity { private native void doSomething(); static { System.loadLibrary("YaC"); }}
15
JNI. Java
package com.shturmann.yac;
public class YaCActivity { private native void doSomething(); static { System.loadLibrary("YaC"); }}
16
JNI
Java C/usr/bin/javah+ =
17
JNI.C++
JNIEXPORT void JNICALL Java_com_shturmann_yac_YaCActivity_doSomething(JNIEnv * env, jobject obj){ ...}
18
JNI.C++
JNIEXPORT void JNICALL Java_com_shturmann_yac_YaCActivity_doSomething(JNIEnv * env, jobject obj){ ...}
19
JNIEnvJavaVM * gJVM = 0;
JNIEXPORT void JNICALLJava_com_shturmann_yac_YaCActivity_init(JNIEnv * env, jobject obj){
gJVM = (*env)->GetJavaVM(env, &gJVM);}
void someInternalFunction(){ JNIEnv * env = 0; (*gJVM)->AttachCurrentThread(gJVM, &env, 0);} 20
Локальные/глобальные ссылки
jclass * gYac = 0;
JNIEXPORT void JNICALLJava_com_shturmann_yac_YaCActivity_doSomething(JNIEnv * env, jobject obj){ jclass yac = (*env)->GetObjectClass(env, obj); gYac = (*env)->NewGlobalRef(env, yac);}
21
JNIEnv::FindClass
jclass gYac = 0;
JNIEXPORT void JNICALL Java_com_shturmann_yac_YaCActivity_init(JNIEnv * env, jobject obj){ jclass yac = (*env)->FindClass(env,
«com/shturmann/yac/YaCActivity»); gYac = (*env)->NewGlobalRef(env, yac);}
22
JNIEnv::ExceptionCheck
JNIEXPORT void JNICALL Java_com_shturmann_yac_YaCActivity_init(JNIEnv * env, jobject obj){ ... if ( !(*env)->ExceptionCheck(env) ) { ... }}
23
JNIEnv::PushLocalFrame/PopLocalFrame
JNIEXPORT void JNICALL Java_com_shturmann_yac_YaCActivity_init(JNIEnv * env, jobject obj){ (*env)->PushLocalFrame(env, 100500); ... (*env)->PopLocalFrame(env, NULL);}
24
JNI
http://java.sun.com/docs/books/jni/download/jni.pdf
25
Дополнительные библиотеки
• OpenGL ES 1.1 / OpenGL ES 2.0
• OpenSL
• C++ и wchar_t
• http://www.crystax.net/ru/android/ndk
• Boost
• https://github.com/MysticTreeGames/Boost-for-Android
• CURL
26
Запускаем сборку приложения
• ndk-build
• ant install
27
28
ОтладкаAndroid 2.3 Gingerbred
• ndk-gdb • Eclipse
http://mitya.pp.ru/gdb/gdb_toc.html29
Разбираемся с ошибками ********** Crash dump: **********Build fingerprint: 'google/soju/crespo:2.3.4/GRJ22/121341:user/release-keys'pid: 7348, tid: 7348 >>> com.shturmann.yac <<<signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),fault addr 00000000Stack frame #00 pc 00000716 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #01 pc 00000740 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #02 pc 00017e34 /system/lib/libdvm.soStack frame #03 pc 0004968c /system/lib/libdvm.soStack frame #04 pc 0004ee62 /system/lib/libdvm.so
30
Разбираемся с ошибками ********** Crash dump: **********Build fingerprint: 'google/soju/crespo:2.3.4/GRJ22/121341:user/release-keys'pid: 7348, tid: 7348 >>> com.shturmann.yac <<<signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),fault addr 00000000Stack frame #00 pc 00000716 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #01 pc 00000740 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #02 pc 00017e34 /system/lib/libdvm.soStack frame #03 pc 0004968c /system/lib/libdvm.soStack frame #04 pc 0004ee62 /system/lib/libdvm.so
31
Разбираемся с ошибками ********** Crash dump: **********Build fingerprint: 'google/soju/crespo:2.3.4/GRJ22/121341:user/release-keys'pid: 7348, tid: 7348 >>> com.shturmann.yac <<<signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),fault addr 00000000Stack frame #00 pc 00000716 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #01 pc 00000740 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #02 pc 00017e34 /system/lib/libdvm.soStack frame #03 pc 0004968c /system/lib/libdvm.soStack frame #04 pc 0004ee62 /system/lib/libdvm.so
32
Разбираемся с ошибками ********** Crash dump: **********Build fingerprint: 'google/soju/crespo:2.3.4/GRJ22/121341:user/release-keys'pid: 7348, tid: 7348 >>> com.shturmann.yac <<<signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),fault addr 00000000Stack frame #00 pc 00000716 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #01 pc 00000740 /data/data/com.shturmann.yac/lib/libYaC.soStack frame #02 pc 00017e34 /system/lib/libdvm.soStack frame #03 pc 0004968c /system/lib/libdvm.soStack frame #04 pc 0004ee62 /system/lib/libdvm.so
33
Разбираемся с ошибками
• addr2line
• objdump
• ndk-stack
34
Разбираемся с ошибками
$ adb logcat -d | ndk-stack -sym ~/src/obj/local/armeabi
35
Разбираемся с ошибками
Stack frame #00 pc 00000716/data/data/com.shturmann.yac/lib/libYaC.so:Routine get_a in /home/ybereza/src/YaC/yac/jni/YaC.cpp:13
Stack frame #01 pc 00000740/data/data/com.shturmann.yac/lib/libYaC.so:Routine Java_com_shturmann_yac_YaCActivity_doSomething in /home/ybereza/src/YaC/yac/jni/YaC.cpp:24
36
Разбираемся с ошибками
Stack frame #00 pc 00000716/data/data/com.shturmann.yac/lib/libYaC.so:Routine get_a in /home/ybereza/src/YaC/yac/jni/YaC.cpp:13
Stack frame #01 pc 00000740/data/data/com.shturmann.yac/lib/libYaC.so:Routine Java_com_shturmann_yac_YaCActivity_doSomething in /home/ybereza/src/YaC/yac/jni/YaC.cpp:24
37
Разбираемся с ошибками
Stack frame #00 pc 00000716/data/data/com.shturmann.yac/lib/libYaC.so:Routine get_a in /home/ybereza/src/YaC/yac/jni/YaC.cpp:13
Stack frame #01 pc 00000740/data/data/com.shturmann.yac/lib/libYaC.so:Routine Java_com_shturmann_yac_YaCActivity_doSomething in /home/ybereza/src/YaC/yac/jni/YaC.cpp:24
38
Ловим сигналы самостоятельноvoid install_sighandler(){ struct sigaction default_action;
struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction));
sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = linux_sig_handler; sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, &default_handler)}
39
Ловим сигналы самостоятельноvoid install_sighandler(){ struct sigaction default_action;
struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction));
sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = linux_sig_handler; sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, &default_handler)}
40
Ловим сигналы самостоятельно
void linux_sig_handler(int sig, struct siginfo_t* info, void* context){ LOG_FLUSH; default_handler.sa_handler(sig);}
41
Ловим сигналы самостоятельно
void linux_sig_handler(int sig, struct siginfo_t* info, void* context){ LOG_FLUSH; default_handler.sa_handler(sig);}
42
Ловим сигналы самостоятельно
43
#include <asm/sigcontext.h>
struct ucontext{ unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; sigcontext uc_mcontext;}
Ловим сигналы самостоятельно
#include <asm/sigcontext.h>
struct ucontext{ unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; sigcontext uc_mcontext;}
44
Ловим сигналы самостоятельно
/proc/<id вашего процесса>/maps
45
Где взять
https://bitbucket.org/ybereza/yac/src
46
Профилирование
47
Профилирование
Но! 48
Профилирование
DDMS Native Heap
~/.android/ddms.cfg“native=true”
:$ emulator -help-memcheck:$ emulator -memcheck 1
:$ ddms Из корня вашего проекта
49
Для чего все это нужно?
50