blob: d77e3f0276166b904d76b5a9e46a8622832f8199 [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"
Elliott Hughes80609252011-09-23 17:24:51 -070021#include "ScopedLocalRef.h"
Brian Carlstromf91c8c32011-09-21 17:30:34 -070022#include "ScopedUtfChars.h"
Elliott Hughesd369bb72011-09-12 14:41:14 -070023
24#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
25
26namespace art {
27
28namespace {
29
Brian Carlstromf91c8c32011-09-21 17:30:34 -070030// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
31jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
32 ScopedUtfChars name(env, javaName);
33 if (name.c_str() == NULL) {
34 return NULL;
35 }
36
37 // We need to validate and convert the name (from x.y.z to x/y/z). This
38 // is especially handy for array types, since we want to avoid
39 // auto-generating bogus array classes.
40 if (!IsValidClassName(name.c_str(), true, true)) {
41 Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;",
42 "Invalid name: %s", name.c_str());
43 return NULL;
44 }
45
46 std::string descriptor(DotToDescriptor(name.c_str()));
47 Object* loader = Decode<Object*>(env, javaLoader);
48 ClassLoader* class_loader = down_cast<ClassLoader*>(loader);
49 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
50 Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
51 if (initialize) {
52 class_linker->EnsureInitialized(c, true);
53 }
54 return AddLocalReference<jclass>(env, c);
55}
56
Elliott Hughes80609252011-09-23 17:24:51 -070057template<typename T>
58jobjectArray ToArray(JNIEnv* env, const char* array_class_name, const std::vector<T*>& objects) {
59 jclass array_class = env->FindClass(array_class_name);
60 jobjectArray result = env->NewObjectArray(objects.size(), array_class, NULL);
61 for (size_t i = 0; i < objects.size(); ++i) {
62 ScopedLocalRef<jobject> object(env, AddLocalReference<jobject>(env, objects[i]));
63 env->SetObjectArrayElement(result, i, object.get());
64 }
65 return result;
66}
67
68bool IsVisibleConstructor(Method* m, bool public_only) {
69 if (public_only && !m->IsPublic()) {
70 return false;
71 }
72 if (m->IsMiranda() || m->IsStatic()) {
73 return false;
74 }
75 if (m->GetName()->CharAt(0) != '<') {
76 return false;
77 }
78 m->InitJavaFields();
79 return true;
80}
81
82jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
83 Class* c = Decode<Class*>(env, javaClass);
84
85 std::vector<Method*> constructors;
86 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
87 Method* m = c->GetDirectMethod(i);
88 if (IsVisibleConstructor(m, publicOnly)) {
89 constructors.push_back(m);
90 }
91 }
92
93 return ToArray(env, "java/lang/reflect/Constructor", constructors);
94}
95
96bool IsVisibleField(Field* f, bool public_only) {
97 if (public_only && ~f->IsPublic()) {
98 return false;
99 }
100 f->InitJavaFields();
101 return true;
102}
103
104jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
105 Class* c = Decode<Class*>(env, javaClass);
106
107 std::vector<Field*> fields;
108 for (size_t i = 0; i < c->NumInstanceFields(); ++i) {
109 Field* f = c->GetInstanceField(i);
110 if (IsVisibleField(f, publicOnly)) {
111 fields.push_back(f);
112 }
113 }
114 for (size_t i = 0; i < c->NumStaticFields(); ++i) {
115 Field* f = c->GetStaticField(i);
116 if (IsVisibleField(f, publicOnly)) {
117 fields.push_back(f);
118 }
119 }
120
121 return ToArray(env, "java/lang/reflect/Field", fields);
122}
123
124bool IsVisibleMethod(Method* m, bool public_only) {
125 if (public_only && !m->IsPublic()) {
126 return false;
127 }
128 if (m->IsMiranda()) {
129 return false;
130 }
131 if (m->GetName()->CharAt(0) == '<') {
132 return false;
133 }
134 m->InitJavaFields();
135 return true;
136}
137
138jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
139 Class* c = Decode<Class*>(env, javaClass);
140
141 std::vector<Method*> methods;
142 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
143 Method* m = c->GetVirtualMethod(i);
144 if (IsVisibleMethod(m, publicOnly)) {
145 methods.push_back(m);
146 }
147 }
148 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
149 Method* m = c->GetDirectMethod(i);
150 if (IsVisibleMethod(m, publicOnly)) {
151 methods.push_back(m);
152 }
153 }
154
155 return ToArray(env, "java/lang/reflect/Method", methods);
156}
157
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700158jboolean Class_desiredAssertionStatus(JNIEnv* env, jobject javaThis) {
159 return JNI_FALSE;
160}
161
162jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
163 Class* c = Decode<Class*>(env, javaClass);
164 Object* result = reinterpret_cast<Object*>(const_cast<ClassLoader*>(c->GetClassLoader()));
165 return AddLocalReference<jobject>(env, result);
166}
167
Elliott Hughesd369bb72011-09-12 14:41:14 -0700168jclass Class_getComponentType(JNIEnv* env, jobject javaThis) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700169 return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType());
Elliott Hughesd369bb72011-09-12 14:41:14 -0700170}
171
Elliott Hughes418d20f2011-09-22 14:00:39 -0700172bool MethodMatches(Method* m, String* name, const std::string& signature) {
173 if (!m->GetName()->Equals(name)) {
174 return false;
175 }
176 std::string method_signature = m->GetSignature()->ToModifiedUtf8();
177 if (!StringPiece(method_signature).starts_with(signature)) {
178 return false;
179 }
180 m->InitJavaFields();
181 return true;
182}
183
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700184jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass,
Elliott Hughes418d20f2011-09-22 14:00:39 -0700185 jclass javaClass, jstring javaName, jobjectArray javaSignature) {
186 Class* c = Decode<Class*>(env, javaClass);
187 String* name = Decode<String*>(env, javaName);
188 ObjectArray<Class>* signature_array = Decode<ObjectArray<Class>*>(env, javaSignature);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700189
Elliott Hughes418d20f2011-09-22 14:00:39 -0700190 std::string signature;
191 signature += "(";
192 for (int i = 0; i < signature_array->GetLength(); i++) {
193 signature += signature_array->Get(i)->GetDescriptor()->ToModifiedUtf8();
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700194 }
Elliott Hughes418d20f2011-09-22 14:00:39 -0700195 signature += ")";
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700196
Elliott Hughes418d20f2011-09-22 14:00:39 -0700197 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
198 Method* m = c->GetVirtualMethod(i);
199 if (MethodMatches(m, name, signature)) {
200 return AddLocalReference<jobject>(env, m);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700201 }
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700202 }
203
Elliott Hughes418d20f2011-09-22 14:00:39 -0700204 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
205 Method* m = c->GetDirectMethod(i);
206 if (MethodMatches(m, name, signature)) {
207 return AddLocalReference<jobject>(env, m);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700208 }
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700209 }
210
211 return NULL;
212}
213
214jobject Class_getDeclaredField(JNIEnv* env, jclass, jclass jklass, jobject jname) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700215 Class* klass = Decode<Class*>(env, jklass);
216 DCHECK(klass->IsClass());
217 String* name = Decode<String*>(env, jname);
218 DCHECK(name->IsString());
219
Elliott Hughes80609252011-09-23 17:24:51 -0700220 for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700221 Field* f = klass->GetInstanceField(i);
222 if (f->GetName()->Equals(name)) {
Elliott Hughes80609252011-09-23 17:24:51 -0700223 f->InitJavaFields();
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700224 return AddLocalReference<jclass>(env, f);
225 }
226 }
227 for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
228 Field* f = klass->GetStaticField(i);
229 if (f->GetName()->Equals(name)) {
Elliott Hughes80609252011-09-23 17:24:51 -0700230 f->InitJavaFields();
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700231 return AddLocalReference<jclass>(env, f);
232 }
233 }
234 return NULL;
235}
236
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700237jclass Class_getDeclaringClass(JNIEnv* env, jobject javaThis) {
238 UNIMPLEMENTED(WARNING) << "needs annotations";
239 return NULL;
240}
241
Brian Carlstrom53d6ff42011-09-23 10:45:07 -0700242jobject Class_getEnclosingConstructor(JNIEnv* env, jobject javaThis) {
243 UNIMPLEMENTED(WARNING) << "needs annotations";
244 return NULL;
245}
246
247jobject Class_getEnclosingMethod(JNIEnv* env, jobject javaThis) {
248 UNIMPLEMENTED(WARNING) << "needs annotations";
249 return NULL;
250}
251
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700252/*
253 * private native String getNameNative()
254 *
255 * Return the class' name. The exact format is bizarre, but it's the specified
256 * behavior: keywords for primitive types, regular "[I" form for primitive
257 * arrays (so "int" but "[I"), and arrays of reference types written
258 * between "L" and ";" but with dots rather than slashes (so "java.lang.String"
259 * but "[Ljava.lang.String;"). Madness.
260 */
261jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
262 Class* c = Decode<Class*>(env, javaThis);
263 std::string descriptor(c->GetDescriptor()->ToModifiedUtf8());
264 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
265 // The descriptor indicates that this is the class for
266 // a primitive type; special-case the return value.
267 const char* name = NULL;
268 switch (descriptor[0]) {
269 case 'Z': name = "boolean"; break;
270 case 'B': name = "byte"; break;
271 case 'C': name = "char"; break;
272 case 'S': name = "short"; break;
273 case 'I': name = "int"; break;
274 case 'J': name = "long"; break;
275 case 'F': name = "float"; break;
276 case 'D': name = "double"; break;
277 case 'V': name = "void"; break;
278 default:
279 LOG(FATAL) << "Unknown primitive type: " << PrintableChar(descriptor[0]);
280 }
281 return env->NewStringUTF(name);
282 }
283
284 // Convert the UTF-8 name to a java.lang.String. The
285 // name must use '.' to separate package components.
286 if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
287 descriptor.erase(0, 1);
288 descriptor.erase(descriptor.size() - 1);
289 }
290 std::replace(descriptor.begin(), descriptor.end(), '/', '.');
291 return env->NewStringUTF(descriptor.c_str());
292}
293
294jclass Class_getSuperclass(JNIEnv* env, jobject javaThis) {
295 Class* c = Decode<Class*>(env, javaThis);
296 Class* result = c->GetSuperClass();
297 return AddLocalReference<jclass>(env, result);
298}
299
300jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) {
301 UNIMPLEMENTED(WARNING) << "needs annotations";
302 return JNI_FALSE;
303}
304
Elliott Hughesdd8df692011-09-23 14:42:41 -0700305jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
306 Class* lhs = Decode<Class*>(env, javaLhs);
307 Class* rhs = Decode<Class*>(env, javaRhs);
308 if (rhs == NULL) {
309 Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "class == null");
310 return JNI_FALSE;
311 }
312 return lhs->IsAssignableFrom(rhs) ? JNI_TRUE : JNI_FALSE;
313}
314
315jboolean Class_isInstance(JNIEnv* env, jobject javaClass, jobject javaObject) {
316 Class* c = Decode<Class*>(env, javaClass);
317 Object* o = Decode<Object*>(env, javaObject);
318 if (o == NULL) {
319 return JNI_FALSE;
320 }
321 return Object::InstanceOf(o, c) ? JNI_TRUE : JNI_FALSE;
322}
323
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700324jboolean Class_isInterface(JNIEnv* env, jobject javaThis) {
325 Class* c = Decode<Class*>(env, javaThis);
326 return c->IsInterface();
327}
328
329jboolean Class_isPrimitive(JNIEnv* env, jobject javaThis) {
330 Class* c = Decode<Class*>(env, javaThis);
331 return c->IsPrimitive();
332}
333
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700334// Validate method/field access.
335bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
336 // quick accept for public access */
337 if (member_flags & kAccPublic) {
338 return true;
339 }
340
341 // quick accept for access from same class
342 if (access_from == access_to) {
343 return true;
344 }
345
346 // quick reject for private access from another class
347 if (member_flags & kAccPrivate) {
348 return false;
349 }
350
351 // Semi-quick test for protected access from a sub-class, which may or
352 // may not be in the same package.
353 if (member_flags & kAccProtected) {
354 if (access_from->IsSubClass(access_to)) {
355 return true;
356 }
357 }
358
359 // Allow protected and private access from other classes in the same
360 return access_from->IsInSamePackage(access_to);
361}
362
363jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
364 Class* c = Decode<Class*>(env, javaThis);
365 if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
366 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
367 "Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
368 return NULL;
369 }
370
371 Method* init = c->FindDirectMethod("<init>", "()V");
372 if (init == NULL) {
373 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
374 "Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
375 return NULL;
376 }
377
378 // Verify access from the call site.
379 //
380 // First, make sure the method invoking Class.newInstance() has permission
381 // to access the class.
382 //
383 // Second, make sure it has permission to invoke the constructor. The
384 // constructor must be public or, if the caller is in the same package,
385 // have package scope.
386 // TODO: need SmartFrame (Thread::WalkStack-like iterator).
387 Frame frame = Thread::Current()->GetTopOfStack();
388 frame.Next();
389 frame.Next();
390 Method* caller_caller = frame.GetMethod();
391 Class* caller_class = caller_caller->GetDeclaringClass();
392
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700393 if (!caller_class->CanAccess(c)) {
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700394 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
395 "Class %s is not accessible from class %s",
396 PrettyDescriptor(c->GetDescriptor()).c_str(),
397 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
398 return NULL;
399 }
400 if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
401 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
402 "%s is not accessible from class %s",
403 PrettyMethod(init).c_str(),
404 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
405 return NULL;
406 }
407
408 Object* new_obj = c->AllocObject();
409 if (new_obj == NULL) {
410 DCHECK(Thread::Current()->IsExceptionPending());
411 return NULL;
412 }
413
414 // invoke constructor; unlike reflection calls, we don't wrap exceptions
415 jclass jklass = AddLocalReference<jclass>(env, c);
416 jmethodID mid = EncodeMethod(init);
417 return env->NewObject(jklass, mid);
418}
419
Elliott Hughesd369bb72011-09-12 14:41:14 -0700420static JNINativeMethod gMethods[] = {
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700421 NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700422 NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
423 NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700424 NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700425 NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
Elliott Hughes80609252011-09-23 17:24:51 -0700426 NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700427 NATIVE_METHOD(Class, getDeclaredField, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"),
Elliott Hughes80609252011-09-23 17:24:51 -0700428 NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
429 NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700430 NATIVE_METHOD(Class, getDeclaringClass, "()Ljava/lang/Class;"),
Brian Carlstrom53d6ff42011-09-23 10:45:07 -0700431 //NATIVE_METHOD(Class, getEnclosingClass, "()Ljava/lang/Class;"),
432 NATIVE_METHOD(Class, getEnclosingConstructor, "()Ljava/lang/reflect/Constructor;"),
433 NATIVE_METHOD(Class, getEnclosingMethod, "()Ljava/lang/reflect/Method;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700434 //NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700435 //NATIVE_METHOD(Class, getModifiers, "(Ljava/lang/Class;Z)I"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700436 NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700437 NATIVE_METHOD(Class, getSuperclass, "()Ljava/lang/Class;"),
438 NATIVE_METHOD(Class, isAnonymousClass, "()Z"),
Elliott Hughesdd8df692011-09-23 14:42:41 -0700439 NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
440 NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700441 NATIVE_METHOD(Class, isInterface, "()Z"),
442 NATIVE_METHOD(Class, isPrimitive, "()Z"),
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700443 NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700444};
445
446} // namespace
447
448void register_java_lang_Class(JNIEnv* env) {
449 jniRegisterNativeMethods(env, "java/lang/Class", gMethods, NELEM(gMethods));
450}
451
452} // namespace art