2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.os;
19 import android.app.ActivityManager;
20 import android.app.ActivityThread;
21 import android.app.ApplicationErrorReport;
22 import android.os.Build;
23 import android.os.DeadObjectException;
24 import android.os.Debug;
25 import android.os.IBinder;
26 import android.os.Process;
27 import android.os.SystemProperties;
28 import android.os.Trace;
29 import android.util.Log;
30 import android.util.Slog;
31 import com.android.internal.logging.AndroidConfig;
32 import com.android.server.NetworkManagementSocketTagger;
33 import dalvik.system.VMRuntime;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Method;
36 import java.lang.reflect.Modifier;
37 import java.util.TimeZone;
38 import java.util.logging.LogManager;
39 import org.apache.harmony.luni.internal.util.TimezoneGetter;
42 * Main entry point for runtime initialization. Not for
46 public class RuntimeInit {
47 final static String TAG = "AndroidRuntime";
48 final static boolean DEBUG = false;
50 /** true if commonInit() has been called */
51 private static boolean initialized;
53 private static IBinder mApplicationObject;
55 private static volatile boolean mCrashing = false;
57 private static final native void nativeFinishInit();
58 private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
60 private static int Clog_e(String tag, String msg, Throwable tr) {
61 return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
65 * 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.
69 private static class LoggingHandler implements Thread.UncaughtExceptionHandler {
71 public void uncaughtException(Thread t, Throwable e) {
72 // Don't re-enter if KillApplicationHandler has already run
73 if (mCrashing) return;
74 if (mApplicationObject == null) {
75 // The "FATAL EXCEPTION" string is still used on Android even though
76 // apps can set a custom UncaughtExceptionHandler that renders uncaught
77 // exceptions non-fatal.
78 Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
80 StringBuilder message = new StringBuilder();
81 // The "FATAL EXCEPTION" string is still used on Android even though
82 // apps can set a custom UncaughtExceptionHandler that renders uncaught
83 // exceptions non-fatal.
84 message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
85 final String processName = ActivityThread.currentProcessName();
86 if (processName != null) {
87 message.append("Process: ").append(processName).append(", ");
89 message.append("PID: ").append(Process.myPid());
90 Clog_e(TAG, message.toString(), e);
96 * Handle application death from an uncaught exception. The framework
97 * catches these for the main threads, so this should only matter for
98 * threads created by applications. Before this method runs,
99 * {@link LoggingHandler} will already have logged details.
101 private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
102 public void uncaughtException(Thread t, Throwable e) {
104 // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
105 if (mCrashing) return;
108 // Try to end profiling. If a profiler is running at this point, and we kill the
109 // process (below), the in-memory buffer will be lost. So try to stop, which will
110 // flush the buffer. (This makes method trace profiling useful to debug crashes.)
111 if (ActivityThread.currentActivityThread() != null) {
112 ActivityThread.currentActivityThread().stopProfiling();
115 // Bring up crash dialog, wait for it to be dismissed
116 ActivityManager.getService().handleApplicationCrash(
117 mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
118 } catch (Throwable t2) {
119 if (t2 instanceof DeadObjectException) {
120 // System process is dead; ignore
123 Clog_e(TAG, "Error reporting crash", t2);
124 } catch (Throwable t3) {
125 // Even Clog_e() fails! Oh well.
129 // Try everything to make sure this process goes away.
130 Process.killProcess(Process.myPid());
136 protected static final void commonInit() {
137 if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
140 * set handlers; these apply to all threads in the VM. Apps can replace
141 * the default handler, but not the pre handler.
143 Thread.setUncaughtExceptionPreHandler(new LoggingHandler());
144 Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
147 * Install a TimezoneGetter subclass for ZoneInfo.db
149 TimezoneGetter.setInstance(new TimezoneGetter() {
151 public String getId() {
152 return SystemProperties.get("persist.sys.timezone");
155 TimeZone.setDefault(null);
158 * Sets handler for java.util.logging to use Android log facilities.
159 * The odd "new instance-and-then-throw-away" is a mirror of how
160 * the "java.util.logging.config.class" system property works. We
161 * can't use the system property here since the logger has almost
162 * certainly already been initialized.
164 LogManager.getLogManager().reset();
168 * Sets the default HTTP User-Agent used by HttpURLConnection.
170 String userAgent = getDefaultUserAgent();
171 System.setProperty("http.agent", userAgent);
174 * Wire socket tagging to traffic stats.
176 NetworkManagementSocketTagger.install();
179 * If we're running in an emulator launched with "-trace", put the
180 * VM into emulator trace profiling mode so that the user can hit
181 * F9/F10 at any time to capture traces. This has performance
182 * consequences, so it's not something you want to do always.
184 String trace = SystemProperties.get("ro.kernel.android.tracing");
185 if (trace.equals("1")) {
186 Slog.i(TAG, "NOTE: emulator trace profiling enabled");
187 Debug.enableEmulatorTraceOutput();
194 * Returns an HTTP user agent of the form
195 * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
197 private static String getDefaultUserAgent() {
198 StringBuilder result = new StringBuilder(64);
199 result.append("Dalvik/");
200 result.append(System.getProperty("java.vm.version")); // such as 1.1.0
201 result.append(" (Linux; U; Android ");
203 String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
204 result.append(version.length() > 0 ? version : "1.0");
206 // add the model for the release build
207 if ("REL".equals(Build.VERSION.CODENAME)) {
208 String model = Build.MODEL;
209 if (model.length() > 0) {
211 result.append(model);
214 String id = Build.ID; // "MASTER" or "M4-rc20"
215 if (id.length() > 0) {
216 result.append(" Build/");
220 return result.toString();
224 * Invokes a static "main(argv[]) method on class "className".
225 * Converts various failing exceptions into RuntimeExceptions, with
226 * the assumption that they will then cause the VM instance to exit.
228 * @param className Fully-qualified class name
229 * @param argv Argument vector for main()
230 * @param classLoader the classLoader to load {@className} with
232 private static Runnable findStaticMain(String className, String[] argv,
233 ClassLoader classLoader) {
237 cl = Class.forName(className, true, classLoader);
238 } catch (ClassNotFoundException ex) {
239 throw new RuntimeException(
240 "Missing class when invoking static main " + className,
246 m = cl.getMethod("main", new Class[] { String[].class });
247 } catch (NoSuchMethodException ex) {
248 throw new RuntimeException(
249 "Missing static main on " + className, ex);
250 } catch (SecurityException ex) {
251 throw new RuntimeException(
252 "Problem getting static main on " + className, ex);
255 int modifiers = m.getModifiers();
256 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
257 throw new RuntimeException(
258 "Main method is not public and static on " + className);
262 * This throw gets caught in ZygoteInit.main(), which responds
263 * by invoking the exception's run() method. This arrangement
264 * clears up all the stack frames that were required in setting
267 return new MethodAndArgsCaller(m, argv);
270 public static final void main(String[] argv) {
272 if (argv.length == 2 && argv[1].equals("application")) {
273 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
274 redirectLogStreams();
276 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
282 * Now that we're running in interpreted code, call back into native code
287 if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
290 protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
291 ClassLoader classLoader) {
292 // If the application calls System.exit(), terminate the process
293 // immediately without running any shutdown hooks. It is not possible to
294 // shutdown an Android application gracefully. Among other things, the
295 // Android runtime shutdown hooks close the Binder driver, which can cause
296 // leftover running threads to crash before the process actually exits.
297 nativeSetExitWithoutCleanup(true);
299 // We want to be fairly aggressive about heap utilization, to avoid
300 // holding on to a lot of memory that isn't needed.
301 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
302 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
304 final Arguments args = new Arguments(argv);
306 // The end of of the RuntimeInit event (see #zygoteInit).
307 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
309 // Remaining arguments are passed to the start class's static main
310 return findStaticMain(args.startClass, args.startArgs, classLoader);
314 * Redirect System.out and System.err to the Android log.
316 public static void redirectLogStreams() {
318 System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
320 System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
324 * Report a serious error in the current process. May or may not cause
325 * the process to terminate (depends on system settings).
327 * @param tag to record with the error
328 * @param t exception describing the error site and conditions
330 public static void wtf(String tag, Throwable t, boolean system) {
332 if (ActivityManager.getService().handleApplicationWtf(
333 mApplicationObject, tag, system,
334 new ApplicationErrorReport.ParcelableCrashInfo(t))) {
335 // The Activity Manager has already written us off -- now exit.
336 Process.killProcess(Process.myPid());
339 } catch (Throwable t2) {
340 if (t2 instanceof DeadObjectException) {
341 // System process is dead; ignore
343 Slog.e(TAG, "Error reporting WTF", t2);
344 Slog.e(TAG, "Original WTF:", t);
350 * Set the object identifying this application/process, for reporting VM
353 public static final void setApplicationObject(IBinder app) {
354 mApplicationObject = app;
357 public static final IBinder getApplicationObject() {
358 return mApplicationObject;
364 static final void enableDdms() {
365 // Register handlers for DDM messages.
366 android.ddm.DdmRegister.registerHandlers();
370 * Handles argument parsing for args related to the runtime.
372 * Current recognized args:
374 * <li> <code> [--] <start class name> <args>
377 static class Arguments {
378 /** first non-option argument */
381 /** all following arguments */
385 * Constructs instance and parses args
386 * @param args runtime command-line args
387 * @throws IllegalArgumentException
389 Arguments(String args[]) throws IllegalArgumentException {
394 * Parses the commandline arguments intended for the Runtime.
396 private void parseArgs(String args[])
397 throws IllegalArgumentException {
399 for (; curArg < args.length; curArg++) {
400 String arg = args[curArg];
402 if (arg.equals("--")) {
405 } else if (!arg.startsWith("--")) {
410 if (curArg == args.length) {
411 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
414 startClass = args[curArg++];
415 startArgs = new String[args.length - curArg];
416 System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
421 * Helper class which holds a method and arguments and can call them. This is used as part of
422 * a trampoline to get rid of the initial process setup stack frames.
424 static class MethodAndArgsCaller implements Runnable {
425 /** method to call */
426 private final Method mMethod;
428 /** argument array */
429 private final String[] mArgs;
431 public MethodAndArgsCaller(Method method, String[] args) {
438 mMethod.invoke(null, new Object[] { mArgs });
439 } catch (IllegalAccessException ex) {
440 throw new RuntimeException(ex);
441 } catch (InvocationTargetException ex) {
442 Throwable cause = ex.getCause();
443 if (cause instanceof RuntimeException) {
444 throw (RuntimeException) cause;
445 } else if (cause instanceof Error) {
448 throw new RuntimeException(ex);