Android 开发中针对 NDK 的书籍很少,《Pro Android C++ with the NDK》也是出版的比较早的一本书,有些内容可能对现在的开发并不适用。但是书中介绍的内容比较全面,难度也不是很大,对于 NDK 开发有很大帮助,特别是在 NDK 开发的配置和代码规范上。

0x02 深入了解 Android NDK

  1. 创建项目时 Android.mk 文件的构建:Android.mk配置参数

  2. ndk-build 脚本参数

#NDK 项目位置
ndk-build -C /path/to/the/project

#强制重构所有代码
ndk-build -B

#清除生成的二进制文件和目标文件
ndk-build clean

#并行构建命令
ndk-build -j 4

0x03 用 JNI 实现与原生代码通信

jni 的开发基础知识,参考:

  1. NDK开发 - JNI开发流程

  2. NDK开发 - JNI数据类型与Java数据类型映射关系

  3. NDK开发 - JNI基本数据和字符串处理

  4. NDK开发 - JNI数组数据处理

  5. NDK开发 - C/C++ 访问 Java 变量和方法

  6. NDK开发-JNI 局部引用、全局引用和弱全局引用

0x05 日志、调试及故障处理

5.1 原生日志 API

//头文件
#include <android.h>

//Android.mk
LOCAL_LALIBS += -llog

_android_log_write(ANDROID_LOG_DEBUG, "hello-jni", "debug log.")

//多参数封装
static void logMessage(JNIEnv *env, jobject obj, const char *format, ...) {
    static jmethodID methodID = NULL;
    if (NULL == methodID) {
        jclass clazz = env->GetObjectClass(obj);
        methodID = env->GetMethodID(clazz, "logMessage", "(Ljava/lang/String;)V");
        env->DeleteLocalRef(clazz);
    }
    if(methodID != NULL) {
        char buffer[MAX_LOG_MSG_LENGTH];
        va_list ap;
        va_start(ap, format); //指向 format 后可变参数的地址
        vsnprintf(buffer, MAX_LOG_MSG_LENGTH, format, ap);
        va_end(ap);

        jstring message = env->NewStringUTF(buffer);
        if (message != NULL) {
            env->CallVoidMethod(obj, methodID, message);
            env->DeleteLocalRef(message);
        }
    }
}

5.2 重定向 Android 日志

adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start

5.3 故障处理

1.堆栈分析

#ndk-stack
adb logcat | ndk-stack -sym obj/local/armeabi

#arm-linux-androideabi-addr2line
arm-linux-androideabi-addr2line -e obj/local/armeabi-v7a/libtongdun.so 0002197e

2.启用 CheckJNI:

adb shell setprop debug.checkjni 1

5.4 内存问题

1.打开 libc 调试模式

adb shell setprop libc.debug.malloc 1
adb shell stop
adb shell start

2.strace 工具

#获取进程
adb shell ps | grep packagename

#附加进程
adb shell strace -v -p <pid>

0x07 原生线程

源码地址: ndk-pro/threads

1.POSIX 线程返回结果

//1.线程句柄 2.返回值指针
int pthread_join(pthread_t thread, void** ret_val);

2.POSIX 线程同步

static pthread_mutex_t mutex;

//初始化
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexarrt_t* attr);

//锁定
int pthread_mutex_lock(pthread_mutex_t* mutex);

//解锁
int pthread_mutex_unlock(pthread_mutex_t* mutex);

//销毁
int pthread_mutex_destroy(pthread_mutex_t* mutex);

3.使用信号量同步 POSIX 线程

//头文件
#include <semaphone.h>

//初始化
extern int sem_init(sem_t* sem, int pshared, unsigned int value);

//锁定信号
extern int sem_wait(sem_t* sem);

//解锁
extern int sem_post(sem_t* sem);

//销毁
extern int sem_destroy(sem_t* sem);

0x08/09/10 POSIX Socket API

TCP && UDP

源码地址: pro-ndk/echo

0x11 支持 C++

11.1 支持的 C++ 运行库

  1. C++系统运行库 不支持:C++标准库、 异常支持库、 RTTI 支持

  2. GAbi++、 STLport、 GUN STL
    效果图

11.2 指定 C++ 运行库

//Application.mk
APP_STL := system //默认
APP_STL := gabi++_static
APP_STL := gabi++_shared
APP_STL := stlport_static
APP_STL := stlport_shared
APP_STL := gunstl_static
APP_STL := gunstl_shared

//1.项目只有一个单一的原生模块时支持静态库
//2.项目中包含多个原生模块时使用动态库
//3.动态库使用时需要先加载 
System.loadLibrary(“strport_shared”)

11.4 C++支持异常

//单个模块 Android.mk
LOCAL_CPP_FEATURES += exceptions

//支持所有原生模块 Application.mk
APP_CPPFLAGS += -fexceptions

11.5 C++ RTTI 支持(Run-Time Type Information)

在运行库展示对象类型信息,只要用于执行安全类型转化。

//单个模块 Android.mk
LOCAL_CPP_FEATURES += rtti

//支持所有原生模块 Application.mk
APP_CPPFLAGS += -frtti

11.6 C++ 标准库

  • 容器

    • 序列

      • vector 支持随机访问,末尾常量插入删除 其他线性

      • deque 与 vector支持随机访问 选择实现队列的基础

      • list 双向列表

      • slist 单项链表

    • 关联容器

      • 排序关联容器 操作复杂度不超过对数阶

        • set 已排序,不重复

        • map 键值对,不重复

        • multiset 已排序,多重关联,允许重复

        • multimap 对拥有相同键值的元素数量不限制

      • 哈希关联容器 查询时间快

        • hashed_set 不重复

        • hash_map

        • hash_multiset 允许重复

        • hash_multimap 允许重复

    • 适配器

      • stack 堆栈 LIFO (Last In First Out)

      • queue 队列 FIFO (First In First Out)

    • String

  • 迭代器

11.8 C++ 运行库调试模式

//GUN STL 调试模式
LOCAL_CFLAGS += -D_GLIBCXX_DEBUG

//STLport 调试模式
LOCAL_CFLAGS += -D_STLP_DEBUG

//日志重定向到 Android 日志 
LOCAL_CFLAGS += -D_STLP_DEBUG
LOCAL_CFLAGS += -D_STLP_DEBUG_MESSAGE
LOCAL_LDLIBS += —llog

void __stl_debug_message(const char* format_str, …){
    va_list ap;
    va_start(ap, format_str);
    __android_log_vprint(ANDROID_LOG_FATAL, “STLport”, format_str, ap);
    va_end(ap);
}

0x12 原生图形 API

源码地址: ndk-pro/abiplayer

0x14 程序概要分析和 NEON 优化

  1. android-ndk-profiler

  2. NEON 指令:并不是所有基于 ARM-V7a 的设备都支持 NEON 指令

原文地址:NDK 高级编程(笔记)


凸一_一凸
582 声望42 粉丝

安全小菜鸡