1-2-3 Kotlin与C++基础-JNI原理与使用

0 阅读15分钟

🏗️ JNI原理与使用深度解析

一、JNI基础概念与架构

1.1 JNI是什么?

JNI(Java Native Interface) 是Java平台提供的一个编程框架,允许:

  1. Java代码调用Native代码(C/C++)
  2. Native代码调用Java代码
  3. 在Java和Native之间共享数据和对象

1.2 JNI在Android中的位置

Java层 (Kotlin/Java)
    ↓ JNI桥接
JNI层 (C/C++)
    ↓
Native层 (系统库、硬件驱动)

1.3 数据类型映射

Java类型JNI类型C/C++类型说明
booleanjbooleanunsigned char8位
bytejbytesigned char8位
charjcharunsigned short16位
shortjshortshort16位
intjintint32位
longjlonglong long64位
floatjfloatfloat32位
doublejdoubledouble64位
voidvoidvoid-
Objectjobject_jobject*对象引用
Stringjstring_jstring*字符串引用
Classjclass_jclass*类引用
Object[]jobjectArray_jobjectArray*对象数组
boolean[]jbooleanArray_jbooleanArray*布尔数组
............

二、JNI开发环境搭建

2.1 Android Studio配置

// app/build.gradle
android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++17 -frtti -fexceptions"
                arguments "-DANDROID_STL=c++_shared"
            }
        }
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
    
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }
    
    // 打包时包含.so文件
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/cpp/libs']
        }
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.12.0'
}

2.2 CMakeLists.txt配置

# CMakeLists.txt
cmake_minimum_required(VERSION 3.18.1)
project("native-lib")

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加NDK头文件路径
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)

# 添加预构建库
add_library(log-lib STATIC IMPORTED)
set_target_properties(log-lib PROPERTIES IMPORTED_LOCATION
    ${ANDROID_NDK}/platforms/android-${ANDROID_PLATFORM}/arch-arm/usr/lib/liblog.so)

# 添加自己的库
add_library(
    native-lib             # 库名
    SHARED                 # 共享库
    src/main/cpp/native-lib.cpp  # 源文件
)

# 链接库
target_link_libraries(
    native-lib            # 目标库
    android               # Android特定API
    log-lib               # Logcat日志
    ${log-lib}
)

2.3 JNI函数命名规范

// 静态注册命名规则:Java_包名_类名_方法名
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainActivity_stringFromJNI(
    JNIEnv* env,
    jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

// 参数说明:
// JNIEnv* env: JNI环境指针,提供所有JNI函数
// jobject thiz: 调用该native方法的Java对象(this)
// 后续参数: Java方法的参数

三、静态注册 vs 动态注册

3.1 静态注册(传统方式)

// Java层
public class NativeLib {
    static {
        System.loadLibrary("native-lib");
    }
    
    public native String getMessage();
    public native int calculate(int a, int b);
    public native void processArray(int[] array);
}
// Native层 - 静态注册
#include <jni.h>
#include <string>

// 必须按照规则命名
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_NativeLib_getMessage(JNIEnv* env, jobject thiz) {
    return env->NewStringUTF("Hello from static registration");
}

extern "C" JNIEXPORT jint JNICALL
Java_com_example_NativeLib_calculate(JNIEnv* env, jobject thiz, jint a, jint b) {
    return a + b;
}

extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeLib_processArray(
    JNIEnv* env, jobject thiz, jintArray array) {
    // 处理数组
}

3.2 动态注册(推荐方式)

// Native层 - 动态注册
#include <jni.h>
#include <string>
#include <android/log.h>

#define LOG_TAG "JNI_DEMO"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// Native方法实现
jstring native_getMessage(JNIEnv* env, jobject thiz) {
    LOGD("native_getMessage called");
    return env->NewStringUTF("Hello from dynamic registration");
}

jint native_calculate(JNIEnv* env, jobject thiz, jint a, jint b) {
    return a * b;
}

void native_processArray(JNIEnv* env, jobject thiz, jintArray array) {
    jint* elements = env->GetIntArrayElements(array, nullptr);
    jsize length = env->GetArrayLength(array);
    
    for (int i = 0; i < length; i++) {
        elements[i] *= 2;
    }
    
    env->ReleaseIntArrayElements(array, elements, 0);
}

// 方法映射表
static JNINativeMethod nativeMethods[] = {
    {"getMessage", "()Ljava/lang/String;", (void*)native_getMessage},
    {"calculate", "(II)I", (void*)native_calculate},
    {"processArray", "([I)V", (void*)native_processArray}
};

// JNI_OnLoad - 库加载时自动调用
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    LOGD("JNI_OnLoad called");
    
    JNIEnv* env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        LOGE("Failed to get JNIEnv");
        return JNI_ERR;
    }
    
    // 找到Java类
    jclass clazz = env->FindClass("com/example/NativeLib");
    if (clazz == nullptr) {
        LOGE("Failed to find class");
        return JNI_ERR;
    }
    
    // 注册Native方法
    jint result = env->RegisterNatives(
        clazz,
        nativeMethods,
        sizeof(nativeMethods) / sizeof(JNINativeMethod)
    );
    
    if (result != JNI_OK) {
        LOGE("Failed to register native methods");
        return JNI_ERR;
    }
    
    LOGD("Native methods registered successfully");
    return JNI_VERSION_1_6;
}

