Android Runtime JNI接口规范实现原理(62)

86 阅读17分钟

码字不易,请大佬们点点关注,谢谢~

一、JNI概述与架构基础

1.1 JNI定义与核心作用

Java Native Interface(JNI)是Android Runtime(ART)的核心组件,它允许Java代码与本地代码(如C、C++)进行双向交互。JNI在Android系统中扮演着关键角色,其主要功能包括:

  • 实现Java与本地代码的方法调用转换
  • 管理Java与本地对象的生命周期映射
  • 提供Java类型与本地类型的转换机制
  • 处理跨语言异常传递

1.2 JNI架构层次

JNI架构分为三个主要层次:

  1. Java层:通过native关键字声明本地方法
  2. JNI层:定义标准接口规范,实现类型映射和方法调用
  3. 本地层:具体实现本地方法的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;
}

静态注册的核心步骤包括:

  1. 通过类名查找Java类对象
  2. 根据方法名和签名查找具体方法
  3. 将本地函数指针设置为方法的入口点

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.ccart/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的执行流程如下:

  1. 方法查找:在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);
    }
  }
}
  1. 参数传递:在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);
  }
  // 其他返回类型处理...
}
  1. 上下文切换:在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的执行流程如下:

  1. 查找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));
}
  1. 调用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();
}
  1. 方法执行:在art/runtime/interpreter/interpreter.ccart/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异常处理需要注意以下几点:

  1. 本地代码必须显式检查和处理异常
  2. 异常发生后,本地代码应避免继续执行可能依赖正常状态的操作
  3. 异常处理完成后,应清除异常状态
  4. 长时间运行的本地方法应定期检查异常状态

这些最佳实践确保了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通过多种机制确保内存安全,包括:

  1. 引用计数与垃圾回收:管理Java对象的生命周期,防止内存泄漏和悬空指针。

  2. 内存访问边界检查:在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;
}
  1. 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可能会引入更多性能优化技术,例如:

  1. 零拷贝数据传输:利用硬件特性实现Java堆和本地堆之间的零拷贝数据传输。

  2. 编译时JNI优化:在编译阶段分析JNI调用模式,生成更高效的代码。

  3. 向量化JNI调用:利用SIMD指令加速JNI数据处理。

10.3 安全性增强

随着安全威胁的增加,JNI的安全机制可能会进一步增强:

  1. 内存安全检查增强:引入更严格的内存访问检查,防止缓冲区溢出等安全漏洞。

  2. 沙箱隔离:对本地代码执行更严格的沙箱隔离,限制其访问权限。

  3. 动态权限控制:根据运行时上下文动态控制JNI方法的访问权限。

这些发展趋势将使JNI在保持灵活性的同时,进一步提升性能和安全性,更好地满足未来Android应用的需求。