Index: content/browser/renderer_host/java/java_bound_object.cc |
diff --git a/content/browser/renderer_host/java/java_bound_object.cc b/content/browser/renderer_host/java/java_bound_object.cc |
index f82588dee3c457ecbee4d1d1f0104216eda70995..63992b2dee3b7881cf1530c459bf9a3fc6f741ee 100644 |
--- a/content/browser/renderer_host/java/java_bound_object.cc |
+++ b/content/browser/renderer_host/java/java_bound_object.cc |
@@ -35,17 +35,19 @@ namespace { |
const char kJavaLangClass[] = "java/lang/Class"; |
const char kJavaLangObject[] = "java/lang/Object"; |
const char kJavaLangReflectMethod[] = "java/lang/reflect/Method"; |
+// TODO(dtrainor): Parameterize this so that WebView and Chrome for Android can |
+// use different annotations. |
+const char kJavaScriptInterfaceAnnotation[] = |
+ "org/chromium/content/browser/JavascriptInterface"; |
const char kGetClass[] = "getClass"; |
-const char kGetDeclaredMethods[] = "getDeclaredMethods"; |
const char kGetMethods[] = "getMethods"; |
-const char kGetModifiers[] = "getModifiers"; |
-const char kReturningInteger[] = "()I"; |
+const char kIsAnnotationPresent[] = "isAnnotationPresent"; |
const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; |
const char kReturningJavaLangReflectMethodArray[] = |
"()[Ljava/lang/reflect/Method;"; |
+const char kTakesJavaLangClassReturningBoolean[] = "(Ljava/lang/Class;)Z"; |
-// This constant represents the value at java.lang.reflect.Modifier.PUBLIC. |
-const int kJavaPublicModifier = 1; |
+jclass g_safe_annotation_clazz = NULL; |
// Our special NPObject type. We extend an NPObject with a pointer to a |
// JavaBoundObject. We also add static methods for each of the NPObject |
@@ -128,7 +130,7 @@ bool JavaNPObject::GetProperty(NPObject* np_object, |
// return value is simply converted to the corresponding NPAPI type. |
bool CallJNIMethod(jobject object, const JavaType& return_type, jmethodID id, |
jvalue* parameters, NPVariant* result, |
- bool allow_inherited_methods) { |
+ bool require_annotation) { |
JNIEnv* env = AttachCurrentThread(); |
switch (return_type.type) { |
case JavaType::TypeBoolean: |
@@ -210,7 +212,7 @@ bool CallJNIMethod(jobject object, const JavaType& return_type, jmethodID id, |
break; |
} |
OBJECT_TO_NPVARIANT(JavaBoundObject::Create(scoped_java_object, |
- allow_inherited_methods), |
+ require_annotation), |
*result); |
break; |
} |
@@ -726,9 +728,16 @@ jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant, |
} // namespace |
+bool RegisterJavaBoundObject(JNIEnv* env) { |
+ g_safe_annotation_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( |
+ base::android::GetUnscopedClass(env, kJavaScriptInterfaceAnnotation))); |
+ DCHECK(g_safe_annotation_clazz); |
+ |
+ return true; |
+} |
NPObject* JavaBoundObject::Create(const JavaRef<jobject>& object, |
- bool allow_inherited_methods) { |
+ bool require_annotation) { |
// The first argument (a plugin's instance handle) is passed through to the |
// allocate function directly, and we don't use it, so it's ok to be 0. |
// The object is created with a ref count of one. |
@@ -736,15 +745,15 @@ NPObject* JavaBoundObject::Create(const JavaRef<jobject>& object, |
&JavaNPObject::kNPClass)); |
// The NPObject takes ownership of the JavaBoundObject. |
reinterpret_cast<JavaNPObject*>(np_object)->bound_object = |
- new JavaBoundObject(object, allow_inherited_methods); |
+ new JavaBoundObject(object, require_annotation); |
return np_object; |
} |
JavaBoundObject::JavaBoundObject(const JavaRef<jobject>& object, |
- bool allow_inherited_methods) |
+ bool require_annotation) |
: java_object_(object), |
are_methods_set_up_(false), |
- allow_inherited_methods_(allow_inherited_methods) { |
+ require_annotation_(require_annotation) { |
// We don't do anything with our Java object when first created. We do it all |
// lazily when a method is first invoked. |
} |
@@ -798,7 +807,7 @@ bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args, |
// Call |
bool ok = CallJNIMethod(java_object_.obj(), method->return_type(), |
method->id(), ¶meters[0], result, |
- allow_inherited_methods_); |
+ require_annotation_); |
// Now that we're done with the jvalue, release any local references created |
// by CoerceJavaScriptValueToJavaValue(). |
@@ -823,39 +832,36 @@ void JavaBoundObject::EnsureMethodsAreSetUp() const { |
kGetClass, |
kReturningJavaLangClass)))); |
- const char* get_method = allow_inherited_methods_ ? |
- kGetMethods : kGetDeclaredMethods; |
- |
ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>( |
env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName( |
env, |
kJavaLangClass, |
- get_method, |
+ kGetMethods, |
kReturningJavaLangReflectMethodArray)))); |
size_t num_methods = env->GetArrayLength(methods.obj()); |
- if (num_methods <= 0) |
- return; |
+ // Java objects always have public methods. |
+ DCHECK(num_methods); |
for (size_t i = 0; i < num_methods; ++i) { |
ScopedJavaLocalRef<jobject> java_method( |
env, |
env->GetObjectArrayElement(methods.obj(), i)); |
- bool is_method_allowed = true; |
- if (!allow_inherited_methods_) { |
- jint modifiers = env->CallIntMethod(java_method.obj(), |
- GetMethodIDFromClassName( |
- env, |
- kJavaLangReflectMethod, |
- kGetModifiers, |
- kReturningInteger)); |
- is_method_allowed &= (modifiers & kJavaPublicModifier); |
+ if (require_annotation_) { |
+ jboolean safe = env->CallBooleanMethod(java_method.obj(), |
+ GetMethodIDFromClassName( |
+ env, |
+ kJavaLangReflectMethod, |
+ kIsAnnotationPresent, |
+ kTakesJavaLangClassReturningBoolean), |
+ g_safe_annotation_clazz); |
+ |
+ if (!safe) |
+ continue; |
} |
- if (is_method_allowed) { |
- JavaMethod* method = new JavaMethod(java_method); |
- methods_.insert(std::make_pair(method->name(), method)); |
- } |
+ JavaMethod* method = new JavaMethod(java_method); |
+ methods_.insert(std::make_pair(method->name(), method)); |
} |
} |