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.Config;
     27 import android.util.Log;
     28 import android.util.Slog;
     29 
     30 import com.android.internal.logging.AndroidConfig;
     31 
     32 import dalvik.system.VMRuntime;
     33 
     34 import java.lang.reflect.Method;
     35 import java.lang.reflect.Modifier;
     36 import java.util.concurrent.atomic.AtomicInteger;
     37 import java.util.logging.LogManager;
     38 import java.util.TimeZone;
     39 
     40 import org.apache.harmony.luni.internal.util.TimezoneGetter;
     41 
     42 /**
     43  * Main entry point for runtime initialization.  Not for
     44  * public consumption.
     45  * @hide
     46  */
     47 public class RuntimeInit {
     48     private final static String TAG = "AndroidRuntime";
     49 
     50     /** true if commonInit() has been called */
     51     private static boolean initialized;
     52 
     53     private static IBinder mApplicationObject;
     54 
     55     private static volatile boolean mCrashing = false;
     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 (Config.LOGV) 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         int hasQwerty = getQwertyKeyboard();
     99 
    100         if (Config.LOGV) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty);
    101         if (hasQwerty == 1) {
    102             System.setProperty("qwerty", "1");
    103         }
    104 
    105         /*
    106          * Install a TimezoneGetter subclass for ZoneInfo.db
    107          */
    108         TimezoneGetter.setInstance(new TimezoneGetter() {
    109             @Override
    110             public String getId() {
    111                 return SystemProperties.get("persist.sys.timezone");
    112             }
    113         });
    114         TimeZone.setDefault(null);
    115 
    116         /*
    117          * Sets handler for java.util.logging to use Android log facilities.
    118          * The odd "new instance-and-then-throw-away" is a mirror of how
    119          * the "java.util.logging.config.class" system property works. We
    120          * can't use the system property here since the logger has almost
    121          * certainly already been initialized.
    122          */
    123         LogManager.getLogManager().reset();
    124         new AndroidConfig();
    125 
    126         /*
    127          * Sets the default HTTP User-Agent used by HttpURLConnection.
    128          */
    129         String userAgent = getDefaultUserAgent();
    130         System.setProperty("http.agent", userAgent);
    131 
    132         /*
    133          * If we're running in an emulator launched with "-trace", put the
    134          * VM into emulator trace profiling mode so that the user can hit
    135          * F9/F10 at any time to capture traces.  This has performance
    136          * consequences, so it's not something you want to do always.
    137          */
    138         String trace = SystemProperties.get("ro.kernel.android.tracing");
    139         if (trace.equals("1")) {
    140             Slog.i(TAG, "NOTE: emulator trace profiling enabled");
    141             Debug.enableEmulatorTraceOutput();
    142         }
    143 
    144         initialized = true;
    145     }
    146 
    147     /**
    148      * Returns an HTTP user agent of the form
    149      * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
    150      */
    151     private static String getDefaultUserAgent() {
    152         StringBuilder result = new StringBuilder(64);
    153         result.append("Dalvik/");
    154         result.append(System.getProperty("java.vm.version")); // such as 1.1.0
    155         result.append(" (Linux; U; Android ");
    156 
    157         String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
    158         result.append(version.length() > 0 ? version : "1.0");
    159 
    160         // add the model for the release build
    161         if ("REL".equals(Build.VERSION.CODENAME)) {
    162             String model = Build.MODEL;
    163             if (model.length() > 0) {
    164                 result.append("; ");
    165                 result.append(model);
    166             }
    167         }
    168         String id = Build.ID; // "MASTER" or "M4-rc20"
    169         if (id.length() > 0) {
    170             result.append(" Build/");
    171             result.append(id);
    172         }
    173         result.append(")");
    174         return result.toString();
    175     }
    176 
    177     /**
    178      * Invokes a static "main(argv[]) method on class "className".
    179      * Converts various failing exceptions into RuntimeExceptions, with
    180      * the assumption that they will then cause the VM instance to exit.
    181      *
    182      * @param className Fully-qualified class name
    183      * @param argv Argument vector for main()
    184      */
    185     private static void invokeStaticMain(String className, String[] argv)
    186             throws ZygoteInit.MethodAndArgsCaller {
    187 
    188         // We want to be fairly aggressive about heap utilization, to avoid
    189         // holding on to a lot of memory that isn't needed.
    190         VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    191 
    192         Class<?> cl;
    193 
    194         try {
    195             cl = Class.forName(className);
    196         } catch (ClassNotFoundException ex) {
    197             throw new RuntimeException(
    198                     "Missing class when invoking static main " + className,
    199                     ex);
    200         }
    201 
    202         Method m;
    203         try {
    204             m = cl.getMethod("main", new Class[] { String[].class });
    205         } catch (NoSuchMethodException ex) {
    206             throw new RuntimeException(
    207                     "Missing static main on " + className, ex);
    208         } catch (SecurityException ex) {
    209             throw new RuntimeException(
    210                     "Problem getting static main on " + className, ex);
    211         }
    212 
    213         int modifiers = m.getModifiers();
    214         if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    215             throw new RuntimeException(
    216                     "Main method is not public and static on " + className);
    217         }
    218 
    219         /*
    220          * This throw gets caught in ZygoteInit.main(), which responds
    221          * by invoking the exception's run() method. This arrangement
    222          * clears up all the stack frames that were required in setting
    223          * up the process.
    224          */
    225         throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    226     }
    227 
    228     public static final void main(String[] argv) {
    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         finishInit();
    236 
    237         if (Config.LOGV) Slog.d(TAG, "Leaving RuntimeInit!");
    238     }
    239 
    240     public static final native void finishInit();
    241 
    242     /**
    243      * The main function called when started through the zygote process. This
    244      * could be unified with main(), if the native code in finishInit()
    245      * were rationalized with Zygote startup.<p>
    246      *
    247      * Current recognized args:
    248      * <ul>
    249      *   <li> --nice-name=<i>nice name to appear in ps</i>
    250      *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
    251      * </ul>
    252      *
    253      * @param argv arg strings
    254      */
    255     public static final void zygoteInit(String[] argv)
    256             throws ZygoteInit.MethodAndArgsCaller {
    257         // TODO: Doing this here works, but it seems kind of arbitrary. Find
    258         // a better place. The goal is to set it up for applications, but not
    259         // tools like am.
    260         System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
    261         System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
    262 
    263         commonInit();
    264         zygoteInitNative();
    265 
    266         int curArg = 0;
    267         for ( /* curArg */ ; curArg < argv.length; curArg++) {
    268             String arg = argv[curArg];
    269 
    270             if (arg.equals("--")) {
    271                 curArg++;
    272                 break;
    273             } else if (!arg.startsWith("--")) {
    274                 break;
    275             } else if (arg.startsWith("--nice-name=")) {
    276                 String niceName = arg.substring(arg.indexOf('=') + 1);
    277                 Process.setArgV0(niceName);
    278             }
    279         }
    280 
    281         if (curArg == argv.length) {
    282             Slog.e(TAG, "Missing classname argument to RuntimeInit!");
    283             // let the process exit
    284             return;
    285         }
    286 
    287         // Remaining arguments are passed to the start class's static main
    288 
    289         String startClass = argv[curArg++];
    290         String[] startArgs = new String[argv.length - curArg];
    291 
    292         System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
    293         invokeStaticMain(startClass, startArgs);
    294     }
    295 
    296     public static final native void zygoteInitNative();
    297 
    298     /**
    299      * Returns 1 if the computer is on. If the computer isn't on, the value returned by this method is undefined.
    300      */
    301     public static final native int isComputerOn();
    302 
    303     /**
    304      * Turns the computer on if the computer is off. If the computer is on, the behavior of this method is undefined.
    305      */
    306     public static final native void turnComputerOn();
    307 
    308     /**
    309      *
    310      * @return 1 if the device has a qwerty keyboard
    311      */
    312     public static native int getQwertyKeyboard();
    313 
    314     /**
    315      * Report a serious error in the current process.  May or may not cause
    316      * the process to terminate (depends on system settings).
    317      *
    318      * @param tag to record with the error
    319      * @param t exception describing the error site and conditions
    320      */
    321     public static void wtf(String tag, Throwable t) {
    322         try {
    323             if (ActivityManagerNative.getDefault().handleApplicationWtf(
    324                     mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) {
    325                 // The Activity Manager has already written us off -- now exit.
    326                 Process.killProcess(Process.myPid());
    327                 System.exit(10);
    328             }
    329         } catch (Throwable t2) {
    330             Slog.e(TAG, "Error reporting WTF", t2);
    331         }
    332     }
    333 
    334     /** Counter used to prevent reentrancy in {@link #reportException}. */
    335     private static final AtomicInteger sInReportException = new AtomicInteger();
    336 
    337     /**
    338      * Set the object identifying this application/process, for reporting VM
    339      * errors.
    340      */
    341     public static final void setApplicationObject(IBinder app) {
    342         mApplicationObject = app;
    343     }
    344 
    345     public static final IBinder getApplicationObject() {
    346         return mApplicationObject;
    347     }
    348 
    349     /**
    350      * Enable debugging features.
    351      */
    352     static {
    353         // Register handlers for DDM messages.
    354         android.ddm.DdmRegister.registerHandlers();
    355     }
    356 }
    357