Permalink
Browse files

Setting bridge up for sharing: allowing native modules to register af…

…ter init

Reviewed By: javache

Differential Revision: D4945784

fbshipit-source-id: 80e7236e9ccd5d5c9a7fba7c96b98fc38b43a2fc
  • Loading branch information...
Kathy Gray authored and facebook-github-bot committed Jun 21, 2017
1 parent 1ae54b5 commit 5c5410459e042c24db555db3e40fc761daba465e
@@ -287,6 +287,7 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) {
*
* Called from UI thread.
*/
@ThreadConfined(UI)
public void createReactContextInBackground() {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()");
Assertions.assertCondition(
@@ -299,6 +300,33 @@ public void createReactContextInBackground() {
recreateReactContextInBackgroundInner();
}
@ThreadConfined(UI)
public void registerAdditionalPackages(List<ReactPackage> packages) {
if (packages == null || packages.isEmpty()) {
return;
}
// CatalystInstance hasn't been created, so add packages for later evaluation
if (!hasStartedCreatingInitialContext()) {
for (ReactPackage p : packages) {
if (!mPackages.contains(p)) {
mPackages.add(p);
}
}
return;
}
ReactContext context = getCurrentReactContext();
CatalystInstance catalystInstance = context != null ? context.getCatalystInstance() : null;
Assertions.assertNotNull(catalystInstance, "CatalystInstance null after hasStartedCreatingInitialContext true.");
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, packages, true);
catalystInstance.extendNativeModules(nativeModuleRegistry);
}
/**
* Recreate the react application and context. This should be called if configuration has
* changed or the developer has requested the app to be reloaded. It should only be called after
@@ -806,7 +834,6 @@ private void setupReactContext(ReactApplicationContext reactContext) {
if (!mSetupReactContextInBackgroundEnabled) {
UiThreadUtil.assertOnUiThread();
}
Assertions.assertCondition(mCurrentReactContext == null);
mCurrentReactContext = Assertions.assertNotNull(reactContext);
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
@@ -922,56 +949,23 @@ private ReactApplicationContext createReactContext(
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
reactContext,
this,
mLazyNativeModulesEnabled);
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
ReactMarker.logMarker(PROCESS_PACKAGES_START);
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCoreModulesPackage");
try {
CoreModulesPackage coreModulesPackage =
new CoreModulesPackage(
this,
mBackBtnHandler,
mUIImplementationProvider,
mLazyViewManagersEnabled);
processPackage(coreModulesPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
// TODO(6818138): Solve use-case of native/js modules overriding
for (ReactPackage reactPackage : mPackages) {
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCustomReactPackage");
try {
processPackage(reactPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
ReactMarker.logMarker(PROCESS_PACKAGES_END);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
NativeModuleRegistry nativeModuleRegistry;
try {
nativeModuleRegistry = nativeModuleRegistryBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
}
CoreModulesPackage coreModulesPackage =
new CoreModulesPackage(
this,
mBackBtnHandler,
mUIImplementationProvider,
mLazyViewManagersEnabled);
mPackages.add(coreModulesPackage);
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(mUseSeparateUIBackgroundThread ?
ReactQueueConfigurationSpec.createWithSeparateUIBackgroundThread() :
@@ -1006,6 +1000,49 @@ private ReactApplicationContext createReactContext(
return reactContext;
}
private NativeModuleRegistry processPackages(
ReactApplicationContext reactContext,
List<ReactPackage> packages,
boolean checkAndUpdatePackageMembership) {
NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(
reactContext,
this,
mLazyNativeModulesEnabled);
ReactMarker.logMarker(PROCESS_PACKAGES_START);
// TODO(6818138): Solve use-case of native modules overriding
for (ReactPackage reactPackage : packages) {
if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage)) {
continue;
}
Systrace.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"createAndProcessCustomReactPackage");
try {
if (checkAndUpdatePackageMembership) {
mPackages.add(reactPackage);
}
processPackage(reactPackage, nativeModuleRegistryBuilder);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
ReactMarker.logMarker(PROCESS_PACKAGES_END);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
NativeModuleRegistry nativeModuleRegistry;
try {
nativeModuleRegistry = nativeModuleRegistryBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
}
return nativeModuleRegistry;
}
private void processPackage(
ReactPackage reactPackage,
NativeModuleRegistryBuilder nativeModuleRegistryBuilder) {
@@ -197,8 +197,8 @@ public ReactInstanceManagerBuilder setSetupReactContextInBackgroundEnabled(
public ReactInstanceManagerBuilder setUseSeparateUIBackgroundThread(
boolean useSeparateUIBackgroundThread) {
mUseSeparateUIBackgroundThread = useSeparateUIBackgroundThread;
return this;
mUseSeparateUIBackgroundThread = useSeparateUIBackgroundThread;
return this;
}
public ReactInstanceManagerBuilder setMinNumShakes(int minNumShakes) {
@@ -68,6 +68,12 @@ void callFunction(
<T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
Collection<NativeModule> getNativeModules();
/**
* This method permits a CatalystInstance to extend the known
* Native modules. This provided registry contains only the new modules to load.
*/
void extendNativeModules(NativeModuleRegistry modules);
/**
* Adds a idle listener for this Catalyst instance. The listener will receive notifications
* whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
@@ -157,6 +157,26 @@ public void decrementPendingJSCalls() {
}
}
/**
* This method and the native below permits a CatalystInstance to extend the known
* Native modules. This registry contains only the new modules to load. The
* registry {@code mNativeModuleRegistry} updates internally to contain all the new modules, and generates
* the new registry for extracting just the new collections.
*/
@Override
public void extendNativeModules(NativeModuleRegistry modules) {
//Extend the Java-visible registry of modules
mNativeModuleRegistry.registerModules(modules);
Collection<JavaModuleWrapper> javaModules = modules.getJavaModules(this);
Collection<ModuleHolder> cxxModules = modules.getCxxModules();
//Extend the Cxx-visible registry of modules wrapped in appropriate interfaces
jniExtendNativeModules(javaModules, cxxModules);
}
private native void jniExtendNativeModules(
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,
@@ -13,6 +13,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import com.facebook.infer.annotation.Assertions;
import com.facebook.systrace.Systrace;
@@ -35,6 +36,21 @@ public NativeModuleRegistry(
mBatchCompleteListenerModules = batchCompleteListenerModules;
}
/**
* Private getters for combining NativeModuleRegistrys
*/
private Map<Class<? extends NativeModule>, ModuleHolder> getModuleMap() {
return mModules;
}
private ReactApplicationContext getReactApplicationContext() {
return mReactApplicationContext;
}
private ArrayList<ModuleHolder> getBatchCompleteListenerModules() {
return mBatchCompleteListenerModules;
}
/* package */ Collection<JavaModuleWrapper> getJavaModules(
JSInstance jsInstance) {
ArrayList<JavaModuleWrapper> javaModules = new ArrayList<>();
@@ -58,6 +74,29 @@ public NativeModuleRegistry(
return cxxModules;
}
/*
* Adds any new modules to the current module regsitry
*/
/* package */ void registerModules(NativeModuleRegistry newRegister) {
Assertions.assertCondition(mReactApplicationContext.equals(newRegister.getReactApplicationContext()),
"Extending native modules with non-matching application contexts.");
Map<Class<? extends NativeModule>, ModuleHolder> newModules = newRegister.getModuleMap();
ArrayList<ModuleHolder> batchCompleteListeners = newRegister.getBatchCompleteListenerModules();
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : newModules.entrySet()) {
Class<? extends NativeModule> key = entry.getKey();
if (!mModules.containsKey(key)) {
ModuleHolder value = entry.getValue();
if (batchCompleteListeners.contains(value)) {
mBatchCompleteListenerModules.add(value);
}
mModules.put(key, value);
}
}
}
/* package */ void notifyJSInstanceDestroy() {
mReactApplicationContext.assertOnNativeModulesQueueThread();
Systrace.beginSection(
@@ -97,6 +97,7 @@ void CatalystInstanceImpl::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid),
makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge),
makeNativeMethod("jniExtendNativeModules", CatalystInstanceImpl::extendNativeModules),
makeNativeMethod("jniSetSourceURL", CatalystInstanceImpl::jniSetSourceURL),
makeNativeMethod("jniLoadScriptFromAssets", CatalystInstanceImpl::jniLoadScriptFromAssets),
makeNativeMethod("jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile),
@@ -147,18 +148,32 @@ void CatalystInstanceImpl::initializeBridge(
// don't need jsModuleDescriptions any more, all the way up and down the
// stack.
moduleRegistry_ = std::make_shared<ModuleRegistry>(
buildNativeModuleList(
std::weak_ptr<Instance>(instance_),
javaModules,
cxxModules,
moduleMessageQueue_,
uiBackgroundMessageQueue_));
instance_->initializeBridge(
folly::make_unique<JInstanceCallback>(
callback,
uiBackgroundMessageQueue_ != NULL ? uiBackgroundMessageQueue_ : moduleMessageQueue_),
jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(jsQueue),
buildModuleRegistry(
std::weak_ptr<Instance>(instance_),
javaModules,
cxxModules,
moduleMessageQueue_,
uiBackgroundMessageQueue_));
moduleRegistry_);
}
void CatalystInstanceImpl::extendNativeModules(
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
moduleRegistry_->registerModules(buildNativeModuleList(
std::weak_ptr<Instance>(instance_),
javaModules,
cxxModules,
moduleMessageQueue_,
uiBackgroundMessageQueue_));
}
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {
@@ -52,6 +52,10 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
void extendNativeModules(
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
/**
* Sets the source URL of the underlying bridge without loading any JS code.
*/
@@ -74,6 +78,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
// This should be the only long-lived strong reference, but every C++ class
// will have a weak reference.
std::shared_ptr<Instance> instance_;
std::shared_ptr<ModuleRegistry> moduleRegistry_;
std::shared_ptr<JMessageQueueThread> moduleMessageQueue_;
std::shared_ptr<JMessageQueueThread> uiBackgroundMessageQueue_;
};
@@ -29,7 +29,7 @@ xplat::module::CxxModule::Provider ModuleHolder::getProvider() const {
};
}
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::vector<std::unique_ptr<NativeModule>> buildNativeModuleList(
std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules,
@@ -60,11 +60,7 @@ std::unique_ptr<ModuleRegistry> buildModuleRegistry(
winstance, cm->getName(), cm->getProvider(), moduleMessageQueue));
}
}
if (modules.empty()) {
return nullptr;
} else {
return folly::make_unique<ModuleRegistry>(std::move(modules));
}
return modules;
}
}}
@@ -23,7 +23,7 @@ class ModuleHolder : public jni::JavaClass<ModuleHolder> {
xplat::module::CxxModule::Provider getProvider() const;
};
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::vector<std::unique_ptr<NativeModule>> buildNativeModuleList(
std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules,
@@ -32,11 +32,12 @@ void Instance::initializeBridge(
std::shared_ptr<MessageQueueThread> jsQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry) {
callback_ = std::move(callback);
moduleRegistry_ = std::move(moduleRegistry);
jsQueue->runOnQueueSync(
[this, &jsef, moduleRegistry, jsQueue] () mutable {
[this, &jsef, jsQueue] () mutable {
nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
jsef.get(), moduleRegistry, jsQueue, callback_);
jsef.get(), moduleRegistry_, jsQueue, callback_);
std::lock_guard<std::mutex> lock(m_syncMutex);
m_syncReady = true;
@@ -73,6 +73,7 @@ class Instance {
std::shared_ptr<InstanceCallback> callback_;
std::unique_ptr<NativeToJsBridge> nativeToJsBridge_;
std::shared_ptr<ModuleRegistry> moduleRegistry_;
std::mutex m_syncMutex;
std::condition_variable m_syncCV;
Oops, something went wrong.

0 comments on commit 5c54104

Please sign in to comment.