InternalNative.cpp
1 /* 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 /* 18 * Internal-native initialization and some common utility functions. 19 */ 20 #include "Dalvik.h" 21 #include "native/InternalNativePriv.h" 22 23 /* 24 * Set of classes for which we provide methods. 25 * 26 * The last field, classNameHash, is filled in at startup. 27 */ 28 static DalvikNativeClass gDvmNativeMethodSet[] = { 29 { "Ljava/lang/Object;", dvm_java_lang_Object, 0 }, 30 { "Ljava/lang/Class;", dvm_java_lang_Class, 0 }, 31 { "Ljava/lang/Double;", dvm_java_lang_Double, 0 }, 32 { "Ljava/lang/Float;", dvm_java_lang_Float, 0 }, 33 { "Ljava/lang/Math;", dvm_java_lang_Math, 0 }, 34 { "Ljava/lang/Runtime;", dvm_java_lang_Runtime, 0 }, 35 { "Ljava/lang/String;", dvm_java_lang_String, 0 }, 36 { "Ljava/lang/System;", dvm_java_lang_System, 0 }, 37 { "Ljava/lang/Throwable;", dvm_java_lang_Throwable, 0 }, 38 { "Ljava/lang/VMClassLoader;", dvm_java_lang_VMClassLoader, 0 }, 39 { "Ljava/lang/VMThread;", dvm_java_lang_VMThread, 0 }, 40 { "Ljava/lang/reflect/AccessibleObject;", 41 dvm_java_lang_reflect_AccessibleObject, 0 }, 42 { "Ljava/lang/reflect/Array;", dvm_java_lang_reflect_Array, 0 }, 43 { "Ljava/lang/reflect/Constructor;", 44 dvm_java_lang_reflect_Constructor, 0 }, 45 { "Ljava/lang/reflect/Field;", dvm_java_lang_reflect_Field, 0 }, 46 { "Ljava/lang/reflect/Method;", dvm_java_lang_reflect_Method, 0 }, 47 { "Ljava/lang/reflect/Proxy;", dvm_java_lang_reflect_Proxy, 0 }, 48 { "Ljava/util/concurrent/atomic/AtomicLong;", 49 dvm_java_util_concurrent_atomic_AtomicLong, 0 }, 50 { "Ldalvik/bytecode/OpcodeInfo;", dvm_dalvik_bytecode_OpcodeInfo, 0 }, 51 { "Ldalvik/system/VMDebug;", dvm_dalvik_system_VMDebug, 0 }, 52 { "Ldalvik/system/DexFile;", dvm_dalvik_system_DexFile, 0 }, 53 { "Ldalvik/system/VMRuntime;", dvm_dalvik_system_VMRuntime, 0 }, 54 { "Ldalvik/system/Zygote;", dvm_dalvik_system_Zygote, 0 }, 55 { "Ldalvik/system/VMStack;", dvm_dalvik_system_VMStack, 0 }, 56 { "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", 57 dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 }, 58 { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;", 59 dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 }, 60 { "Lorg/apache/harmony/dalvik/NativeTestTarget;", 61 dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 }, 62 { "Lsun/misc/Unsafe;", dvm_sun_misc_Unsafe, 0 }, 63 { NULL, NULL, 0 }, 64 }; 65 66 67 /* 68 * Set up hash values on the class names. 69 */ 70 bool dvmInternalNativeStartup() 71 { 72 DalvikNativeClass* classPtr = gDvmNativeMethodSet; 73 74 while (classPtr->classDescriptor != NULL) { 75 classPtr->classDescriptorHash = 76 dvmComputeUtf8Hash(classPtr->classDescriptor); 77 classPtr++; 78 } 79 80 gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); 81 if (gDvm.userDexFiles == NULL) 82 return false; 83 84 return true; 85 } 86 87 /* 88 * Clean up. 89 */ 90 void dvmInternalNativeShutdown() 91 { 92 dvmHashTableFree(gDvm.userDexFiles); 93 } 94 95 /* 96 * Search the internal native set for a match. 97 */ 98 DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method) 99 { 100 const char* classDescriptor = method->clazz->descriptor; 101 const DalvikNativeClass* pClass; 102 u4 hash; 103 104 hash = dvmComputeUtf8Hash(classDescriptor); 105 pClass = gDvmNativeMethodSet; 106 while (true) { 107 if (pClass->classDescriptor == NULL) 108 break; 109 if (pClass->classDescriptorHash == hash && 110 strcmp(pClass->classDescriptor, classDescriptor) == 0) 111 { 112 const DalvikNativeMethod* pMeth = pClass->methodInfo; 113 while (true) { 114 if (pMeth->name == NULL) 115 break; 116 117 if (dvmCompareNameDescriptorAndMethod(pMeth->name, 118 pMeth->signature, method) == 0) 119 { 120 /* match */ 121 //ALOGV("+++ match on %s.%s %s at %p", 122 // className, methodName, methodSignature, pMeth->fnPtr); 123 return pMeth->fnPtr; 124 } 125 126 pMeth++; 127 } 128 } 129 130 pClass++; 131 } 132 133 return NULL; 134 } 135 136 137 /* 138 * Magic "internal native" code stub, inserted into abstract method 139 * definitions when a class is first loaded. This throws the expected 140 * exception so we don't have to explicitly check for it in the interpreter. 141 */ 142 void dvmAbstractMethodStub(const u4* args, JValue* pResult) 143 { 144 ALOGD("--- called into dvmAbstractMethodStub"); 145 dvmThrowAbstractMethodError("abstract method not implemented"); 146 } 147 148 149 /* 150 * Verify that "obj" is non-null and is an instance of "clazz". 151 * Used to implement reflection on fields and methods. 152 * 153 * Returns "false" and throws an exception if not. 154 */ 155 bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) { 156 ClassObject* exceptionClass = NULL; 157 if (obj == NULL) { 158 exceptionClass = gDvm.exNullPointerException; 159 } else if (!dvmInstanceof(obj->clazz, clazz)) { 160 exceptionClass = gDvm.exIllegalArgumentException; 161 } 162 163 if (exceptionClass == NULL) { 164 return true; 165 } 166 167 std::string expectedClassName(dvmHumanReadableDescriptor(clazz->descriptor)); 168 std::string actualClassName(dvmHumanReadableType(obj)); 169 dvmThrowExceptionFmt(exceptionClass, "expected receiver of type %s, but got %s", 170 expectedClassName.c_str(), actualClassName.c_str()); 171 return false; 172 } 173 174 /* 175 * Find a class by name, initializing it if requested. 176 */ 177 ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader, 178 bool doInit) 179 { 180 ClassObject* clazz = NULL; 181 char* name = NULL; 182 char* descriptor = NULL; 183 184 if (nameObj == NULL) { 185 dvmThrowNullPointerException("name == null"); 186 goto bail; 187 } 188 name = dvmCreateCstrFromString(nameObj); 189 190 /* 191 * We need to validate and convert the name (from x.y.z to x/y/z). This 192 * is especially handy for array types, since we want to avoid 193 * auto-generating bogus array classes. 194 */ 195 if (!dexIsValidClassName(name, true)) { 196 ALOGW("dvmFindClassByName rejecting '%s'", name); 197 dvmThrowClassNotFoundException(name); 198 goto bail; 199 } 200 201 descriptor = dvmDotToDescriptor(name); 202 if (descriptor == NULL) { 203 goto bail; 204 } 205 206 if (doInit) 207 clazz = dvmFindClass(descriptor, loader); 208 else 209 clazz = dvmFindClassNoInit(descriptor, loader); 210 211 if (clazz == NULL) { 212 LOGVV("FAIL: load %s (%d)", descriptor, doInit); 213 Thread* self = dvmThreadSelf(); 214 Object* oldExcep = dvmGetException(self); 215 dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */ 216 dvmClearException(self); 217 dvmThrowChainedClassNotFoundException(name, oldExcep); 218 dvmReleaseTrackedAlloc(oldExcep, self); 219 } else { 220 LOGVV("GOOD: load %s (%d) --> %p ldr=%p", 221 descriptor, doInit, clazz, clazz->classLoader); 222 } 223 224 bail: 225 free(name); 226 free(descriptor); 227 return clazz; 228 } 229 230 /* 231 * We insert native method stubs for abstract methods so we don't have to 232 * check the access flags at the time of the method call. This results in 233 * "native abstract" methods, which can't exist. If we see the "abstract" 234 * flag set, clear the "native" flag. 235 * 236 * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED 237 * position, because the callers of this function are trying to convey 238 * the "traditional" meaning of the flags to their callers. 239 */ 240 u4 dvmFixMethodFlags(u4 flags) 241 { 242 if ((flags & ACC_ABSTRACT) != 0) { 243 flags &= ~ACC_NATIVE; 244 } 245 246 flags &= ~ACC_SYNCHRONIZED; 247 248 if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) { 249 flags |= ACC_SYNCHRONIZED; 250 } 251 252 return flags & JAVA_FLAGS_MASK; 253 }