• 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.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 
nativeZygoteInit()53     private static final native void nativeZygoteInit();
nativeFinishInit()54     private static final native void nativeFinishInit();
nativeSetExitWithoutCleanup(boolean exitWithoutCleanup)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 {
uncaughtException(Thread t, Throwable e)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 
commonInit()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      */
getDefaultUserAgent()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      */
invokeStaticMain(String className, String[] argv)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 
main(String[] argv)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      */
zygoteInit(int targetSdkVersion, String[] argv)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      */
wrapperInit(int targetSdkVersion, String[] argv)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 
applicationInit(int targetSdkVersion, String[] argv)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      */
redirectLogStreams()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      */
wtf(String tag, Throwable t)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      */
setApplicationObject(IBinder app)344     public static final void setApplicationObject(IBinder app) {
345         mApplicationObject = app;
346     }
347 
getApplicationObject()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.
android.ddm.DdmRegister.registerHandlers()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          */
Arguments(String args[])380         Arguments(String args[]) throws IllegalArgumentException {
381             parseArgs(args);
382         }
383 
384         /**
385          * Parses the commandline arguments intended for the Runtime.
386          */
parseArgs(String args[])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