2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Command-line invocation of the Dalvik VM.
29 * We want failed write() calls to just return with an error.
31 static void blockSigpipe()
36 sigaddset(&mask, SIGPIPE);
37 if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
38 fprintf(stderr, "WARNING: SIGPIPE not blocked\n");
42 * Create a String[] and populate it with the contents of argv.
44 static jobjectArray createStringArray(JNIEnv* env, char* const argv[], int argc)
46 jclass stringClass = NULL;
47 jobjectArray strArray = NULL;
48 jobjectArray result = NULL;
51 stringClass = (*env)->FindClass(env, "java/lang/String");
52 if ((*env)->ExceptionCheck(env)) {
53 fprintf(stderr, "Got exception while finding class String\n");
56 assert(stringClass != NULL);
57 strArray = (*env)->NewObjectArray(env, argc, stringClass, NULL);
58 if ((*env)->ExceptionCheck(env)) {
59 fprintf(stderr, "Got exception while creating String array\n");
62 assert(strArray != NULL);
64 for (i = 0; i < argc; i++) {
67 argStr = (*env)->NewStringUTF(env, argv[i]);
68 if ((*env)->ExceptionCheck(env)) {
69 fprintf(stderr, "Got exception while allocating Strings\n");
72 assert(argStr != NULL);
73 (*env)->SetObjectArrayElement(env, strArray, i, argStr);
74 (*env)->DeleteLocalRef(env, argStr);
77 /* return the array, and ensure we don't delete the local ref to it */
82 (*env)->DeleteLocalRef(env, stringClass);
83 (*env)->DeleteLocalRef(env, strArray);
88 * Determine whether or not the specified method is public.
90 * Returns JNI_TRUE on success, JNI_FALSE on failure.
92 static int methodIsPublic(JNIEnv* env, jclass clazz, jmethodID methodId)
94 static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
95 jobject refMethod = NULL;
96 jclass methodClass = NULL;
97 jmethodID getModifiersId;
99 int result = JNI_FALSE;
101 refMethod = (*env)->ToReflectedMethod(env, clazz, methodId, JNI_FALSE);
102 if (refMethod == NULL) {
103 fprintf(stderr, "Dalvik VM unable to get reflected method\n");
108 * We now have a Method instance. We need to call
109 * its getModifiers() method.
111 methodClass = (*env)->FindClass(env, "java/lang/reflect/Method");
112 if (methodClass == NULL) {
113 fprintf(stderr, "Dalvik VM unable to find class Method\n");
116 getModifiersId = (*env)->GetMethodID(env, methodClass,
117 "getModifiers", "()I");
118 if (getModifiersId == NULL) {
119 fprintf(stderr, "Dalvik VM unable to find reflect.Method.getModifiers\n");
123 modifiers = (*env)->CallIntMethod(env, refMethod, getModifiersId);
124 if ((modifiers & PUBLIC) == 0) {
125 fprintf(stderr, "Dalvik VM: main() is not public\n");
132 (*env)->DeleteLocalRef(env, refMethod);
133 (*env)->DeleteLocalRef(env, methodClass);
138 * Parse arguments. Most of it just gets passed through to the VM. The
139 * JNI spec defines a handful of standard arguments.
141 int main(int argc, char* const argv[])
145 JavaVMInitArgs initArgs;
146 JavaVMOption* options = NULL;
147 char* slashClass = NULL;
148 int optionCount, curOpt, i, argIdx;
149 int needExtra = JNI_FALSE;
152 setvbuf(stdout, NULL, _IONBF, 0);
159 * If we're adding any additional stuff, e.g. function hook specifiers,
160 * add them to the count here.
162 * We're over-allocating, because this includes the options to the VM
163 * plus the options to the program.
167 options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * optionCount);
168 memset(options, 0, sizeof(JavaVMOption) * optionCount);
171 * Copy options over. Everything up to the name of the class starts
172 * with a '-' (the function hook stuff is strictly internal).
174 * [Do we need to catch & handle "-jar" here?]
176 for (curOpt = argIdx = 0; argIdx < argc; argIdx++) {
177 if (argv[argIdx][0] != '-' && !needExtra)
179 options[curOpt++].optionString = strdup(argv[argIdx]);
181 /* some options require an additional arg */
182 needExtra = JNI_FALSE;
183 if (strcmp(argv[argIdx], "-classpath") == 0 ||
184 strcmp(argv[argIdx], "-cp") == 0)
187 needExtra = JNI_TRUE;
192 fprintf(stderr, "Dalvik VM requires value after last option flag\n");
196 /* insert additional internal options here */
198 assert(curOpt <= optionCount);
200 initArgs.version = JNI_VERSION_1_4;
201 initArgs.options = options;
202 initArgs.nOptions = curOpt;
203 initArgs.ignoreUnrecognized = JNI_FALSE;
205 //printf("nOptions = %d\n", initArgs.nOptions);
210 * Start VM. The current thread becomes the main thread of the VM.
212 if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0) {
213 fprintf(stderr, "Dalvik VM init failed (check log file)\n");
218 * Make sure they provided a class name. We do this after VM init
219 * so that things like "-Xrunjdwp:help" have the opportunity to emit
222 if (argIdx == argc) {
223 fprintf(stderr, "Dalvik VM requires a class name\n");
228 * We want to call main() with a String array with our arguments in it.
229 * Create an array and populate it. Note argv[0] is not included.
231 jobjectArray strArray;
232 strArray = createStringArray(env, &argv[argIdx+1], argc-argIdx-1);
233 if (strArray == NULL)
237 * Find [class].main(String[]).
243 /* convert "com.android.Blah" to "com/android/Blah" */
244 slashClass = strdup(argv[argIdx]);
245 for (cp = slashClass; *cp != '\0'; cp++)
249 startClass = (*env)->FindClass(env, slashClass);
250 if (startClass == NULL) {
251 fprintf(stderr, "Dalvik VM unable to locate class '%s'\n", slashClass);
255 startMeth = (*env)->GetStaticMethodID(env, startClass,
256 "main", "([Ljava/lang/String;)V");
257 if (startMeth == NULL) {
258 fprintf(stderr, "Dalvik VM unable to find static main(String[]) in '%s'\n",
264 * Make sure the method is public. JNI doesn't prevent us from calling
265 * a private method, so we have to check it explicitly.
267 if (!methodIsPublic(env, startClass, startMeth))
273 (*env)->CallStaticVoidMethod(env, startClass, startMeth, strArray);
275 if (!(*env)->ExceptionCheck(env))
279 /*printf("Shutting down Dalvik VM\n");*/
282 * This allows join() and isAlive() on the main thread to work
283 * correctly, and also provides uncaught exception handling.
285 if ((*vm)->DetachCurrentThread(vm) != JNI_OK) {
286 fprintf(stderr, "Warning: unable to detach main thread\n");
290 if ((*vm)->DestroyJavaVM(vm) != 0)
291 fprintf(stderr, "Warning: Dalvik VM did not shut down cleanly\n");
292 /*printf("\nDalvik VM has exited\n");*/
295 for (i = 0; i < optionCount; i++)
296 free((char*) options[i].optionString);
299 /*printf("--- VM is down, process exiting\n");*/