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.ActivityManagerNative;
20 import android.app.ActivityThread;
21 import android.app.ApplicationErrorReport;
22 import android.os.Build;
23 import android.os.Debug;
24 import android.os.IBinder;
25 import android.os.Process;
26 import android.os.SystemProperties;
27 import android.util.Log;
28 import android.util.Slog;
29 import com.android.internal.logging.AndroidConfig;
30 import com.android.server.NetworkManagementSocketTagger;
31 import dalvik.system.VMRuntime;
32 import java.lang.reflect.Method;
33 import java.lang.reflect.Modifier;
34 import java.util.TimeZone;
35 import java.util.logging.LogManager;
36 import org.apache.harmony.luni.internal.util.TimezoneGetter;
39 * Main entry point for runtime initialization. Not for
43 public class RuntimeInit {
44 private final static String TAG = "AndroidRuntime";
45 private final static boolean DEBUG = false;
47 /** true if commonInit() has been called */
48 private static boolean initialized;
50 private static IBinder mApplicationObject;
52 private static volatile boolean mCrashing = false;
54 private static final native void nativeZygoteInit();
55 private static final native void nativeFinishInit();
56 private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
58 private static int Clog_e(String tag, String msg, Throwable tr) {
59 return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
60 msg + '\n' + Log.getStackTraceString(tr));
64 * Use this to log a message when a thread exits due to an uncaught
65 * exception. The framework catches these for the main threads, so
66 * this should only matter for threads created by applications.
68 private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
69 public void uncaughtException(Thread t, Throwable e) {
71 // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
72 if (mCrashing) return;
75 if (mApplicationObject == null) {
76 Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
78 StringBuilder message = new StringBuilder();
79 message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
80 final String processName = ActivityThread.currentProcessName();
81 if (processName != null) {
82 message.append("Process: ").append(processName).append(", ");
84 message.append("PID: ").append(Process.myPid());
85 Clog_e(TAG, message.toString(), e);
88 // Bring up crash dialog, wait for it to be dismissed
89 ActivityManagerNative.getDefault().handleApplicationCrash(
90 mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
91 } catch (Throwable t2) {
93 Clog_e(TAG, "Error reporting crash", t2);
94 } catch (Throwable t3) {
95 // Even Clog_e() fails! Oh well.
98 // Try everything to make sure this process goes away.
99 Process.killProcess(Process.myPid());
105 private static final void commonInit() {
106 if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
108 /* set default handler; this applies to all threads in the VM */
109 Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
112 * Install a TimezoneGetter subclass for ZoneInfo.db
114 TimezoneGetter.setInstance(new TimezoneGetter() {
116 public String getId() {
117 return SystemProperties.get("persist.sys.timezone");
120 TimeZone.setDefault(null);
123 * Sets handler for java.util.logging to use Android log facilities.
124 * The odd "new instance-and-then-throw-away" is a mirror of how
125 * the "java.util.logging.config.class" system property works. We
126 * can't use the system property here since the logger has almost
127 * certainly already been initialized.
129 LogManager.getLogManager().reset();
133 * Sets the default HTTP User-Agent used by HttpURLConnection.
135 String userAgent = getDefaultUserAgent();
136 System.setProperty("http.agent", userAgent);
139 * Wire socket tagging to traffic stats.
141 NetworkManagementSocketTagger.install();
144 * If we're running in an emulator launched with "-trace", put the
145 * VM into emulator trace profiling mode so that the user can hit
146 * F9/F10 at any time to capture traces. This has performance
147 * consequences, so it's not something you want to do always.
149 String trace = SystemProperties.get("ro.kernel.android.tracing");
150 if (trace.equals("1")) {
151 Slog.i(TAG, "NOTE: emulator trace profiling enabled");
152 Debug.enableEmulatorTraceOutput();
159 * Returns an HTTP user agent of the form
160 * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
162 private static String getDefaultUserAgent() {
163 StringBuilder result = new StringBuilder(64);
164 result.append("Dalvik/");
165 result.append(System.getProperty("java.vm.version")); // such as 1.1.0
166 result.append(" (Linux; U; Android ");
168 String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
169 result.append(version.length() > 0 ? version : "1.0");
171 // add the model for the release build
172 if ("REL".equals(Build.VERSION.CODENAME)) {
173 String model = Build.MODEL;
174 if (model.length() > 0) {
176 result.append(model);
179 String id = Build.ID; // "MASTER" or "M4-rc20"
180 if (id.length() > 0) {
181 result.append(" Build/");
185 return result.toString();
189 * Invokes a static "main(argv[]) method on class "className".
190 * Converts various failing exceptions into RuntimeExceptions, with
191 * the assumption that they will then cause the VM instance to exit.
193 * @param className Fully-qualified class name
194 * @param argv Argument vector for main()
196 private static void invokeStaticMain(String className, String[] argv)
197 throws ZygoteInit.MethodAndArgsCaller {
201 cl = Class.forName(className);
202 } catch (ClassNotFoundException ex) {
203 throw new RuntimeException(
204 "Missing class when invoking static main " + className,
210 m = cl.getMethod("main", new Class[] { String[].class });
211 } catch (NoSuchMethodException ex) {
212 throw new RuntimeException(
213 "Missing static main on " + className, ex);
214 } catch (SecurityException ex) {
215 throw new RuntimeException(
216 "Problem getting static main on " + className, ex);
219 int modifiers = m.getModifiers();
220 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
221 throw new RuntimeException(
222 "Main method is not public and static on " + className);
226 * This throw gets caught in ZygoteInit.main(), which responds
227 * by invoking the exception's run() method. This arrangement
228 * clears up all the stack frames that were required in setting
231 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
234 public static final void main(String[] argv) {
235 if (argv.length == 2 && argv[1].equals("application")) {
236 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
237 redirectLogStreams();
239 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
245 * Now that we're running in interpreted code, call back into native code
250 if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
254 * The main function called when started through the zygote process. This
255 * could be unified with main(), if the native code in nativeFinishInit()
256 * were rationalized with Zygote startup.<p>
258 * Current recognized args:
260 * <li> <code> [--] <start class name> <args>
263 * @param targetSdkVersion target SDK version
264 * @param argv arg strings
266 public static final void zygoteInit(int targetSdkVersion, String[] argv)
267 throws ZygoteInit.MethodAndArgsCaller {
268 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
270 redirectLogStreams();
275 applicationInit(targetSdkVersion, argv);
279 * The main function called when an application is started through a
282 * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
283 * which calls {@link WrapperInit#main} which then calls this method.
284 * So we don't need to call commonInit() here.
286 * @param targetSdkVersion target SDK version
287 * @param argv arg strings
289 public static void wrapperInit(int targetSdkVersion, String[] argv)
290 throws ZygoteInit.MethodAndArgsCaller {
291 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
293 applicationInit(targetSdkVersion, argv);
296 private static void applicationInit(int targetSdkVersion, String[] argv)
297 throws ZygoteInit.MethodAndArgsCaller {
298 // If the application calls System.exit(), terminate the process
299 // immediately without running any shutdown hooks. It is not possible to
300 // shutdown an Android application gracefully. Among other things, the
301 // Android runtime shutdown hooks close the Binder driver, which can cause
302 // leftover running threads to crash before the process actually exits.
303 nativeSetExitWithoutCleanup(true);
305 // We want to be fairly aggressive about heap utilization, to avoid
306 // holding on to a lot of memory that isn't needed.
307 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
308 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
310 final Arguments args;
312 args = new Arguments(argv);
313 } catch (IllegalArgumentException ex) {
314 Slog.e(TAG, ex.getMessage());
315 // let the process exit
319 // Remaining arguments are passed to the start class's static main
320 invokeStaticMain(args.startClass, args.startArgs);
324 * Redirect System.out and System.err to the Android log.
326 public static void redirectLogStreams() {
328 System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
330 System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
334 * Report a serious error in the current process. May or may not cause
335 * the process to terminate (depends on system settings).
337 * @param tag to record with the error
338 * @param t exception describing the error site and conditions
340 public static void wtf(String tag, Throwable t) {
342 if (ActivityManagerNative.getDefault().handleApplicationWtf(
343 mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) {
344 // The Activity Manager has already written us off -- now exit.
345 Process.killProcess(Process.myPid());
348 } catch (Throwable t2) {
349 Slog.e(TAG, "Error reporting WTF", t2);
350 Slog.e(TAG, "Original WTF:", t);
355 * Set the object identifying this application/process, for reporting VM
358 public static final void setApplicationObject(IBinder app) {
359 mApplicationObject = app;
362 public static final IBinder getApplicationObject() {
363 return mApplicationObject;
367 * Enable debugging features.
370 // Register handlers for DDM messages.
371 android.ddm.DdmRegister.registerHandlers();
375 * Handles argument parsing for args related to the runtime.
377 * Current recognized args:
379 * <li> <code> [--] <start class name> <args>
382 static class Arguments {
383 /** first non-option argument */
386 /** all following arguments */
390 * Constructs instance and parses args
391 * @param args runtime command-line args
392 * @throws IllegalArgumentException
394 Arguments(String args[]) throws IllegalArgumentException {
399 * Parses the commandline arguments intended for the Runtime.
401 private void parseArgs(String args[])
402 throws IllegalArgumentException {
404 for (; curArg < args.length; curArg++) {
405 String arg = args[curArg];
407 if (arg.equals("--")) {
410 } else if (!arg.startsWith("--")) {
415 if (curArg == args.length) {
416 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
419 startClass = args[curArg++];
420 startArgs = new String[args.length - curArg];
421 System.arraycopy(args, curArg, startArgs, 0, startArgs.length);