Support ModuleHolder-based lazy init of C++ modules with C++ bridge on android

Reviewed By: AaaChiuuu

Differential Revision: D4614479

fbshipit-source-id: 109ac34b8688f0113675e4a4479d1ddcc6169ed4
This commit is contained in:
Marc Horowitz
2017-03-14 15:35:01 -07:00
committed by Facebook Github Bot
parent 6410e256c5
commit e622d51e20
20 changed files with 174 additions and 52 deletions
@@ -110,7 +110,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
final JavaScriptModuleRegistry jsModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge.");
mHybridData = initHybrid();
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
@@ -123,6 +123,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mTraceListener = new JSProfilerTraceListener(this);
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
initializeBridge(
new BridgeCallback(this),
jsExecutor,
@@ -130,6 +131,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
mReactQueueConfiguration.getNativeModulesQueueThread(),
mJavaRegistry.getJavaModules(this),
mJavaRegistry.getCxxModules());
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
mMainExecutorToken = getMainExecutorToken();
}
@@ -182,7 +184,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
MessageQueueThread jsQueue,
MessageQueueThread moduleQueue,
Collection<JavaModuleWrapper> javaModules,
Collection<CxxModuleWrapper> cxxModules);
Collection<ModuleHolder> cxxModules);
/**
* This API is used in situations where the JS bundle is being executed not on
@@ -53,12 +53,12 @@ public class NativeModuleRegistry {
return javaModules;
}
/* package */ Collection<CxxModuleWrapper> getCxxModules() {
ArrayList<CxxModuleWrapper> cxxModules = new ArrayList<>();
/* package */ Collection<ModuleHolder> getCxxModules() {
ArrayList<ModuleHolder> cxxModules = new ArrayList<>();
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
Class<?> type = entry.getKey();
if (CxxModuleWrapper.class.isAssignableFrom(type)) {
cxxModules.add((CxxModuleWrapper) entry.getValue().getModule());
cxxModules.add(entry.getValue());
}
}
return cxxModules;
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \
JSLogging.cpp \
JniJSModulesUnbundle.cpp \
MethodInvoker.cpp \
ModuleRegistryBuilder.cpp \
NativeArray.cpp \
NativeCommon.cpp \
NativeMap.cpp \
@@ -6,6 +6,7 @@ EXPORTED_HEADERS = [
"JExecutorToken.h",
"JSLoader.h",
"MethodInvoker.h",
"ModuleRegistryBuilder.h",
"NativeArray.h",
"NativeCommon.h",
"NativeMap.h",
@@ -20,6 +20,7 @@
#include <cxxreact/ModuleRegistry.h>
#include <cxxreact/CxxNativeModule.h>
#include "CxxModuleWrapper.h"
#include "JavaScriptExecutorHolder.h"
#include "JniJSModulesUnbundle.h"
#include "JNativeRunnable.h"
@@ -128,21 +129,10 @@ void CatalystInstanceImpl::initializeBridge(
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules) {
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
// TODO mhorowitz: how to assert here?
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
std::vector<std::unique_ptr<NativeModule>> modules;
std::weak_ptr<Instance> winstance(instance_);
for (const auto& jm : *javaModules) {
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
}
for (const auto& cm : *cxxModules) {
modules.emplace_back(
folly::make_unique<CxxNativeModule>(winstance, std::move(cthis(cm)->getModule())));
}
auto moduleRegistry = std::make_shared<ModuleRegistry>(std::move(modules));
// This used to be:
//
// Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> Bridge::Callback
@@ -163,7 +153,8 @@ void CatalystInstanceImpl::initializeBridge(
jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(jsQueue),
folly::make_unique<JMessageQueueThread>(moduleQueue),
moduleRegistry);
buildModuleRegistry(std::weak_ptr<Instance>(instance_),
javaModules, cxxModules));
}
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {
@@ -10,6 +10,7 @@
#include "JMessageQueueThread.h"
#include "JSLoader.h"
#include "JavaModuleWrapper.h"
#include "ModuleRegistryBuilder.h"
namespace facebook {
namespace react {
@@ -48,7 +49,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules);
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
/**
* Sets the source URL of the underlying bridge without loading any JS code.
@@ -12,7 +12,13 @@
namespace facebook {
namespace react {
class CxxModuleWrapper : public jni::HybridClass<CxxModuleWrapper> {
struct JNativeModule : jni::JavaClass<JNativeModule> {
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/bridge/NativeModule;";
};
class CxxModuleWrapper :
public jni::HybridClass<CxxModuleWrapper, JNativeModule> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/cxxbridge/CxxModuleWrapper;";
@@ -27,6 +27,8 @@ struct JavaModuleWrapper : jni::JavaClass<JavaModuleWrapper> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/JavaModuleWrapper;";
jni::local_ref<JBaseJavaModule::javaobject> getModule() {
// This is the call which causes a lazy Java module to actually be
// created.
static auto getModule = javaClassStatic()->getMethod<JBaseJavaModule::javaobject()>("getModule");
return getModule(self());
}
@@ -0,0 +1,51 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "ModuleRegistryBuilder.h"
#include <cxxreact/CxxNativeModule.h>
#include <folly/Memory.h>
namespace facebook {
namespace react {
std::string ModuleHolder::getName() const {
static auto method = getClass()->getMethod<jstring()>("getName");
return method(self())->toStdString();
}
xplat::module::CxxModule::Provider ModuleHolder::getProvider() const {
return [self=jni::make_global(self())] {
static auto method =
ModuleHolder::javaClassStatic()->getMethod<JNativeModule::javaobject()>(
"getModule");
// This is the call which uses the lazy Java Provider to instantiate the
// Java CxxModuleWrapper which contains the CxxModule.
auto module = method(self);
CHECK(module->isInstanceOf(CxxModuleWrapper::javaClassStatic()))
<< "module isn't a C++ module";
auto cxxModule = jni::static_ref_cast<CxxModuleWrapper::javaobject>(module);
// Then, we grab the CxxModule from the wrapper, which is no longer needed.
return cxxModule->cthis()->getModule();
};
}
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
std::vector<std::unique_ptr<NativeModule>> modules;
for (const auto& jm : *javaModules) {
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
}
for (const auto& cm : *cxxModules) {
modules.emplace_back(
folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider()));
}
if (modules.empty()) {
return nullptr;
} else {
return folly::make_unique<ModuleRegistry>(std::move(modules));
}
}
}}
@@ -0,0 +1,30 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <string>
#include <cxxreact/CxxModule.h>
#include <cxxreact/ModuleRegistry.h>
#include <fb/fbjni.h>
#include "CxxModuleWrapper.h"
#include "JavaModuleWrapper.h"
namespace facebook {
namespace react {
class ModuleHolder : public jni::JavaClass<ModuleHolder> {
public:
static auto constexpr kJavaDescriptor =
"Lcom/facebook/react/cxxbridge/ModuleHolder;";
std::string getName() const;
xplat::module::CxxModule::Provider getProvider() const;
};
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
}
}