RuntimeInit.java revision 02890fd0f98b3b8d98baf0bda1ea906afd723d8b
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
17package com.android.internal.os;
18
19import android.app.ActivityManagerNative;
20import android.app.ApplicationErrorReport;
21import android.os.Build;
22import android.os.Debug;
23import android.os.IBinder;
24import android.os.Process;
25import android.os.SystemProperties;
26import android.util.Config;
27import android.util.Finalizers;
28import android.util.Log;
29import android.util.Slog;
30
31import com.android.internal.logging.AndroidConfig;
32
33import dalvik.system.VMRuntime;
34
35import java.lang.reflect.Method;
36import java.lang.reflect.Modifier;
37import java.util.concurrent.atomic.AtomicInteger;
38import java.util.logging.LogManager;
39import java.util.TimeZone;
40
41import org.apache.harmony.luni.internal.util.TimezoneGetter;
42
43/**
44 * Main entry point for runtime initialization.  Not for
45 * public consumption.
46 * @hide
47 */
48public class RuntimeInit {
49    private final static String TAG = "AndroidRuntime";
50
51    /** true if commonInit() has been called */
52    private static boolean initialized;
53
54    private static IBinder mApplicationObject;
55
56    private static volatile boolean mCrashing = false;
57
58    /**
59     * Use this to log a message when a thread exits due to an uncaught
60     * exception.  The framework catches these for the main threads, so
61     * this should only matter for threads created by applications.
62     */
63    private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
64        public void uncaughtException(Thread t, Throwable e) {
65            try {
66                // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
67                if (mCrashing) return;
68                mCrashing = true;
69
70                if (mApplicationObject == null) {
71                    Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
72                } else {
73                    Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);
74                }
75
76                // Bring up crash dialog, wait for it to be dismissed
77                ActivityManagerNative.getDefault().handleApplicationCrash(
78                        mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
79            } catch (Throwable t2) {
80                try {
81                    Slog.e(TAG, "Error reporting crash", t2);
82                } catch (Throwable t3) {
83                    // Even Slog.e() fails!  Oh well.
84                }
85            } finally {
86                // Try everything to make sure this process goes away.
87                Process.killProcess(Process.myPid());
88                System.exit(10);
89            }
90        }
91    }
92
93    private static final void commonInit() {
94        if (Config.LOGV) Slog.d(TAG, "Entered RuntimeInit!");
95
96        /* set default handler; this applies to all threads in the VM */
97        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
98
99        int hasQwerty = getQwertyKeyboard();
100
101        if (Config.LOGV) Slog.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty);
102        if (hasQwerty == 1) {
103            System.setProperty("qwerty", "1");
104        }
105
106        /*
107         * Install a TimezoneGetter subclass for ZoneInfo.db
108         */
109        TimezoneGetter.setInstance(new TimezoneGetter() {
110            @Override
111            public String getId() {
112                return SystemProperties.get("persist.sys.timezone");
113            }
114        });
115        TimeZone.setDefault(null);
116
117        /*
118         * Sets handler for java.util.logging to use Android log facilities.
119         * The odd "new instance-and-then-throw-away" is a mirror of how
120         * the "java.util.logging.config.class" system property works. We
121         * can't use the system property here since the logger has almost
122         * certainly already been initialized.
123         */
124        LogManager.getLogManager().reset();
125        new AndroidConfig();
126
127        /*
128         * Sets the default HTTP User-Agent used by HttpURLConnection.
129         */
130        String userAgent = getDefaultUserAgent();
131        System.setProperty("http.agent", userAgent);
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        /**
146         * Initialize the thread used to reclaim resources without
147         * going through finalizers.
148         */
149        Finalizers.init();
150
151        initialized = true;
152    }
153
154    /**
155     * Returns an HTTP user agent of the form
156     * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MASTER)".
157     */
158    private static String getDefaultUserAgent() {
159        StringBuilder result = new StringBuilder(64);
160        result.append("Dalvik/");
161        result.append(System.getProperty("java.vm.version")); // such as 1.1.0
162        result.append(" (Linux; U; Android ");
163
164        String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
165        result.append(version.length() > 0 ? version : "1.0");
166
167        // add the model for the release build
168        if ("REL".equals(Build.VERSION.CODENAME)) {
169            String model = Build.MODEL;
170            if (model.length() > 0) {
171                result.append("; ");
172                result.append(model);
173            }
174        }
175        String id = Build.ID; // "MASTER" or "M4-rc20"
176        if (id.length() > 0) {
177            result.append(" Build/");
178            result.append(id);
179        }
180        result.append(")");
181        return result.toString();
182    }
183
184    /**
185     * Invokes a static "main(argv[]) method on class "className".
186     * Converts various failing exceptions into RuntimeExceptions, with
187     * the assumption that they will then cause the VM instance to exit.
188     *
189     * @param className Fully-qualified class name
190     * @param argv Argument vector for main()
191     */
192    private static void invokeStaticMain(String className, String[] argv)
193            throws ZygoteInit.MethodAndArgsCaller {
194
195        // We want to be fairly aggressive about heap utilization, to avoid
196        // holding on to a lot of memory that isn't needed.
197        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
198
199        Class<?> cl;
200
201        try {
202            cl = Class.forName(className);
203        } catch (ClassNotFoundException ex) {
204            throw new RuntimeException(
205                    "Missing class when invoking static main " + className,
206                    ex);
207        }
208
209        Method m;
210        try {
211            m = cl.getMethod("main", new Class[] { String[].class });
212        } catch (NoSuchMethodException ex) {
213            throw new RuntimeException(
214                    "Missing static main on " + className, ex);
215        } catch (SecurityException ex) {
216            throw new RuntimeException(
217                    "Problem getting static main on " + className, ex);
218        }
219
220        int modifiers = m.getModifiers();
221        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
222            throw new RuntimeException(
223                    "Main method is not public and static on " + className);
224        }
225
226        /*
227         * This throw gets caught in ZygoteInit.main(), which responds
228         * by invoking the exception's run() method. This arrangement
229         * clears up all the stack frames that were required in setting
230         * up the process.
231         */
232        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
233    }
234
235    public static final void main(String[] argv) {
236        commonInit();
237
238        /*
239         * Now that we're running in interpreted code, call back into native code
240         * to run the system.
241         */
242        finishInit();
243
244        if (Config.LOGV) Slog.d(TAG, "Leaving RuntimeInit!");
245    }
246
247    public static final native void finishInit();
248
249    /**
250     * The main function called when started through the zygote process. This
251     * could be unified with main(), if the native code in finishInit()
252     * were rationalized with Zygote startup.<p>
253     *
254     * Current recognized args:
255     * <ul>
256     *   <li> --nice-name=<i>nice name to appear in ps</i>
257     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
258     * </ul>
259     *
260     * @param argv arg strings
261     */
262    public static final void zygoteInit(String[] argv)
263            throws ZygoteInit.MethodAndArgsCaller {
264        // TODO: Doing this here works, but it seems kind of arbitrary. Find
265        // a better place. The goal is to set it up for applications, but not
266        // tools like am.
267        System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
268        System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
269
270        commonInit();
271        zygoteInitNative();
272
273        int curArg = 0;
274        for ( /* curArg */ ; curArg < argv.length; curArg++) {
275            String arg = argv[curArg];
276
277            if (arg.equals("--")) {
278                curArg++;
279                break;
280            } else if (!arg.startsWith("--")) {
281                break;
282            } else if (arg.startsWith("--nice-name=")) {
283                String niceName = arg.substring(arg.indexOf('=') + 1);
284                Process.setArgV0(niceName);
285            }
286        }
287
288        if (curArg == argv.length) {
289            Slog.e(TAG, "Missing classname argument to RuntimeInit!");
290            // let the process exit
291            return;
292        }
293
294        // Remaining arguments are passed to the start class's static main
295
296        String startClass = argv[curArg++];
297        String[] startArgs = new String[argv.length - curArg];
298
299        System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
300        invokeStaticMain(startClass, startArgs);
301    }
302
303    public static final native void zygoteInitNative();
304
305    /**
306     * Returns 1 if the computer is on. If the computer isn't on, the value returned by this method is undefined.
307     */
308    public static final native int isComputerOn();
309
310    /**
311     * Turns the computer on if the computer is off. If the computer is on, the behavior of this method is undefined.
312     */
313    public static final native void turnComputerOn();
314
315    /**
316     *
317     * @return 1 if the device has a qwerty keyboard
318     */
319    public static native int getQwertyKeyboard();
320
321    /**
322     * Report a serious error in the current process.  May or may not cause
323     * the process to terminate (depends on system settings).
324     *
325     * @param tag to record with the error
326     * @param t exception describing the error site and conditions
327     */
328    public static void wtf(String tag, Throwable t) {
329        try {
330            if (ActivityManagerNative.getDefault().handleApplicationWtf(
331                    mApplicationObject, tag, new ApplicationErrorReport.CrashInfo(t))) {
332                // The Activity Manager has already written us off -- now exit.
333                Process.killProcess(Process.myPid());
334                System.exit(10);
335            }
336        } catch (Throwable t2) {
337            Slog.e(TAG, "Error reporting WTF", t2);
338        }
339    }
340
341    /**
342     * Set the object identifying this application/process, for reporting VM
343     * errors.
344     */
345    public static final void setApplicationObject(IBinder app) {
346        mApplicationObject = app;
347    }
348
349    public static final IBinder getApplicationObject() {
350        return mApplicationObject;
351    }
352
353    /**
354     * Enable debugging features.
355     */
356    static {
357        // Register handlers for DDM messages.
358        android.ddm.DdmRegister.registerHandlers();
359    }
360}
361