• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
dvmInternalNativeStartup(void)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  */
dvmInternalNativeShutdown(void)89 void dvmInternalNativeShutdown(void)
90 {
91     dvmHashTableFree(gDvm.userDexFiles);
92 }
93 
94 /*
95  * Search the internal native set for a match.
96  */
dvmLookupInternalNativeMethod(const Method * method)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  */
dvmAbstractMethodStub(const u4 * args,JValue * pResult)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  */
dvmVerifyObjectInClass(Object * obj,ClassObject * clazz)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  */
validateClassName(const char * name)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  */
dvmFindClassByName(StringObject * nameObj,Object * loader,bool doInit)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  */
dvmFixMethodFlags(u4 flags)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  */
dvmIsPrivilegedMethod(const Method * method)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