1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include <signal.h>
18*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
19*795d594fSAndroid Build Coastguard Worker #include <stdlib.h>
20*795d594fSAndroid Build Coastguard Worker #include <string.h>
21*795d594fSAndroid Build Coastguard Worker #include <algorithm>
22*795d594fSAndroid Build Coastguard Worker #include <memory>
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker #include "base/fast_exit.h"
25*795d594fSAndroid Build Coastguard Worker #include "jni.h"
26*795d594fSAndroid Build Coastguard Worker #include "nativehelper/JniInvocation.h"
27*795d594fSAndroid Build Coastguard Worker #include "nativehelper/ScopedLocalRef.h"
28*795d594fSAndroid Build Coastguard Worker #include "nativehelper/toStringArray.h"
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker namespace art {
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker // Determine whether or not the specified method is public.
IsMethodPublic(JNIEnv * env,jclass c,jmethodID method_id)33*795d594fSAndroid Build Coastguard Worker static bool IsMethodPublic(JNIEnv* env, jclass c, jmethodID method_id) {
34*795d594fSAndroid Build Coastguard Worker ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(c, method_id, JNI_FALSE));
35*795d594fSAndroid Build Coastguard Worker if (reflected.get() == nullptr) {
36*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to get reflected method\n");
37*795d594fSAndroid Build Coastguard Worker return false;
38*795d594fSAndroid Build Coastguard Worker }
39*795d594fSAndroid Build Coastguard Worker // We now have a Method instance. We need to call its
40*795d594fSAndroid Build Coastguard Worker // getModifiers() method.
41*795d594fSAndroid Build Coastguard Worker jclass method_class = env->FindClass("java/lang/reflect/Method");
42*795d594fSAndroid Build Coastguard Worker if (method_class == nullptr) {
43*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to find class java.lang.reflect.Method\n");
44*795d594fSAndroid Build Coastguard Worker return false;
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker jmethodID mid = env->GetMethodID(method_class, "getModifiers", "()I");
47*795d594fSAndroid Build Coastguard Worker if (mid == nullptr) {
48*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to find java.lang.reflect.Method.getModifiers\n");
49*795d594fSAndroid Build Coastguard Worker return false;
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker int modifiers = env->CallIntMethod(reflected.get(), mid);
52*795d594fSAndroid Build Coastguard Worker static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
53*795d594fSAndroid Build Coastguard Worker if ((modifiers & PUBLIC) == 0) {
54*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Modifiers mismatch\n");
55*795d594fSAndroid Build Coastguard Worker return false;
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker return true;
58*795d594fSAndroid Build Coastguard Worker }
59*795d594fSAndroid Build Coastguard Worker
InvokeMain(JNIEnv * env,char ** argv)60*795d594fSAndroid Build Coastguard Worker static int InvokeMain(JNIEnv* env, char** argv) {
61*795d594fSAndroid Build Coastguard Worker // We want to call main() with a String array with our arguments in
62*795d594fSAndroid Build Coastguard Worker // it. Create an array and populate it. Note argv[0] is not
63*795d594fSAndroid Build Coastguard Worker // included.
64*795d594fSAndroid Build Coastguard Worker ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
65*795d594fSAndroid Build Coastguard Worker if (args.get() == nullptr) {
66*795d594fSAndroid Build Coastguard Worker env->ExceptionDescribe();
67*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker
70*795d594fSAndroid Build Coastguard Worker // Find [class].main(String[]).
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker // Convert "com.android.Blah" to "com/android/Blah".
73*795d594fSAndroid Build Coastguard Worker std::string class_name(argv[0]);
74*795d594fSAndroid Build Coastguard Worker std::replace(class_name.begin(), class_name.end(), '.', '/');
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Worker ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
77*795d594fSAndroid Build Coastguard Worker if (klass.get() == nullptr) {
78*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
79*795d594fSAndroid Build Coastguard Worker env->ExceptionDescribe();
80*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker
83*795d594fSAndroid Build Coastguard Worker jmethodID method = env->GetStaticMethodID(klass.get(), "main", "([Ljava/lang/String;)V");
84*795d594fSAndroid Build Coastguard Worker if (method == nullptr) {
85*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Unable to find static main(String[]) in '%s'\n", class_name.c_str());
86*795d594fSAndroid Build Coastguard Worker env->ExceptionDescribe();
87*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker // Make sure the method is public. JNI doesn't prevent us from
91*795d594fSAndroid Build Coastguard Worker // calling a private method, so we have to check it explicitly.
92*795d594fSAndroid Build Coastguard Worker if (!IsMethodPublic(env, klass.get(), method)) {
93*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Sorry, main() is not public in '%s'\n", class_name.c_str());
94*795d594fSAndroid Build Coastguard Worker env->ExceptionDescribe();
95*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker
98*795d594fSAndroid Build Coastguard Worker // Invoke main().
99*795d594fSAndroid Build Coastguard Worker env->CallStaticVoidMethod(klass.get(), method, args.get());
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker // Check whether there was an uncaught exception. We don't log any uncaught exception here;
102*795d594fSAndroid Build Coastguard Worker // detaching this thread will do that for us, but it will clear the exception (and invalidate
103*795d594fSAndroid Build Coastguard Worker // our JNIEnv), so we need to check here.
104*795d594fSAndroid Build Coastguard Worker return env->ExceptionCheck() ? EXIT_FAILURE : EXIT_SUCCESS;
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker
107*795d594fSAndroid Build Coastguard Worker // Parse arguments. Most of it just gets passed through to the runtime.
108*795d594fSAndroid Build Coastguard Worker // The JNI spec defines a handful of standard arguments.
dalvikvm(int argc,char ** argv)109*795d594fSAndroid Build Coastguard Worker static int dalvikvm(int argc, char** argv) {
110*795d594fSAndroid Build Coastguard Worker setvbuf(stdout, nullptr, _IONBF, 0);
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker // Skip over argv[0].
113*795d594fSAndroid Build Coastguard Worker argv++;
114*795d594fSAndroid Build Coastguard Worker argc--;
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker // If we're adding any additional stuff, e.g. function hook specifiers,
117*795d594fSAndroid Build Coastguard Worker // add them to the count here.
118*795d594fSAndroid Build Coastguard Worker //
119*795d594fSAndroid Build Coastguard Worker // We're over-allocating, because this includes the options to the runtime
120*795d594fSAndroid Build Coastguard Worker // plus the options to the program.
121*795d594fSAndroid Build Coastguard Worker int option_count = argc;
122*795d594fSAndroid Build Coastguard Worker std::unique_ptr<JavaVMOption[]> options(new JavaVMOption[option_count]());
123*795d594fSAndroid Build Coastguard Worker
124*795d594fSAndroid Build Coastguard Worker // Copy options over. Everything up to the name of the class starts
125*795d594fSAndroid Build Coastguard Worker // with a '-' (the function hook stuff is strictly internal).
126*795d594fSAndroid Build Coastguard Worker //
127*795d594fSAndroid Build Coastguard Worker // [Do we need to catch & handle "-jar" here?]
128*795d594fSAndroid Build Coastguard Worker bool need_extra = false;
129*795d594fSAndroid Build Coastguard Worker const char* lib = nullptr;
130*795d594fSAndroid Build Coastguard Worker const char* what = nullptr;
131*795d594fSAndroid Build Coastguard Worker int curr_opt, arg_idx;
132*795d594fSAndroid Build Coastguard Worker for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) {
133*795d594fSAndroid Build Coastguard Worker if (argv[arg_idx][0] != '-' && !need_extra) {
134*795d594fSAndroid Build Coastguard Worker break;
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker if (strncmp(argv[arg_idx], "-XXlib:", strlen("-XXlib:")) == 0) {
137*795d594fSAndroid Build Coastguard Worker lib = argv[arg_idx] + strlen("-XXlib:");
138*795d594fSAndroid Build Coastguard Worker continue;
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker options[curr_opt++].optionString = argv[arg_idx];
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard Worker // Some options require an additional argument.
144*795d594fSAndroid Build Coastguard Worker need_extra = false;
145*795d594fSAndroid Build Coastguard Worker if (strcmp(argv[arg_idx], "-classpath") == 0 || strcmp(argv[arg_idx], "-cp") == 0) {
146*795d594fSAndroid Build Coastguard Worker need_extra = true;
147*795d594fSAndroid Build Coastguard Worker what = argv[arg_idx];
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker if (need_extra) {
152*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "%s must be followed by an additional argument giving a value\n", what);
153*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
154*795d594fSAndroid Build Coastguard Worker }
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker if (curr_opt > option_count) {
157*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "curr_opt(%d) > option_count(%d)\n", curr_opt, option_count);
158*795d594fSAndroid Build Coastguard Worker abort();
159*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker
162*795d594fSAndroid Build Coastguard Worker // Find the JNI_CreateJavaVM implementation.
163*795d594fSAndroid Build Coastguard Worker JniInvocation jni_invocation;
164*795d594fSAndroid Build Coastguard Worker if (!jni_invocation.Init(lib)) {
165*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to initialize JNI invocation API from %s\n", lib);
166*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker
169*795d594fSAndroid Build Coastguard Worker JavaVMInitArgs init_args;
170*795d594fSAndroid Build Coastguard Worker init_args.version = JNI_VERSION_1_6;
171*795d594fSAndroid Build Coastguard Worker init_args.options = options.get();
172*795d594fSAndroid Build Coastguard Worker init_args.nOptions = curr_opt;
173*795d594fSAndroid Build Coastguard Worker init_args.ignoreUnrecognized = JNI_FALSE;
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker // Start the runtime. The current thread becomes the main thread.
176*795d594fSAndroid Build Coastguard Worker JavaVM* vm = nullptr;
177*795d594fSAndroid Build Coastguard Worker JNIEnv* env = nullptr;
178*795d594fSAndroid Build Coastguard Worker if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) {
179*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to initialize runtime (check log for details)\n");
180*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker
183*795d594fSAndroid Build Coastguard Worker // Make sure they provided a class name. We do this after
184*795d594fSAndroid Build Coastguard Worker // JNI_CreateJavaVM so that things like "-help" have the opportunity
185*795d594fSAndroid Build Coastguard Worker // to emit a usage statement.
186*795d594fSAndroid Build Coastguard Worker if (arg_idx == argc) {
187*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Class name required\n");
188*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
189*795d594fSAndroid Build Coastguard Worker }
190*795d594fSAndroid Build Coastguard Worker
191*795d594fSAndroid Build Coastguard Worker int rc = InvokeMain(env, &argv[arg_idx]);
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker #if defined(NDEBUG)
194*795d594fSAndroid Build Coastguard Worker // The DestroyJavaVM call will detach this thread for us. In debug builds, we don't want to
195*795d594fSAndroid Build Coastguard Worker // detach because detaching disables the CheckSafeToLockOrUnlock checking.
196*795d594fSAndroid Build Coastguard Worker if (vm->DetachCurrentThread() != JNI_OK) {
197*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Warning: unable to detach main thread\n");
198*795d594fSAndroid Build Coastguard Worker rc = EXIT_FAILURE;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker #endif
201*795d594fSAndroid Build Coastguard Worker
202*795d594fSAndroid Build Coastguard Worker if (vm->DestroyJavaVM() != 0) {
203*795d594fSAndroid Build Coastguard Worker fprintf(stderr, "Warning: runtime did not shut down cleanly\n");
204*795d594fSAndroid Build Coastguard Worker rc = EXIT_FAILURE;
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker
207*795d594fSAndroid Build Coastguard Worker return rc;
208*795d594fSAndroid Build Coastguard Worker }
209*795d594fSAndroid Build Coastguard Worker
210*795d594fSAndroid Build Coastguard Worker } // namespace art
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker // TODO(b/141622862): stop leaks
__asan_default_options()213*795d594fSAndroid Build Coastguard Worker extern "C" const char *__asan_default_options() {
214*795d594fSAndroid Build Coastguard Worker return "detect_leaks=0";
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker
main(int argc,char ** argv)217*795d594fSAndroid Build Coastguard Worker int main(int argc, char** argv) {
218*795d594fSAndroid Build Coastguard Worker // Do not allow static destructors to be called, since it's conceivable that
219*795d594fSAndroid Build Coastguard Worker // daemons may still awaken (literally).
220*795d594fSAndroid Build Coastguard Worker art::FastExit(art::dalvikvm(argc, argv));
221*795d594fSAndroid Build Coastguard Worker }
222