dalvikvm.cc revision c1674ed06662420213441ff2b818f2f71f9098dc
16b6b5f0e67ce03f38223a525612955663bc1799bCarl Shapiro// Copyright 2011 Google Inc. All Rights Reserved. 26b6b5f0e67ce03f38223a525612955663bc1799bCarl Shapiro 32ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include <cstring> 42ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include <cstdio> 52ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include <signal.h> 62ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include <string> 77b21670581d13db32f1384a3b2692bcfc8f57320Carl Shapiro 82ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include "jni.h" 92ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include "logging.h" 102ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro#include "scoped_ptr.h" 110a96fe07175b960050a606fadbf76d85a060e4faElliott Hughes#include "toStringArray.h" 120dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes#include "ScopedLocalRef.h" 132ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 142ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro// Determine whether or not the specified method is public. 152ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapirostatic bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) { 160dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz, 170dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes method_id, JNI_FALSE)); 182ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (reflected.get() == NULL) { 192ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Unable to get reflected method\n"); 202ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return false; 212ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 222ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // We now have a Method instance. We need to call its 232ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // getModifiers() method. 240dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes ScopedLocalRef<jclass> method(env, 250dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes env->FindClass("java/lang/reflect/Method")); 262ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (method.get() == NULL) { 272ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Unable to find class Method\n"); 282ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return false; 292ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 302ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro jmethodID get_modifiers = env->GetMethodID(method.get(), 312ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro "getModifiers", 322ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro "()I"); 332ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (get_modifiers == NULL) { 342ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Unable to find reflect.Method.getModifiers\n"); 352ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return false; 362ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 372ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC 38a0b8feb34a8492c6b8d430f6ca0716e7ff4f4c57Elliott Hughes#if 0 // CallIntMethod not yet implemented 39c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes int modifiers = env->CallIntMethod(reflected.get(), get_modifiers); 40a0b8feb34a8492c6b8d430f6ca0716e7ff4f4c57Elliott Hughes#else 41a0b8feb34a8492c6b8d430f6ca0716e7ff4f4c57Elliott Hughes int modifiers = PUBLIC; 42a0b8feb34a8492c6b8d430f6ca0716e7ff4f4c57Elliott Hughes UNIMPLEMENTED(WARNING) << "assuming main is public..."; 43a0b8feb34a8492c6b8d430f6ca0716e7ff4f4c57Elliott Hughes#endif 442ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if ((modifiers & PUBLIC) == 0) { 452ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return false; 462ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 472ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return true; 482ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro} 492ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 50c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughesstatic void InvokeMain(JNIEnv* env, int argc, char** argv) { 512ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // We want to call main() with a String array with our arguments in 522ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // it. Create an array and populate it. Note argv[0] is not 532ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // included. 540a96fe07175b960050a606fadbf76d85a060e4faElliott Hughes ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1)); 552ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (args.get() == NULL) { 56c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes return; 572ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 582ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 592ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Find [class].main(String[]). 602ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 612ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Convert "com.android.Blah" to "com/android/Blah". 62e5b0dc83537bf915c6abe4efeae6e501daf75a27Elliott Hughes std::string class_name(argv[0]); 632ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro std::replace(class_name.begin(), class_name.end(), '.', '/'); 642ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 650dab4ecc01c5db0d0846bf5b4f608634d7404f74Elliott Hughes ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str())); 662ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (klass.get() == NULL) { 672ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str()); 68c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes return; 692ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 702ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 712ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro jmethodID method = env->GetStaticMethodID(klass.get(), 722ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro "main", 732ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro "([Ljava/lang/String;)V"); 742ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (method == NULL) { 752ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Unable to find static main(String[]) in '%s'\n", 762ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro class_name.c_str()); 77c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes return; 782ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 792ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 802ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Make sure the method is public. JNI doesn't prevent us from 812ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // calling a private method, so we have to check it explicitly. 822ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (!IsMethodPublic(env, klass.get(), method)) { 832ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Sorry, main() is not public\n"); 84c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes return; 852ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 862ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 872ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Invoke main(). 882ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro env->CallStaticVoidMethod(klass.get(), method, args.get()); 892ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro} 902ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 912ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro// Parse arguments. Most of it just gets passed through to the VM. 922ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro// The JNI spec defines a handful of standard arguments. 937b21670581d13db32f1384a3b2692bcfc8f57320Carl Shapiroint main(int argc, char** argv) { 942ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro setvbuf(stdout, NULL, _IONBF, 0); 952ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 962ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Skip over argv[0]. 972ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro argv++; 982ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro argc--; 992ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1002ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // If we're adding any additional stuff, e.g. function hook specifiers, 1012ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // add them to the count here. 1022ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // 1032ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // We're over-allocating, because this includes the options to the VM 1042ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // plus the options to the program. 1052ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro int option_count = argc; 1062ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro scoped_array<JavaVMOption> options(new JavaVMOption[option_count]()); 1072ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1082ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Copy options over. Everything up to the name of the class starts 1092ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // with a '-' (the function hook stuff is strictly internal). 1102ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // 1112ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // [Do we need to catch & handle "-jar" here?] 1122ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro bool need_extra = false; 1132ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro int curr_opt, arg_idx; 1142ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) { 1152ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (argv[arg_idx][0] != '-' && !need_extra) { 1162ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro break; 1172ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1182ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro options[curr_opt++].optionString = argv[arg_idx]; 1192ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1202ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Some options require an additional argument. 1212ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro need_extra = false; 1222ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (strcmp(argv[arg_idx], "-classpath") == 0 || 1232ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro strcmp(argv[arg_idx], "-cp") == 0) { 1242ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // others? 1252ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro need_extra = true; 1262ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1272ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1282ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1292ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (need_extra) { 1302ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "VM requires value after last option flag\n"); 1312ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return EXIT_FAILURE; 1322ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1332ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1342ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Make sure they provided a class name. We do this after VM init 1352ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // so that things like "-Xrunjdwp:help" have the opportunity to emit 1362ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // a usage statement. 1372ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (arg_idx == argc) { 1382ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Class name required\n"); 1392ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return EXIT_FAILURE; 1402ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1412ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1422ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // insert additional internal options here 1432ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1442ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro DCHECK_LE(curr_opt, option_count); 1452ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1462ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro JavaVMInitArgs init_args; 147f2682d5a6ce0f7de58da8fd4ec8aec200c43b92eElliott Hughes init_args.version = JNI_VERSION_1_6; 1482ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro init_args.options = options.get(); 1492ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro init_args.nOptions = curr_opt; 1502ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro init_args.ignoreUnrecognized = JNI_FALSE; 1512ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 1522ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro // Start VM. The current thread becomes the main thread of the VM. 1532ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro JavaVM* vm = NULL; 1542ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro JNIEnv* env = NULL; 1552ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) { 1562ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "VM init failed (check log file)\n"); 1572ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro return EXIT_FAILURE; 1582ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1592ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 160c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes InvokeMain(env, argc - arg_idx, &argv[arg_idx]); 161c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes int rc = env->ExceptionCheck() ? EXIT_FAILURE : EXIT_SUCCESS; 162c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes if (rc == EXIT_FAILURE) { 163c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes env->ExceptionDescribe(); 164c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes } 1652ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 166f2682d5a6ce0f7de58da8fd4ec8aec200c43b92eElliott Hughes if (vm->DetachCurrentThread() != JNI_OK) { 1672ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Warning: unable to detach main thread\n"); 168c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes rc = EXIT_FAILURE; 1692ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1702ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 171f2682d5a6ce0f7de58da8fd4ec8aec200c43b92eElliott Hughes if (vm->DestroyJavaVM() != 0) { 1722ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro fprintf(stderr, "Warning: VM did not shut down cleanly\n"); 173c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes rc = EXIT_FAILURE; 1742ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro } 1752ed144c2b49ae1da6c464d7a1be0062870530802Carl Shapiro 176c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes return rc; 1777b21670581d13db32f1384a3b2692bcfc8f57320Carl Shapiro} 178