// JNI_OnUnload - 库卸载时调用
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
    LOGD("JNI_OnUnload called");
}

3.3 方法签名详解

// 方法签名格式:(参数类型)返回值类型

// 基本类型签名
"()V"                        // void func()
"(I)V"                       // void func(int)
"(II)I"                      // int func(int, int)
"(Ljava/lang/String;)V"      // void func(String)
"(I[Ljava/lang/String;)Z"    // boolean func(int, String[])

// 类型签名速查表:
// Z -> boolean
// B -> byte
// C -> char
// S -> short
// I -> int
// J -> long
// F -> float
// D -> double
// V -> void
// L完整类名; -> 对象类型(如 Ljava/lang/String;)
// [类型 -> 数组(如 [I -> int[],[Ljava/lang/String; -> String[])

// 完整的类描述符
"(Ljava/lang/String;ILjava/util/List;)V"
// 对应:void func(String, int, List)

四、JNI核心API详解

4.1 字符串操作

// 字符串转换示例
void stringOperations(JNIEnv* env) {
    // 1. Java字符串 -> C字符串
    jstring javaStr = env->NewStringUTF("Hello Java");
    
    // 转换为UTF-8字符串(需要释放)
    const char* cStr = env->GetStringUTFChars(javaStr, nullptr);
    if (cStr != nullptr) {
        printf("C String: %s\n", cStr);
        env->ReleaseStringUTFChars(javaStr, cStr);
    }
    
    // 转换为UTF-16字符串(用于宽字符)
    const jchar* wideStr = env->GetStringChars(javaStr, nullptr);
    if (wideStr != nullptr) {
        // 处理宽字符串
        env->ReleaseStringChars(javaStr, wideStr);
    }
    
    // 2. C字符串 -> Java字符串
    const char* cppStr = "Hello from C++";
    jstring newJavaStr = env->NewStringUTF(cppStr);
    
    // 3. 获取字符串长度
    jsize utf8Length = env->GetStringUTFLength(javaStr);
    jsize unicodeLength = env->GetStringLength(javaStr);
    
    // 4. 获取字符串区域(避免完整复制)
    char buffer[256];
    env->GetStringUTFRegion(javaStr, 0, 5, buffer);
    buffer[5] = '\0';
    
    // 5. 预分配字符串
    jcharArray charArray = env->NewCharArray(100);
    // ... 填充charArray
    jstring fromCharArray = env->NewString(env->GetCharArrayElements(charArray, nullptr), 100);
}

// 字符串操作最佳实践
class JNIStringGuard {
private:
    JNIEnv* env;
    jstring javaString;
    const char* cString;
    
public:
    JNIStringGuard(JNIEnv* env, jstring str) : env(env), javaString(str) {
        cString = env->GetStringUTFChars(javaString, nullptr);
    }
    
    ~JNIStringGuard() {
        if (cString) {
            env->ReleaseStringUTFChars(javaString, cString);
        }
    }
    
    const char* get() const { return cString; }
    operator const char*() const { return cString; }
};

4.2 数组操作

