Remove unused functionality in CxxModuleWrapper
Reviewed By: mhorowitz Differential Revision: D4409789 fbshipit-source-id: 91e70d8333141e1e4dcba0e2620ef2c744d0c9d3
This commit is contained in:
parent
59226f022c
commit
2a638c2ee7
|
@ -15,6 +15,8 @@ import com.facebook.soloader.SoLoader;
|
|||
/**
|
||||
* A Java Object which represents a cross-platform C++ module
|
||||
*
|
||||
* This module implements the NativeModule interface but will never be invoked from Java,
|
||||
* instead the underlying Cxx module will be extracted by the bridge and called directly.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class CxxModuleWrapper implements NativeModule
|
||||
|
@ -26,28 +28,6 @@ public class CxxModuleWrapper implements NativeModule
|
|||
@DoNotStrip
|
||||
private HybridData mHybridData;
|
||||
|
||||
@DoNotStrip
|
||||
private static class MethodWrapper implements NativeMethod
|
||||
{
|
||||
@DoNotStrip
|
||||
HybridData mHybridData;
|
||||
|
||||
MethodWrapper() {
|
||||
mHybridData = initHybrid();
|
||||
}
|
||||
|
||||
public native HybridData initHybrid();
|
||||
|
||||
@Override
|
||||
public native void invoke(
|
||||
CatalystInstance catalystInstance,
|
||||
ExecutorToken executorToken,
|
||||
ReadableNativeArray args);
|
||||
|
||||
@Override
|
||||
public native String getType();
|
||||
}
|
||||
|
||||
public CxxModuleWrapper(String library, String factory) {
|
||||
SoLoader.loadLibrary(library);
|
||||
mHybridData =
|
||||
|
@ -58,9 +38,9 @@ public class CxxModuleWrapper implements NativeModule
|
|||
public native String getName();
|
||||
|
||||
@Override
|
||||
public native Map<String, NativeMethod> getMethods();
|
||||
|
||||
public native String getConstantsJson();
|
||||
public Map<String, NativeMethod> getMethods() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
|
|
@ -4,171 +4,22 @@
|
|||
|
||||
#include <fb/fbjni.h>
|
||||
#include <fb/Environment.h>
|
||||
#include <jni/LocalString.h>
|
||||
#include <jni/Registration.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <folly/json.h>
|
||||
#include <folly/ScopeGuard.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_set>
|
||||
#include <cxxreact/CxxModule.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
|
||||
#include "ReadableNativeArray.h"
|
||||
|
||||
|
||||
using namespace facebook::jni;
|
||||
using namespace facebook::xplat::module;
|
||||
using namespace facebook::react;
|
||||
|
||||
namespace {
|
||||
|
||||
class ExecutorToken : public HybridClass<ExecutorToken> {
|
||||
public:
|
||||
constexpr static const char *const kJavaDescriptor = "Lcom/facebook/react/bridge/ExecutorToken;";
|
||||
};
|
||||
|
||||
class CxxMethodWrapper : public HybridClass<CxxMethodWrapper> {
|
||||
public:
|
||||
constexpr static const char *const kJavaDescriptor =
|
||||
"Lcom/facebook/react/cxxbridge/CxxModuleWrapper$MethodWrapper;";
|
||||
|
||||
static local_ref<jhybriddata> initHybrid(alias_ref<jhybridobject>) {
|
||||
return makeCxxInstance();
|
||||
}
|
||||
|
||||
static void registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("initHybrid", CxxMethodWrapper::initHybrid),
|
||||
makeNativeMethod("getType", CxxMethodWrapper::getType),
|
||||
makeNativeMethod("invoke",
|
||||
"(Lcom/facebook/react/bridge/CatalystInstance;Lcom/facebook/react/bridge/ExecutorToken;Lcom/facebook/react/bridge/ReadableNativeArray;)V",
|
||||
CxxMethodWrapper::invoke),
|
||||
});
|
||||
}
|
||||
|
||||
std::string getType() {
|
||||
if (method_->func) {
|
||||
return "async";
|
||||
} else {
|
||||
return "sync";
|
||||
}
|
||||
}
|
||||
|
||||
void invoke(jobject catalystinstance, ExecutorToken::jhybridobject executorToken, NativeArray* args);
|
||||
|
||||
const CxxModule::Method* method_;
|
||||
};
|
||||
|
||||
void CxxMethodWrapper::invoke(jobject jCatalystInstance, ExecutorToken::jhybridobject jExecutorToken, NativeArray* arguments) {
|
||||
CxxModule::Callback first;
|
||||
CxxModule::Callback second;
|
||||
|
||||
if (!method_->func) {
|
||||
throw std::runtime_error(
|
||||
folly::to<std::string>("Method ", method_->name,
|
||||
" is synchronous but invoked asynchronously"));
|
||||
}
|
||||
|
||||
if (method_->callbacks >= 1) {
|
||||
auto catalystInstance = make_global(adopt_local(jCatalystInstance));
|
||||
global_ref<ExecutorToken::jhybridobject> executorToken = make_global(jExecutorToken);
|
||||
// TODO(10184774): Support ExecutorToken in CxxModules
|
||||
static auto sCatalystInstanceInvokeCallback =
|
||||
catalystInstance->getClass()->getMethod<void(ExecutorToken::jhybridobject, jint, NativeArray::jhybridobject)>(
|
||||
"invokeCallback");
|
||||
|
||||
int id1;
|
||||
|
||||
if (!arguments->array[arguments->array.size() - 1].isInt()) {
|
||||
throwNewJavaException(gJavaLangIllegalArgumentException,
|
||||
"Expected callback as last argument");
|
||||
}
|
||||
|
||||
if (method_->callbacks == 2) {
|
||||
if (!arguments->array[arguments->array.size() - 2].isInt()) {
|
||||
throwNewJavaException(gJavaLangIllegalArgumentException,
|
||||
"Expected callback as penultimate argument");
|
||||
return;
|
||||
}
|
||||
|
||||
id1 = arguments->array[arguments->array.size() - 2].getInt();
|
||||
int id2 = arguments->array[arguments->array.size() - 1].getInt();
|
||||
second = [catalystInstance, executorToken, id2](std::vector<folly::dynamic> args) mutable {
|
||||
folly::dynamic argsArray(std::make_move_iterator(args.begin()),
|
||||
std::make_move_iterator(args.end()));
|
||||
ThreadScope guard;
|
||||
sCatalystInstanceInvokeCallback(
|
||||
catalystInstance.get(), executorToken.get(), id2,
|
||||
ReadableNativeArray::newObjectCxxArgs(std::move(argsArray)).get());
|
||||
catalystInstance.reset();
|
||||
executorToken.reset();
|
||||
};
|
||||
} else {
|
||||
id1 = arguments->array[arguments->array.size() - 1].getInt();
|
||||
}
|
||||
|
||||
first = [catalystInstance, executorToken, id1](std::vector<folly::dynamic> args) mutable {
|
||||
folly::dynamic argsArray(std::make_move_iterator(args.begin()),
|
||||
std::make_move_iterator(args.end()));
|
||||
ThreadScope guard;
|
||||
sCatalystInstanceInvokeCallback(
|
||||
catalystInstance.get(), executorToken.get(), id1,
|
||||
ReadableNativeArray::newObjectCxxArgs(std::move(argsArray)).get());
|
||||
// This is necessary because by the time the lambda's dtor runs,
|
||||
// the guard has been destroyed, and it may not be possible to
|
||||
// get a JNIEnv* to clean up the captured global_ref.
|
||||
catalystInstance.reset();
|
||||
executorToken.reset();
|
||||
};
|
||||
}
|
||||
|
||||
// I've got a few flawed options here. I can catch C++ exceptions
|
||||
// here, and log/convert them to java exceptions. This lets all the
|
||||
// java handling work ok, but the only info I can capture about the
|
||||
// C++ exception is the what() string, not the stack. I can let the
|
||||
// C++ exception escape, crashing the app. This causes the full,
|
||||
// accurate C++ stack trace to be added to logcat by debuggerd. The
|
||||
// java state is lost, but in practice, the java stack is always the
|
||||
// same in this case since the javascript stack is not visible. The
|
||||
// what() value is also lost. Finally, I can catch, log the java
|
||||
// stack, then rethrow the C++ exception. In this case I get java
|
||||
// and C++ stack data, but the C++ stack is as of the rethrow, not
|
||||
// the original throw, both the C++ and java stacks always look the
|
||||
// same.
|
||||
//
|
||||
// I am going with option 2, since that seems like the most useful
|
||||
// choice. It would be nice to be able to get what() and the C++
|
||||
// stack. I'm told that will be possible in the future. TODO
|
||||
// mhorowitz #7128529: convert C++ exceptions to Java
|
||||
|
||||
folly::dynamic dargs = arguments->array;
|
||||
dargs.resize(arguments->array.size() - method_->callbacks);
|
||||
|
||||
try {
|
||||
method_->func(dargs, first, second);
|
||||
} catch (const facebook::xplat::JsArgumentException& ex) {
|
||||
throwNewJavaException(gJavaLangIllegalArgumentException, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CxxModuleWrapper
|
||||
|
||||
void CxxModuleWrapper::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("initHybrid", CxxModuleWrapper::initHybrid),
|
||||
makeNativeMethod("getName", CxxModuleWrapper::getName),
|
||||
makeNativeMethod("getConstantsJson", CxxModuleWrapper::getConstantsJson),
|
||||
makeNativeMethod("getMethods", "()Ljava/util/Map;", CxxModuleWrapper::getMethods),
|
||||
makeNativeMethod("getName", CxxModuleWrapper::getName)
|
||||
});
|
||||
|
||||
CxxMethodWrapper::registerNatives();
|
||||
}
|
||||
|
||||
CxxModuleWrapper::CxxModuleWrapper(const std::string& soPath, const std::string& fname) {
|
||||
|
@ -196,45 +47,8 @@ CxxModuleWrapper::CxxModuleWrapper(const std::string& soPath, const std::string&
|
|||
}
|
||||
auto factory = reinterpret_cast<CxxModule* (*)()>(sym);
|
||||
module_.reset((*factory)());
|
||||
methods_ = module_->getMethods();
|
||||
}
|
||||
|
||||
std::string CxxModuleWrapper::getName() {
|
||||
return module_->getName();
|
||||
}
|
||||
|
||||
std::string CxxModuleWrapper::getConstantsJson() {
|
||||
std::map<std::string, folly::dynamic> constants = module_->getConstants();
|
||||
folly::dynamic constsobject = folly::dynamic::object;
|
||||
|
||||
for (auto& c : constants) {
|
||||
constsobject.insert(std::move(c.first), std::move(c.second));
|
||||
}
|
||||
|
||||
return folly::toJson(constsobject);
|
||||
}
|
||||
|
||||
jobject CxxModuleWrapper::getMethods() {
|
||||
static auto hashmap = findClassStatic("java/util/HashMap");
|
||||
static auto hashmap_put = hashmap->getMethod<jobject(jobject, jobject)>("put");
|
||||
|
||||
auto methods = hashmap->newObject(hashmap->getConstructor<jobject()>());
|
||||
|
||||
std::unordered_set<std::string> names;
|
||||
for (const auto& m : methods_) {
|
||||
if (names.find(m.name) != names.end()) {
|
||||
throwNewJavaException(gJavaLangIllegalArgumentException,
|
||||
"C++ Module %s method name already registered: %s",
|
||||
module_->getName().c_str(), m.name.c_str());
|
||||
}
|
||||
names.insert(m.name);
|
||||
auto name = make_jstring(m.name);
|
||||
static auto ctor =
|
||||
CxxMethodWrapper::javaClassStatic()->getConstructor<CxxMethodWrapper::jhybridobject()>();
|
||||
auto method = CxxMethodWrapper::javaClassStatic()->newObject(ctor);
|
||||
cthis(method)->method_ = &m;
|
||||
hashmap_put(methods.get(), name.get(), method.get());
|
||||
}
|
||||
|
||||
return methods.release();
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <fb/fbjni.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <fb/fbjni.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
@ -27,14 +28,11 @@ public:
|
|||
|
||||
// JNI methods
|
||||
std::string getName();
|
||||
std::string getConstantsJson();
|
||||
jobject getMethods();
|
||||
|
||||
// This steals ownership of the underlying module for use by the C++ bridge
|
||||
std::unique_ptr<xplat::module::CxxModule> getModule() {
|
||||
// TODO mhorowitz: remove this (and a lot of other code) once the java
|
||||
// bridge is dead.
|
||||
methods_.clear();
|
||||
return std::move(module_);
|
||||
}
|
||||
|
||||
|
@ -42,11 +40,9 @@ protected:
|
|||
friend HybridBase;
|
||||
|
||||
explicit CxxModuleWrapper(std::unique_ptr<xplat::module::CxxModule> module)
|
||||
: module_(std::move(module))
|
||||
, methods_(module_->getMethods()) {}
|
||||
: module_(std::move(module)) {}
|
||||
|
||||
std::unique_ptr<xplat::module::CxxModule> module_;
|
||||
std::vector<xplat::module::CxxModule::Method> methods_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue