blob: c334f046e55941ae3530632fae2bb012cb48228a [file] [log] [blame]
Elliott Hughesd369bb72011-09-12 14:41:14 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni_internal.h"
18#include "class_linker.h"
Brian Carlstromf91c8c32011-09-21 17:30:34 -070019#include "class_loader.h"
Elliott Hughesd369bb72011-09-12 14:41:14 -070020#include "object.h"
Brian Carlstromf91c8c32011-09-21 17:30:34 -070021#include "ScopedUtfChars.h"
Elliott Hughesd369bb72011-09-12 14:41:14 -070022
23#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
24
25namespace art {
26
27namespace {
28
Brian Carlstromf91c8c32011-09-21 17:30:34 -070029// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
30jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
31 ScopedUtfChars name(env, javaName);
32 if (name.c_str() == NULL) {
33 return NULL;
34 }
35
36 // We need to validate and convert the name (from x.y.z to x/y/z). This
37 // is especially handy for array types, since we want to avoid
38 // auto-generating bogus array classes.
39 if (!IsValidClassName(name.c_str(), true, true)) {
40 Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;",
41 "Invalid name: %s", name.c_str());
42 return NULL;
43 }
44
45 std::string descriptor(DotToDescriptor(name.c_str()));
46 Object* loader = Decode<Object*>(env, javaLoader);
47 ClassLoader* class_loader = down_cast<ClassLoader*>(loader);
48 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
49 Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
50 if (initialize) {
51 class_linker->EnsureInitialized(c, true);
52 }
53 return AddLocalReference<jclass>(env, c);
54}
55
Elliott Hughes6bdc3b22011-09-16 19:24:10 -070056jboolean Class_desiredAssertionStatus(JNIEnv* env, jobject javaThis) {
57 return JNI_FALSE;
58}
59
60jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
61 Class* c = Decode<Class*>(env, javaClass);
62 Object* result = reinterpret_cast<Object*>(const_cast<ClassLoader*>(c->GetClassLoader()));
63 return AddLocalReference<jobject>(env, result);
64}
65
Elliott Hughesd369bb72011-09-12 14:41:14 -070066jclass Class_getComponentType(JNIEnv* env, jobject javaThis) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070067 return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType());
Elliott Hughesd369bb72011-09-12 14:41:14 -070068}
69
Elliott Hughes418d20f2011-09-22 14:00:39 -070070bool MethodMatches(Method* m, String* name, const std::string& signature) {
71 if (!m->GetName()->Equals(name)) {
72 return false;
73 }
74 std::string method_signature = m->GetSignature()->ToModifiedUtf8();
75 if (!StringPiece(method_signature).starts_with(signature)) {
76 return false;
77 }
78 m->InitJavaFields();
79 return true;
80}
81
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070082jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass,
Elliott Hughes418d20f2011-09-22 14:00:39 -070083 jclass javaClass, jstring javaName, jobjectArray javaSignature) {
84 Class* c = Decode<Class*>(env, javaClass);
85 String* name = Decode<String*>(env, javaName);
86 ObjectArray<Class>* signature_array = Decode<ObjectArray<Class>*>(env, javaSignature);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070087
Elliott Hughes418d20f2011-09-22 14:00:39 -070088 std::string signature;
89 signature += "(";
90 for (int i = 0; i < signature_array->GetLength(); i++) {
91 signature += signature_array->Get(i)->GetDescriptor()->ToModifiedUtf8();
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070092 }
Elliott Hughes418d20f2011-09-22 14:00:39 -070093 signature += ")";
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070094
Elliott Hughes418d20f2011-09-22 14:00:39 -070095 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
96 Method* m = c->GetVirtualMethod(i);
97 if (MethodMatches(m, name, signature)) {
98 return AddLocalReference<jobject>(env, m);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070099 }
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700100 }
101
Elliott Hughes418d20f2011-09-22 14:00:39 -0700102 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
103 Method* m = c->GetDirectMethod(i);
104 if (MethodMatches(m, name, signature)) {
105 return AddLocalReference<jobject>(env, m);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700106 }
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700107 }
108
109 return NULL;
110}
111
112jobject Class_getDeclaredField(JNIEnv* env, jclass, jclass jklass, jobject jname) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700113 Class* klass = Decode<Class*>(env, jklass);
114 DCHECK(klass->IsClass());
115 String* name = Decode<String*>(env, jname);
116 DCHECK(name->IsString());
117
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700118 for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700119 Field* f = klass->GetInstanceField(i);
120 if (f->GetName()->Equals(name)) {
121 return AddLocalReference<jclass>(env, f);
122 }
123 }
124 for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
125 Field* f = klass->GetStaticField(i);
126 if (f->GetName()->Equals(name)) {
127 return AddLocalReference<jclass>(env, f);
128 }
129 }
130 return NULL;
131}
132
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700133jclass Class_getDeclaringClass(JNIEnv* env, jobject javaThis) {
134 UNIMPLEMENTED(WARNING) << "needs annotations";
135 return NULL;
136}
137
Brian Carlstrom53d6ff42011-09-23 10:45:07 -0700138jobject Class_getEnclosingConstructor(JNIEnv* env, jobject javaThis) {
139 UNIMPLEMENTED(WARNING) << "needs annotations";
140 return NULL;
141}
142
143jobject Class_getEnclosingMethod(JNIEnv* env, jobject javaThis) {
144 UNIMPLEMENTED(WARNING) << "needs annotations";
145 return NULL;
146}
147
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700148/*
149 * private native String getNameNative()
150 *
151 * Return the class' name. The exact format is bizarre, but it's the specified
152 * behavior: keywords for primitive types, regular "[I" form for primitive
153 * arrays (so "int" but "[I"), and arrays of reference types written
154 * between "L" and ";" but with dots rather than slashes (so "java.lang.String"
155 * but "[Ljava.lang.String;"). Madness.
156 */
157jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
158 Class* c = Decode<Class*>(env, javaThis);
159 std::string descriptor(c->GetDescriptor()->ToModifiedUtf8());
160 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
161 // The descriptor indicates that this is the class for
162 // a primitive type; special-case the return value.
163 const char* name = NULL;
164 switch (descriptor[0]) {
165 case 'Z': name = "boolean"; break;
166 case 'B': name = "byte"; break;
167 case 'C': name = "char"; break;
168 case 'S': name = "short"; break;
169 case 'I': name = "int"; break;
170 case 'J': name = "long"; break;
171 case 'F': name = "float"; break;
172 case 'D': name = "double"; break;
173 case 'V': name = "void"; break;
174 default:
175 LOG(FATAL) << "Unknown primitive type: " << PrintableChar(descriptor[0]);
176 }
177 return env->NewStringUTF(name);
178 }
179
180 // Convert the UTF-8 name to a java.lang.String. The
181 // name must use '.' to separate package components.
182 if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
183 descriptor.erase(0, 1);
184 descriptor.erase(descriptor.size() - 1);
185 }
186 std::replace(descriptor.begin(), descriptor.end(), '/', '.');
187 return env->NewStringUTF(descriptor.c_str());
188}
189
190jclass Class_getSuperclass(JNIEnv* env, jobject javaThis) {
191 Class* c = Decode<Class*>(env, javaThis);
192 Class* result = c->GetSuperClass();
193 return AddLocalReference<jclass>(env, result);
194}
195
196jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) {
197 UNIMPLEMENTED(WARNING) << "needs annotations";
198 return JNI_FALSE;
199}
200
Elliott Hughesdd8df692011-09-23 14:42:41 -0700201jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
202 Class* lhs = Decode<Class*>(env, javaLhs);
203 Class* rhs = Decode<Class*>(env, javaRhs);
204 if (rhs == NULL) {
205 Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "class == null");
206 return JNI_FALSE;
207 }
208 return lhs->IsAssignableFrom(rhs) ? JNI_TRUE : JNI_FALSE;
209}
210
211jboolean Class_isInstance(JNIEnv* env, jobject javaClass, jobject javaObject) {
212 Class* c = Decode<Class*>(env, javaClass);
213 Object* o = Decode<Object*>(env, javaObject);
214 if (o == NULL) {
215 return JNI_FALSE;
216 }
217 return Object::InstanceOf(o, c) ? JNI_TRUE : JNI_FALSE;
218}
219
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700220jboolean Class_isInterface(JNIEnv* env, jobject javaThis) {
221 Class* c = Decode<Class*>(env, javaThis);
222 return c->IsInterface();
223}
224
225jboolean Class_isPrimitive(JNIEnv* env, jobject javaThis) {
226 Class* c = Decode<Class*>(env, javaThis);
227 return c->IsPrimitive();
228}
229
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700230// Validate method/field access.
231bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
232 // quick accept for public access */
233 if (member_flags & kAccPublic) {
234 return true;
235 }
236
237 // quick accept for access from same class
238 if (access_from == access_to) {
239 return true;
240 }
241
242 // quick reject for private access from another class
243 if (member_flags & kAccPrivate) {
244 return false;
245 }
246
247 // Semi-quick test for protected access from a sub-class, which may or
248 // may not be in the same package.
249 if (member_flags & kAccProtected) {
250 if (access_from->IsSubClass(access_to)) {
251 return true;
252 }
253 }
254
255 // Allow protected and private access from other classes in the same
256 return access_from->IsInSamePackage(access_to);
257}
258
259jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
260 Class* c = Decode<Class*>(env, javaThis);
261 if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
262 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
263 "Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
264 return NULL;
265 }
266
267 Method* init = c->FindDirectMethod("<init>", "()V");
268 if (init == NULL) {
269 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
270 "Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
271 return NULL;
272 }
273
274 // Verify access from the call site.
275 //
276 // First, make sure the method invoking Class.newInstance() has permission
277 // to access the class.
278 //
279 // Second, make sure it has permission to invoke the constructor. The
280 // constructor must be public or, if the caller is in the same package,
281 // have package scope.
282 // TODO: need SmartFrame (Thread::WalkStack-like iterator).
283 Frame frame = Thread::Current()->GetTopOfStack();
284 frame.Next();
285 frame.Next();
286 Method* caller_caller = frame.GetMethod();
287 Class* caller_class = caller_caller->GetDeclaringClass();
288
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700289 if (!caller_class->CanAccess(c)) {
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700290 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
291 "Class %s is not accessible from class %s",
292 PrettyDescriptor(c->GetDescriptor()).c_str(),
293 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
294 return NULL;
295 }
296 if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
297 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
298 "%s is not accessible from class %s",
299 PrettyMethod(init).c_str(),
300 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
301 return NULL;
302 }
303
304 Object* new_obj = c->AllocObject();
305 if (new_obj == NULL) {
306 DCHECK(Thread::Current()->IsExceptionPending());
307 return NULL;
308 }
309
310 // invoke constructor; unlike reflection calls, we don't wrap exceptions
311 jclass jklass = AddLocalReference<jclass>(env, c);
312 jmethodID mid = EncodeMethod(init);
313 return env->NewObject(jklass, mid);
314}
315
Elliott Hughesd369bb72011-09-12 14:41:14 -0700316static JNINativeMethod gMethods[] = {
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700317 NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700318 NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
319 NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700320 NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700321 NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700322 //NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700323 NATIVE_METHOD(Class, getDeclaredField, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700324 //NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
325 //NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700326 NATIVE_METHOD(Class, getDeclaringClass, "()Ljava/lang/Class;"),
Brian Carlstrom53d6ff42011-09-23 10:45:07 -0700327 //NATIVE_METHOD(Class, getEnclosingClass, "()Ljava/lang/Class;"),
328 NATIVE_METHOD(Class, getEnclosingConstructor, "()Ljava/lang/reflect/Constructor;"),
329 NATIVE_METHOD(Class, getEnclosingMethod, "()Ljava/lang/reflect/Method;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700330 //NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700331 //NATIVE_METHOD(Class, getModifiers, "(Ljava/lang/Class;Z)I"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700332 NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700333 NATIVE_METHOD(Class, getSuperclass, "()Ljava/lang/Class;"),
334 NATIVE_METHOD(Class, isAnonymousClass, "()Z"),
Elliott Hughesdd8df692011-09-23 14:42:41 -0700335 NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
336 NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700337 NATIVE_METHOD(Class, isInterface, "()Z"),
338 NATIVE_METHOD(Class, isPrimitive, "()Z"),
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700339 NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700340};
341
342} // namespace
343
344void register_java_lang_Class(JNIEnv* env) {
345 jniRegisterNativeMethods(env, "java/lang/Class", gMethods, NELEM(gMethods));
346}
347
348} // namespace art