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/Runtime;", dvm_java_lang_Runtime, 0 }, 32 { "Ljava/lang/String;", dvm_java_lang_String, 0 }, 33 { "Ljava/lang/System;", dvm_java_lang_System, 0 }, 34 { "Ljava/lang/SystemProperties;", dvm_java_lang_SystemProperties, 0 }, 35 { "Ljava/lang/Throwable;", dvm_java_lang_Throwable, 0 }, 36 { "Ljava/lang/VMClassLoader;", dvm_java_lang_VMClassLoader, 0 }, 37 { "Ljava/lang/VMThread;", dvm_java_lang_VMThread, 0 }, 38 { "Ljava/lang/reflect/AccessibleObject;", 39 dvm_java_lang_reflect_AccessibleObject, 0 }, 40 { "Ljava/lang/reflect/Array;", dvm_java_lang_reflect_Array, 0 }, 41 { "Ljava/lang/reflect/Constructor;", 42 dvm_java_lang_reflect_Constructor, 0 }, 43 { "Ljava/lang/reflect/Field;", dvm_java_lang_reflect_Field, 0 }, 44 { "Ljava/lang/reflect/Method;", dvm_java_lang_reflect_Method, 0 }, 45 { "Ljava/lang/reflect/Proxy;", dvm_java_lang_reflect_Proxy, 0 }, 46 { "Ljava/security/AccessController;", 47 dvm_java_security_AccessController, 0 }, 48 { "Ljava/util/concurrent/atomic/AtomicLong;", 49 dvm_java_util_concurrent_atomic_AtomicLong, 0 }, 50 { "Ldalvik/system/VMDebug;", dvm_dalvik_system_VMDebug, 0 }, 51 { "Ldalvik/system/DexFile;", dvm_dalvik_system_DexFile, 0 }, 52 { "Ldalvik/system/VMRuntime;", dvm_dalvik_system_VMRuntime, 0 }, 53 { "Ldalvik/system/Zygote;", dvm_dalvik_system_Zygote, 0 }, 54 { "Ldalvik/system/VMStack;", dvm_dalvik_system_VMStack, 0 }, 55 { "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", 56 dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 }, 57 { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;", 58 dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 }, 59 { "Lorg/apache/harmony/dalvik/NativeTestTarget;", 60 dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 }, 61 { "Lsun/misc/Unsafe;", dvm_sun_misc_Unsafe, 0 }, 62 { NULL, NULL, 0 }, 63 }; 64 65 66 /* 67 * Set up hash values on the class names. 68 */ 69 bool dvmInternalNativeStartup(void) 70 { 71 DalvikNativeClass* classPtr = gDvmNativeMethodSet; 72 73 while (classPtr->classDescriptor != NULL) { 74 classPtr->classDescriptorHash = 75 dvmComputeUtf8Hash(classPtr->classDescriptor); 76 classPtr++; 77 } 78 79 gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); 80 if (gDvm.userDexFiles == NULL) 81 return false; 82 83 return true; 84 } 85 86 /* 87 * Clean up. 88 */ 89 void dvmInternalNativeShutdown(void) 90 { 91 dvmHashTableFree(gDvm.userDexFiles); 92 } 93 94 /* 95 * Search the internal native set for a match. 96 */ 97 DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method) 98 { 99 const char* classDescriptor = method->clazz->descriptor; 100 const DalvikNativeClass* pClass; 101 u4 hash; 102 103 hash = dvmComputeUtf8Hash(classDescriptor); 104 pClass = gDvmNativeMethodSet; 105 while (true) { 106 if (pClass->classDescriptor == NULL) 107 break; 108 if (pClass->classDescriptorHash == hash && 109 strcmp(pClass->classDescriptor, classDescriptor) == 0) 110 { 111 const DalvikNativeMethod* pMeth = pClass->methodInfo; 112 while (true) { 113 if (pMeth->name == NULL) 114 break; 115 116 if (dvmCompareNameDescriptorAndMethod(pMeth->name, 117 pMeth->signature, method) == 0) 118 { 119 /* match */ 120 //LOGV("+++ match on %s.%s %s at %p\n", 121 // className, methodName, methodSignature, pMeth->fnPtr); 122 return pMeth->fnPtr; 123 } 124 125 pMeth++; 126 } 127 } 128 129 pClass++; 130 } 131 132 return NULL; 133 } 134 135 136 /* 137 * Magic "internal native" code stub, inserted into abstract method 138 * definitions when a class is first loaded. This throws the expected 139 * exception so we don't have to explicitly check for it in the interpreter. 140 */ 141 void dvmAbstractMethodStub(const u4* args, JValue* pResult) 142 { 143 LOGD("--- called into dvmAbstractMethodStub\n"); 144 dvmThrowException("Ljava/lang/AbstractMethodError;", 145 "abstract method not implemented"); 146 } 147 148 149 /* 150 * Verify that "obj" is non-null and is an instance of "clazz". 151 * 152 * Returns "false" and throws an exception if not. 153 */ 154 bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) 155 { 156 if (obj == NULL) { 157 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 158 return false; 159 } 160 if (!dvmInstanceof(obj->clazz, clazz)) { 161 dvmThrowException("Ljava/lang/IllegalArgumentException;", 162 "object is not an instance of the class"); 163 return false; 164 } 165 166 return true; 167 } 168 169 /* 170 * Validate a "binary" class name, e.g. "java.lang.String" or "[I". 171 */ 172 static bool validateClassName(const char* name) 173 { 174 int len = strlen(name); 175 int i = 0; 176 177 /* check for reasonable array types */ 178 if (name[0] == '[') { 179 while (name[i] == '[') 180 i++; 181 182 if (name[i] == 'L') { 183 /* array of objects, make sure it ends well */ 184 if (name[len-1] != ';') 185 return false; 186 } else if (strchr(PRIM_TYPE_TO_LETTER, name[i]) != NULL) { 187 if (i != len-1) 188 return false; 189 } else { 190 return false; 191 } 192 } 193 194 /* quick check for illegal chars */ 195 for ( ; i < len; i++) { 196 if (name[i] == '/') 197 return false; 198 } 199 200 return true; 201 } 202 203 /* 204 * Find a class by name, initializing it if requested. 205 */ 206 ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader, 207 bool doInit) 208 { 209 ClassObject* clazz = NULL; 210 char* name = NULL; 211 char* descriptor = NULL; 212 213 if (nameObj == NULL) { 214 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 215 goto bail; 216 } 217 name = dvmCreateCstrFromString(nameObj); 218 219 /* 220 * We need to validate and convert the name (from x.y.z to x/y/z). This 221 * is especially handy for array types, since we want to avoid 222 * auto-generating bogus array classes. 223 */ 224 if (!validateClassName(name)) { 225 LOGW("dvmFindClassByName rejecting '%s'\n", name); 226 dvmThrowException("Ljava/lang/ClassNotFoundException;", name); 227 goto bail; 228 } 229 230 descriptor = dvmDotToDescriptor(name); 231 if (descriptor == NULL) { 232 goto bail; 233 } 234 235 if (doInit) 236 clazz = dvmFindClass(descriptor, loader); 237 else 238 clazz = dvmFindClassNoInit(descriptor, loader); 239 240 if (clazz == NULL) { 241 LOGVV("FAIL: load %s (%d)\n", descriptor, doInit); 242 Thread* self = dvmThreadSelf(); 243 Object* oldExcep = dvmGetException(self); 244 dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */ 245 dvmClearException(self); 246 dvmThrowChainedException("Ljava/lang/ClassNotFoundException;", 247 name, oldExcep); 248 dvmReleaseTrackedAlloc(oldExcep, self); 249 } else { 250 LOGVV("GOOD: load %s (%d) --> %p ldr=%p\n", 251 descriptor, doInit, clazz, clazz->classLoader); 252 } 253 254 bail: 255 free(name); 256 free(descriptor); 257 return clazz; 258 } 259 260 /* 261 * We insert native method stubs for abstract methods so we don't have to 262 * check the access flags at the time of the method call. This results in 263 * "native abstract" methods, which can't exist. If we see the "abstract" 264 * flag set, clear the "native" flag. 265 * 266 * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED 267 * position, because the callers of this function are trying to convey 268 * the "traditional" meaning of the flags to their callers. 269 */ 270 u4 dvmFixMethodFlags(u4 flags) 271 { 272 if ((flags & ACC_ABSTRACT) != 0) { 273 flags &= ~ACC_NATIVE; 274 } 275 276 flags &= ~ACC_SYNCHRONIZED; 277 278 if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) { 279 flags |= ACC_SYNCHRONIZED; 280 } 281 282 return flags & JAVA_FLAGS_MASK; 283 } 284 285 286 #define NUM_DOPRIV_FUNCS 4 287 288 /* 289 * Determine if "method" is a "privileged" invocation, i.e. is it one 290 * of the variations of AccessController.doPrivileged(). 291 * 292 * Because the security stuff pulls in a pile of stuff that we may not 293 * want or need, we don't do the class/method lookups at init time, but 294 * instead on first use. 295 */ 296 bool dvmIsPrivilegedMethod(const Method* method) 297 { 298 int i; 299 300 assert(method != NULL); 301 302 if (!gDvm.javaSecurityAccessControllerReady) { 303 /* 304 * Populate on first use. No concurrency risk since we're just 305 * finding pointers to fixed structures. 306 */ 307 static const char* kSignatures[NUM_DOPRIV_FUNCS] = { 308 "(Ljava/security/PrivilegedAction;)Ljava/lang/Object;", 309 "(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;", 310 "(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", 311 "(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;", 312 }; 313 ClassObject* clazz; 314 315 clazz = dvmFindClassNoInit("Ljava/security/AccessController;", NULL); 316 if (clazz == NULL) { 317 LOGW("Couldn't find java/security/AccessController\n"); 318 return false; 319 } 320 321 assert(NELEM(gDvm.methJavaSecurityAccessController_doPrivileged) == 322 NELEM(kSignatures)); 323 324 /* verify init */ 325 for (i = 0; i < NUM_DOPRIV_FUNCS; i++) { 326 gDvm.methJavaSecurityAccessController_doPrivileged[i] = 327 dvmFindDirectMethodByDescriptor(clazz, "doPrivileged", kSignatures[i]); 328 if (gDvm.methJavaSecurityAccessController_doPrivileged[i] == NULL) { 329 LOGW("Warning: couldn't find java/security/AccessController" 330 ".doPrivileged %s\n", kSignatures[i]); 331 return false; 332 } 333 } 334 335 /* all good, raise volatile readiness flag */ 336 android_atomic_release_store(true, 337 &gDvm.javaSecurityAccessControllerReady); 338 } 339 340 for (i = 0; i < NUM_DOPRIV_FUNCS; i++) { 341 if (gDvm.methJavaSecurityAccessController_doPrivileged[i] == method) { 342 //LOGI("+++ doPriv match\n"); 343 return true; 344 } 345 } 346 return false; 347 } 348