// 基本类型数组
void processIntArray(JNIEnv* env, jintArray array) {
    // 方式1:获取数组指针(可修改原始数组)
    jint* elements = env->GetIntArrayElements(array, nullptr);
    jsize length = env->GetArrayLength(array);
    
    for (int i = 0; i < length; i++) {
        elements[i] *= 2;
    }
    
    // 第三个参数:
    // 0 - 复制回Java数组并释放C数组
    // JNI_COMMIT - 复制回Java数组但不释放C数组
    // JNI_ABORT - 不复制回Java数组,直接释放C数组
    env->ReleaseIntArrayElements(array, elements, 0);
    
    // 方式2:获取数组区域(适合读取,不修改)
    jint buffer[100];
    env->GetIntArrayRegion(array, 0, 100, buffer);
    
    // 方式3:设置数组区域
    jint newData[100];
    // ... 填充newData
    env->SetIntArrayRegion(array, 0, 100, newData);
}

// 对象数组
void processObjectArray(JNIEnv* env, jobjectArray array) {
    jsize length = env->GetArrayLength(array);
    
    for (int i = 0; i < length; i++) {
        jobject element = env->GetObjectArrayElement(array, i);
        
        if (element != nullptr) {
            // 处理每个对象
            jclass stringClass = env->FindClass("java/lang/String");
            jmethodID toUpperCase = env->GetMethodID(stringClass, "toUpperCase", "()Ljava/lang/String;");
            
            jobject upper = env->CallObjectMethod(element, toUpperCase);
            env->SetObjectArrayElement(array, i, upper);
        }
    }
}

// 创建新数组
jintArray createIntArray(JNIEnv* env, jsize size) {
    jintArray array = env->NewIntArray(size);
    if (array != nullptr) {
        jint* elements = env->GetIntArrayElements(array, nullptr);
        for (int i = 0; i < size; i++) {
            elements[i] = i * i;
        }
        env->ReleaseIntArrayElements(array, elements, 0);
    }
    return array;
}

// 多维数组
jobjectArray create2DArray(JNIEnv* env, jsize rows, jsize cols) {
    // 找到内部数组的类
    jclass intArrayClass = env->FindClass("[I");
    
    // 创建外层数组
    jobjectArray result = env->NewObjectArray(rows, intArrayClass, nullptr);
    
    for (int i = 0; i < rows; i++) {
        jintArray row = env->NewIntArray(cols);
        jint* elements = env->GetIntArrayElements(row, nullptr);
        
        for (int j = 0; j < cols; j++) {
            elements[j] = i * cols + j;
        }
        
        env->ReleaseIntArrayElements(row, elements, 0);
        env->SetObjectArrayElement(result, i, row);
        env->DeleteLocalRef(row);
    }
    
    return result;
}

4.3 对象操作与反射

class JNIReflectionHelper {
private:
    JNIEnv* env;
    
public:
    explicit JNIReflectionHelper(JNIEnv* env) : env(env) {}
    
    // 创建Java对象
    jobject createObject(const char* className, const char* constructorSig, ...) {
        jclass clazz = env->FindClass(className);
        if (clazz == nullptr) return nullptr;
        
        jmethodID constructor = env->GetMethodID(clazz, "<init>", constructorSig);
        if (constructor == nullptr) return nullptr;
        
        va_list args;
        va_start(args, constructorSig);
        jobject obj = env->NewObjectV(clazz, constructor, args);
        va_end(args);
        
        env->DeleteLocalRef(clazz);
        return obj;
    }
    
    // 调用实例方法
    template<typename T>
    T callMethod(jobject obj, const char* methodName, const char* signature, ...) {
        jclass clazz = env->GetObjectClass(obj);
        jmethodID method = env->GetMethodID(clazz, methodName, signature);
        
        va_list args;
        va_start(args, signature);
        
        T result;
        if constexpr (std::is_same_v<T, jobject>) {
            result = env->CallObjectMethodV(obj, method, args);
        } else if constexpr (std::is_same_v<T, jint>) {
            result = env->CallIntMethodV(obj, method, args);
        } else if constexpr (std::is_same_v<T, jlong>) {
            result = env->CallLongMethodV(obj, method, args);
        } else if constexpr (std::is_same_v<T, jfloat>) {
            result = env->CallFloatMethodV(obj, method, args);
        } else if constexpr (std::is_same_v<T, jdouble>) {
            result = env->CallDoubleMethodV(obj, method, args);
        } else if constexpr (std::is_same_v<T, jboolean>) {
            result = env->CallBooleanMethodV(obj, method, args);
        } else {
            env->CallVoidMethodV(obj, method, args);
        }
        
        va_end(args);
        env->DeleteLocalRef(clazz);
        return result;
    }
    
