summaryrefslogtreecommitdiffstats
path: root/src/java_lang_Class.cc
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2011-09-21 17:30:34 -0700
committerBrian Carlstrom <bdc@google.com>2011-09-22 11:28:21 -0700
commitf91c8c328c922ecd522e1d3508d2603e78de8a7b (patch)
tree9ae1b28516bfac8698f34e56b4a07037b5c81c28 /src/java_lang_Class.cc
parentff1ed4770bf7ff024a807b9f909b1a26abb78341 (diff)
downloadart-f91c8c328c922ecd522e1d3508d2603e78de8a7b.zip
art-f91c8c328c922ecd522e1d3508d2603e78de8a7b.tar.gz
art-f91c8c328c922ecd522e1d3508d2603e78de8a7b.tar.bz2
Adding JNI code for dalvik.system.DexFile and java.lang.Class
Change-Id: I079c037db77aeaca0dec06660f7551f57adf2607
Diffstat (limited to 'src/java_lang_Class.cc')
-rw-r--r--src/java_lang_Class.cc126
1 files changed, 124 insertions, 2 deletions
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 8ad59b4..fe5da98 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -16,7 +16,9 @@
#include "jni_internal.h"
#include "class_linker.h"
+#include "class_loader.h"
#include "object.h"
+#include "ScopedUtfChars.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -24,6 +26,33 @@ namespace art {
namespace {
+// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
+jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return NULL;
+ }
+
+ // We need to validate and convert the name (from x.y.z to x/y/z). This
+ // is especially handy for array types, since we want to avoid
+ // auto-generating bogus array classes.
+ if (!IsValidClassName(name.c_str(), true, true)) {
+ Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;",
+ "Invalid name: %s", name.c_str());
+ return NULL;
+ }
+
+ std::string descriptor(DotToDescriptor(name.c_str()));
+ Object* loader = Decode<Object*>(env, javaLoader);
+ ClassLoader* class_loader = down_cast<ClassLoader*>(loader);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
+ if (initialize) {
+ class_linker->EnsureInitialized(c, true);
+ }
+ return AddLocalReference<jclass>(env, c);
+}
+
jboolean Class_desiredAssertionStatus(JNIEnv* env, jobject javaThis) {
return JNI_FALSE;
}
@@ -194,8 +223,101 @@ jboolean Class_isPrimitive(JNIEnv* env, jobject javaThis) {
return c->IsPrimitive();
}
+bool CheckClassAccess(const Class* access_from, const Class* klass) {
+ if (klass->IsPublic()) {
+ return true;
+ }
+ return access_from->IsInSamePackage(klass);
+}
+
+// Validate method/field access.
+bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
+ // quick accept for public access */
+ if (member_flags & kAccPublic) {
+ return true;
+ }
+
+ // quick accept for access from same class
+ if (access_from == access_to) {
+ return true;
+ }
+
+ // quick reject for private access from another class
+ if (member_flags & kAccPrivate) {
+ return false;
+ }
+
+ // Semi-quick test for protected access from a sub-class, which may or
+ // may not be in the same package.
+ if (member_flags & kAccProtected) {
+ if (access_from->IsSubClass(access_to)) {
+ return true;
+ }
+ }
+
+ // Allow protected and private access from other classes in the same
+ return access_from->IsInSamePackage(access_to);
+}
+
+jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
+ Class* c = Decode<Class*>(env, javaThis);
+ if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
+ Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+ "Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
+ return NULL;
+ }
+
+ Method* init = c->FindDirectMethod("<init>", "()V");
+ if (init == NULL) {
+ Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+ "Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
+ return NULL;
+ }
+
+ // Verify access from the call site.
+ //
+ // First, make sure the method invoking Class.newInstance() has permission
+ // to access the class.
+ //
+ // Second, make sure it has permission to invoke the constructor. The
+ // constructor must be public or, if the caller is in the same package,
+ // have package scope.
+ // TODO: need SmartFrame (Thread::WalkStack-like iterator).
+ Frame frame = Thread::Current()->GetTopOfStack();
+ frame.Next();
+ frame.Next();
+ Method* caller_caller = frame.GetMethod();
+ Class* caller_class = caller_caller->GetDeclaringClass();
+
+ if (!CheckClassAccess(c, caller_class)) {
+ Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
+ "Class %s is not accessible from class %s",
+ PrettyDescriptor(c->GetDescriptor()).c_str(),
+ PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+ return NULL;
+ }
+ if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
+ Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
+ "%s is not accessible from class %s",
+ PrettyMethod(init).c_str(),
+ PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+ return NULL;
+ }
+
+ Object* new_obj = c->AllocObject();
+ if (new_obj == NULL) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+
+ // invoke constructor; unlike reflection calls, we don't wrap exceptions
+ jclass jklass = AddLocalReference<jclass>(env, c);
+ jmethodID mid = EncodeMethod(init);
+ return env->NewObject(jklass, mid);
+}
+
static JNINativeMethod gMethods[] = {
- //NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
@@ -223,7 +345,7 @@ static JNINativeMethod gMethods[] = {
//NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"),
NATIVE_METHOD(Class, isInterface, "()Z"),
NATIVE_METHOD(Class, isPrimitive, "()Z"),
- //NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
+ NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
};
} // namespace