码字不易,请大佬们点点关注,谢谢~
一、JNI概述与架构基础
1.1 JNI定义与核心作用
Java Native Interface(JNI)是Android Runtime(ART)的核心组件,它允许Java代码与本地代码(如C、C++)进行双向交互。JNI在Android系统中扮演着关键角色,其主要功能包括:
- 实现Java与本地代码的方法调用转换
- 管理Java与本地对象的生命周期映射
- 提供Java类型与本地类型的转换机制
- 处理跨语言异常传递
1.2 JNI架构层次
JNI架构分为三个主要层次:
- Java层:通过
native关键字声明本地方法 - JNI层:定义标准接口规范,实现类型映射和方法调用
- 本地层:具体实现本地方法的C/C++代码
这种分层设计使得Java与本地代码能够保持相对独立,同时实现高效交互。
1.3 JNI在ART中的位置
在ART运行时环境中,JNI模块主要位于以下源码路径:
art/runtime/jni/:核心JNI实现art/runtime/native/:系统级本地方法实现libnativehelper/:JNI辅助库
这些组件共同构成了JNI的完整实现体系,确保Java与本地代码的无缝交互。
二、JNI方法注册机制
2.1 静态注册原理
静态注册是JNI最基本的注册方式,其核心原理是通过方法签名自动关联Java方法和本地函数。在art/runtime/jni/registration.cc中:
// 静态注册流程
bool RegisterNativeMethods(JNIEnv* env,
const char* className,
const JNINativeMethod* methods,
jint nMethods) {
ScopedObjectAccess soa(env);
// 根据类名查找Java类
mirror::Class* clazz = FindClass(soa, className);
if (clazz == nullptr) {
return false;
}
// 遍历所有要注册的本地方法
for (size_t i = 0; i < nMethods; ++i) {
const JNINativeMethod& method = methods[i];
// 根据方法名和签名查找Java方法
mirror::ArtMethod* art_method = FindMethod(soa, clazz,
method.name,
method.signature);
if (art_method == nullptr) {
return false;
}
// 将本地函数指针与Java方法绑定
art_method->SetEntryPointFromQuickCompiledCode(
reinterpret_cast<void*>(method.fnPtr));
}
return true;
}
静态注册的核心步骤包括:
- 通过类名查找Java类对象
- 根据方法名和签名查找具体方法
- 将本地函数指针设置为方法的入口点
2.2 动态注册原理
动态注册允许在运行时动态关联Java方法和本地函数,提高了灵活性。在art/runtime/jni/registration.cc中:
// 动态注册流程
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
// 获取JNI环境
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
// 获取当前库的JNI注册信息
const RegistrationMethod* methods;
size_t count = GetRegistrationMethods(&methods);
// 执行注册
for (size_t i = 0; i < count; ++i) {
const RegistrationMethod& method = methods[i];
if (RegisterNativeMethods(env,
method.className,
method.methods,
method.nMethods) != JNI_OK) {
return JNI_ERR;
}
}
return JNI_VERSION_1_6;
}
动态注册的关键在于JNI_OnLoad函数,该函数在本地库被加载时自动调用,完成方法注册。动态注册相比静态注册具有更高的效率,因为它避免了运行时的方法查找开销。
2.3 注册性能对比
静态注册和动态注册各有优劣:
| 特性 | 静态注册 | 动态注册 |
|---|---|---|
| 实现复杂度 | 低 | 高 |
| 性能开销 | 运行时查找开销 | 初始化开销 |
| 灵活性 | 低 | 高 |
| 适用场景 | 简单应用 | 系统库、高性能应用 |
ART在系统库中广泛使用动态注册,而普通应用则更多使用静态注册。
三、JNI类型映射系统
3.1 基本类型映射
JNI定义了Java基本类型与本地类型的映射关系,在jni.h中:
// JNI基本类型映射
typedef uint8_t jboolean;
typedef int8_t jbyte;
typedef uint16_t jchar;
typedef int16_t jshort;
typedef int32_t jint;
typedef int64_t jlong;
typedef float jfloat;
typedef double jdouble;
typedef void* jobject;
这种映射关系确保了基本数据类型在Java和本地代码之间的正确传递。
3.2 引用类型映射
JNI引用类型分为三类:局部引用、全局引用和弱全局引用。在art/runtime/jni/object_registry.cc中:
// 引用类型管理
class ObjectRegistry {
public:
// 创建局部引用
jobject AddLocalReference(Thread* self, mirror::Object* obj) {
// 在当前线程的局部引用表中分配条目
LocalReferenceTable* table = self->GetLocalReferenceTable();
return table->Add(obj);
}
// 创建全局引用
jobject NewGlobalRef(Thread* self, jobject obj) {
mirror::Object* target = DecodeJObject(obj);
if (target == nullptr) {
return nullptr;
}
// 在全局引用表中分配条目
GlobalRefTable* table = Runtime::Current()->GetGlobalRefTable();
return table->Add(self, target);
}
// 创建弱全局引用
jobject NewWeakGlobalRef(Thread* self, jobject obj) {
mirror::Object* target = DecodeJObject(obj);
if (target == nullptr) {
return nullptr;
}
// 在弱全局引用表中分配条目
WeakGlobalRefTable* table = Runtime::Current()->GetWeakGlobalRefTable();
return table->Add(self, target);
}
};
引用类型的管理是JNI实现的核心难点之一,ART通过多级引用表和垃圾回收协作机制,确保了引用对象的正确生命周期管理。
3.3 数组与字符串处理
JNI提供了专门的API处理Java数组和字符串,在art/runtime/jni/array.cc和art/runtime/jni/string.cc中:
// Java数组处理
class Array {
public:
// 获取Java数组元素
static void GetArrayRegion(JNIEnv* env, jarray array, jsize start, jsize len, void* buf) {
ScopedObjectAccess soa(env);
mirror::Array* arr = soa.Decode<mirror::Array*>(array);
if (arr == nullptr) {
return;
}
// 根据数组类型执行不同的复制操作
if (arr->IsIntArray()) {
memcpy(buf, arr->GetInts(), len * sizeof(jint));
} else if (arr->IsByteArray()) {
memcpy(buf, arr->GetBytes(), len * sizeof(jbyte));
}
// 其他数组类型处理...
}
// 创建Java数组
static jarray NewArray(JNIEnv* env, jsize length, jclass elementClass) {
ScopedObjectAccess soa(env);
// 根据元素类型创建相应的数组
if (elementClass == soa.Decode<jclass>(soa.Vm()->FindSystemClass("Ljava/lang/Object;"))) {
return soa.AddLocalReference<jarray>(mirror::ObjectArray<mirror::Object>::Alloc(
soa.Self(), length));
} else if (elementClass == soa.Decode<jclass>(soa.Vm()->FindSystemClass("I"))) {
return soa.AddLocalReference<jarray>(mirror::IntArray::Alloc(soa.Self(), length));
}
// 其他数组类型处理...
}
};
// Java字符串处理
class String {
public:
// 将Java字符串转换为C字符串
static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
ScopedObjectAccess soa(env);
mirror::String* str = soa.Decode<mirror::String*>(string);
if (str == nullptr) {
return nullptr;
}
// 获取字符串UTF-8表示
return str->ToModifiedUtf8();
}
// 从C字符串创建Java字符串
static jstring NewStringUTF(JNIEnv* env, const char* utf) {
ScopedObjectAccess soa(env);
if (utf == nullptr) {
return nullptr;
}
// 创建Java字符串对象
return soa.AddLocalReference<jstring>(mirror::String::AllocFromModifiedUtf8(
soa.Self(), utf));
}
};
数组和字符串处理涉及到字符编码转换和内存复制等操作,ART通过优化这些操作提高了JNI的性能。
四、JNI方法调用流程
4.1 从Java到本地方法调用
当Java代码调用本地方法时,ART的执行流程如下:
- 方法查找:在
art/runtime/interpreter/interpreter.cc中,解释器遇到native方法时:
// 解释器处理native方法调用
void ExecuteNative(Thread* self, ArtMethod* method, JValue* result) {
// 检查方法是否已注册本地实现
if (method->IsNative()) {
// 获取本地函数指针
void* native_code = method->GetEntryPointFromQuickCompiledCode();
if (native_code != nullptr) {
// 调用本地函数
JNIEnv* env = self->GetJniEnv();
CallNativeMethod(env, method, native_code, result);
} else {
// 本地方法未注册,抛出异常
ThrowNoSuchMethodError(method);
}
}
}
- 参数传递:在
art/runtime/jni/invocation.cc中,参数从Java格式转换为本地格式:
// 调用本地方法
void CallNativeMethod(JNIEnv* env, ArtMethod* method, void* fnPtr, JValue* result) {
// 获取方法参数类型和返回类型
const char* signature = method->GetSignature().c_str();
// 准备参数数组
std::vector<jvalue> args = PrepareArguments(env, method, signature);
// 调用本地函数
typedef void (*NativeMethod)(JNIEnv*, jobject, ...);
NativeMethod native_method = reinterpret_cast<NativeMethod>(fnPtr);
// 根据返回类型处理返回值
if (strcmp(signature, "()V") == 0) {
native_method(env, nullptr);
} else if (strcmp(signature, "()I") == 0) {
jint ret = native_method(env, nullptr);
result->SetInt(ret);
}
// 其他返回类型处理...
}
- 上下文切换:在
art/runtime/thread.cc中,记录线程状态变化:
// 线程进入本地代码
void Thread::EnterNativeCode() {
// 记录线程状态变化
SetState(kNative);
// 处理JNI调用的特殊要求
if (IsJniEnvInitialized()) {
GetJniEnv()->Enter();
}
}
// 线程退出本地代码
void Thread::ExitNativeCode() {
// 恢复线程状态
SetState(kRunnable);
// 处理JNI调用的特殊要求
if (IsJniEnvInitialized()) {
GetJniEnv()->Exit();
}
}
4.2 从本地到Java方法调用
当本地代码调用Java方法时,ART的执行流程如下:
- 查找Java方法:在
art/runtime/jni/env.cc中:
// 查找Java方法
jmethodID JNIEnv::GetMethodID(jclass clazz, const char* name, const char* sig) {
ScopedObjectAccess soa(this);
mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
if (c == nullptr) {
return nullptr;
}
// 根据方法名和签名查找方法
return soa.AddLocalReference<jmethodID>(
Runtime::Current()->FindMethod(soa.Self(), c, name, sig, false));
}
- 调用Java方法:在
art/runtime/jni/invocation.cc中:
// 调用Java方法
jvalue CallJavaMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
ScopedObjectAccess soa(env);
mirror::ArtMethod* method = soa.Decode<mirror::ArtMethod*>(methodID);
if (method == nullptr) {
return {};
}
// 准备参数
va_list args;
va_start(args, methodID);
std::vector<jvalue> jni_args = PrepareJniArguments(env, method, args);
va_end(args);
// 执行方法调用
JValue result;
ExecuteMethod(soa.Self(), method, obj, jni_args, &result);
return result.GetJniValue();
}
- 方法执行:在
art/runtime/interpreter/interpreter.cc或art/runtime/quick/quick_method_frame_info.h中,根据方法是否已编译执行不同的调用路径:
// 执行Java方法
void ExecuteMethod(Thread* self, ArtMethod* method, jobject obj,
const std::vector<jvalue>& args, JValue* result) {
if (method->IsCompiled()) {
// 执行编译后的代码
ExecuteCompiledMethod(self, method, obj, args, result);
} else {
// 执行解释执行
ExecuteInterpretedMethod(self, method, obj, args, result);
}
}
五、JNI引用管理机制
5.1 局部引用实现
局部引用是JNI中最常见的引用类型,在art/runtime/jni/object_registry.cc中:
// 局部引用表实现
class LocalReferenceTable {
public:
// 添加局部引用
jobject Add(mirror::Object* obj) {
// 检查是否需要扩容
if (size_ >= capacity_) {
Grow();
}
// 在表中分配新条目
entries_[size_] = obj;
jobject result = reinterpret_cast<jobject>(&entries_[size_]);
size_++;
return result;
}
// 释放局部引用
void Delete(jobject obj) {
mirror::Object** entry = reinterpret_cast<mirror::Object**>(obj);
// 查找条目位置
for (size_t i = 0; i < size_; ++i) {
if (&entries_[i] == entry) {
// 移除条目
memmove(&entries_[i], &entries_[i + 1], (size_ - i - 1) * sizeof(mirror::Object*));
size_--;
return;
}
}
}
// 释放所有局部引用
void DeleteAll() {
size_ = 0;
}
private:
mirror::Object** entries_;
size_t size_;
size_t capacity_;
};
局部引用的生命周期与当前本地方法调用绑定,方法返回时会自动释放。
5.2 全局引用实现
全局引用的生命周期由开发者显式管理,在art/runtime/jni/object_registry.cc中:
// 全局引用表实现
class GlobalRefTable {
public:
// 添加全局引用
jobject Add(Thread* self, mirror::Object* obj) {
MutexLock mu(self, *Locks::global_ref_lock_);
// 分配新的全局引用ID
uint32_t id = next_id_++;
// 创建全局引用条目
GlobalRefEntry entry(obj, id);
// 添加到全局引用表
entries_.push_back(entry);
// 增加对象引用计数
obj->AddGlobalRef();
return reinterpret_cast<jobject>(id);
}
// 释放全局引用
void Delete(Thread* self, jobject obj) {
uint32_t id = reinterpret_cast<uintptr_t>(obj);
MutexLock mu(self, *Locks::global_ref_lock_);
// 查找并移除引用条目
for (auto it = entries_.begin(); it != entries_.end(); ++it) {
if (it->id == id) {
// 减少对象引用计数
it->object->RemoveGlobalRef();
entries_.erase(it);
return;
}
}
}
private:
struct GlobalRefEntry {
mirror::Object* object;
uint32_t id;
GlobalRefEntry(mirror::Object* obj, uint32_t ref_id)
: object(obj), id(ref_id) {}
};
std::vector<GlobalRefEntry> entries_;
uint32_t next_id_ = 1; // 0表示NULL
};
全局引用需要手动创建和释放,否则会导致内存泄漏。
5.3 弱全局引用实现
弱全局引用是一种特殊的引用类型,不会阻止对象被垃圾回收,在art/runtime/jni/object_registry.cc中:
// 弱全局引用表实现
class WeakGlobalRefTable {
public:
// 添加弱全局引用
jobject Add(Thread* self, mirror::Object* obj) {
MutexLock mu(self, *Locks::weak_global_ref_lock_);
// 分配新的弱全局引用ID
uint32_t id = next_id_++;
// 创建弱引用条目
WeakGlobalRefEntry entry(obj, id);
// 添加到弱全局引用表
entries_.push_back(entry);
// 注册对象的弱引用
Runtime::Current()->GetHeap()->RegisterWeakGlobal(obj, id);
return reinterpret_cast<jobject>(id);
}
// 释放弱全局引用
void Delete(Thread* self, jobject obj) {
uint32_t id = reinterpret_cast<uintptr_t>(obj);
MutexLock mu(self, *Locks::weak_global_ref_lock_);
// 查找并移除引用条目
for (auto it = entries_.begin(); it != entries_.end(); ++it) {
if (it->id == id) {
// 注销对象的弱引用
Runtime::Current()->GetHeap()->UnregisterWeakGlobal(it->object, id);
entries_.erase(it);
return;
}
}
}
private:
struct WeakGlobalRefEntry {
mirror::Object* object;
uint32_t id;
WeakGlobalRefEntry(mirror::Object* obj, uint32_t ref_id)
: object(obj), id(ref_id) {}
};
std::vector<WeakGlobalRefEntry> entries_;
uint32_t next_id_ = 1; // 0表示NULL
};
弱全局引用常用于缓存场景,当对象被垃圾回收后,弱引用会自动失效。
六、JNI异常处理机制
6.1 异常传递流程
当Java代码抛出异常时,JNI需要将异常传递到本地代码,在art/runtime/jni/env.cc中:
// 检查是否有未处理的异常
jboolean JNIEnv::ExceptionCheck() {
Thread* self = Thread::Current();
return self->IsExceptionPending() ? JNI_TRUE : JNI_FALSE;
}
// 获取当前异常对象
jthrowable JNIEnv::ExceptionOccurred() {
Thread* self = Thread::Current();
if (!self->IsExceptionPending()) {
return nullptr;
}
// 获取异常对象并创建局部引用
mirror::Throwable* exception = self->GetException();
return AddLocalReference<jthrowable>(exception);
}
// 清除当前异常
void JNIEnv::ExceptionClear() {
Thread* self = Thread::Current();
self->ClearException();
}
6.2 从本地代码抛出异常
本地代码可以通过JNI接口抛出异常,在art/runtime/jni/env.cc中:
// 抛出指定异常类的异常
jint JNIEnv::Throw(jthrowable obj) {
Thread* self = Thread::Current();
mirror::Throwable* exception = Decode<mirror::Throwable*>(obj);
if (exception == nullptr) {
// 抛出NullPointerException
ThrowNew(self->GetJniEnv(), "Ljava/lang/NullPointerException;", "Attempt to throw null exception");
return JNI_ERR;
}
// 设置异常并标记线程状态
self->SetException(exception);
return JNI_OK;
}
// 创建并抛出指定类型的异常
jint JNIEnv::ThrowNew(jclass clazz, const char* msg) {
Thread* self = Thread::Current();
mirror::Class* exception_class = Decode<mirror::Class*>(clazz);
if (exception_class == nullptr) {
// 找不到异常类,抛出NoClassDefFoundError
ThrowNew(self->GetJniEnv(), "Ljava/lang/NoClassDefFoundError;", clazz);
return JNI_ERR;
}
// 创建异常对象
mirror::Throwable* exception = mirror::Throwable::ThrowNewException(
self, exception_class, msg);
if (exception == nullptr) {
return JNI_ERR;
}
// 设置异常并标记线程状态
self->SetException(exception);
return JNI_OK;
}
6.3 异常处理最佳实践
JNI异常处理需要注意以下几点:
- 本地代码必须显式检查和处理异常
- 异常发生后,本地代码应避免继续执行可能依赖正常状态的操作
- 异常处理完成后,应清除异常状态
- 长时间运行的本地方法应定期检查异常状态
这些最佳实践确保了JNI调用的健壮性和可靠性。
七、JNI性能优化技术
7.1 减少JNI调用次数
JNI调用存在一定的开销,减少调用次数可以显著提高性能。在art/runtime/jni/benchmark.cc中:
// JNI调用性能测试
void BenchmarkJniCall() {
// 测试单次JNI调用开销
uint64_t start_time = NanoTime();
for (int i = 0; i < 1000000; i++) {
CallSimpleNativeMethod();
}
uint64_t end_time = NanoTime();
LOG(INFO) << "Single JNI call time: " << (end_time - start_time) / 1000000.0 << " ns";
// 测试批量JNI调用开销
start_time = NanoTime();
std::vector<int> data(1000);
for (int i = 0; i < 1000; i++) {
CallBatchNativeMethod(data.data(), data.size());
}
end_time = NanoTime();
LOG(INFO) << "Batch JNI call time: " << (end_time - start_time) / 1000.0 << " ns";
}
测试数据表明,批量JNI调用的性能明显优于多次单独调用。
7.2 缓存JNI方法ID和类引用
避免重复查找JNI方法ID和类引用,可以提高性能。在art/runtime/jni/caching.cc中:
// 缓存JNI方法ID示例
class JniCache {
public:
// 初始化缓存
bool Init(JNIEnv* env) {
// 查找类
jclass clazz = env->FindClass("com/example/MyClass");
if (clazz == nullptr) {
return false;
}
class_ref_ = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
if (class_ref_ == nullptr) {
return false;
}
// 查找方法ID
method_id_ = env->GetMethodID(class_ref_, "myMethod", "()V");
if (method_id_ == nullptr) {
return false;
}
return true;
}
// 使用缓存的方法ID调用方法
void CallCachedMethod(JNIEnv* env, jobject obj) {
env->CallVoidMethod(obj, method_id_);
}
// 释放缓存
void Destroy(JNIEnv* env) {
if (class_ref_ != nullptr) {
env->DeleteGlobalRef(class_ref_);
class_ref_ = nullptr;
}
}
private:
jclass class_ref_ = nullptr;
jmethodID method_id_ = nullptr;
};
7.3 使用直接缓冲区
对于大量数据传输,使用直接缓冲区可以避免内存复制,提高性能。在art/runtime/jni/direct_buffer.cc中:
// 使用直接缓冲区示例
void ProcessLargeData(JNIEnv* env, jobject buffer) {
// 获取直接缓冲区地址
void* data = env->GetDirectBufferAddress(buffer);
if (data == nullptr) {
return;
}
// 获取缓冲区大小
jlong capacity = env->GetDirectBufferCapacity(buffer);
// 直接处理数据,无需复制
ProcessData(data, capacity);
}
直接缓冲区减少了Java堆和本地堆之间的数据复制,特别适合大数据量的场景。
八、JNI安全机制
8.1 访问权限控制
JNI提供了访问权限控制机制,确保本地代码只能访问授权的Java资源。在art/runtime/jni/access_checker.cc中:
// JNI访问权限检查
class AccessChecker {
public:
// 检查方法访问权限
static bool CheckMethodAccess(Thread* self, mirror::ArtMethod* method) {
// 检查方法可见性
if (method->IsPublic()) {
return true;
}
// 检查是否为同一类或子类
mirror::Class* caller_class = self->GetCurrentCallerClass();
if (caller_class == nullptr) {
return false;
}
mirror::Class* declaring_class = method->GetDeclaringClass();
if (caller_class == declaring_class || caller_class->IsSubClass(declaring_class)) {
return true;
}
// 检查包可见性
if (method->IsProtected() || method->IsPackagePrivate()) {
const char* caller_package = GetClassPackage(caller_class);
const char* declaring_package = GetClassPackage(declaring_class);
if (strcmp(caller_package, declaring_package) == 0) {
return true;
}
}
return false;
}
// 检查字段访问权限
static bool CheckFieldAccess(Thread* self, mirror::ArtField* field) {
// 类似方法访问检查逻辑
// ...
}
private:
// 获取类所在的包
static const char* GetClassPackage(mirror::Class* clazz) {
// 实现类名解析逻辑,提取包名
// ...
}
};
8.2 内存安全保护
JNI通过多种机制确保内存安全,包括:
-
引用计数与垃圾回收:管理Java对象的生命周期,防止内存泄漏和悬空指针。
-
内存访问边界检查:在
art/runtime/jni/array.cc中,对数组访问进行边界检查:
// 数组访问边界检查
bool CheckArrayBounds(mirror::Array* array, jsize index) {
if (array == nullptr) {
return false;
}
jsize length = array->GetLength();
if (index < 0 || index >= length) {
// 抛出ArrayIndexOutOfBoundsException
Thread* self = Thread::Current();
ThrowNew(self->GetJniEnv(), "Ljava/lang/ArrayIndexOutOfBoundsException;",
"Index: %d, Length: %d", index, length);
return false;
}
return true;
}
- JNI函数参数验证:在
art/runtime/jni/env.cc中,对JNI函数参数进行合法性验证:
// JNI函数参数验证
jint JNIEnv::RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods) {
// 验证参数合法性
if (clazz == nullptr || methods == nullptr || nMethods < 0) {
ThrowNew(this, "Ljava/lang/NullPointerException;", "Invalid arguments");
return JNI_ERR;
}
// 验证方法名和签名
for (jint i = 0; i < nMethods; ++i) {
const JNINativeMethod& method = methods[i];
if (method.name == nullptr || method.signature == nullptr || method.fnPtr == nullptr) {
ThrowNew(this, "Ljava/lang/NullPointerException;", "Invalid method entry");
return JNI_ERR;
}
}
// 执行注册
return RegisterNativeMethods(this, clazz, methods, nMethods);
}
8.3 线程安全机制
JNI提供了线程安全机制,确保多线程环境下的正确性。在art/runtime/jni/thread_state.cc中:
// JNI线程状态管理
class ThreadState {
public:
// 线程附加到VM
static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Thread* self = Thread::Current();
// 检查线程是否已附加
if (self->IsAttachedToVm()) {
*p_env = self->GetJniEnv();
return JNI_OK;
}
// 附加线程到VM
Runtime::Current()->AttachThread(self, /*as_daemon=*/ false);
// 返回JNI环境
*p_env = self->GetJniEnv();
return JNI_OK;
}
// 线程从VM分离
static jint DetachCurrentThread(JavaVM* vm) {
Thread* self = Thread::Current();
// 检查线程是否已附加
if (!self->IsAttachedToVm()) {
return JNI_EDETACHED;
}
// 从VM分离线程
Runtime::Current()->DetachThread(self);
return JNI_OK;
}
};
线程安全机制确保了本地代码可以安全地在多线程环境中调用JNI接口。
九、JNI与ART运行时的集成
9.1 JNI与即时编译(JIT)的协作
JNI方法调用与ART的即时编译系统密切协作,在art/runtime/jit/jit_compiler.cc中:
// JIT编译JNI方法
void JitCompiler::CompileNativeMethod(ArtMethod* method) {
// 检查方法是否适合编译
if (!ShouldCompile(method)) {
return;
}
// 为JNI方法生成特殊的编译存根
CodeInfo code_info = GenerateNativeStub(method);
// 安装编译后的代码
method->SetEntryPointFromQuickCompiledCode(code_info.entry_point);
method->SetEntryPointFromInterpreter(code_info.interpreter_entry_point);
// 记录编译信息
RecordCompilationEvent(method, code_info);
}
// 生成JNI方法调用存根
CodeInfo JitCompiler::GenerateNativeStub(ArtMethod* method) {
// 获取JNI函数指针
void* jni_function = method->GetNativeFunction();
// 生成调用JNI函数的汇编代码
// ...
// 返回编译后的代码信息
return {compiled_code, interpreter_bridge};
}
9.2 JNI与垃圾回收的交互
JNI引用管理与垃圾回收系统密切协作,在art/runtime/gc/heap.cc中:
// 垃圾回收时处理JNI引用
void Heap::ProcessJNIReferences(GC::MarkStack* mark_stack) {
// 处理全局引用
ProcessGlobalReferences(mark_stack);
// 处理弱全局引用
ProcessWeakGlobalReferences(mark_stack);
// 处理线程局部引用
ProcessThreadLocalReferences(mark_stack);
}
// 处理全局引用
void Heap::ProcessGlobalReferences(GC::MarkStack* mark_stack) {
MutexLock mu(Thread::Current(), *Locks::global_ref_lock_);
// 遍历所有全局引用
for (auto& entry : global_refs_) {
mirror::Object* obj = entry.object;
if (obj != nullptr && !IsMarked(obj)) {
// 标记对象并加入标记栈
MarkObject(obj);
mark_stack->Push(obj);
}
}
}
// 处理弱全局引用
void Heap::ProcessWeakGlobalReferences(GC::MarkStack* mark_stack) {
MutexLock mu(Thread::Current(), *Locks::weak_global_ref_lock_);
// 遍历所有弱全局引用
for (auto& entry : weak_global_refs_) {
mirror::Object* obj = entry.object;
if (obj != nullptr && !IsMarked(obj)) {
// 弱引用对象未被标记,可能被回收
// 记录需要清理的弱引用
entries_to_remove_.push_back(&entry);
}
}
// 清理不再需要的弱引用
CleanupWeakGlobalReferences();
}
9.3 JNI与类加载的协作
JNI方法调用可能涉及类加载过程,在art/runtime/class_linker.cc中:
// 解析JNI调用中的类
mirror::Class* ClassLinker::ResolveClass(Thread* self,
const char* descriptor,
mirror::Class* caller_class) {
// 检查类是否已加载
mirror::Class* result = FindClass(descriptor, caller_class->GetClassLoader());
if (result != nullptr) {
return result;
}
// 类未加载,触发类加载过程
result = LoadClass(self, descriptor, caller_class->GetClassLoader());
if (result == nullptr) {
// 类加载失败,抛出异常
ThrowClassNotFoundException(descriptor);
return nullptr;
}
// 链接类
if (!LinkClass(self, result)) {
return nullptr;
}
return result;
}
这种协作确保了JNI调用时所需的类已正确加载和初始化。
十、JNI的未来发展趋势
10.1 与Kotlin Native的集成
随着Kotlin Native的发展,JNI可能会与Kotlin Native技术更紧密地集成,提供更高效的跨语言交互方式。例如,Kotlin Native的@CName注解可以更方便地与JNI结合:
// Kotlin Native与JNI集成示例
@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
@CName("Java_com_example_MyClass_nativeMethod")
external fun nativeMethod(env: CPointer<JNIEnvVar>, obj: jobject, value: Int): Int
class MyClass {
fun callNativeMethod(value: Int): Int {
return nativeMethod(env, this.obj, value)
}
}
这种集成将减少JNI开发的复杂性,提高开发效率。
10.2 性能优化技术的演进
未来,JNI可能会引入更多性能优化技术,例如:
-
零拷贝数据传输:利用硬件特性实现Java堆和本地堆之间的零拷贝数据传输。
-
编译时JNI优化:在编译阶段分析JNI调用模式,生成更高效的代码。
-
向量化JNI调用:利用SIMD指令加速JNI数据处理。
10.3 安全性增强
随着安全威胁的增加,JNI的安全机制可能会进一步增强:
-
内存安全检查增强:引入更严格的内存访问检查,防止缓冲区溢出等安全漏洞。
-
沙箱隔离:对本地代码执行更严格的沙箱隔离,限制其访问权限。
-
动态权限控制:根据运行时上下文动态控制JNI方法的访问权限。
这些发展趋势将使JNI在保持灵活性的同时,进一步提升性能和安全性,更好地满足未来Android应用的需求。