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