Home | History | Annotate | Download | only in os
      1 /*
      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 
     17 package com.android.internal.os;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.ApplicationErrorReport;
     21 import android.os.Build;
     22 import android.os.Debug;
     23 import android.os.IBinder;
     24 import android.os.Process;
     25 import android.os.SystemProperties;
     26 import android.util.Log;
     27 import android.util.Slog;
     28 import com.android.internal.logging.AndroidConfig;
     29 import com.android.server.NetworkManagementSocketTagger;
     30 import dalvik.system.VMRuntime;
     31 import java.lang.reflect.Method;
     32 import java.lang.reflect.Modifier;
     33 import java.util.TimeZone;
     34 import java.util.logging.LogManager;
     35 import org.apache.harmony.luni.internal.util.TimezoneGetter;
     36 
     37 /**
     38  * Main entry point for runtime initialization.  Not for
     39  * public consumption.
     40  * @hide
     41  */
     42 public class RuntimeInit {
     43     private final static String TAG = "AndroidRuntime";
     44     private final static boolean DEBUG = false;
     45 
     46     /** true if commonInit() has been called */
     47     private static boolean initialized;
     48 
     49     private static IBinder mApplicationObject;
     50 
     51     private static volatile boolean mCrashing = false;
     52 
     53     private static final native void nativeZygoteInit();
     54     private static final native void nativeFinishInit();
     55     private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
     56 
     57     /**
     58      * Use this to log a message when a thread exits due to an uncaught
     59      * exception.  The framework catches these for the main threads, so
     60      * this should only matter for threads created by applications.
     61      */
     62     private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
     63         public void uncaughtException(Thread t, Throwable e) {
     64             try {
     65                 // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
     66                 if (mCrashing) return;
     67                 mCrashing = true;
     68 
     69                 if (mApplicationObject == null) {
     70                     Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
     71                 } else {
     72                     Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
     73                 }
     74 
     75                 // Bring up crash dialog, wait for it to be dismissed
     76                 ActivityManagerNative.getDefault().handleApplicationCrash(
     77                         mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
     78             } catch (Throwable t2) {
     79                 try {
     80                     Slog.e(TAG, "Error reporting crash", t2);
     81                 } catch (Throwable t3) {
     82                     // Even Slog.e() fails!  Oh well.
     83                 }
     84             } finally {
     85                 // Try everything to make sure this process goes away.
     86                 Process.killProcess(Process.myPid());
     87                 System.exit(10);
     88             }
     89         }
     90     }
     91 
     92     private static final void commonInit() {
     93         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
     94 
     95         /* set default handler; this applies to all threads in the VM */
     96         Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
     97 
     98         /*
     99          * Install a TimezoneGetter subclass for ZoneInfo.db
    100          */
    101         TimezoneGetter.setInstance(new TimezoneGetter() {
    102             @Override
    103             public String getId() {
    104                 return SystemProperties.get("persist.sys.timezone");
    105             }
    106         });
    107         TimeZone.setDefault(null);
    108 
    109         /*
    110          * Sets handler for java.util.logging to use Android log facilities.
    111          * The odd "new instance-and-then-throw-away" is a mirror of how
    112          * the "java.util.logging.config.class" system property works. We
    113          * can't use the system property here since the logger has almost
    114          * certainly already been initialized.
    115          */
    116         LogManager.getLogManager().reset();
    117         new AndroidConfig();
    118 
    119         /*
    120          * Sets the default HTTP User-Agent used by HttpURLConnection.
    121          */
    122         String userAgent = getDefaultUserAgent();
    123         System.setProperty("http.agent", userAgent);
    124 
    125         /*
    126          * Wire socket tagging to traffic stats.
    127          */
    128         NetworkManagementSocketTagger.install();
    129 
    130         /*
    131          * If we're running in an emulator launched with "-trace", put the
    132          * VM into emulator trace profiling mode so that the user can hit
    133          * F9/F10 at any time to capture traces.  This has performance
    134          * consequences, so it's not something you want to do always.
    135          */
    136         String trace = SystemProperties.get("ro.kernel.android.tracing");
    137         if (trace.equals("1")) {
    138             Slog.i(TAG, "NOTE: emulator trace profiling enabled");
    139             Debug.enableEmulatorTraceOutput();
    140         }
    141 
    142         initialized = true;
    143     }
    144 
    145     /**
    146      * Returns an HTTP user agent of the form
    147      * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
    148      */
    149     private static String getDefaultUserAgent() {
    150         StringBuilder result = new StringBuilder(64);
    151         result.append("Dalvik/");
    152         result.append(System.getProperty("java.vm.version")); // such as 1.1.0
    153         result.append(" (Linux; U; Android ");
    154 
    155         String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
    156         result.append(version.length() > 0 ? version : "1.0");
    157 
    158         // add the model for the release build
    159         if ("REL".equals(Build.VERSION.CODENAME)) {
    160             String model = Build.MODEL;
    161             if (model.length() > 0) {
    162                 result.append("; ");
    163                 result.append(model);
    164             }
    165         }
    166         String id = Build.ID; // "MASTER" or "M4-rc20"
    167         if (id.length() > 0) {
    168             result.append(" Build/");
    169             result.append(id);
    170         }
    171         result.append(")");
    172         return result.toString();
    173     }
    174 
    175     /**
    176      * Invokes a static "main(argv[]) method on class "className".
    177      * Converts various failing exceptions into RuntimeExceptions, with
    178      * the assumption that they will then cause the VM instance to exit.
    179      *
    180      * @param className Fully-qualified class name
    181      * @param argv Argument vector for main()
    182      */
    183     private static void invokeStaticMain(String className, String[] argv)
    184             throws ZygoteInit.MethodAndArgsCaller {
    185         Class<?> cl;
    186 
    187         try {
    188             cl = Class.forName(className);
    189         } catch (ClassNotFoundException ex) {
    190             throw new RuntimeException(
    191                     "Missing class when invoking static main " + className,
    192                     ex);
    193         }
    194 
    195         Method m;
    196         try {
    197             m = cl.getMethod("main", new Class[] { String[].class });
    198         } catch (NoSuchMethodException ex) {
    199             throw new RuntimeException(
    200                     "Missing static main on " + className, ex);
    201         } catch (SecurityException ex) {
    202             throw new RuntimeException(
    203                     "Problem getting static main on " + className, ex);
    204         }
    205 
    206         int modifiers = m.getModifiers();
    207         if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    208             throw new RuntimeException(
    209                     "Main method is not public and static on " + className);
    210         }
    211 
    212         /*
    213          * This throw gets caught in ZygoteInit.main(), which responds
    214          * by invoking the exception's run() method. This arrangement
    215          * clears up all the stack frames that were required in setting
    216          * up the process.
    217          */
    218         throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    219     }
    220 
    221     public static final void main(String[] argv) {
    222         if (argv.length == 2 && argv[1].equals("application")) {
    223             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
    224             redirectLogStreams();
    225         } else {
    226             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
    227         }
    228 
    229         commonInit();
    230 
    231         /*
    232          * Now that we're running in interpreted code, call back into native code
    233          * to run the system.
    234          */
    235         nativeFinishInit();
    236 
    237         if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
    238     }
    239 
    240     /**
    241      * The main function called when started through the zygote process. This
    242      * could be unified with main(), if the native code in nativeFinishInit()
    243      * were rationalized with Zygote startup.<p>
    244      *
    245      * Current recognized args:
    246      * <ul>
    247      *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
    248      * </ul>
    249      *
    250      * @param targetSdkVersion target SDK version
    251      * @param argv arg strings
    252      */
    253     public static final void zygoteInit(int targetSdkVersion, String[] argv)
    254             throws ZygoteInit.MethodAndArgsCaller {
    255         if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
    256 
    257         redirectLogStreams();
    258 
    259         commonInit();
    260         nativeZygoteInit();
    261 
    262         applicationInit(targetSdkVersion, argv);
    263     }
    264 
    265     /**
    266      * The main function called when an application is started through a
    267      * wrapper process.
    268      *
    269      * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
    270      * which calls {@link WrapperInit#main} which then calls this method.
    271      * So we don't need to call commonInit() here.
    272      *
    273      * @param targetSdkVersion target SDK version
    274      * @param argv arg strings
    275      */
    276     public static void wrapperInit(int targetSdkVersion, String[] argv)
    277             throws ZygoteInit.MethodAndArgsCaller {
    278         if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
    279 
    280         applicationInit(targetSdkVersion, argv);
    281     }
    282 
    283     private static void applicationInit(int targetSdkVersion, String[] argv)
    284             throws ZygoteInit.MethodAndArgsCaller {
    285         // If the application calls System.exit(), terminate the process
    286         // immediately without running any shutdown hooks.  It is not possible to
    287         // shutdown an Android application gracefully.  Among other things, the
    288         // Android runtime shutdown hooks close the Binder driver, which can cause
    289         // leftover running threads to crash before the process actually exits.
    290         nativeSetExitWithoutCleanup(true);
    291 
    292         // We want to be fairly aggressive about heap utilization, to avoid
    293         // holding on to a lot of memory that isn't needed.
    294         VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    295         VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    296 
    297         final Arguments args;
    298         try {
    299             args = new Arguments(argv);
    300         } catch (IllegalArgumentException ex) {
    301             Slog.e(TAG, ex.getMessage());
    302             // let the process exit
    303             return;
    304         }
    305 
    306         // Remaining arguments are passed to the start class's static main
    307         invokeStaticMain(args.startClass, args.startArgs);
    308     }
    309 
    310     /**
    311      * Redirect System.out and System.err to the Android log.
    312      */
    313     public static void redirectLogStreams() {
    314         System.out.close();
    315         System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
    316         System.err.close();
    317         System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
    318     }
    319 
    320     /**
    321      * Report a serious error in the current process.  May or may not cause
    322      * the process to terminate (depends on system settings).
    323      *
    324      * @param tag to record with the error
    325      * @param t exception describing the error site and conditions
    326      */
    327     public static void wtf(String tag, Throwable t) {
    328         try {
    329             if (ActivityManagerNative.getDefault().handleApplicationWtf(
    330                     mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) {
    331                 // The Activity Manager has already written us off -- now exit.
    332                 Process.killProcess(Process.myPid());
    333                 System.exit(10);
    334             }
    335         } catch (Throwable t2) {
    336             Slog.e(TAG, "Error reporting WTF", t2);
    337         }
    338     }
    339 
    340     /**
    341      * Set the object identifying this application/process, for reporting VM
    342      * errors.
    343      */
    344     public static final void setApplicationObject(IBinder app) {
    345         mApplicationObject = app;
    346     }
    347 
    348     public static final IBinder getApplicationObject() {
    349         return mApplicationObject;
    350     }
    351 
    352     /**
    353      * Enable debugging features.
    354      */
    355     static {
    356         // Register handlers for DDM messages.
    357         android.ddm.DdmRegister.registerHandlers();
    358     }
    359 
    360     /**
    361      * Handles argument parsing for args related to the runtime.
    362      *
    363      * Current recognized args:
    364      * <ul>
    365      *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
    366      * </ul>
    367      */
    368     static class Arguments {
    369         /** first non-option argument */
    370         String startClass;
    371 
    372         /** all following arguments */
    373         String[] startArgs;
    374 
    375         /**
    376          * Constructs instance and parses args
    377          * @param args runtime command-line args
    378          * @throws IllegalArgumentException
    379          */
    380         Arguments(String args[]) throws IllegalArgumentException {
    381             parseArgs(args);
    382         }
    383 
    384         /**
    385          * Parses the commandline arguments intended for the Runtime.
    386          */
    387         private void parseArgs(String args[])
    388                 throws IllegalArgumentException {
    389             int curArg = 0;
    390             for (; curArg < args.length; curArg++) {
    391                 String arg = args[curArg];
    392 
    393                 if (arg.equals("--")) {
    394                     curArg++;
    395                     break;
    396                 } else if (!arg.startsWith("--")) {
    397                     break;
    398                 }
    399             }
    400 
    401             if (curArg == args.length) {
    402                 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
    403             }
    404 
    405             startClass = args[curArg++];
    406             startArgs = new String[args.length - curArg];
    407             System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
    408         }
    409     }
    410 }
    411