Jni数据转换

数据转换总结

graph TB
jstring-->|soa.decode|mirror::String*
mirror::String*-->|encode/AddLocalReference|jstring
mirror::String*-->char*
char*-->|mirror::String::AllocFromModifiedUtf8|mirror::String*
jmethodid-->|decode|ArtMethod*
ArtMethod*-->|encode|jmethodid
jobject("jobject/IndirectRef")-->|decode|mirrorObject("art::mirror::Object*")
mirrorObject-->|Assign/Compress|StackReference("art::StackReference<mirror::Object>*")
StackReference-->|AsMirrorPtr/UnCompress|mirrorObject
StackReference-->|OwnedBy|Handle("art::Handle~T~")
StackHandleScope-->|Provided|Handle
StackHandleScope-->|OwnsMulti|StackReference
ThreadTlsPtr-->|OwnsLinkedList|StackHandleScope
mirrorObject-->|encode|jobject

HandleScope的作用

image-20210211084129068

类设计

//8.2.2 ScopedObjectAccess等辅助类

ScopedObjectAccessAlreadyRunnable

DecodeMethod

  ArtMethod* DecodeMethod(jmethodID mid) const SHARED_REQUIRES(Locks::mutator_lock_) {
    Locks::mutator_lock_->AssertSharedHeld(Self());
    return reinterpret_cast<ArtMethod*>(mid);//main
  }

EncodeMethod

  jmethodID EncodeMethod(ArtMethod* method) const SHARED_REQUIRES(Locks::mutator_lock_) {
    Locks::mutator_lock_->AssertSharedHeld(Self());
    return reinterpret_cast<jmethodID>(method);//main
  }

T AddLocalReference(mirror::Object* obj)

  /*
   * Add a local reference for an object to the indirect reference table associated with the
   * current stack frame.  When the native function returns, the reference will be discarded.
   *
   * We need to allow the same reference to be added multiple times, and cope with nullptr.
   *
   * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
   * it's best if we don't grab a mutex.
   */
  template<typename T>
  T AddLocalReference(mirror::Object* obj) const SHARED_REQUIRES(Locks::mutator_lock_) {
    return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
  }

T Decode(jobject obj)

  template<typename T>
  T Decode(jobject obj) const
      SHARED_REQUIRES(Locks::mutator_lock_) {
    Locks::mutator_lock_->AssertSharedHeld(Self());
    return down_cast<T>(Self()->DecodeJObject(obj));//main
  }

jni_env_ext(-inl.h).h

AddLocalReference

// JNI local references.
IndirectReferenceTable locals GUARDED_BY(Locks::mutator_lock_);

template<typename T>
inline T JNIEnvExt::AddLocalReference(mirror::Object* obj) {
    IndirectRef ref = locals.Add(local_ref_cookie, obj);
    return reinterpret_cast<T>(ref);
}

libnativehelper/include_jni/jni.h

jni.h

类型定义

/* Primitive types that match up with Java equivalents. */
typedef uint8_t  jboolean; /* unsigned 8 bits */
typedef int8_t   jbyte;    /* signed 8 bits */
typedef uint16_t jchar;    /* unsigned 16 bits */
typedef int16_t  jshort;   /* signed 16 bits */
typedef int32_t  jint;     /* signed 32 bits */
typedef int64_t  jlong;    /* signed 64 bits */
typedef float    jfloat;   /* 32-bit IEEE 754 */
typedef double   jdouble;  /* 64-bit IEEE 754 */

/* "cardinal indices and sizes" */
typedef jint     jsize;

class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};

typedef _jobject*       jobject;
typedef _jclass*        jclass;
typedef _jstring*       jstring;
typedef _jarray*        jarray;
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;
typedef _jthrowable*    jthrowable;
typedef _jobject*       jweak;


struct _jfieldID;                       /* opaque structure */
typedef struct _jfieldID* jfieldID;     /* field IDs */

struct _jmethodID;                      /* opaque structure */
typedef struct _jmethodID* jmethodID;   /* method IDs */

