diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:03:55 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:03:55 -0800 |
| commit | 89c1feb0a69a7707b271086e749975b3f7acacf7 (patch) | |
| tree | 003624a03635e05020a47fc72a2c42934e3f0703 /vm/native/InternalNative.c | |
| parent | 2ad60cfc28e14ee8f0bb038720836a4696c478ad (diff) | |
| download | android_dalvik-89c1feb0a69a7707b271086e749975b3f7acacf7.tar.gz android_dalvik-89c1feb0a69a7707b271086e749975b3f7acacf7.tar.bz2 android_dalvik-89c1feb0a69a7707b271086e749975b3f7acacf7.zip | |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'vm/native/InternalNative.c')
| -rw-r--r-- | vm/native/InternalNative.c | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/vm/native/InternalNative.c b/vm/native/InternalNative.c new file mode 100644 index 000000000..9e90a87c4 --- /dev/null +++ b/vm/native/InternalNative.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Internal-native initialization and some common utility functions. + */ +#include "Dalvik.h" +#include "native/InternalNativePriv.h" + +/* + * Set of classes for which we provide methods. + * + * The last field, classNameHash, is filled in at startup. + */ +static DalvikNativeClass gDvmNativeMethodSet[] = { + { "Ljava/lang/Object;", dvm_java_lang_Object, 0 }, + { "Ljava/lang/Class;", dvm_java_lang_Class, 0 }, + { "Ljava/lang/Runtime;", dvm_java_lang_Runtime, 0 }, + { "Ljava/lang/String;", dvm_java_lang_String, 0 }, + { "Ljava/lang/System;", dvm_java_lang_System, 0 }, + { "Ljava/lang/SystemProperties;", dvm_java_lang_SystemProperties, 0 }, + { "Ljava/lang/Throwable;", dvm_java_lang_Throwable, 0 }, + { "Ljava/lang/VMClassLoader;", dvm_java_lang_VMClassLoader, 0 }, + { "Ljava/lang/VMThread;", dvm_java_lang_VMThread, 0 }, + { "Ljava/lang/reflect/AccessibleObject;", + dvm_java_lang_reflect_AccessibleObject, 0 }, + { "Ljava/lang/reflect/Array;", dvm_java_lang_reflect_Array, 0 }, + { "Ljava/lang/reflect/Constructor;", + dvm_java_lang_reflect_Constructor, 0 }, + { "Ljava/lang/reflect/Field;", dvm_java_lang_reflect_Field, 0 }, + { "Ljava/lang/reflect/Method;", dvm_java_lang_reflect_Method, 0 }, + { "Ljava/lang/reflect/Proxy;", dvm_java_lang_reflect_Proxy, 0 }, + { "Ljava/security/AccessController;", + dvm_java_security_AccessController, 0 }, + { "Ljava/util/concurrent/atomic/AtomicLong;", + dvm_java_util_concurrent_atomic_AtomicLong, 0 }, + { "Ldalvik/system/VMDebug;", dvm_dalvik_system_VMDebug, 0 }, + { "Ldalvik/system/DexFile;", dvm_dalvik_system_DexFile, 0 }, + { "Ldalvik/system/VMRuntime;", dvm_dalvik_system_VMRuntime, 0 }, + { "Ldalvik/system/Zygote;", dvm_dalvik_system_Zygote, 0 }, + { "Ldalvik/system/VMStack;", dvm_dalvik_system_VMStack, 0 }, + { "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", + dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 }, + { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;", + dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 }, + { "Lorg/apache/harmony/dalvik/NativeTestTarget;", + dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 }, + { "Lsun/misc/Unsafe;", dvm_sun_misc_Unsafe, 0 }, + { NULL, NULL, 0 }, +}; + + +/* + * Set up hash values on the class names. + */ +bool dvmInternalNativeStartup(void) +{ + DalvikNativeClass* classPtr = gDvmNativeMethodSet; + + while (classPtr->classDescriptor != NULL) { + classPtr->classDescriptorHash = + dvmComputeUtf8Hash(classPtr->classDescriptor); + classPtr++; + } + + gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); + if (gDvm.userDexFiles == NULL) + return false; + + return true; +} + +/* + * Clean up. + */ +void dvmInternalNativeShutdown(void) +{ + dvmHashTableFree(gDvm.userDexFiles); +} + +/* + * Search the internal native set for a match. + */ +DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method) +{ + const char* classDescriptor = method->clazz->descriptor; + const DalvikNativeClass* pClass; + u4 hash; + + hash = dvmComputeUtf8Hash(classDescriptor); + pClass = gDvmNativeMethodSet; + while (true) { + if (pClass->classDescriptor == NULL) + break; + if (pClass->classDescriptorHash == hash && + strcmp(pClass->classDescriptor, classDescriptor) == 0) + { + const DalvikNativeMethod* pMeth = pClass->methodInfo; + while (true) { + if (pMeth->name == NULL) + break; + + if (dvmCompareNameDescriptorAndMethod(pMeth->name, + pMeth->signature, method) == 0) + { + /* match */ + //LOGV("+++ match on %s.%s %s at %p\n", + // className, methodName, methodSignature, pMeth->fnPtr); + return pMeth->fnPtr; + } + + pMeth++; + } + } + + pClass++; + } + + return NULL; +} + + +/* + * Magic "internal native" code stub, inserted into abstract method + * definitions when a class is first loaded. This throws the expected + * exception so we don't have to explicitly check for it in the interpreter. + */ +void dvmAbstractMethodStub(const u4* args, JValue* pResult) +{ + LOGD("--- called into dvmAbstractMethodStub\n"); + dvmThrowException("Ljava/lang/AbstractMethodError;", + "abstract method not implemented"); +} + + +/* + * Verify that "obj" is non-null and is an instance of "clazz". + * + * Returns "false" and throws an exception if not. + */ +bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) +{ + if (obj == NULL) { + dvmThrowException("Ljava/lang/NullPointerException;", NULL); + return false; + } + if (!dvmInstanceof(obj->clazz, clazz)) { + dvmThrowException("Ljava/lang/IllegalArgumentException;", + "object is not an instance of the class"); + return false; + } + + return true; +} + +/* + * Validate a "fully qualified" class name, e.g. "Ljava/lang/String;" or "[I". + */ +static bool validateClassName(const char* name) +{ + int len = strlen(name); + int i = 0; + + /* check for reasonable array types */ + if (name[0] == '[') { + while (name[i] == '[') + i++; + + if (name[i] == 'L') { + /* array of objects, make sure it ends well */ + if (name[len-1] != ';') + return false; + } else if (strchr(PRIM_TYPE_TO_LETTER, name[i]) != NULL) { + if (i != len-1) + return false; + } else { + return false; + } + } + + /* quick check for illegal chars */ + for ( ; i < len; i++) { + if (name[i] == '/') + return false; + } + + return true; +} + +/* + * Find a class by name, initializing it if requested. + */ +ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader, + bool doInit) +{ + ClassObject* clazz = NULL; + char* name = NULL; + char* descriptor = NULL; + + if (nameObj == NULL) { + dvmThrowException("Ljava/lang/NullPointerException;", NULL); + goto bail; + } + name = dvmCreateCstrFromString(nameObj); + + /* + * 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 (!validateClassName(name)) { + LOGW("dvmFindClassByName rejecting '%s'\n", name); + dvmThrowException("Ljava/lang/ClassNotFoundException;", name); + goto bail; + } + + descriptor = dvmDotToDescriptor(name); + if (descriptor == NULL) { + goto bail; + } + + if (doInit) + clazz = dvmFindClass(descriptor, loader); + else + clazz = dvmFindClassNoInit(descriptor, loader); + + if (clazz == NULL) { + LOGVV("FAIL: load %s (%d)\n", descriptor, doInit); + Thread* self = dvmThreadSelf(); + Object* oldExcep = dvmGetException(self); + dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */ + dvmClearException(self); + dvmThrowChainedException("Ljava/lang/ClassNotFoundException;", + name, oldExcep); + dvmReleaseTrackedAlloc(oldExcep, self); + } else { + LOGVV("GOOD: load %s (%d) --> %p ldr=%p\n", + descriptor, doInit, clazz, clazz->classLoader); + } + +bail: + free(name); + free(descriptor); + return clazz; +} + +/* + * We insert native method stubs for abstract methods so we don't have to + * check the access flags at the time of the method call. This results in + * "native abstract" methods, which can't exist. If we see the "abstract" + * flag set, clear the "native" flag. + * + * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED + * position, because the callers of this function are trying to convey + * the "traditional" meaning of the flags to their callers. + */ +u4 dvmFixMethodFlags(u4 flags) +{ + if ((flags & ACC_ABSTRACT) != 0) { + flags &= ~ACC_NATIVE; + } + + flags &= ~ACC_SYNCHRONIZED; + + if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) { + flags |= ACC_SYNCHRONIZED; + } + + return flags & JAVA_FLAGS_MASK; +} + + +/* + * Return the hash code for the specified object. + */ +u4 dvmGetObjectHashCode(Object* obj) +{ + return (u4) obj; +} + + +#define NUM_DOPRIV_FUNCS 4 + +/* + * Determine if "method" is a "privileged" invocation, i.e. is it one + * of the variations of AccessController.doPrivileged(). + * + * Because the security stuff pulls in a pile of stuff that we may not + * want or need, we don't do the class/method lookups at init time, but + * instead on first use. + */ +bool dvmIsPrivilegedMethod(const Method* method) +{ + int i; + + assert(method != NULL); + + if (!gDvm.javaSecurityAccessControllerReady) { + /* + * Populate on first use. No concurrency risk since we're just + * finding pointers to fixed structures. + */ + static const char* kSignatures[NUM_DOPRIV_FUNCS] = { + "(Ljava/security/PrivilegedAction;)Ljava/lang/Object;", + "(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;", + "(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", + "(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", + }; + ClassObject* clazz; + + clazz = dvmFindClassNoInit("Ljava/security/AccessController;", NULL); + if (clazz == NULL) { + LOGW("Couldn't find java/security/AccessController\n"); + return false; + } + + assert(NELEM(gDvm.methJavaSecurityAccessController_doPrivileged) == + NELEM(kSignatures)); + + /* verify init */ + for (i = 0; i < NUM_DOPRIV_FUNCS; i++) { + gDvm.methJavaSecurityAccessController_doPrivileged[i] = + dvmFindDirectMethodByDescriptor(clazz, "doPrivileged", kSignatures[i]); + if (gDvm.methJavaSecurityAccessController_doPrivileged[i] == NULL) { + LOGW("Warning: couldn't find java/security/AccessController" + ".doPrivileged %s\n", kSignatures[i]); + return false; + } + } + + /* all good, raise volatile readiness flag */ + gDvm.javaSecurityAccessControllerReady = true; + } + + for (i = 0; i < NUM_DOPRIV_FUNCS; i++) { + if (gDvm.methJavaSecurityAccessController_doPrivileged[i] == method) { + //LOGI("+++ doPriv match\n"); + return true; + } + } + return false; +} + |