    // 访问字段
    template<typename T>
    T getField(jobject obj, const char* fieldName, const char* signature) {
        jclass clazz = env->GetObjectClass(obj);
        jfieldID field = env->GetFieldID(clazz, fieldName, signature);
        
        T result;
        if constexpr (std::is_same_v<T, jobject>) {
            result = env->GetObjectField(obj, field);
        } else if constexpr (std::is_same_v<T, jint>) {
            result = env->GetIntField(obj, field);
        } else if constexpr (std::is_same_v<T, jlong>) {
            result = env->GetLongField(obj, field);
        } // 其他类型类似...
        
        env->DeleteLocalRef(clazz);
        return result;
    }
    
    // 调用静态方法
    jobject callStaticMethod(const char* className, const char* methodName, 
                            const char* signature, ...) {
        jclass clazz = env->FindClass(className);
        if (clazz == nullptr) return nullptr;
        
        jmethodID method = env->GetStaticMethodID(clazz, methodName, signature);
        if (method == nullptr) {
            env->DeleteLocalRef(clazz);
            return nullptr;
        }
        
        va_list args;
        va_start(args, signature);
        jobject result = env->CallStaticObjectMethodV(clazz, method, args);
        va_end(args);
        
        env->DeleteLocalRef(clazz);
        return result;
    }
};

// 使用示例
void reflectionExample(JNIEnv* env, jobject context) {
    JNIReflectionHelper helper(env);
    
    // 创建Java对象
    jobject point = helper.createObject(
        "android/graphics/Point", 
        "(II)V", 
        100, 200
    );
    
    // 调用方法
    jint x = helper.callMethod<jint>(point, "getX", "()I");
    jint y = helper.callMethod<jint>(point, "getY", "()I");
    
    // 调用静态方法
    jobject display = helper.callStaticMethod(
        "android/view/Display",
        "getDefaultDisplay",
        "(Landroid/content/Context;)Landroid/view/Display;",
        context
    );
    
    // 访问字段
    jobject size = helper.getField<jobject>(display, "mSize", "Landroid/graphics/Point;");
}

五、引用管理

5.1 局部引用 vs 全局引用

void referenceManagement(JNIEnv* env) {
    // 1. 局部引用(Local Reference)
    jstring localStr = env->NewStringUTF("局部引用");
    // 在函数返回时自动释放,或手动释放:
    env->DeleteLocalRef(localStr);
    
    // 重要:局部引用数量有限制(默认16个)
    for (int i = 0; i < 100; i++) {
        jstring temp = env->NewStringUTF("test");
        env->DeleteLocalRef(temp);  // 必须及时释放
    }
    
    // 2. 全局引用(Global Reference)
    jstring globalStr = static_cast<jstring>(env->NewGlobalRef(localStr));
    // 全局引用不会被自动释放,必须手动:
    env->DeleteGlobalRef(globalStr);
    
    // 3. 弱全局引用(Weak Global Reference)
    jstring weakStr = static_cast<jstring>(env->NewWeakGlobalRef(localStr));
    
    // 检查弱引用是否有效
    if (env->IsSameObject(weakStr, nullptr) == JNI_FALSE) {
        // 引用仍然有效
    }
    
    env->DeleteWeakGlobalRef(weakStr);
}

// 引用管理工具类
template<typename T>
class JNIGlobalRef {
private:
    T ref;
    
public:
    explicit JNIGlobalRef(JNIEnv* env, T obj) : ref(nullptr) {
        if (obj != nullptr) {
            ref = static_cast<T>(env->NewGlobalRef(obj));
        }
    }
    
    ~JNIGlobalRef() {
        if (ref != nullptr) {
            JNIEnv* env = getEnv();
            if (env != nullptr) {
                env->DeleteGlobalRef(ref);
            }
        }
    }
    
    // 禁止拷贝
    JNIGlobalRef(const JNIGlobalRef&) = delete;
    JNIGlobalRef& operator=(const JNIGlobalRef&) = delete;
    
    // 允许移动
    JNIGlobalRef(JNIGlobalRef&& other) noexcept : ref(other.ref) {
        other.ref = nullptr;
    }
    
