OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/java/java_bound_object.h" | 5 #include "content/browser/renderer_host/java/java_bound_object.h" |
6 | 6 |
7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
9 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" |
10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
27 // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. | 27 // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. |
28 | 28 |
29 // Note that in some cases, we differ from from the spec in order to maintain | 29 // Note that in some cases, we differ from from the spec in order to maintain |
30 // existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may | 30 // existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may |
31 // revisit this decision in the future. | 31 // revisit this decision in the future. |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 const char kJavaLangClass[] = "java/lang/Class"; | 35 const char kJavaLangClass[] = "java/lang/Class"; |
36 const char kJavaLangObject[] = "java/lang/Object"; | 36 const char kJavaLangObject[] = "java/lang/Object"; |
37 const char kJavaLangReflectMethod[] = "java/lang/reflect/Method"; | |
37 const char kGetClass[] = "getClass"; | 38 const char kGetClass[] = "getClass"; |
39 const char kGetDeclaredMethods[] = "getDeclaredMethods"; | |
38 const char kGetMethods[] = "getMethods"; | 40 const char kGetMethods[] = "getMethods"; |
41 const char kGetModifiers[] = "getModifiers"; | |
42 const char kReturningInteger[] = "()I"; | |
39 const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; | 43 const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; |
40 const char kReturningJavaLangReflectMethodArray[] = | 44 const char kReturningJavaLangReflectMethodArray[] = |
41 "()[Ljava/lang/reflect/Method;"; | 45 "()[Ljava/lang/reflect/Method;"; |
42 | 46 |
47 // This constant represents the value at java.lang.reflect.Modifier.PUBLIC. | |
48 const int kJavaPublicModifier = 1; | |
49 | |
43 // Our special NPObject type. We extend an NPObject with a pointer to a | 50 // Our special NPObject type. We extend an NPObject with a pointer to a |
44 // JavaBoundObject. We also add static methods for each of the NPObject | 51 // JavaBoundObject. We also add static methods for each of the NPObject |
45 // callbacks, which are registered by our NPClass. These methods simply | 52 // callbacks, which are registered by our NPClass. These methods simply |
46 // delegate to the private implementation methods of JavaBoundObject. | 53 // delegate to the private implementation methods of JavaBoundObject. |
47 struct JavaNPObject : public NPObject { | 54 struct JavaNPObject : public NPObject { |
48 JavaBoundObject* bound_object; | 55 JavaBoundObject* bound_object; |
49 | 56 |
50 static const NPClass kNPClass; | 57 static const NPClass kNPClass; |
51 | 58 |
52 static NPObject* Allocate(NPP npp, NPClass* np_class); | 59 static NPObject* Allocate(NPP npp, NPClass* np_class); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
113 // that the property is undefined. Spec requires supporting this correctly. | 120 // that the property is undefined. Spec requires supporting this correctly. |
114 return false; | 121 return false; |
115 } | 122 } |
116 | 123 |
117 // Calls a Java method through JNI. If the Java method raises an uncaught | 124 // Calls a Java method through JNI. If the Java method raises an uncaught |
118 // exception, it is cleared and this method returns false. Otherwise, this | 125 // exception, it is cleared and this method returns false. Otherwise, this |
119 // method returns true and the Java method's return value is provided as an | 126 // method returns true and the Java method's return value is provided as an |
120 // NPVariant. Note that this method does not do any type coercion. The Java | 127 // NPVariant. Note that this method does not do any type coercion. The Java |
121 // return value is simply converted to the corresponding NPAPI type. | 128 // return value is simply converted to the corresponding NPAPI type. |
122 bool CallJNIMethod(jobject object, const JavaType& return_type, jmethodID id, | 129 bool CallJNIMethod(jobject object, const JavaType& return_type, jmethodID id, |
123 jvalue* parameters, NPVariant* result) { | 130 jvalue* parameters, NPVariant* result, |
131 bool allow_inherited_methods) { | |
124 JNIEnv* env = AttachCurrentThread(); | 132 JNIEnv* env = AttachCurrentThread(); |
125 switch (return_type.type) { | 133 switch (return_type.type) { |
126 case JavaType::TypeBoolean: | 134 case JavaType::TypeBoolean: |
127 BOOLEAN_TO_NPVARIANT(env->CallBooleanMethodA(object, id, parameters), | 135 BOOLEAN_TO_NPVARIANT(env->CallBooleanMethodA(object, id, parameters), |
128 *result); | 136 *result); |
129 break; | 137 break; |
130 case JavaType::TypeByte: | 138 case JavaType::TypeByte: |
131 INT32_TO_NPVARIANT(env->CallByteMethodA(object, id, parameters), *result); | 139 INT32_TO_NPVARIANT(env->CallByteMethodA(object, id, parameters), *result); |
132 break; | 140 break; |
133 case JavaType::TypeChar: | 141 case JavaType::TypeChar: |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
194 // first. | 202 // first. |
195 jobject java_object = env->CallObjectMethodA(object, id, parameters); | 203 jobject java_object = env->CallObjectMethodA(object, id, parameters); |
196 if (base::android::ClearException(env)) { | 204 if (base::android::ClearException(env)) { |
197 return false; | 205 return false; |
198 } | 206 } |
199 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); | 207 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); |
200 if (!scoped_java_object.obj()) { | 208 if (!scoped_java_object.obj()) { |
201 NULL_TO_NPVARIANT(*result); | 209 NULL_TO_NPVARIANT(*result); |
202 break; | 210 break; |
203 } | 211 } |
204 OBJECT_TO_NPVARIANT(JavaBoundObject::Create(scoped_java_object), *result); | 212 OBJECT_TO_NPVARIANT(JavaBoundObject::Create(scoped_java_object, |
213 allow_inherited_methods), | |
214 *result); | |
205 break; | 215 break; |
206 } | 216 } |
207 } | 217 } |
208 return !base::android::ClearException(env); | 218 return !base::android::ClearException(env); |
209 } | 219 } |
210 | 220 |
211 jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant, | 221 jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant, |
212 const JavaType& target_type, | 222 const JavaType& target_type, |
213 bool coerce_to_string) { | 223 bool coerce_to_string) { |
214 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. | 224 // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
710 return CoerceJavaScriptNullOrUndefinedToJavaValue(variant, target_type, | 720 return CoerceJavaScriptNullOrUndefinedToJavaValue(variant, target_type, |
711 coerce_to_string); | 721 coerce_to_string); |
712 } | 722 } |
713 NOTREACHED(); | 723 NOTREACHED(); |
714 return jvalue(); | 724 return jvalue(); |
715 } | 725 } |
716 | 726 |
717 } // namespace | 727 } // namespace |
718 | 728 |
719 | 729 |
720 NPObject* JavaBoundObject::Create(const JavaRef<jobject>& object) { | 730 NPObject* JavaBoundObject::Create(const JavaRef<jobject>& object, |
731 bool allow_inherited_methods) { | |
721 // The first argument (a plugin's instance handle) is passed through to the | 732 // The first argument (a plugin's instance handle) is passed through to the |
722 // allocate function directly, and we don't use it, so it's ok to be 0. | 733 // allocate function directly, and we don't use it, so it's ok to be 0. |
723 // The object is created with a ref count of one. | 734 // The object is created with a ref count of one. |
724 NPObject* np_object = WebBindings::createObject(0, const_cast<NPClass*>( | 735 NPObject* np_object = WebBindings::createObject(0, const_cast<NPClass*>( |
725 &JavaNPObject::kNPClass)); | 736 &JavaNPObject::kNPClass)); |
726 // The NPObject takes ownership of the JavaBoundObject. | 737 // The NPObject takes ownership of the JavaBoundObject. |
727 reinterpret_cast<JavaNPObject*>(np_object)->bound_object = | 738 reinterpret_cast<JavaNPObject*>(np_object)->bound_object = |
728 new JavaBoundObject(object); | 739 new JavaBoundObject(object, allow_inherited_methods); |
729 return np_object; | 740 return np_object; |
730 } | 741 } |
731 | 742 |
732 JavaBoundObject::JavaBoundObject(const JavaRef<jobject>& object) | 743 JavaBoundObject::JavaBoundObject(const JavaRef<jobject>& object, |
733 : java_object_(object) { | 744 bool allow_inherited_methods) |
745 : java_object_(object), | |
746 are_methods_set_up_(false), | |
747 allow_inherited_methods_(allow_inherited_methods) { | |
734 // We don't do anything with our Java object when first created. We do it all | 748 // We don't do anything with our Java object when first created. We do it all |
735 // lazily when a method is first invoked. | 749 // lazily when a method is first invoked. |
736 } | 750 } |
737 | 751 |
738 JavaBoundObject::~JavaBoundObject() { | 752 JavaBoundObject::~JavaBoundObject() { |
739 } | 753 } |
740 | 754 |
741 jobject JavaBoundObject::GetJavaObject(NPObject* object) { | 755 jobject JavaBoundObject::GetJavaObject(NPObject* object) { |
742 DCHECK_EQ(&JavaNPObject::kNPClass, object->_class); | 756 DCHECK_EQ(&JavaNPObject::kNPClass, object->_class); |
743 JavaBoundObject* jbo = reinterpret_cast<JavaNPObject*>(object)->bound_object; | 757 JavaBoundObject* jbo = reinterpret_cast<JavaNPObject*>(object)->bound_object; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
776 // Coerce | 790 // Coerce |
777 std::vector<jvalue> parameters(arg_count); | 791 std::vector<jvalue> parameters(arg_count); |
778 for (size_t i = 0; i < arg_count; ++i) { | 792 for (size_t i = 0; i < arg_count; ++i) { |
779 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], | 793 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], |
780 method->parameter_type(i), | 794 method->parameter_type(i), |
781 true); | 795 true); |
782 } | 796 } |
783 | 797 |
784 // Call | 798 // Call |
785 bool ok = CallJNIMethod(java_object_.obj(), method->return_type(), | 799 bool ok = CallJNIMethod(java_object_.obj(), method->return_type(), |
786 method->id(), ¶meters[0], result); | 800 method->id(), ¶meters[0], result, |
801 allow_inherited_methods_); | |
787 | 802 |
788 // Now that we're done with the jvalue, release any local references created | 803 // Now that we're done with the jvalue, release any local references created |
789 // by CoerceJavaScriptValueToJavaValue(). | 804 // by CoerceJavaScriptValueToJavaValue(). |
790 JNIEnv* env = AttachCurrentThread(); | 805 JNIEnv* env = AttachCurrentThread(); |
791 for (size_t i = 0; i < arg_count; ++i) { | 806 for (size_t i = 0; i < arg_count; ++i) { |
792 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | 807 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); |
793 } | 808 } |
794 | 809 |
795 return ok; | 810 return ok; |
796 } | 811 } |
797 | 812 |
798 void JavaBoundObject::EnsureMethodsAreSetUp() const { | 813 void JavaBoundObject::EnsureMethodsAreSetUp() const { |
799 if (!methods_.empty()) { | 814 if (are_methods_set_up_) |
800 return; | 815 return; |
801 } | 816 are_methods_set_up_ = true; |
802 | 817 |
803 JNIEnv* env = AttachCurrentThread(); | 818 JNIEnv* env = AttachCurrentThread(); |
804 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | 819 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( |
805 env->CallObjectMethod(java_object_.obj(), GetMethodIDFromClassName( | 820 env->CallObjectMethod(java_object_.obj(), GetMethodIDFromClassName( |
806 env, | 821 env, |
807 kJavaLangObject, | 822 kJavaLangObject, |
808 kGetClass, | 823 kGetClass, |
809 kReturningJavaLangClass)))); | 824 kReturningJavaLangClass)))); |
825 | |
826 const char* get_method = allow_inherited_methods_ ? | |
827 kGetMethods : kGetDeclaredMethods; | |
828 | |
810 ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>( | 829 ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>( |
811 env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName( | 830 env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName( |
812 env, | 831 env, |
813 kJavaLangClass, | 832 kJavaLangClass, |
814 kGetMethods, | 833 get_method, |
815 kReturningJavaLangReflectMethodArray)))); | 834 kReturningJavaLangReflectMethodArray)))); |
835 | |
816 size_t num_methods = env->GetArrayLength(methods.obj()); | 836 size_t num_methods = env->GetArrayLength(methods.obj()); |
817 DCHECK(num_methods) << "Java objects always have public methods"; | 837 if (num_methods <= 0) |
838 return; | |
839 | |
818 for (size_t i = 0; i < num_methods; ++i) { | 840 for (size_t i = 0; i < num_methods; ++i) { |
819 ScopedJavaLocalRef<jobject> java_method( | 841 ScopedJavaLocalRef<jobject> java_method( |
820 env, | 842 env, |
821 env->GetObjectArrayElement(methods.obj(), i)); | 843 env->GetObjectArrayElement(methods.obj(), i)); |
822 JavaMethod* method = new JavaMethod(java_method); | 844 |
823 methods_.insert(std::make_pair(method->name(), method)); | 845 bool is_method_allowed = true; |
846 if (!allow_inherited_methods_) { | |
847 jint modifiers = env->CallIntMethod(java_method.obj(), | |
848 GetMethodIDFromClassName( | |
849 env, | |
850 kJavaLangReflectMethod, | |
851 kGetModifiers, | |
852 kReturningInteger)); | |
joth
2012/07/18 17:28:39
after the fact -- just noticed this is non-standar
| |
853 is_method_allowed &= (modifiers & kJavaPublicModifier); | |
854 } | |
855 | |
856 if (is_method_allowed) { | |
857 JavaMethod* method = new JavaMethod(java_method); | |
858 methods_.insert(std::make_pair(method->name(), method)); | |
859 } | |
824 } | 860 } |
825 } | 861 } |
OLD | NEW |