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