提交 a5104c4a 编写于 作者: J Jason Simmons

Implement simple method calls in the Dart/JNI bridge

Also adopt a standard pattern for handling exceptions in JNI APIs
上级 087da323
......@@ -62,6 +62,7 @@ action("generate_snapshot_bin") {
inputs = [
"//dart/runtime/tools/create_snapshot_bin.py",
"//sky/engine/bindings/internals.dart",
"//sky/engine/bindings/jni/jni.dart",
"snapshot.dart",
] + rebase_path(dart_mojo_internal_sdk_sources,
"",
......
......@@ -4,17 +4,24 @@
#include "sky/engine/bindings/jni/dart_jni.h"
#include <vector>
#include "base/logging.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "sky/engine/tonic/dart_args.h"
#include "sky/engine/tonic/dart_binding_macros.h"
#include "sky/engine/tonic/dart_converter.h"
namespace blink {
using base::android::ScopedJavaLocalRef;
using base::android::ScopedJavaGlobalRef;
#define ENTER_JNI() \
JNIEnv* env = base::android::AttachCurrentThread(); \
base::android::ScopedJavaLocalFrame java_frame(env);
namespace {
DartLibraryNatives* g_natives = nullptr;
......@@ -29,30 +36,43 @@ const uint8_t* GetSymbol(Dart_NativeFunction native_function) {
return g_natives->GetSymbol(native_function);
}
// Check if a JNI API has thrown an exception. If so, rethrow it as a
// Check if a JNI API has thrown an exception. If so, convert it to a
// Dart exception.
void CheckJniException(JNIEnv* env) {
bool CheckJniException(JNIEnv* env, Dart_Handle *exception) {
if (env->ExceptionCheck() == JNI_FALSE)
return;
return false;
jthrowable java_throwable = env->ExceptionOccurred();
env->ExceptionClear();
std::string info = base::android::GetJavaExceptionInfo(
env, java_throwable);
Dart_ThrowException(StdStringToDart(info));
*exception = StdStringToDart(info);
return true;
}
// Check if a Dart API returned an error handle.
bool CheckDartException(Dart_Handle result, Dart_Handle* exception) {
if (!Dart_IsError(result))
return false;
*exception = result;
return true;
}
} // anonymous namespace
DART_NATIVE_CALLBACK_STATIC(JniClass, fromName);
DART_NATIVE_CALLBACK_STATIC(JniClass, FromName);
#define FOR_EACH_BINDING(V) \
V(JniClass, getFieldId) \
V(JniClass, getStaticFieldId) \
V(JniClass, getStaticIntField) \
V(JniClass, getStaticObjectField) \
V(JniObject, getIntField)
V(JniClass, CallStaticLongMethod) \
V(JniClass, GetFieldId) \
V(JniClass, GetMethodId) \
V(JniClass, GetStaticFieldId) \
V(JniClass, GetStaticIntField) \
V(JniClass, GetStaticMethodId) \
V(JniClass, GetStaticObjectField) \
V(JniObject, GetIntField)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
......@@ -61,7 +81,7 @@ void DartJni::InitForGlobal() {
g_natives = new DartLibraryNatives();
g_natives->Register({
DART_REGISTER_NATIVE_STATIC(JniClass, fromName)
DART_REGISTER_NATIVE_STATIC(JniClass, FromName)
FOR_EACH_BINDING(DART_REGISTER_NATIVE)
});
}
......@@ -103,6 +123,62 @@ ScopedJavaLocalRef<jclass> DartJni::GetClass(JNIEnv* env, const char* name) {
return ScopedJavaLocalRef<jclass>(env, static_cast<jclass>(clazz));
}
class JniMethodArgs {
public:
void Convert(JNIEnv* env,
const Vector<Dart_Handle>& dart_args,
Dart_Handle* exception);
jvalue* jvalues() { return jvalues_.data(); }
private:
jvalue DartToJavaValue(JNIEnv* env,
Dart_Handle handle,
Dart_Handle* exception);
std::vector<jvalue> jvalues_;
};
void JniMethodArgs::Convert(JNIEnv* env,
const Vector<Dart_Handle>& dart_args,
Dart_Handle* exception) {
jvalues_.reserve(dart_args.size());
for (Dart_Handle dart_arg : dart_args) {
jvalue value = DartToJavaValue(env, dart_arg, exception);
if (*exception) return;
jvalues_.push_back(value);
}
}
jvalue JniMethodArgs::DartToJavaValue(JNIEnv* env,
Dart_Handle dart_value,
Dart_Handle* exception) {
jvalue java_value = jvalue();
if (Dart_IsBoolean(dart_value)) {
java_value.z = DartConverter<bool>::FromDart(dart_value);
} else if (Dart_IsInteger(dart_value)) {
java_value.j = DartConverter<jlong>::FromDart(dart_value);
} else if (Dart_IsDouble(dart_value)) {
java_value.d = DartConverter<jdouble>::FromDart(dart_value);
} else if (Dart_IsString(dart_value)) {
intptr_t length;
Dart_Handle result = Dart_StringLength(dart_value, &length);
if (CheckDartException(result, exception)) return java_value;
std::vector<uint16_t> string_data(length);
result = Dart_StringToUTF16(dart_value, string_data.data(), &length);
if (CheckDartException(result, exception)) return java_value;
java_value.l = env->NewString(string_data.data(), length);
CheckJniException(env, exception);
} else {
*exception = ToDart("Argument has unsupported data type");
}
return java_value;
}
IMPLEMENT_WRAPPERTYPEINFO(jni, JniClass);
JniClass::JniClass(JNIEnv* env, jclass clazz)
......@@ -112,38 +188,130 @@ JniClass::JniClass(JNIEnv* env, jclass clazz)
JniClass::~JniClass() {
}
PassRefPtr<JniClass> JniClass::fromName(const char* name) {
JNIEnv* env = base::android::AttachCurrentThread();
PassRefPtr<JniClass> JniClass::FromName(const char* name) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
ScopedJavaLocalRef<jclass> clazz = DartJni::GetClass(env, name);
CheckJniException(env);
ScopedJavaLocalRef<jclass> clazz = DartJni::GetClass(env, name);
if (CheckJniException(env, &exception)) goto fail;
return adoptRef(new JniClass(env, clazz.obj()));
return adoptRef(new JniClass(env, clazz.obj()));
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
intptr_t JniClass::getFieldId(const char* name, const char* sig) {
JNIEnv* env = base::android::AttachCurrentThread();
jfieldID id = env->GetFieldID(clazz_.obj(), name, sig);
CheckJniException(env);
return reinterpret_cast<intptr_t>(id);
intptr_t JniClass::GetFieldId(const char* name, const char* sig) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jfieldID id = env->GetFieldID(clazz_.obj(), name, sig);
if (CheckJniException(env, &exception)) goto fail;
return reinterpret_cast<intptr_t>(id);
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
intptr_t JniClass::getStaticFieldId(const char* name, const char* sig) {
JNIEnv* env = base::android::AttachCurrentThread();
jfieldID id = env->GetStaticFieldID(clazz_.obj(), name, sig);
CheckJniException(env);
return reinterpret_cast<intptr_t>(id);
intptr_t JniClass::GetStaticFieldId(const char* name, const char* sig) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jfieldID id = env->GetStaticFieldID(clazz_.obj(), name, sig);
if (CheckJniException(env, &exception)) goto fail;
return reinterpret_cast<intptr_t>(id);
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
jint JniClass::getStaticIntField(jfieldID fieldId) {
JNIEnv* env = base::android::AttachCurrentThread();
return env->GetStaticIntField(clazz_.obj(), fieldId);
intptr_t JniClass::GetMethodId(const char* name, const char* sig) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jmethodID id = env->GetMethodID(clazz_.obj(), name, sig);
if (CheckJniException(env, &exception)) goto fail;
return reinterpret_cast<intptr_t>(id);
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
PassRefPtr<JniObject> JniClass::getStaticObjectField(jfieldID fieldId) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject obj = env->GetStaticObjectField(clazz_.obj(), fieldId);
return JniObject::create(env, obj);
intptr_t JniClass::GetStaticMethodId(const char* name, const char* sig) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jmethodID id = env->GetStaticMethodID(clazz_.obj(), name, sig);
if (CheckJniException(env, &exception)) goto fail;
return reinterpret_cast<intptr_t>(id);
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
jint JniClass::GetStaticIntField(jfieldID fieldId) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jint result = env->GetStaticIntField(clazz_.obj(), fieldId);
if (CheckJniException(env, &exception)) goto fail;
return result;
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
PassRefPtr<JniObject> JniClass::GetStaticObjectField(jfieldID fieldId) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jobject obj = env->GetStaticObjectField(clazz_.obj(), fieldId);
if (CheckJniException(env, &exception)) goto fail;
return JniObject::create(env, obj);
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
jlong JniClass::CallStaticLongMethod(jmethodID methodId,
const Vector<Dart_Handle>& args) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
JniMethodArgs java_args;
java_args.Convert(env, args, &exception);
if (exception) goto fail;
jlong result = env->CallStaticLongMethodA(clazz_.obj(), methodId,
java_args.jvalues());
if (CheckJniException(env, &exception)) goto fail;
return result;
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
IMPLEMENT_WRAPPERTYPEINFO(jni, JniObject);
......@@ -159,9 +327,19 @@ PassRefPtr<JniObject> JniObject::create(JNIEnv* env, jobject object) {
return adoptRef(new JniObject(env, object));
}
jint JniObject::getIntField(jfieldID fieldId) {
JNIEnv* env = base::android::AttachCurrentThread();
return env->GetIntField(object_.obj(), fieldId);
jint JniObject::GetIntField(jfieldID fieldId) {
Dart_Handle exception = nullptr;
{
ENTER_JNI();
jint result = env->GetIntField(object_.obj(), fieldId);
if (CheckJniException(env, &exception)) goto fail;
return result;
}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
} // namespace blink
......@@ -37,13 +37,18 @@ class JniClass : public RefCounted<JniClass>, public DartWrappable {
public:
~JniClass() override;
static PassRefPtr<JniClass> fromName(const char* className);
static PassRefPtr<JniClass> FromName(const char* className);
intptr_t getFieldId(const char* name, const char* sig);
intptr_t getStaticFieldId(const char* name, const char* sig);
intptr_t GetFieldId(const char* name, const char* sig);
intptr_t GetStaticFieldId(const char* name, const char* sig);
intptr_t GetMethodId(const char* name, const char* sig);
intptr_t GetStaticMethodId(const char* name, const char* sig);
jint getStaticIntField(jfieldID fieldId);
PassRefPtr<JniObject> getStaticObjectField(jfieldID fieldId);
jint GetStaticIntField(jfieldID fieldId);
PassRefPtr<JniObject> GetStaticObjectField(jfieldID fieldId);
jlong CallStaticLongMethod(jmethodID methodId,
const Vector<Dart_Handle>& args);
private:
JniClass(JNIEnv* env, jclass clazz);
......@@ -60,7 +65,7 @@ class JniObject : public RefCounted<JniObject>, public DartWrappable {
static PassRefPtr<JniObject> create(JNIEnv* env, jobject object);
jint getIntField(jfieldID fieldId);
jint GetIntField(jfieldID fieldId);
private:
JniObject(JNIEnv* env, jobject object);
......@@ -74,11 +79,26 @@ struct DartConverter<jfieldID> {
int index,
Dart_Handle& exception) {
int64_t result = 0;
Dart_GetNativeIntegerArgument(args, index, &result);
Dart_Handle handle = Dart_GetNativeIntegerArgument(args, index, &result);
if (Dart_IsError(handle))
exception = handle;
return reinterpret_cast<jfieldID>(result);
}
};
template <>
struct DartConverter<jmethodID> {
static jmethodID FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
int64_t result = 0;
Dart_Handle handle = Dart_GetNativeIntegerArgument(args, index, &result);
if (Dart_IsError(handle))
exception = handle;
return reinterpret_cast<jmethodID>(result);
}
};
} // namespace blink
#endif // SKY_ENGINE_BINDINGS_OBJC_DART_JNI_H_
......@@ -8,13 +8,17 @@ import 'dart:nativewrappers';
/// Wrapper for a Java class accessed via JNI.
class JniClass extends NativeFieldWrapperClass2 {
static JniClass fromName(String name) native 'JniClass_fromName';
static JniClass fromName(String name) native 'JniClass_FromName';
int getFieldId(String name, String sig) native 'JniClass_getFieldId';
int getStaticFieldId(String name, String sig) native 'JniClass_getStaticFieldId';
int getFieldId(String name, String sig) native 'JniClass_GetFieldId';
int getStaticFieldId(String name, String sig) native 'JniClass_GetStaticFieldId';
int getMethodId(String name, String sig) native 'JniClass_GetMethodId';
int getStaticMethodId(String name, String sig) native 'JniClass_GetStaticMethodId';
int getStaticIntField(int fieldId) native 'JniClass_getStaticIntField';
JniObject getStaticObjectField(int fieldId) native 'JniClass_getStaticObjectField';
int getStaticIntField(int fieldId) native 'JniClass_GetStaticIntField';
JniObject getStaticObjectField(int fieldId) native 'JniClass_GetStaticObjectField';
int callStaticLongMethod(int methodId, List args) native 'JniClass_CallStaticLongMethod';
}
/// Wrapper for a Java object accessed via JNI.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册