Разработка приложений для 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 Support
    http://www.eclipse.org/sequoyah/




                                       7
Добавляем поддержку NDK




                          8
Application.mk


APP_MODULES   :=   YaC
APP_CFLAGS    :=   -DDEBUG -D__ANDROID__
APP_OPTIM     :=   debug
APP_STL       :=   gnustl_static
APP_ABI       :=   armeabi armeabi-v7a




                                           9
Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE      :=   YaC
LOCAL_CFLAGS      :=   -I$(LOCAL_PATH)/inc
LOCAL_SRC_FILES   :=   YaC.cpp
LOCAL_LDLIBS      :=   -llog

include $(BUILD_SHARED_LIBRARY)

                                             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 := arm
 endif


                                                         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   +   /usr/bin/javah   =   C




                                    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
JNIEnv
JavaVM * gJVM = 0;

JNIEXPORT void JNICALL
Java_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 JNICALL
Java_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.html     29
Разбираемся с ошибками
        ********** 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 00000000
Stack frame #00 pc 00000716 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #01 pc 00000740 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #02 pc 00017e34 /system/lib/libdvm.so
Stack frame #03 pc 0004968c /system/lib/libdvm.so
Stack 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 00000000
Stack frame #00 pc 00000716 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #01 pc 00000740 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #02 pc 00017e34 /system/lib/libdvm.so
Stack frame #03 pc 0004968c /system/lib/libdvm.so
Stack 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 00000000
Stack frame #00 pc 00000716 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #01 pc 00000740 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #02 pc 00017e34 /system/lib/libdvm.so
Stack frame #03 pc 0004968c /system/lib/libdvm.so
Stack 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 00000000
Stack frame #00 pc 00000716 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #01 pc 00000740 /data/data/
com.shturmann.yac/lib/libYaC.so
Stack frame #02 pc 00017e34 /system/lib/libdvm.so
Stack frame #03 pc 0004968c /system/lib/libdvm.so
Stack 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
Ловим сигналы самостоятельно
#include <asm/sigcontext.h>

struct ucontext
{
    unsigned long uc_flags;
    struct ucontext *uc_link;
    stack_t uc_stack;
    sigcontext uc_mcontext;
}
                                43
Ловим сигналы самостоятельно
#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”
 :$ ddms      Из корня вашего проекта



 :$ emulator -help-memcheck
 :$ emulator -memcheck 1


                                        49
Для чего все это нужно?




                          50
Берёза Юрий
Shturmann

ybereza@gmail.com


                    51

Разработка приложений для Android на С++. Юрий Береза, Shturmann