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