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--; optionCount = argc; options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * optionCount); memset(options, 0, sizeof(JavaVMOption) * optionCount); for (curOpt = argIdx = 0; argIdx < argc; argIdx++) { if (argv[argIdx][0] != '-' && !needExtra) break; options[curOpt++].optionString = strdup(argv[argIdx]); 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; } 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(); if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0) { fprintf(stderr, "Dalvik VM init failed (check log file)\n"); goto bail; } if (argIdx == argc) { fprintf(stderr, "Dalvik VM requires a class name\n"); goto bail; } jobjectArray strArray; strArray = createStringArray(env, &argv[argIdx+1], argc-argIdx-1); if (strArray == NULL) goto bail; jclass startClass; jmethodID startMeth; char* cp; 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; } if (!methodIsPublic(env, startClass, startMeth)) goto bail; env->CallStaticVoidMethod(startClass, startMeth, strArray); if (!env->ExceptionCheck()) result = 0; bail: /*printf("Shutting down Dalvik VM\n");*/ if (vm != NULL) { 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; }
/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ void AndroidRuntime::start(const char* className, const char* options) { ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", className != NULL ? className : "(unknown)"); blockSigpipe(); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ if (strcmp(options, "start-system-server") == 0) { /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /android does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); } //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); /* start the virtual machine */ JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) { return; } onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } /* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; jstring optionsStr; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(2, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); optionsStr = env->NewStringUTF(options); env->SetObjectArrayElement(strArray, 1, optionsStr); /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } free(slashClassName); ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); }
/* * 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[]) { printf("ZHK test printf\n"); 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. */ jint ret_JNI_CreateJavaVM; ret_JNI_CreateJavaVM = JNI_CreateJavaVM(&vm, &env, &initArgs); //printf("ZHK in Main.cpp:215 ret_JNI_CreateJavaVM = %d\n" ,ret_JNI_CreateJavaVM); if (ret_JNI_CreateJavaVM < 0) { printf("ZHK in Main.cpp:217 Dalvik VM init failed! (check log file)\n"); 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) { printf("ZHK in Main.cpp:228 Dalvik VM requires a class name\n"); 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) { printf("ZHK in Main.cpp:257 Dalvik VM unable to locate class '%s'\n", slashClass); 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) { printf("ZHK in Main.cpp:265 Dalvik VM unable to find static main(String[]) in '%s'\n", slashClass); 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; }