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