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