JNINativeMethod

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

NewObject

jobject NewObject(jclass clazz, jmethodID methodID, ...)
 {
   va_list args;
   va_start(args, methodID);
   jobject result = functions->NewObjectV(this, clazz, methodID, args);
   va_end(args);
   return result;
 }

libnativehelper/platform_include/nativehelper/jni_macros.h

NATIVE_METHOD

#define NATIVE_METHOD(className, functionName, signature)                \
  MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) //java方法对应的native实现函数方法名规范

art/runtime/jni_internal.cc

jni_internal.cc

GetStringUTFChars

static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
  if (is_copy != nullptr) {
    *is_copy = JNI_TRUE;
  }
  ScopedObjectAccess soa(env);
  ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
  size_t byte_count = s->GetUtfLength();
  char* bytes = new char[byte_count + 1];
  CHECK(bytes != nullptr);  // bionic aborts anyway.
  if (s->IsCompressed()) {
    for (size_t i = 0; i < byte_count; ++i) {
      bytes[i] = s->CharAt(i);
    }
  } else {
    const uint16_t* chars = s->GetValue();
    ConvertUtf16ToModifiedUtf8(bytes, byte_count, chars, s->GetLength());
  }
  bytes[byte_count] = '\0';
  return bytes;
}

ReleaseStringUTFChars

  static void ReleaseStringUTFChars(JNIEnv*, jstring, const char* chars) {
    delete[] chars;
  }

NewStringUTF

  static jstring NewStringUTF(JNIEnv* env, const char* utf) {
    if (utf == nullptr) {
      return nullptr;
    }
    ScopedObjectAccess soa(env);
    mirror::String* result = mirror::String::AllocFromModifiedUtf8(soa.Self(), utf);
    return soa.AddLocalReference<jstring>(result);
  }