    JNIGlobalRef& operator=(JNIGlobalRef&& other) noexcept {
        if (this != &other) {
            if (ref != nullptr) {
                JNIEnv* env = getEnv();
                if (env != nullptr) {
                    env->DeleteGlobalRef(ref);
                }
            }
            ref = other.ref;
            other.ref = nullptr;
        }
        return *this;
    }
    
    T get() const { return ref; }
    operator T() const { return ref; }
    
private:
    static JNIEnv* getEnv() {
        JNIEnv* env = nullptr;
        JavaVM* vm = getJavaVM();
        if (vm != nullptr) {
            vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
        }
        return env;
    }
    
    static JavaVM* getJavaVM() {
        static JavaVM* vm = nullptr;
        // 在JNI_OnLoad中设置
        return vm;
    }
};

5.2 线程中的JNI使用

// Native线程访问JVM
class NativeThread {
private:
    JavaVM* javaVM;
    JNIGlobalRef<jobject> javaObject;
    
public:
    NativeThread(JavaVM* vm, jobject obj) : javaVM(vm), javaObject(nullptr) {
        JNIEnv* env = nullptr;
        vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
        if (env != nullptr) {
            javaObject = JNIGlobalRef<jobject>(env, obj);
        }
    }
    
    void runInNativeThread() {
        // 在Native线程中访问Java对象
        JNIEnv* env = attachThread();
        if (env != nullptr) {
            // 可以安全地调用Java方法
            jclass clazz = env->GetObjectClass(javaObject.get());
            jmethodID method = env->GetMethodID(clazz, "onNativeCallback", "(I)V");
            env->CallVoidMethod(javaObject.get(), method, 123);
            
            detachThread();
        }
    }
    
private:
    JNIEnv* attachThread() {
        JNIEnv* env = nullptr;
        javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
        
        if (env == nullptr) {
            // 当前线程未附加到JVM,需要附加
            JavaVMAttachArgs args = {JNI_VERSION_1_6, "NativeThread", nullptr};
            if (javaVM->AttachCurrentThread(&env, &args) != JNI_OK) {
                return nullptr;
            }
        }
        return env;
    }
    
    void detachThread() {
        // 检查是否需要分离
        JNIEnv* env = nullptr;
        if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_EDETACHED) {
            javaVM->DetachCurrentThread();
        }
    }
};

六、JNI最佳实践

6.1 性能优化

// 1. 缓存ID和类引用
class CachedJNI {
private:
    struct CachedIDs {
        jclass stringClass;
        jmethodID toUpperCase;
        jfieldID valueField;
        
        CachedIDs(JNIEnv* env) {
            stringClass = static_cast<jclass>(env->NewGlobalRef(
                env->FindClass("java/lang/String")));
            toUpperCase = env->GetMethodID(stringClass, "toUpperCase", 
                                         "()Ljava/lang/String;");
            valueField = env->GetFieldID(stringClass, "value", "[C");
        }
        
        ~CachedIDs() {
            JNIEnv* env = getEnv();
            if (env != nullptr) {
                env->DeleteGlobalRef(stringClass);
            }
        }
    };
    
    static CachedIDs& getCached() {
        static CachedIDs cached(getEnv());
        return cached;
    }
};

// 2. 减少JNI调用次数
jstring efficientStringProcessing(JNIEnv* env, jobjectArray stringArray) {
    jsize count = env->GetArrayLength(stringArray);
    std::vector<std::string> nativeStrings;
    nativeStrings.reserve(count);
    
    // 一次性获取所有字符串
    for (int i = 0; i < count; i++) {
        jstring str = static_cast<jstring>(env->GetObjectArrayElement(stringArray, i));
        const char* cstr = env->GetStringUTFChars(str, nullptr);
        nativeStrings.emplace_back(cstr);
        env->ReleaseStringUTFChars(str, cstr);
        env->DeleteLocalRef(str);
    }
    
    // 在Native层进行批量处理
    std::string result;
    for (const auto& str : nativeStrings) {
        result += str + " ";
    }
    
    return env->NewStringUTF(result.c_str());
}

// 3. 使用直接缓冲区(Direct Buffer)
void processDirectBuffer(JNIEnv* env, jobject directBuffer) {
    void* buffer = env->GetDirectBufferAddress(directBuffer);
    jlong capacity = env->GetDirectBufferCapacity(directBuffer);
    
    if (buffer != nullptr) {
        // 直接操作内存,避免拷贝
        auto* data = static_cast<float*>(buffer);
        for (int i = 0; i < capacity / sizeof(float); i++) {
            data[i] *= 2.0f;
        }
    }
}

