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("java/lang/String");
52 if (env
->ExceptionCheck()) {
53 fprintf(stderr
, "Got exception while finding class String\n");
56 assert(stringClass
!= NULL
);
57 strArray
= env
->NewObjectArray(argc
, stringClass
, NULL
);
58 if (env
->ExceptionCheck()) {
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(argv
[i
]);
68 if (env
->ExceptionCheck()) {
69 fprintf(stderr
, "Got exception while allocating Strings\n");
72 assert(argStr
!= NULL
);
73 env
->SetObjectArrayElement(strArray
, i
, argStr
);
74 env
->DeleteLocalRef(argStr
);
77 /* return the array, and ensure we don't delete the local ref to it */
82 env
->DeleteLocalRef(stringClass
);
83 env
->DeleteLocalRef(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(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("java/lang/reflect/Method");
112 if (methodClass
== NULL
) {
113 fprintf(stderr
, "Dalvik VM unable to find class Method\n");
116 getModifiersId
= env
->GetMethodID(methodClass
,
117 "getModifiers", "()I");
118 if (getModifiersId
== NULL
) {
119 fprintf(stderr
, "Dalvik VM unable to find reflect.Method.getModifiers\n");
123 modifiers
= env
->CallIntMethod(refMethod
, getModifiersId
);
124 if ((modifiers
& PUBLIC
) == 0) {
125 fprintf(stderr
, "Dalvik VM: main() is not public\n");
132 env
->DeleteLocalRef(refMethod
);
133 env
->DeleteLocalRef(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(slashClass
);
250 if (startClass
== NULL
) {
251 fprintf(stderr
, "Dalvik VM unable to locate class '%s'\n", slashClass
);
255 startMeth
= env
->GetStaticMethodID(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(startClass
, startMeth
, strArray
);
275 if (!env
->ExceptionCheck())
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() != JNI_OK
) {
286 fprintf(stderr
, "Warning: unable to detach main thread\n");
290 if (vm
->DestroyJavaVM() != 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");*/