• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "JavaClassJobjectV8.h"
28 
29 #if ENABLE(JAVA_BRIDGE)
30 
31 #include "JavaFieldJobjectV8.h"
32 #include "JavaMethodJobject.h"
33 
34 using namespace JSC::Bindings;
35 
36 #if PLATFORM(ANDROID)
37 const char kJavaScriptInterfaceAnnotation[] = "android/webkit/JavascriptInterface";
38 const char kIsAnnotationPresent[] = "isAnnotationPresent";
39 const char kGetMethods[] = "getMethods";
40 
41 static jclass safeAnnotationClazz = NULL;
42 
JavaClassJobject(jobject anInstance,bool requireAnnotation)43 JavaClassJobject::JavaClassJobject(jobject anInstance, bool requireAnnotation)
44     : m_requireAnnotation(requireAnnotation)
45 #else
46 JavaClassJobject::JavaClassJobject(jobject anInstance)
47 #endif
48 {
49     jobject aClass = callJNIMethod<jobject>(anInstance, "getClass", "()Ljava/lang/Class;");
50 
51     if (!aClass) {
52         LOG_ERROR("unable to call getClass on instance %p", anInstance);
53         return;
54     }
55 
56     JNIEnv* env = getJNIEnv();
57 
58     // Get the fields
59     jarray fields = static_cast<jarray>(callJNIMethod<jobject>(aClass, "getFields", "()[Ljava/lang/reflect/Field;"));
60     int numFields = env->GetArrayLength(fields);
61     for (int i = 0; i < numFields; i++) {
62         jobject aJField = env->GetObjectArrayElement(static_cast<jobjectArray>(fields), i);
63         JavaField* aField = new JavaFieldJobject(env, aJField); // deleted in the JavaClass destructor
64         m_fields.set(aField->name(), aField);
65         env->DeleteLocalRef(aJField);
66     }
67 
68     // Get the methods
69     jarray methods = static_cast<jarray>(callJNIMethod<jobject>(aClass, "getMethods", "()[Ljava/lang/reflect/Method;"));
70     int numMethods = env->GetArrayLength(methods);
71 #if PLATFORM(ANDROID)
72     jmethodID isAnnotationPresentMethodID = getAnnotationMethodID(env);
73     if (!isAnnotationPresentMethodID) {
74         LOG_ERROR("unable to find method %s on instance %p", kIsAnnotationPresent, anInstance);
75         return;
76     }
77 #endif
78     for (int i = 0; i < numMethods; i++) {
79         jobject aJMethod = env->GetObjectArrayElement(static_cast<jobjectArray>(methods), i);
80 #if PLATFORM(ANDROID)
81         if (jsAccessAllowed(env, isAnnotationPresentMethodID, aJMethod)) {
82 #endif
83             JavaMethod* aMethod = new JavaMethodJobject(env, aJMethod); // deleted in the JavaClass destructor
84             MethodList* methodList = m_methods.get(aMethod->name());
85             if (!methodList) {
86                 methodList = new MethodList();
87                 m_methods.set(aMethod->name(), methodList);
88             }
89             methodList->append(aMethod);
90 #if PLATFORM(ANDROID)
91         }
92 #endif
93         env->DeleteLocalRef(aJMethod);
94     }
95     env->DeleteLocalRef(fields);
96     env->DeleteLocalRef(methods);
97     env->DeleteLocalRef(aClass);
98 }
99 
~JavaClassJobject()100 JavaClassJobject::~JavaClassJobject()
101 {
102     deleteAllValues(m_fields);
103     m_fields.clear();
104 
105     MethodListMap::const_iterator end = m_methods.end();
106     for (MethodListMap::const_iterator it = m_methods.begin(); it != end; ++it) {
107         const MethodList* methodList = it->second;
108         deleteAllValues(*methodList);
109         delete methodList;
110     }
111     m_methods.clear();
112 }
113 
114 #if PLATFORM(ANDROID)
jsAccessAllowed(JNIEnv * env,jmethodID mid,jobject aJMethod)115 bool JavaClassJobject::jsAccessAllowed(JNIEnv* env, jmethodID mid, jobject aJMethod)
116 {
117     if (!m_requireAnnotation)
118         return true;
119     bool accessAllowed = env->CallBooleanMethod(aJMethod, mid, safeAnnotationClazz);
120     if (env->ExceptionCheck()) {
121         env->ExceptionDescribe();
122         env->ExceptionClear();
123         return false;
124     }
125     return accessAllowed;
126 }
127 
getAnnotationMethodID(JNIEnv * env)128 jmethodID JavaClassJobject::getAnnotationMethodID(JNIEnv* env)
129 {
130     jclass methodClass = env->FindClass("java/lang/reflect/Method");
131     jmethodID mid = 0;
132     if (methodClass)
133         mid = env->GetMethodID(methodClass, kIsAnnotationPresent, "(Ljava/lang/Class;)Z");
134     if (!methodClass || !mid) {
135         env->ExceptionDescribe();
136         env->ExceptionClear();
137     }
138     env->DeleteLocalRef(methodClass);
139     return mid;
140 }
141 
RegisterJavaClassJobject(JNIEnv * env)142 bool JavaClassJobject::RegisterJavaClassJobject(JNIEnv* env) {
143     safeAnnotationClazz = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(kJavaScriptInterfaceAnnotation)));
144     if (!safeAnnotationClazz) {
145         LOG_ERROR("failed to register %s", kJavaScriptInterfaceAnnotation);
146         return false;
147     }
148     return true;
149 }
150 #endif
151 
methodsNamed(const char * name) const152 MethodList JavaClassJobject::methodsNamed(const char* name) const
153 {
154     MethodList* methodList = m_methods.get(name);
155 
156     if (methodList)
157         return *methodList;
158     return MethodList();
159 }
160 
fieldNamed(const char * name) const161 JavaField* JavaClassJobject::fieldNamed(const char* name) const
162 {
163     return m_fields.get(name);
164 }
165 
166 #endif // ENABLE(JAVA_BRIDGE)
167