ReactNative 源码分析1——HybridData 机制深度分析

14 阅读3分钟

基于RN0.77 源码

一、HybridData 是什么

HybridData 来自 Facebook 的 fbjni 库(com.facebook.jni.HybridData),它是一个将 C++ 对象指针封装在 Java 对象中的桥梁类。本质上是 Java 层持有 C++ 层对象的"句柄",实现了 Java 和 C++ 之间一对一的对象绑定。

二、内存管理流程

┌─────────────────────────────────────────────────┐
│  Java 层                                         │
│  ┌──────────────────────────────┐                │
│  │ HermesExecutor         │                │
│  │  mHybridData ──────────────────┐              │
│  └──────────────────────────────┘ │              │
│                                   ▼              │
│  ┌──────────────────────────────┐                │
│  │ HybridData (fbjni)          │                │
│  │  内部持有 C++ 指针 (long)    │                │
│  └──────────────────────────────┘                │
└─────────────────────────────────────────────────┘
                │ JNI
                ▼
┌─────────────────────────────────────────────────┐
│  C++ 层                                         │
│  ┌──────────────────────────────┐                │
│  │ HermesExecutorHolder (C++)   │                │
│  │                              │                │
│  │                              │                │
│  └──────────────────────────────┘                │
└─────────────────────────────────────────────────┘

二、核心工作原理

public class HermesExecutor extends JavaScriptExecutor {
  private static String mode_ ;

  static {
    loadLibrary();
  }

  public static void loadLibrary() throws UnsatisfiedLinkError {
    if (mode_ == null) {
      // libhermes must be loaded explicitly to invoke its JNI_OnLoad.
      SoLoader.loadLibrary( "hermes" );
      SoLoader.loadLibrary( "hermes_executor" );
      // libhermes_executor is built differently for Debug & Release so we load the proper mode.
      mode_ = ReactBuildConfig.DEBUG ? "Debug" : "Release" ;
    }
  }

  HermesExecutor(@Nullable RuntimeConfig config, boolean enableDebugger, String debuggerName) {
    super(
        config == null
            ? initHybridDefaultConfig(enableDebugger, debuggerName)
            : initHybrid(enableDebugger, debuggerName, config.getHeapSizeMB()));
  }

  @Override
  public String getName() {
    return "HermesExecutor" + mode_ ;
  }

  private static native HybridData initHybridDefaultConfig(
      boolean enableDebugger, String debuggerName);

  private static native HybridData initHybrid(
      boolean enableDebugger, String debuggerName, long heapSizeMB);
}

HermesExecutor继承JavaScriptExecutor,JavaScriptExecutor中定义了一个mHybridData字段

private final HybridData mHybridData;

HermesExecutor构造函数调用initHybridDefaultConfig或initHybrid返回一个HybridData对象,initHybridDefaultConfig和initHybrid都是native方法;

在OnLoad.cpp中注册了这两个方法,并且这两个方法都是HermesExecutorHolder类中

static void registerNatives() {
  registerHybrid(
      {makeNativeMethod( "initHybrid" , HermesExecutorHolder::initHybrid),
       makeNativeMethod(
           "initHybridDefaultConfig" ,
           HermesExecutorHolder::initHybridDefaultConfig)});
}

initHybrid中会创建HermesExecutorFactory对象,然后调用makeCxxInstance,它是实现了 Java 和 C++ 之间一对一的对象绑定的关键

static jni::local_ref<jhybriddata> initHybrid(
    jni::alias_ref<jclass>,
    bool enableDebugger,
    std::string debuggerName,
    jlong heapSizeMB) {
  JReactMarker::setLogPerfMarkerIfNeeded();
  auto runtimeConfig = makeRuntimeConfig(heapSizeMB);
  std::call_once(flag, []() {
    facebook::hermes::HermesRuntime::setFatalHandler(hermesFatalHandler);
  });
  auto factory = std::make_unique<HermesExecutorFactory>(
      installBindings, JSIExecutor::defaultTimeoutInvoker, runtimeConfig);
  factory->setEnableDebugger(enableDebugger);
  if (!debuggerName.empty()) {
    factory->setDebuggerName(debuggerName);
  }
  return makeCxxInstance(std::move(factory));
}

makeCxxInstance中会创建T对象,在这个案例中T为C++层的HermesExecutorHolder(OnLoad.cpp)

static local_ref<detail::HybridData> makeCxxInstance(Args&&... args) {
  return makeHybridData(
      std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
}

makeHybridData中创建了一个HybridData对象并返回到Java层

static local_ref<detail::HybridData> makeHybridData(
    std::unique_ptr<T> cxxPart) {
  auto hybridData = detail::HybridData::create();
  setNativePointer(hybridData, std::move(cxxPart));
  return hybridData;
}

setNativePointer中t是HybridData对象,new_value是HermesExecutorHolder对象

void setNativePointer(
    basic_strong_ref<T, Alloc> t,
    std::unique_ptr<detail::BaseHybridClass> new_value) {
  getHolder(&*t)->setNativePointer(std::move(new_value));
}

看完getHolder就明白了,它是取出HybridData对象中的mDestructor字段

local_ref<HybridDestructor::javaobject> getHolder(const T* t) {
  static auto holderField = getDestructorField(t->getClass());
  return t->getFieldValue(holderField);
}

inline JField<HybridDestructor::javaobject> getDestructorField(
    const local_ref<JClass>& c) {
  return c->template getField<HybridDestructor::javaobject>( "mDestructor" );
}

setNativePointer最终会将mDestructor.mNativePointer指向HermesExecutorHolder对象

getHolder(&*t)->setNativePointer(std::move(new_value));
变成
HybridDestructor->setNativePointer(std::move(new_value));


//fbjni-0.7.0/prefab/modules/fbjni/include/fbjni/fbjni.cpp:227-237
void HybridDestructor::setNativePointer(
    std::unique_ptr<detail::BaseHybridClass> new_value) {
  static auto pointerField =
      javaClassStatic()->getField<jlong>("mNativePointer");
  auto old_value = std::unique_ptr<detail::BaseHybridClass>(
      reinterpret_cast<detail::BaseHybridClass*>(getFieldValue(pointerField)));
  if (new_value && old_value) {
    FBJNI_LOGF("Attempt to set C++ native pointer twice");
  }
  setFieldValue(pointerField, reinterpret_cast<jlong>(new_value.release()));
}

这就是“Java 对象 -> native 指针 -> C++ 实例”的回路。

HermesExecutor (Java++对象) ->HybridData->mDestructor.mNativePointer(指针)->HermesExecutorHolder(C++对象) 

四、在 RN 中的应用场景

HybridData 在 React Native 中无处不在,覆盖了几乎所有核心子系统:

子系统Java 类C++ 对应作用
旧架构 BridgeCatalystInstanceImplCatalystInstanceImpl.cpp → InstanceJS 桥的核心实例
新架构 BridgelessReactInstanceJReactInstance.cpp → ReactInstance新架构的运行时实例
JS 引擎HermesExecutor / JSCExecutor对应的 C++ executorJS 执行引擎
JS RuntimeHermesInstance / JSCInstanceC++ runtime factory创建和管理 JS 运行时
数据类型WritableNativeMap / WritableNativeArrayC++ dynamic 对象JS 与 Java 间的数据传递
TurboModuleTurboModuleManagerC++ TurboModule 管理新架构的模块系统
Fabric 渲染ComponentFactoryC++ 组件注册表新架构的渲染系统
运行时工具RuntimeExecutor / RuntimeSchedulerC++ executor/schedulerJS 任务调度