NewObjectV

  static jobject NewObjectV(JNIEnv* env, jclass java_class, jmethodID mid, va_list args) {
    CHECK_NON_NULL_ARGUMENT(java_class);
    CHECK_NON_NULL_ARGUMENT(mid);
    ScopedObjectAccess soa(env);
    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
    if (c == nullptr) {
      return nullptr;
    }
    if (c->IsStringClass()) {
      // Replace calls to String.<init> with equivalent StringFactory call.
      jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
      return CallStaticObjectMethodV(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
    }
    mirror::Object* result = c->AllocObject(soa.Self());
    if (result == nullptr) {
      return nullptr;
    }
    jobject local_result = soa.AddLocalReference<jobject>(result);
    CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
    if (soa.Self()->IsExceptionPending()) {
      return nullptr;
    }
    return local_result;
 

art/runtime/thread.cc

thread.cc

GetTopHandleScope

  HandleScope* GetTopHandleScope() {
    return tlsPtr_.top_handle_scope;
  }

PushHandleScope

  void PushHandleScope(HandleScope* handle_scope) {
    DCHECK_EQ(handle_scope->GetLink(), tlsPtr_.top_handle_scope);
    tlsPtr_.top_handle_scope = handle_scope;
  }

DecodeJObject

ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {
  if (obj == nullptr) {
    return nullptr;
  }
  //将jobject转换为IndirectRef
  IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
  IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(ref);
  ObjPtr<mirror::Object> result;
  bool expect_null = false;
  // The "kinds" below are sorted by the frequency we expect to encounter them.
  if (kind == kLocal) {//如果是local型引用,则从local的IRTable中找到对应的对象
    IndirectReferenceTable& locals = tlsPtr_.jni_env->locals_;
    // Local references do not need a read barrier.
    result = locals.Get<kWithoutReadBarrier>(ref);
  } else if (kind == kHandleScopeOrInvalid) {
    // TODO: make stack indirect reference table lookup more efficient.
    // Check if this is a local reference in the handle scope.
    if (LIKELY(HandleScopeContains(obj))) {
      //如果是栈上传递过来的对象(如方法参数),则可以直接转换成mirror Object对象
      // Read from handle scope.
      result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
      VerifyObject(result);
    } else {
      tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of invalid jobject %p", obj);
      expect_null = true;
      result = nullptr;
    }
  } else if (kind == kGlobal) {
    //对Global型对象的处理,想必是要交给JavaVMExt globals_来处理
    result = tlsPtr_.jni_env->vm_->DecodeGlobal(ref);
  } else {//对WeakGlobal型对象的处理,如果该对象已经回收,则返回nullptr
    DCHECK_EQ(kind, kWeakGlobal);
    result = tlsPtr_.jni_env->vm_->DecodeWeakGlobal(const_cast<Thread*>(this), ref);
    if (Runtime::Current()->IsClearedJniWeakGlobal(result)) {
       //对象被回收了,所以返回nullptr
      // This is a special case where it's okay to return null.
      expect_null = true;
      result = nullptr;
    }
  }

  if (UNLIKELY(!expect_null && result == nullptr)) {
    tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of deleted %s %p",
                                   ToStr<IndirectRefKind>(kind).c_str(), obj);
  }
  return result;
}

indirect_reference_table(-inl).h

  IrtEntry* const table_;
  size_t i_;
  const size_t capacity_;

Get

template<ReadBarrierOption kReadBarrierOption>
inline mirror::Object* IndirectReferenceTable::Get(IndirectRef iref) const {
  if (!GetChecked(iref)) {
    return nullptr;
  }
  uint32_t idx = ExtractIndex(iref);
  mirror::Object* obj = table_[idx].GetReference()->Read<kReadBarrierOption>();
  VerifyObject(obj);
  return obj;
}

Add

IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
  // We know there's enough room in the table.  Now we just need to find
  // the right spot.  If there's a hole, find it and fill it; otherwise,
  // add to the end of the list.
  IndirectRef result;
......
  table_[index].Add(obj);
  result = ToIndirectRef(index);
return result;

ToIndirectRef

  /*
   * The object pointer itself is subject to relocation in some GC
   * implementations, so we shouldn't really be using it here.
   */
  IndirectRef ToIndirectRef(uint32_t tableIndex) const {
    DCHECK_LT(tableIndex, 65536U);
    uint32_t serialChunk = table_[tableIndex].GetSerial();
    uintptr_t uref = (serialChunk << 20) | (tableIndex << 2) | kind_;
    return reinterpret_cast<IndirectRef>(uref);
  }

class IrtEntry

class IrtEntry {
  void Add(mirror::Object* obj) SHARED_REQUIRES(Locks::mutator_lock_) {
    ++serial_;
    if (serial_ == kIRTPrevCount) {
      serial_ = 0;
    }
    references_[serial_] = GcRoot<mirror::Object>(obj);
  }

  GcRoot<mirror::Object>* GetReference() {
    DCHECK_LT(serial_, kIRTPrevCount);
    return &references_[serial_];
  }

  void SetReference(mirror::Object* obj) {
    DCHECK_LT(serial_, kIRTPrevCount);
    references_[serial_] = GcRoot<mirror::Object>(obj);
  }

 private:
  uint32_t serial_;
  GcRoot<mirror::Object> references_[kIRTPrevCount];
}

Gc_root.h

template<class MirrorType>
class GcRoot {
 public:
  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
  ALWAYS_INLINE MirrorType* Read(GcRootSource* gc_root_source = nullptr) const
      SHARED_REQUIRES(Locks::mutator_lock_);

art/rumtime/mirror/String.h

mirror/String.h

GetValue

uint16_t value_[0];
uint16_t* GetValue() SHARED_REQUIRES(Locks::mutator_lock_) {
    return &value_[0];
}

art/runtime/native/java_lang_reflect_Method.cc

ava_lang_reflect_Method.cc

Method_invoke

static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver,
                             jobjectArray javaArgs) {
  ScopedFastNativeObjectAccess soa(env);
  return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
}