Home | History | Annotate | Download | only in native
      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