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