blob: 32941be0c0a1ded95616820324fcf8e1573f4993 [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
Elliott Hughes98fb4162011-09-22 15:24:13 -070060jobject Class_getDex(JNIEnv* env, jobject javaClass) {
61 Class* c = Decode<Class*>(env, javaClass);
62
63 DexCache* dex_cache = c->GetDexCache();
64 if (dex_cache == NULL) {
65 return NULL;
66 }
67
68 return Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache).GetDexObject(env);
69}
70
Elliott Hughes6bdc3b22011-09-16 19:24:10 -070071jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
72 Class* c = Decode<Class*>(env, javaClass);
73 Object* result = reinterpret_cast<Object*>(const_cast<ClassLoader*>(c->GetClassLoader()));
74 return AddLocalReference<jobject>(env, result);
75}
76
Elliott Hughesd369bb72011-09-12 14:41:14 -070077jclass Class_getComponentType(JNIEnv* env, jobject javaThis) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070078 return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType());
Elliott Hughesd369bb72011-09-12 14:41:14 -070079}
80
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070081jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass,
82 jclass jklass, jstring jname, jobjectArray jsignature) {
83 Class* klass = Decode<Class*>(env, jklass);
84 DCHECK(klass->IsClass());
85 String* name = Decode<String*>(env, jname);
86 DCHECK(name->IsString());
87 Object* signature_obj = Decode<Object*>(env, jsignature);
88 DCHECK(signature_obj->IsArrayInstance());
Brian Carlstrom03c99df2011-09-18 10:52:00 -070089 // check that this is a Class[] by checking that component type is Class
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -070090 // foo->GetClass()->GetClass() is an idiom for getting java.lang.Class from an arbitrary object
91 DCHECK(signature_obj->GetClass()->GetComponentType() == signature_obj->GetClass()->GetClass());
92 ObjectArray<Class>* signature = down_cast<ObjectArray<Class>*>(signature_obj);
93
94 std::string name_string = name->ToModifiedUtf8();
95 std::string signature_string;
96 signature_string += "(";
97 for (int i = 0; i < signature->GetLength(); i++) {
98 Class* argument_class = signature->Get(0);
99 if (argument_class == NULL) {
100 UNIMPLEMENTED(FATAL) << "throw null pointer exception?";
101 }
102 signature_string += argument_class->GetDescriptor()->ToModifiedUtf8();
103 }
104 signature_string += ")";
105
106 for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
107 Method* method = klass->GetVirtualMethod(i);
108 if (!method->GetName()->Equals(name)) {
109 continue;
110 }
111 std::string method_signature = method->GetSignature()->ToModifiedUtf8();
112 if (!StringPiece(method_signature).starts_with(signature_string)) {
113 continue;
114 }
115 return AddLocalReference<jobject>(env, method);
116 }
117
Brian Carlstrom03c99df2011-09-18 10:52:00 -0700118 for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
119 Method* method = klass->GetDirectMethod(i);
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700120 if (!method->GetName()->Equals(name)) {
121 continue;
122 }
123 std::string method_signature = method->GetSignature()->ToModifiedUtf8();
124 if (!StringPiece(method_signature).starts_with(signature_string)) {
125 continue;
126 }
127 return AddLocalReference<jobject>(env, method);
128 }
129
130 return NULL;
131}
132
133jobject Class_getDeclaredField(JNIEnv* env, jclass, jclass jklass, jobject jname) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700134 Class* klass = Decode<Class*>(env, jklass);
135 DCHECK(klass->IsClass());
136 String* name = Decode<String*>(env, jname);
137 DCHECK(name->IsString());
138
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700139 for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700140 Field* f = klass->GetInstanceField(i);
141 if (f->GetName()->Equals(name)) {
142 return AddLocalReference<jclass>(env, f);
143 }
144 }
145 for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
146 Field* f = klass->GetStaticField(i);
147 if (f->GetName()->Equals(name)) {
148 return AddLocalReference<jclass>(env, f);
149 }
150 }
151 return NULL;
152}
153
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700154jclass Class_getDeclaringClass(JNIEnv* env, jobject javaThis) {
155 UNIMPLEMENTED(WARNING) << "needs annotations";
156 return NULL;
157}
158
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700159/*
160 * private native String getNameNative()
161 *
162 * Return the class' name. The exact format is bizarre, but it's the specified
163 * behavior: keywords for primitive types, regular "[I" form for primitive
164 * arrays (so "int" but "[I"), and arrays of reference types written
165 * between "L" and ";" but with dots rather than slashes (so "java.lang.String"
166 * but "[Ljava.lang.String;"). Madness.
167 */
168jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
169 Class* c = Decode<Class*>(env, javaThis);
170 std::string descriptor(c->GetDescriptor()->ToModifiedUtf8());
171 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
172 // The descriptor indicates that this is the class for
173 // a primitive type; special-case the return value.
174 const char* name = NULL;
175 switch (descriptor[0]) {
176 case 'Z': name = "boolean"; break;
177 case 'B': name = "byte"; break;
178 case 'C': name = "char"; break;
179 case 'S': name = "short"; break;
180 case 'I': name = "int"; break;
181 case 'J': name = "long"; break;
182 case 'F': name = "float"; break;
183 case 'D': name = "double"; break;
184 case 'V': name = "void"; break;
185 default:
186 LOG(FATAL) << "Unknown primitive type: " << PrintableChar(descriptor[0]);
187 }
188 return env->NewStringUTF(name);
189 }
190
191 // Convert the UTF-8 name to a java.lang.String. The
192 // name must use '.' to separate package components.
193 if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
194 descriptor.erase(0, 1);
195 descriptor.erase(descriptor.size() - 1);
196 }
197 std::replace(descriptor.begin(), descriptor.end(), '/', '.');
198 return env->NewStringUTF(descriptor.c_str());
199}
200
201jclass Class_getSuperclass(JNIEnv* env, jobject javaThis) {
202 Class* c = Decode<Class*>(env, javaThis);
203 Class* result = c->GetSuperClass();
204 return AddLocalReference<jclass>(env, result);
205}
206
207jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) {
208 UNIMPLEMENTED(WARNING) << "needs annotations";
209 return JNI_FALSE;
210}
211
212jboolean Class_isInterface(JNIEnv* env, jobject javaThis) {
213 Class* c = Decode<Class*>(env, javaThis);
214 return c->IsInterface();
215}
216
217jboolean Class_isPrimitive(JNIEnv* env, jobject javaThis) {
218 Class* c = Decode<Class*>(env, javaThis);
219 return c->IsPrimitive();
220}
221
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700222bool CheckClassAccess(const Class* access_from, const Class* klass) {
223 if (klass->IsPublic()) {
224 return true;
225 }
226 return access_from->IsInSamePackage(klass);
227}
228
229// Validate method/field access.
230bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
231 // quick accept for public access */
232 if (member_flags & kAccPublic) {
233 return true;
234 }
235
236 // quick accept for access from same class
237 if (access_from == access_to) {
238 return true;
239 }
240
241 // quick reject for private access from another class
242 if (member_flags & kAccPrivate) {
243 return false;
244 }
245
246 // Semi-quick test for protected access from a sub-class, which may or
247 // may not be in the same package.
248 if (member_flags & kAccProtected) {
249 if (access_from->IsSubClass(access_to)) {
250 return true;
251 }
252 }
253
254 // Allow protected and private access from other classes in the same
255 return access_from->IsInSamePackage(access_to);
256}
257
258jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
259 Class* c = Decode<Class*>(env, javaThis);
260 if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
261 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
262 "Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
263 return NULL;
264 }
265
266 Method* init = c->FindDirectMethod("<init>", "()V");
267 if (init == NULL) {
268 Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
269 "Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
270 return NULL;
271 }
272
273 // Verify access from the call site.
274 //
275 // First, make sure the method invoking Class.newInstance() has permission
276 // to access the class.
277 //
278 // Second, make sure it has permission to invoke the constructor. The
279 // constructor must be public or, if the caller is in the same package,
280 // have package scope.
281 // TODO: need SmartFrame (Thread::WalkStack-like iterator).
282 Frame frame = Thread::Current()->GetTopOfStack();
283 frame.Next();
284 frame.Next();
285 Method* caller_caller = frame.GetMethod();
286 Class* caller_class = caller_caller->GetDeclaringClass();
287
288 if (!CheckClassAccess(c, caller_class)) {
289 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
290 "Class %s is not accessible from class %s",
291 PrettyDescriptor(c->GetDescriptor()).c_str(),
292 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
293 return NULL;
294 }
295 if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
296 Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
297 "%s is not accessible from class %s",
298 PrettyMethod(init).c_str(),
299 PrettyDescriptor(caller_class->GetDescriptor()).c_str());
300 return NULL;
301 }
302
303 Object* new_obj = c->AllocObject();
304 if (new_obj == NULL) {
305 DCHECK(Thread::Current()->IsExceptionPending());
306 return NULL;
307 }
308
309 // invoke constructor; unlike reflection calls, we don't wrap exceptions
310 jclass jklass = AddLocalReference<jclass>(env, c);
311 jmethodID mid = EncodeMethod(init);
312 return env->NewObject(jklass, mid);
313}
314
Elliott Hughesd369bb72011-09-12 14:41:14 -0700315static JNINativeMethod gMethods[] = {
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700316 NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700317 NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
318 NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700319 NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
Brian Carlstrom3a7b4f22011-09-17 15:01:57 -0700320 NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700321 //NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700322 NATIVE_METHOD(Class, getDeclaredField, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700323 //NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
324 //NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700325 NATIVE_METHOD(Class, getDeclaringClass, "()Ljava/lang/Class;"),
Elliott Hughes98fb4162011-09-22 15:24:13 -0700326 NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700327 //NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"),
328 //NATIVE_METHOD(Class, getInterfaces, "()[Ljava/lang/Class;"),
329 //NATIVE_METHOD(Class, getModifiers, "(Ljava/lang/Class;Z)I"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700330 NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700331 NATIVE_METHOD(Class, getSuperclass, "()Ljava/lang/Class;"),
332 NATIVE_METHOD(Class, isAnonymousClass, "()Z"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700333 //NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700334 //NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"),
Elliott Hughes6bdc3b22011-09-16 19:24:10 -0700335 NATIVE_METHOD(Class, isInterface, "()Z"),
336 NATIVE_METHOD(Class, isPrimitive, "()Z"),
Brian Carlstromf91c8c32011-09-21 17:30:34 -0700337 NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
Elliott Hughesd369bb72011-09-12 14:41:14 -0700338};
339
340} // namespace
341
342void register_java_lang_Class(JNIEnv* env) {
343 jniRegisterNativeMethods(env, "java/lang/Class", gMethods, NELEM(gMethods));
344}
345
346} // namespace art