6.2 内存管理

// 自动资源管理RAII类
class JNIEnvPtr {
private:
    JavaVM* vm;
    JNIEnv* env;
    bool attached;
    
public:
    explicit JNIEnvPtr(JavaVM* vm) : vm(vm), env(nullptr), attached(false) {
        if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_EDETACHED) {
            vm->AttachCurrentThread(&env, nullptr);
            attached = true;
        }
    }
    
    ~JNIEnvPtr() {
        if (attached) {
            vm->DetachCurrentThread();
        }
    }
    
    JNIEnv* operator->() const { return env; }
    JNIEnv* get() const { return env; }
    
    // 禁止拷贝
    JNIEnvPtr(const JNIEnvPtr&) = delete;
    JNIEnvPtr& operator=(const JNIEnvPtr&) = delete;
    
    // 允许移动
    JNIEnvPtr(JNIEnvPtr&& other) noexcept 
        : vm(other.vm), env(other.env), attached(other.attached) {
        other.env = nullptr;
        other.attached = false;
    }
};

// 使用示例
void safeNativeFunction(JavaVM* vm) {
    JNIEnvPtr env(vm);
    
    // 现在可以安全地使用env
    jstring result = env->NewStringUTF("Safe JNI usage");
    // ...
}

6.3 异常处理

class JNIExceptionGuard {
private:
    JNIEnv* env;
    
public:
    explicit JNIExceptionGuard(JNIEnv* env) : env(env) {}
    
    ~JNIExceptionGuard() {
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe();  // 打印异常信息到logcat
            env->ExceptionClear();     // 清除异常
        }
    }
    
    bool checkException() const {
        return env->ExceptionCheck() != JNI_FALSE;
    }
    
    void throwNewException(const char* className, const char* message) {
        jclass clazz = env->FindClass(className);
        if (clazz != nullptr) {
            env->ThrowNew(clazz, message);
            env->DeleteLocalRef(clazz);
        }
    }
};

// 使用示例
jstring safeNativeCall(JNIEnv* env) {
    JNIExceptionGuard guard(env);
    
    // 可能会抛出异常的操作
    jclass clazz = env->FindClass("java/lang/String");
    if (clazz == nullptr) {
        guard.throwNewException("java/lang/RuntimeException", "Class not found");
        return nullptr;
    }
    
    // 其他操作...
    return env->NewStringUTF("Success");
}

七、JNI与Android Framework集成

7.1 Bitmap处理

#include <android/bitmap.h>

jobject processBitmap(JNIEnv* env, jobject bitmap) {
    AndroidBitmapInfo info;
    if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS) {
        return nullptr;
    }
    
    void* pixels;
    if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
        return nullptr;
    }
    
    // 处理像素数据
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        auto* pixelData = static_cast<uint32_t*>(pixels);
        for (int y = 0; y < info.height; y++) {
            for (int x = 0; x < info.width; x++) {
                uint32_t pixel = pixelData[y * info.width + x];
                // 例如:将红色通道设为最大值
                pixel = (pixel & 0xFF00FFFF) | 0x00FF0000;
                pixelData[y * info.width + x] = pixel;
            }
        }
    }
    
    AndroidBitmap_unlockPixels(env, bitmap);
    return bitmap;
}

7.2 与Java对象交互

