summaryrefslogtreecommitdiff
path: root/dalvikvm/Main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dalvikvm/Main.cpp')
-rw-r--r--dalvikvm/Main.cpp301
1 files changed, 301 insertions, 0 deletions
diff --git a/dalvikvm/Main.cpp b/dalvikvm/Main.cpp
new file mode 100644
index 0000000..4aa6e20
--- /dev/null
+++ b/dalvikvm/Main.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Command-line invocation of the Dalvik VM.
+ */
+#include "jni.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+
+
+/*
+ * We want failed write() calls to just return with an error.
+ */
+static void blockSigpipe()
+{
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGPIPE);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
+ fprintf(stderr, "WARNING: SIGPIPE not blocked\n");
+}
+
+/*
+ * Create a String[] and populate it with the contents of argv.
+ */
+static jobjectArray createStringArray(JNIEnv* env, char* const argv[], int argc)
+{
+ jclass stringClass = NULL;
+ jobjectArray strArray = NULL;
+ jobjectArray result = NULL;
+ int i;
+
+ stringClass = env->FindClass("java/lang/String");
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "Got exception while finding class String\n");
+ goto bail;
+ }
+ assert(stringClass != NULL);
+ strArray = env->NewObjectArray(argc, stringClass, NULL);
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "Got exception while creating String array\n");
+ goto bail;
+ }
+ assert(strArray != NULL);
+
+ for (i = 0; i < argc; i++) {
+ jstring argStr;
+
+ argStr = env->NewStringUTF(argv[i]);
+ if (env->ExceptionCheck()) {
+ fprintf(stderr, "Got exception while allocating Strings\n");
+ goto bail;
+ }
+ assert(argStr != NULL);
+ env->SetObjectArrayElement(strArray, i, argStr);
+ env->DeleteLocalRef(argStr);
+ }
+
+ /* return the array, and ensure we don't delete the local ref to it */
+ result = strArray;
+ strArray = NULL;
+
+bail:
+ env->DeleteLocalRef(stringClass);
+ env->DeleteLocalRef(strArray);
+ return result;
+}
+
+/*
+ * Determine whether or not the specified method is public.
+ *
+ * Returns JNI_TRUE on success, JNI_FALSE on failure.
+ */
+static int methodIsPublic(JNIEnv* env, jclass clazz, jmethodID methodId)
+{
+ static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
+ jobject refMethod = NULL;
+ jclass methodClass = NULL;
+ jmethodID getModifiersId;
+ int modifiers;
+ int result = JNI_FALSE;
+
+ refMethod = env->ToReflectedMethod(clazz, methodId, JNI_FALSE);
+ if (refMethod == NULL) {
+ fprintf(stderr, "Dalvik VM unable to get reflected method\n");
+ goto bail;
+ }
+
+ /*
+ * We now have a Method instance. We need to call
+ * its getModifiers() method.
+ */
+ methodClass = env->FindClass("java/lang/reflect/Method");
+ if (methodClass == NULL) {
+ fprintf(stderr, "Dalvik VM unable to find class Method\n");
+ goto bail;
+ }
+ getModifiersId = env->GetMethodID(methodClass,
+ "getModifiers", "()I");
+ if (getModifiersId == NULL) {
+ fprintf(stderr, "Dalvik VM unable to find reflect.Method.getModifiers\n");
+ goto bail;
+ }
+
+ modifiers = env->CallIntMethod(refMethod, getModifiersId);
+ if ((modifiers & PUBLIC) == 0) {
+ fprintf(stderr, "Dalvik VM: main() is not public\n");
+ goto bail;
+ }
+
+ result = JNI_TRUE;
+
+bail:
+ env->DeleteLocalRef(refMethod);
+ env->DeleteLocalRef(methodClass);
+ return result;
+}
+
+/*
+ * Parse arguments. Most of it just gets passed through to the VM. The
+ * JNI spec defines a handful of standard arguments.
+ */
+int main(int argc, char* const argv[])
+{
+ JavaVM* vm = NULL;
+ JNIEnv* env = NULL;
+ JavaVMInitArgs initArgs;
+ JavaVMOption* options = NULL;
+ char* slashClass = NULL;
+ int optionCount, curOpt, i, argIdx;
+ int needExtra = JNI_FALSE;
+ int result = 1;
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* ignore argv[0] */
+ argv++;
+ argc--;
+
+ /*
+ * If we're adding any additional stuff, e.g. function hook specifiers,
+ * add them to the count here.
+ *
+ * We're over-allocating, because this includes the options to the VM
+ * plus the options to the program.
+ */
+ optionCount = argc;
+
+ options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * optionCount);
+ memset(options, 0, sizeof(JavaVMOption) * optionCount);
+
+ /*
+ * Copy options over. Everything up to the name of the class starts
+ * with a '-' (the function hook stuff is strictly internal).
+ *
+ * [Do we need to catch & handle "-jar" here?]
+ */
+ for (curOpt = argIdx = 0; argIdx < argc; argIdx++) {
+ if (argv[argIdx][0] != '-' && !needExtra)
+ break;
+ options[curOpt++].optionString = strdup(argv[argIdx]);
+
+ /* some options require an additional arg */
+ needExtra = JNI_FALSE;
+ if (strcmp(argv[argIdx], "-classpath") == 0 ||
+ strcmp(argv[argIdx], "-cp") == 0)
+ /* others? */
+ {
+ needExtra = JNI_TRUE;
+ }
+ }
+
+ if (needExtra) {
+ fprintf(stderr, "Dalvik VM requires value after last option flag\n");
+ goto bail;
+ }
+
+ /* insert additional internal options here */
+
+ assert(curOpt <= optionCount);
+
+ initArgs.version = JNI_VERSION_1_4;
+ initArgs.options = options;
+ initArgs.nOptions = curOpt;
+ initArgs.ignoreUnrecognized = JNI_FALSE;
+
+ //printf("nOptions = %d\n", initArgs.nOptions);
+
+ blockSigpipe();
+
+ /*
+ * Start VM. The current thread becomes the main thread of the VM.
+ */
+ if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0) {
+ fprintf(stderr, "Dalvik VM init failed (check log file)\n");
+ goto bail;
+ }
+
+ /*
+ * Make sure they provided a class name. We do this after VM init
+ * so that things like "-Xrunjdwp:help" have the opportunity to emit
+ * a usage statement.
+ */
+ if (argIdx == argc) {
+ fprintf(stderr, "Dalvik VM requires a class name\n");
+ goto bail;
+ }
+
+ /*
+ * We want to call main() with a String array with our arguments in it.
+ * Create an array and populate it. Note argv[0] is not included.
+ */
+ jobjectArray strArray;
+ strArray = createStringArray(env, &argv[argIdx+1], argc-argIdx-1);
+ if (strArray == NULL)
+ goto bail;
+
+ /*
+ * Find [class].main(String[]).
+ */
+ jclass startClass;
+ jmethodID startMeth;
+ char* cp;
+
+ /* convert "com.android.Blah" to "com/android/Blah" */
+ slashClass = strdup(argv[argIdx]);
+ for (cp = slashClass; *cp != '\0'; cp++)
+ if (*cp == '.')
+ *cp = '/';
+
+ startClass = env->FindClass(slashClass);
+ if (startClass == NULL) {
+ fprintf(stderr, "Dalvik VM unable to locate class '%s'\n", slashClass);
+ goto bail;
+ }
+
+ startMeth = env->GetStaticMethodID(startClass,
+ "main", "([Ljava/lang/String;)V");
+ if (startMeth == NULL) {
+ fprintf(stderr, "Dalvik VM unable to find static main(String[]) in '%s'\n",
+ slashClass);
+ goto bail;
+ }
+
+ /*
+ * Make sure the method is public. JNI doesn't prevent us from calling
+ * a private method, so we have to check it explicitly.
+ */
+ if (!methodIsPublic(env, startClass, startMeth))
+ goto bail;
+
+ /*
+ * Invoke main().
+ */
+ env->CallStaticVoidMethod(startClass, startMeth, strArray);
+
+ if (!env->ExceptionCheck())
+ result = 0;
+
+bail:
+ /*printf("Shutting down Dalvik VM\n");*/
+ if (vm != NULL) {
+ /*
+ * This allows join() and isAlive() on the main thread to work
+ * correctly, and also provides uncaught exception handling.
+ */
+ if (vm->DetachCurrentThread() != JNI_OK) {
+ fprintf(stderr, "Warning: unable to detach main thread\n");
+ result = 1;
+ }
+
+ if (vm->DestroyJavaVM() != 0)
+ fprintf(stderr, "Warning: Dalvik VM did not shut down cleanly\n");
+ /*printf("\nDalvik VM has exited\n");*/
+ }
+
+ for (i = 0; i < optionCount; i++)
+ free((char*) options[i].optionString);
+ free(options);
+ free(slashClass);
+ /*printf("--- VM is down, process exiting\n");*/
+ return result;
+}