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