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