// 创建复杂的Java对象
jobject createComplexObject(JNIEnv* env) {
    // 创建HashMap
    jclass hashMapClass = env->FindClass("java/util/HashMap");
    jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
    jobject hashMap = env->NewObject(hashMapClass, hashMapConstructor);
    
    // 获取put方法
    jmethodID putMethod = env->GetMethodID(hashMapClass, "put", 
        "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    
    // 添加键值对
    jstring key1 = env->NewStringUTF("name");
    jstring value1 = env->NewStringUTF("张三");
    env->CallObjectMethod(hashMap, putMethod, key1, value1);
    
    jstring key2 = env->NewStringUTF("age");
    jobject value2 = env->NewObject(
        env->FindClass("java/lang/Integer"),
        env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"),
        25
    );
    env->CallObjectMethod(hashMap, putMethod, key2, value2);
    
    // 清理局部引用
    env->DeleteLocalRef(key1);
    env->DeleteLocalRef(value1);
    env->DeleteLocalRef(key2);
    env->DeleteLocalRef(value2);
    env->DeleteLocalRef(hashMapClass);
    
    return hashMap;
}

7.3 在Framework中的应用示例

// 模拟Android Framework中的JNI使用
class NativeHandler {
private:
    JavaVM* javaVM;
    jclass handlerClass;
    jmethodID callbackMethod;
    
public:
    NativeHandler() : javaVM(nullptr), handlerClass(nullptr), 
                     callbackMethod(nullptr) {}
    
    bool init(JavaVM* vm) {
        javaVM = vm;
        JNIEnv* env = getEnv();
        if (env == nullptr) return false;
        
        // 缓存Java类和方法ID
        handlerClass = static_cast<jclass>(env->NewGlobalRef(
            env->FindClass("android/os/Handler")));
        
        callbackMethod = env->GetMethodID(handlerClass, "handleMessage", 
                                         "(Landroid/os/Message;)V");
        
        return handlerClass != nullptr && callbackMethod != nullptr;
    }
    
    void sendMessageToJava(jobject handler, int what, jobject obj) {
        JNIEnv* env = getEnv();
        if (env == nullptr || handler == nullptr) return;
        
        // 创建Message对象
        jclass messageClass = env->FindClass("android/os/Message");
        jmethodID obtainMethod = env->GetStaticMethodID(messageClass, "obtain", 
                                                       "()Landroid/os/Message;");
        jobject message = env->CallStaticObjectMethod(messageClass, obtainMethod);
        
        // 设置Message内容
        jfieldID whatField = env->GetFieldID(messageClass, "what", "I");
        jfieldID objField = env->GetFieldID(messageClass, "obj", "Ljava/lang/Object;");
        
        env->SetIntField(message, whatField, what);
        env->SetObjectField(message, objField, obj);
        
        // 发送给Handler
        env->CallVoidMethod(handler, callbackMethod, message);
        
        // 清理
        env->DeleteLocalRef(messageClass);
        env->DeleteLocalRef(message);
    }
    
private:
    JNIEnv* getEnv() {
        JNIEnv* env = nullptr;
        if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
            return nullptr;
        }
        return env;
    }
};

八、调试与性能分析

8.1 JNI调试技巧

// 1. 启用CheckJNI
// 在adb shell中执行:
// setprop debug.checkjni 1
// 或adb shell setprop dalvik.vm.checkjni true

// 2. 使用__android_log_print
#include <android/log.h>

#define TAG "JNI_DEBUG"

