blob: e37e650f6e50bf1c29a156b99aa9926c42291030 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.internal.os;
18
Sudheer Shankadc589ac2016-11-10 15:30:17 -080019import android.app.ActivityManager;
Eric Rowe35980b22013-09-03 10:51:15 -070020import android.app.ActivityThread;
Dan Egnorb7f03672009-12-09 16:22:32 -080021import android.app.ApplicationErrorReport;
Dan Egnorb7f03672009-12-09 16:22:32 -080022import android.os.Build;
Jeff Sharkeyf8880562016-02-26 13:03:01 -070023import android.os.DeadObjectException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.os.Debug;
25import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.os.SystemProperties;
Narayan Kamathfbb32f62015-06-12 15:34:35 +010028import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.util.Log;
Dianne Hackbornc9421ba2010-03-11 22:23:46 -080030import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import com.android.internal.logging.AndroidConfig;
Jesse Wilson8568db52011-06-28 19:06:31 -070032import com.android.server.NetworkManagementSocketTagger;
Neil Fullera84056a2018-07-11 13:59:45 +010033import dalvik.system.RuntimeHooks;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import dalvik.system.VMRuntime;
Narayan Kamathac0b4be2017-07-05 14:45:38 +010035import java.lang.reflect.InvocationTargetException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import java.lang.reflect.Method;
37import java.lang.reflect.Modifier;
Andreas Gampe50fa1222018-04-02 14:00:47 -070038import java.util.Objects;
Jesse Wilson8568db52011-06-28 19:06:31 -070039import java.util.logging.LogManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
42 * Main entry point for runtime initialization. Not for
43 * public consumption.
44 * @hide
45 */
46public class RuntimeInit {
Andreas Gampe76d4fc82017-02-07 19:44:37 -080047 final static String TAG = "AndroidRuntime";
48 final static boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50 /** true if commonInit() has been called */
51 private static boolean initialized;
52
Dan Egnor60d87622009-12-16 16:32:58 -080053 private static IBinder mApplicationObject;
54
55 private static volatile boolean mCrashing = false;
56
Jeff Brown16f5f5c2012-03-15 16:53:55 -070057 private static final native void nativeFinishInit();
Jeff Brown4280c4a2012-03-15 17:48:02 -070058 private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
Jeff Brown16f5f5c2012-03-15 16:53:55 -070059
Mark Salyzyn69eb6f52014-04-09 07:39:15 -070060 private static int Clog_e(String tag, String msg, Throwable tr) {
Andreas Gamped888beb2016-02-18 14:01:41 -080061 return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
Mark Salyzyn69eb6f52014-04-09 07:39:15 -070062 }
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 /**
Tobias Thiereraddbf902016-07-21 15:05:19 +010065 * Logs a message when a thread encounters an uncaught exception. By
66 * default, {@link KillApplicationHandler} will terminate this process later,
67 * but apps can override that behavior.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 */
Tobias Thiereraddbf902016-07-21 15:05:19 +010069 private static class LoggingHandler implements Thread.UncaughtExceptionHandler {
Andreas Gampe50fa1222018-04-02 14:00:47 -070070 public volatile boolean mTriggered = false;
71
Tobias Thiereraddbf902016-07-21 15:05:19 +010072 @Override
73 public void uncaughtException(Thread t, Throwable e) {
Andreas Gampe50fa1222018-04-02 14:00:47 -070074 mTriggered = true;
75
Tobias Thiereraddbf902016-07-21 15:05:19 +010076 // Don't re-enter if KillApplicationHandler has already run
77 if (mCrashing) return;
yuanhuihuie669ac22017-03-18 19:34:31 +080078
79 // mApplicationObject is null for non-zygote java programs (e.g. "am")
80 // There are also apps running with the system UID. We don't want the
81 // first clause in either of these two cases, only for system_server.
82 if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) {
Tobias Thiereraddbf902016-07-21 15:05:19 +010083 Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
84 } else {
85 StringBuilder message = new StringBuilder();
86 // The "FATAL EXCEPTION" string is still used on Android even though
87 // apps can set a custom UncaughtExceptionHandler that renders uncaught
88 // exceptions non-fatal.
89 message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
90 final String processName = ActivityThread.currentProcessName();
91 if (processName != null) {
92 message.append("Process: ").append(processName).append(", ");
93 }
94 message.append("PID: ").append(Process.myPid());
95 Clog_e(TAG, message.toString(), e);
96 }
97 }
98 }
99
100 /**
101 * Handle application death from an uncaught exception. The framework
102 * catches these for the main threads, so this should only matter for
Andreas Gampe50fa1222018-04-02 14:00:47 -0700103 * threads created by applications. Before this method runs, the given
104 * instance of {@link LoggingHandler} should already have logged details
105 * (and if not it is run first).
Tobias Thiereraddbf902016-07-21 15:05:19 +0100106 */
107 private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
Andreas Gampe50fa1222018-04-02 14:00:47 -0700108 private final LoggingHandler mLoggingHandler;
109
110 /**
111 * Create a new KillApplicationHandler that follows the given LoggingHandler.
112 * If {@link #uncaughtException(Thread, Throwable) uncaughtException} is called
113 * on the created instance without {@code loggingHandler} having been triggered,
114 * {@link LoggingHandler#uncaughtException(Thread, Throwable)
115 * loggingHandler.uncaughtException} will be called first.
116 *
117 * @param loggingHandler the {@link LoggingHandler} expected to have run before
118 * this instance's {@link #uncaughtException(Thread, Throwable) uncaughtException}
119 * is being called.
120 */
121 public KillApplicationHandler(LoggingHandler loggingHandler) {
122 this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
123 }
124
125 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 public void uncaughtException(Thread t, Throwable e) {
127 try {
Andreas Gampe50fa1222018-04-02 14:00:47 -0700128 ensureLogging(t, e);
129
Dan Egnor60d87622009-12-16 16:32:58 -0800130 // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
131 if (mCrashing) return;
132 mCrashing = true;
133
Andreas Gampe4c79fea2016-01-28 20:11:41 -0800134 // Try to end profiling. If a profiler is running at this point, and we kill the
135 // process (below), the in-memory buffer will be lost. So try to stop, which will
136 // flush the buffer. (This makes method trace profiling useful to debug crashes.)
137 if (ActivityThread.currentActivityThread() != null) {
138 ActivityThread.currentActivityThread().stopProfiling();
139 }
140
Dan Egnor60d87622009-12-16 16:32:58 -0800141 // Bring up crash dialog, wait for it to be dismissed
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800142 ActivityManager.getService().handleApplicationCrash(
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700143 mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
Dan Egnor60d87622009-12-16 16:32:58 -0800144 } catch (Throwable t2) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700145 if (t2 instanceof DeadObjectException) {
146 // System process is dead; ignore
147 } else {
148 try {
149 Clog_e(TAG, "Error reporting crash", t2);
150 } catch (Throwable t3) {
151 // Even Clog_e() fails! Oh well.
152 }
Dan Egnor60d87622009-12-16 16:32:58 -0800153 }
154 } finally {
155 // Try everything to make sure this process goes away.
156 Process.killProcess(Process.myPid());
157 System.exit(10);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
Andreas Gampe50fa1222018-04-02 14:00:47 -0700160
161 /**
162 * Ensures that the logging handler has been triggered.
163 *
164 * See b/73380984. This reinstates the pre-O behavior of
165 *
166 * {@code thread.getUncaughtExceptionHandler().uncaughtException(thread, e);}
167 *
168 * logging the exception (in addition to killing the app). This behavior
169 * was never documented / guaranteed but helps in diagnostics of apps
170 * using the pattern.
171 *
172 * If this KillApplicationHandler is invoked the "regular" way (by
173 * {@link Thread#dispatchUncaughtException(Throwable)
174 * Thread.dispatchUncaughtException} in case of an uncaught exception)
175 * then the pre-handler (expected to be {@link #mLoggingHandler}) will already
176 * have run. Otherwise, we manually invoke it here.
177 */
178 private void ensureLogging(Thread t, Throwable e) {
179 if (!mLoggingHandler.mTriggered) {
180 try {
181 mLoggingHandler.uncaughtException(t, e);
182 } catch (Throwable loggingThrowable) {
183 // Ignored.
184 }
185 }
186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 }
188
Andreas Gampe76d4fc82017-02-07 19:44:37 -0800189 protected static final void commonInit() {
Jeff Brownebed7d62011-05-16 17:08:42 -0700190 if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
Tobias Thiereraddbf902016-07-21 15:05:19 +0100192 /*
193 * set handlers; these apply to all threads in the VM. Apps can replace
194 * the default handler, but not the pre handler.
195 */
Andreas Gampe50fa1222018-04-02 14:00:47 -0700196 LoggingHandler loggingHandler = new LoggingHandler();
Neil Fullera84056a2018-07-11 13:59:45 +0100197 RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
Andreas Gampe50fa1222018-04-02 14:00:47 -0700198 Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 /*
Neil Fullera84056a2018-07-11 13:59:45 +0100201 * Install a time zone supplier that uses the Android persistent time zone system property.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 */
Neil Fullera84056a2018-07-11 13:59:45 +0100203 RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
205 /*
206 * Sets handler for java.util.logging to use Android log facilities.
207 * The odd "new instance-and-then-throw-away" is a mirror of how
208 * the "java.util.logging.config.class" system property works. We
209 * can't use the system property here since the logger has almost
210 * certainly already been initialized.
211 */
212 LogManager.getLogManager().reset();
213 new AndroidConfig();
214
215 /*
Jesse Wilsond0f80d42009-09-18 18:06:43 -0700216 * Sets the default HTTP User-Agent used by HttpURLConnection.
217 */
218 String userAgent = getDefaultUserAgent();
219 System.setProperty("http.agent", userAgent);
220
221 /*
Jesse Wilson8568db52011-06-28 19:06:31 -0700222 * Wire socket tagging to traffic stats.
223 */
224 NetworkManagementSocketTagger.install();
225
226 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 * If we're running in an emulator launched with "-trace", put the
228 * VM into emulator trace profiling mode so that the user can hit
229 * F9/F10 at any time to capture traces. This has performance
230 * consequences, so it's not something you want to do always.
231 */
232 String trace = SystemProperties.get("ro.kernel.android.tracing");
233 if (trace.equals("1")) {
Dianne Hackbornc9421ba2010-03-11 22:23:46 -0800234 Slog.i(TAG, "NOTE: emulator trace profiling enabled");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 Debug.enableEmulatorTraceOutput();
236 }
237
238 initialized = true;
239 }
240
241 /**
Jesse Wilsond0f80d42009-09-18 18:06:43 -0700242 * Returns an HTTP user agent of the form
243 * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
244 */
245 private static String getDefaultUserAgent() {
246 StringBuilder result = new StringBuilder(64);
247 result.append("Dalvik/");
248 result.append(System.getProperty("java.vm.version")); // such as 1.1.0
249 result.append(" (Linux; U; Android ");
250
251 String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
252 result.append(version.length() > 0 ? version : "1.0");
253
254 // add the model for the release build
255 if ("REL".equals(Build.VERSION.CODENAME)) {
256 String model = Build.MODEL;
257 if (model.length() > 0) {
258 result.append("; ");
259 result.append(model);
260 }
261 }
262 String id = Build.ID; // "MASTER" or "M4-rc20"
263 if (id.length() > 0) {
264 result.append(" Build/");
265 result.append(id);
266 }
267 result.append(")");
268 return result.toString();
269 }
270
271 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 * Invokes a static "main(argv[]) method on class "className".
273 * Converts various failing exceptions into RuntimeExceptions, with
274 * the assumption that they will then cause the VM instance to exit.
275 *
276 * @param className Fully-qualified class name
277 * @param argv Argument vector for main()
Narayan Kamath29564cd2014-08-07 10:57:40 +0100278 * @param classLoader the classLoader to load {@className} with
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 */
Robert Sesekd0a190df2018-02-12 18:46:01 -0500280 protected static Runnable findStaticMain(String className, String[] argv,
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100281 ClassLoader classLoader) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 Class<?> cl;
283
284 try {
Narayan Kamath29564cd2014-08-07 10:57:40 +0100285 cl = Class.forName(className, true, classLoader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 } catch (ClassNotFoundException ex) {
287 throw new RuntimeException(
288 "Missing class when invoking static main " + className,
289 ex);
290 }
291
292 Method m;
293 try {
294 m = cl.getMethod("main", new Class[] { String[].class });
295 } catch (NoSuchMethodException ex) {
296 throw new RuntimeException(
297 "Missing static main on " + className, ex);
298 } catch (SecurityException ex) {
299 throw new RuntimeException(
300 "Problem getting static main on " + className, ex);
301 }
302
303 int modifiers = m.getModifiers();
304 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
305 throw new RuntimeException(
306 "Main method is not public and static on " + className);
307 }
308
309 /*
310 * This throw gets caught in ZygoteInit.main(), which responds
311 * by invoking the exception's run() method. This arrangement
312 * clears up all the stack frames that were required in setting
313 * up the process.
314 */
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100315 return new MethodAndArgsCaller(m, argv);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317
318 public static final void main(String[] argv) {
Piotr Jastrzebskida74a622015-02-12 13:55:23 +0000319 enableDdms();
Jeff Brownebed7d62011-05-16 17:08:42 -0700320 if (argv.length == 2 && argv[1].equals("application")) {
321 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
322 redirectLogStreams();
323 } else {
324 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
325 }
326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 commonInit();
Bob Leee5408332009-09-04 18:31:17 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 /*
330 * Now that we're running in interpreted code, call back into native code
331 * to run the system.
332 */
Jeff Brown16f5f5c2012-03-15 16:53:55 -0700333 nativeFinishInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334
Jeff Brownebed7d62011-05-16 17:08:42 -0700335 if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
Bob Leee5408332009-09-04 18:31:17 -0700337
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100338 protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
339 ClassLoader classLoader) {
Jeff Brown4280c4a2012-03-15 17:48:02 -0700340 // If the application calls System.exit(), terminate the process
341 // immediately without running any shutdown hooks. It is not possible to
342 // shutdown an Android application gracefully. Among other things, the
343 // Android runtime shutdown hooks close the Binder driver, which can cause
344 // leftover running threads to crash before the process actually exits.
345 nativeSetExitWithoutCleanup(true);
346
Jeff Brownebed7d62011-05-16 17:08:42 -0700347 // We want to be fairly aggressive about heap utilization, to avoid
348 // holding on to a lot of memory that isn't needed.
349 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700350 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
Jeff Brownebed7d62011-05-16 17:08:42 -0700351
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100352 final Arguments args = new Arguments(argv);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100354 // The end of of the RuntimeInit event (see #zygoteInit).
355 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 // Remaining arguments are passed to the start class's static main
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100358 return findStaticMain(args.startClass, args.startArgs, classLoader);
Jeff Brownebed7d62011-05-16 17:08:42 -0700359 }
Bob Leee5408332009-09-04 18:31:17 -0700360
Jeff Brownebed7d62011-05-16 17:08:42 -0700361 /**
362 * Redirect System.out and System.err to the Android log.
363 */
364 public static void redirectLogStreams() {
365 System.out.close();
366 System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
367 System.err.close();
368 System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 /**
Dan Egnor60d87622009-12-16 16:32:58 -0800372 * Report a serious error in the current process. May or may not cause
373 * the process to terminate (depends on system settings).
Bob Leee5408332009-09-04 18:31:17 -0700374 *
Dan Egnor60d87622009-12-16 16:32:58 -0800375 * @param tag to record with the error
376 * @param t exception describing the error site and conditions
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 */
Dianne Hackborn52322712014-08-26 22:47:26 -0700378 public static void wtf(String tag, Throwable t, boolean system) {
Dan Egnor60d87622009-12-16 16:32:58 -0800379 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800380 if (ActivityManager.getService().handleApplicationWtf(
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700381 mApplicationObject, tag, system,
382 new ApplicationErrorReport.ParcelableCrashInfo(t))) {
Dan Egnor60d87622009-12-16 16:32:58 -0800383 // The Activity Manager has already written us off -- now exit.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 Process.killProcess(Process.myPid());
385 System.exit(10);
386 }
Dan Egnor60d87622009-12-16 16:32:58 -0800387 } catch (Throwable t2) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700388 if (t2 instanceof DeadObjectException) {
389 // System process is dead; ignore
390 } else {
391 Slog.e(TAG, "Error reporting WTF", t2);
392 Slog.e(TAG, "Original WTF:", t);
393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 }
395 }
396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 * Set the object identifying this application/process, for reporting VM
399 * errors.
400 */
401 public static final void setApplicationObject(IBinder app) {
402 mApplicationObject = app;
403 }
404
Brad Fitzpatrick438d0592010-06-10 12:19:19 -0700405 public static final IBinder getApplicationObject() {
406 return mApplicationObject;
407 }
408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 /**
Piotr Jastrzebskida74a622015-02-12 13:55:23 +0000410 * Enable DDMS.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 */
Piotr Jastrzebskida74a622015-02-12 13:55:23 +0000412 static final void enableDdms() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 // Register handlers for DDM messages.
414 android.ddm.DdmRegister.registerHandlers();
415 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700416
417 /**
418 * Handles argument parsing for args related to the runtime.
419 *
420 * Current recognized args:
421 * <ul>
422 * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
423 * </ul>
424 */
425 static class Arguments {
426 /** first non-option argument */
427 String startClass;
428
429 /** all following arguments */
430 String[] startArgs;
431
432 /**
433 * Constructs instance and parses args
434 * @param args runtime command-line args
435 * @throws IllegalArgumentException
436 */
437 Arguments(String args[]) throws IllegalArgumentException {
438 parseArgs(args);
439 }
440
441 /**
442 * Parses the commandline arguments intended for the Runtime.
443 */
444 private void parseArgs(String args[])
445 throws IllegalArgumentException {
446 int curArg = 0;
447 for (; curArg < args.length; curArg++) {
448 String arg = args[curArg];
449
450 if (arg.equals("--")) {
451 curArg++;
452 break;
453 } else if (!arg.startsWith("--")) {
454 break;
455 }
456 }
457
458 if (curArg == args.length) {
459 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
460 }
461
462 startClass = args[curArg++];
463 startArgs = new String[args.length - curArg];
464 System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
465 }
466 }
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100467
468 /**
469 * Helper class which holds a method and arguments and can call them. This is used as part of
470 * a trampoline to get rid of the initial process setup stack frames.
471 */
472 static class MethodAndArgsCaller implements Runnable {
473 /** method to call */
474 private final Method mMethod;
475
476 /** argument array */
477 private final String[] mArgs;
478
479 public MethodAndArgsCaller(Method method, String[] args) {
480 mMethod = method;
481 mArgs = args;
482 }
483
484 public void run() {
485 try {
486 mMethod.invoke(null, new Object[] { mArgs });
487 } catch (IllegalAccessException ex) {
488 throw new RuntimeException(ex);
489 } catch (InvocationTargetException ex) {
490 Throwable cause = ex.getCause();
491 if (cause instanceof RuntimeException) {
492 throw (RuntimeException) cause;
493 } else if (cause instanceof Error) {
494 throw (Error) cause;
495 }
496 throw new RuntimeException(ex);
497 }
498 }
499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500}