NDK 高级编程(笔记)

只是作为读书笔记。

0x02 深入了解 Android NDK

  1. 创建项目时 Android.mk 文件的构建:Android.mk配置参数
  2. ndk-build 脚本参数
1
2
3
4
5
6
7
8
9
10
11
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//头文件
#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 日志

1
2
3
adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start

5.3 故障处理

1.堆栈分析

1
2
3
4
5
#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:

1
adb shell setprop debug.checkjni 1

5.4 内存问题

1.打开 libc 调试模式

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

2.strace 工具

1
2
3
4
5
#获取进程
adb shell ps | grep packagename
#附加进程
adb shell strace -v -p <pid>

0x07 原生线程

源码地址: ndk-pro/threads

1.POSIX 线程返回结果

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

2.POSIX 线程同步

1
2
3
4
5
6
7
8
9
10
11
12
13
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 线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//头文件
#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++ 运行库

1
2
3
4
5
6
7
8
9
10
11
12
13
//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++支持异常

1
2
3
4
5
//单个模块 Android.mk
LOCAL_CPP_FEATURES += exceptions
//支持所有原生模块 Application.mk
APP_CPPFLAGS += -fexceptions

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

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

1
2
3
4
5
//单个模块 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++ 运行库调试模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//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 指令