/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.ApplicationErrorReport; import android.os.Build; import android.os.Debug; import android.os.IBinder; import android.os.Process; import android.os.SystemProperties; import android.util.Log; import android.util.Slog; import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.VMRuntime; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.TimeZone; import java.util.logging.LogManager; import org.apache.harmony.luni.internal.util.TimezoneGetter; /** * Main entry point for runtime initialization. Not for * public consumption. * @hide */ public class RuntimeInit { private final static String TAG = "AndroidRuntime"; private final static boolean DEBUG = false; /** true if commonInit() has been called */ private static boolean initialized; private static IBinder mApplicationObject; private static volatile boolean mCrashing = false; private static final native void nativeZygoteInit(); private static final native void nativeFinishInit(); private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup); private static int Clog_e(String tag, String msg, Throwable tr) { return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag, msg + '\n' + Log.getStackTraceString(tr)); } /** * Use this to log a message when a thread exits due to an uncaught * exception. The framework catches these for the main threads, so * this should only matter for threads created by applications. */ private static class UncaughtHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { try { // Don't re-enter -- avoid infinite loops if crash-reporting crashes. if (mCrashing) return; mCrashing = true; if (mApplicationObject == null) { Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n"); final String processName = ActivityThread.currentProcessName(); if (processName != null) { message.append("Process: ").append(processName).append(", "); } message.append("PID: ").append(Process.myPid()); Clog_e(TAG, message.toString(), e); } // Bring up crash dialog, wait for it to be dismissed ActivityManagerNative.getDefault().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); } catch (Throwable t2) { try { Clog_e(TAG, "Error reporting crash", t2); } catch (Throwable t3) { // Even Clog_e() fails! Oh well. } } finally { // Try everything to make sure this process goes away. Process.killProcess(Process.myPid()); System.exit(10); } } } private static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); /* * Install a TimezoneGetter subclass for ZoneInfo.db */ TimezoneGetter.setInstance(new TimezoneGetter() { @Override public String getId() { return SystemProperties.get("persist.sys.timezone"); } }); TimeZone.setDefault(null); /* * Sets handler for java.util.logging to use Android log facilities. * The odd "new instance-and-then-throw-away" is a mirror of how * the "java.util.logging.config.class" system property works. We * can't use the system property here since the logger has almost * certainly already been initialized. */ LogManager.getLogManager().reset(); new AndroidConfig(); /* * Sets the default HTTP User-Agent used by HttpURLConnection. */ String userAgent = getDefaultUserAgent(); System.setProperty("http.agent", userAgent); /* * Wire socket tagging to traffic stats. */ NetworkManagementSocketTagger.install(); /* * If we're running in an emulator launched with "-trace", put the * VM into emulator trace profiling mode so that the user can hit * F9/F10 at any time to capture traces. This has performance * consequences, so it's not something you want to do always. */ String trace = SystemProperties.get("ro.kernel.android.tracing"); if (trace.equals("1")) { Slog.i(TAG, "NOTE: emulator trace profiling enabled"); Debug.enableEmulatorTraceOutput(); } initialized = true; } /** * Returns an HTTP user agent of the form * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)". */ private static String getDefaultUserAgent() { StringBuilder result = new StringBuilder(64); result.append("Dalvik/"); result.append(System.getProperty("java.vm.version")); // such as 1.1.0 result.append(" (Linux; U; Android "); String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5" result.append(version.length() > 0 ? version : "1.0"); // add the model for the release build if ("REL".equals(Build.VERSION.CODENAME)) { String model = Build.MODEL; if (model.length() > 0) { result.append("; "); result.append(model); } } String id = Build.ID; // "MASTER" or "M4-rc20" if (id.length() > 0) { result.append(" Build/"); result.append(id); } result.append(")"); return result.toString(); } /** * Invokes a static "main(argv[]) method on class "className". * Converts various failing exceptions into RuntimeExceptions, with * the assumption that they will then cause the VM instance to exit. * * @param className Fully-qualified class name * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { Class> cl; try { cl = Class.forName(className, true, classLoader); } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className, ex); } Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex); } int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv); } public static final void main(String[] argv) { if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); } else { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool"); } commonInit(); /* * Now that we're running in interpreted code, call back into native code * to run the system. */ nativeFinishInit(); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } /** * The main function called when started through the zygote process. This * could be unified with main(), if the native code in nativeFinishInit() * were rationalized with Zygote startup.
* * Current recognized args: *
[--] <start class name> <args>
*
[--] <start class name> <args>
*