void debugExample(JNIEnv* env) {
    __android_log_print(ANDROID_LOG_VERBOSE, TAG, "进入JNI函数");
    
    // 检查JNI调用错误
    if (env->ExceptionCheck()) {
        __android_log_print(ANDROID_LOG_ERROR, TAG, "JNI调用抛出异常");
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    
    __android_log_print(ANDROID_LOG_DEBUG, TAG, "退出JNI函数");
}

// 3. 使用jni.h中的调试函数
void jniDebugFunctions() {
    // 这些函数需要在CheckJNI启用时才有用
    // env->GetStringUTFChars(nullptr, nullptr); // 会触发CheckJNI警告
}

// 4. 使用addr2line解析崩溃堆栈
// arm-linux-androideabi-addr2line -e libnative-lib.so -f -C 0x12345678

8.2 性能测试

#include <chrono>

class JNIPerformanceTest {
public:
    static void testStringConversion(JNIEnv* env, jstring javaString, int iterations) {
        auto start = std::chrono::high_resolution_clock::now();
        
        for (int i = 0; i < iterations; i++) {
            const char* cstr = env->GetStringUTFChars(javaString, nullptr);
            // 模拟处理
            size_t len = strlen(cstr);
            env->ReleaseStringUTFChars(javaString, cstr);
        }
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        
        __android_log_print(ANDROID_LOG_INFO, "PERF_TEST", 
                           "String转换 %d次耗时: %lld微秒", 
                           iterations, duration.count());
    }
    
    static void testArrayAccess(JNIEnv* env, jintArray array, int iterations) {
        jsize length = env->GetArrayLength(array);
        
        auto start = std::chrono::high_resolution_clock::now();
        
        for (int iter = 0; iter < iterations; iter++) {
            // 方法1:使用GetIntArrayElements
            {
                jint* elements = env->GetIntArrayElements(array, nullptr);
                for (int i = 0; i < length; i++) {
                    elements[i] = elements[i] * 2;
                }
                env->ReleaseIntArrayElements(array, elements, 0);
            }
            
            // 方法2:使用GetIntArrayRegion/SetIntArrayRegion
            {
                std::vector<jint> buffer(length);
                env->GetIntArrayRegion(array, 0, length, buffer.data());
                for (auto& val : buffer) {
                    val /= 2;
                }
                env->SetIntArrayRegion(array, 0, length, buffer.data());
            }
        }
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        
        __android_log_print(ANDROID_LOG_INFO, "PERF_TEST", 
                           "数组访问 %d次耗时: %lld微秒", 
                           iterations, duration.count());
    }
};

九、常见问题与解决方案

9.1 JNI常见错误

// 错误1:JNI引用表溢出
void referenceTableOverflow(JNIEnv* env) {
    // ❌ 错误:创建太多局部引用不释放
    for (int i = 0; i < 1000; i++) {
        jstring str = env->NewStringUTF("test");
        // 忘记调用 env->DeleteLocalRef(str);
    }
    
    // ✅ 正确:及时释放局部引用
    for (int i = 0; i < 1000; i++) {
        jstring str = env->NewStringUTF("test");
        // 处理str...
        env->DeleteLocalRef(str);
    }
}

// 错误2:跨线程使用JNIEnv
void crossThreadJNIError(JavaVM* vm) {
    std::thread nativeThread([vm]() {
        // ❌ 错误:直接使用其他线程的JNIEnv
        // JNIEnv* env = ...;
        // env->NewStringUTF("error");
        
        // ✅ 正确:先附加线程
        JNIEnv* env = nullptr;
        vm->AttachCurrentThread(&env, nullptr);
        if (env != nullptr) {
            jstring str = env->NewStringUTF("correct");
            // 处理...
            env->DeleteLocalRef(str);
            vm->DetachCurrentThread();
        }
    });
    nativeThread.detach();
}

// 错误3:内存泄漏
void memoryLeakExample(JNIEnv* env) {
    // ❌ 错误:创建全局引用不释放
    jstring globalStr = static_cast<jstring>(env->NewGlobalRef(
        env->NewStringUTF("leak")));
    // 忘记调用 env->DeleteGlobalRef(globalStr);
    
    // ✅ 正确:使用RAII管理
    JNIGlobalRef<jstring> safeRef(env, env->NewStringUTF("safe"));
    // 自动管理生命周期
}

9.2 最佳实践总结

  1. 优先使用动态注册:代码更清晰,维护更方便
  2. 缓存常用ID:在JNI_OnLoad中缓存类引用和方法ID
  3. 及时释放引用:局部引用在不再使用时立即释放
  4. 使用RAII包装:自动管理资源生命周期
  5. 线程安全:每个线程使用自己的JNIEnv
  6. 异常检查:每次JNI调用后检查异常
  7. 性能优化:减少JNI调用次数,批量处理数据
  8. 启用CheckJNI:开发阶段启用CheckJNI检测错误

十、学习路径与资源

10.1 推荐学习路径

第一阶段:基础(1-2周)
    ├── JNI数据类型映射
    ├── 静态/动态注册
    ├── 基本类型操作
    └── 字符串处理

第二阶段:进阶(2-3周)
    ├── 数组操作
    ├── 对象操作与反射
    ├── 引用管理
    └── 异常处理

第三阶段:高级(3-4周)
    ├── 多线程JNI
    ├── 性能优化
    ├── Android特定集成
    └── 调试与测试

第四阶段:实战(持续)
    ├── 阅读Framework JNI代码
    ├── 实现复杂Native模块
    └── 性能调优与问题排查

10.2 学习资源

  1. 官方文档

  2. 开源项目

    • Android Framework源码(尤其看JNI部分)
    • android-ndk
  3. 调试工具

    • addr2line:解析Native崩溃堆栈
    • ndk-stack:自动符号化堆栈
    • AddressSanitizer:内存错误检测

10.3 实践项目建议

  1. 基础项目:实现Java与C++的字符串转换工具
  2. 中级项目:实现图像处理的JNI接口
  3. 高级项目:实现一个完整的Native计算模块,包含多线程和异常处理
  4. Framework项目:阅读并理解Android Framework中的关键JNI模块

通过系统学习和实践,你将能够熟练掌握JNI开发,为深入Android Framework开发打下坚实基础。