• 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.ActivityManager;
20 import android.app.ActivityThread;
21 import android.app.ApplicationErrorReport;
22 import android.app.IActivityManager;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.type.DefaultMimeMapFactory;
25 import android.net.TrafficStats;
26 import android.os.Build;
27 import android.os.DeadObjectException;
28 import android.os.IBinder;
29 import android.os.Process;
30 import android.os.SystemProperties;
31 import android.os.Trace;
32 import android.util.Log;
33 import android.util.Slog;
34 
35 import com.android.internal.logging.AndroidConfig;
36 
37 import dalvik.system.RuntimeHooks;
38 import dalvik.system.VMRuntime;
39 
40 import libcore.content.type.MimeMap;
41 
42 import java.io.PrintStream;
43 import java.lang.reflect.InvocationTargetException;
44 import java.lang.reflect.Method;
45 import java.lang.reflect.Modifier;
46 import java.util.Objects;
47 import java.util.logging.LogManager;
48 
49 /**
50  * Main entry point for runtime initialization.  Not for
51  * public consumption.
52  * @hide
53  */
54 @android.ravenwood.annotation.RavenwoodKeepPartialClass
55 public class RuntimeInit {
56     final static String TAG = "AndroidRuntime";
57     final static boolean DEBUG = false;
58 
59     /** true if commonInit() has been called */
60     @UnsupportedAppUsage
61     private static boolean initialized;
62 
63     @UnsupportedAppUsage
64     private static IBinder mApplicationObject;
65 
66     private static volatile boolean mCrashing = false;
67     private static final String SYSPROP_CRASH_COUNT = "sys.system_server.crash_java";
68     private static int mCrashCount;
69 
70     private static volatile ApplicationWtfHandler sDefaultApplicationWtfHandler;
71 
72     /**
73      * Stored values of System.out and System.err before they've been replaced by
74      * redirectLogStreams(). Kept open here for other Ravenwood internals to use.
75      */
76     public static PrintStream sOut$ravenwood;
77     public static PrintStream sErr$ravenwood;
78 
nativeFinishInit()79     private static final native void nativeFinishInit();
80 
nativeSetExitWithoutCleanup(boolean exitWithoutCleanup)81     private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
82 
Clog_e(String tag, String msg, Throwable tr)83     private static int Clog_e(String tag, String msg, Throwable tr) {
84         return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
85     }
86 
logUncaught(String threadName, String processName, int pid, Throwable e)87     public static void logUncaught(String threadName, String processName, int pid, Throwable e) {
88         StringBuilder message = new StringBuilder();
89         // The "FATAL EXCEPTION" string is still used on Android even though
90         // apps can set a custom UncaughtExceptionHandler that renders uncaught
91         // exceptions non-fatal.
92         message.append("FATAL EXCEPTION: ").append(threadName).append("\n");
93         if (processName != null) {
94             message.append("Process: ").append(processName).append(", ");
95         }
96         message.append("PID: ").append(pid);
97         Clog_e(TAG, message.toString(), e);
98     }
99 
100     /**
101      * Logs a message when a thread encounters an uncaught exception. By
102      * default, {@link KillApplicationHandler} will terminate this process later,
103      * but apps can override that behavior.
104      */
105     private static class LoggingHandler implements Thread.UncaughtExceptionHandler {
106         public volatile boolean mTriggered = false;
107 
108         @Override
uncaughtException(Thread t, Throwable e)109         public void uncaughtException(Thread t, Throwable e) {
110             mTriggered = true;
111 
112             // Don't re-enter if KillApplicationHandler has already run
113             if (mCrashing) return;
114 
115             // mApplicationObject is null for non-zygote java programs (e.g. "am")
116             // There are also apps running with the system UID. We don't want the
117             // first clause in either of these two cases, only for system_server.
118             if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) {
119                 Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
120                 mCrashCount = SystemProperties.getInt(SYSPROP_CRASH_COUNT, 0) + 1;
121                 SystemProperties.set(SYSPROP_CRASH_COUNT, String.valueOf(mCrashCount));
122             } else {
123                 logUncaught(t.getName(), ActivityThread.currentProcessName(), Process.myPid(), e);
124             }
125         }
126     }
127 
128     /**
129      * Handle application death from an uncaught exception.  The framework
130      * catches these for the main threads, so this should only matter for
131      * threads created by applications. Before this method runs, the given
132      * instance of {@link LoggingHandler} should already have logged details
133      * (and if not it is run first).
134      */
135     private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
136         private final LoggingHandler mLoggingHandler;
137 
138         /**
139          * Create a new KillApplicationHandler that follows the given LoggingHandler.
140          * If {@link #uncaughtException(Thread, Throwable) uncaughtException} is called
141          * on the created instance without {@code loggingHandler} having been triggered,
142          * {@link LoggingHandler#uncaughtException(Thread, Throwable)
143          * loggingHandler.uncaughtException} will be called first.
144          *
145          * @param loggingHandler the {@link LoggingHandler} expected to have run before
146          *     this instance's {@link #uncaughtException(Thread, Throwable) uncaughtException}
147          *     is being called.
148          */
KillApplicationHandler(LoggingHandler loggingHandler)149         public KillApplicationHandler(LoggingHandler loggingHandler) {
150             this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
151         }
152 
153         @Override
uncaughtException(Thread t, Throwable e)154         public void uncaughtException(Thread t, Throwable e) {
155             try {
156                 ensureLogging(t, e);
157 
158                 // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
159                 if (mCrashing) return;
160                 mCrashing = true;
161 
162                 // Try to end profiling. If a profiler is running at this point, and we kill the
163                 // process (below), the in-memory buffer will be lost. So try to stop, which will
164                 // flush the buffer. (This makes method trace profiling useful to debug crashes.)
165                 if (ActivityThread.currentActivityThread() != null) {
166                     ActivityThread.currentActivityThread().stopProfiling();
167                 }
168 
169                 // Bring up crash dialog, wait for it to be dismissed
170                 ActivityManager.getService().handleApplicationCrash(
171                         mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
172             } catch (Throwable t2) {
173                 if (t2 instanceof DeadObjectException) {
174                     // System process is dead; ignore
175                 } else {
176                     try {
177                         // Log original crash and then log the error reporting exception.
178                         Clog_e(TAG, "Couldn't report crash. Here's the crash:", e);
179                         Clog_e(TAG, "Error reporting crash. Here's the error:", t2);
180                     } catch (Throwable t3) {
181                         // Even Clog_e() fails!  Oh well.
182                     }
183                 }
184             } finally {
185                 // Try everything to make sure this process goes away.
186                 Process.killProcess(Process.myPid());
187                 System.exit(10);
188             }
189         }
190 
191         /**
192          * Ensures that the logging handler has been triggered.
193          *
194          * See b/73380984. This reinstates the pre-O behavior of
195          *
196          *   {@code thread.getUncaughtExceptionHandler().uncaughtException(thread, e);}
197          *
198          * logging the exception (in addition to killing the app). This behavior
199          * was never documented / guaranteed but helps in diagnostics of apps
200          * using the pattern.
201          *
202          * If this KillApplicationHandler is invoked the "regular" way (by
203          * {@link Thread#dispatchUncaughtException(Throwable)
204          * Thread.dispatchUncaughtException} in case of an uncaught exception)
205          * then the pre-handler (expected to be {@link #mLoggingHandler}) will already
206          * have run. Otherwise, we manually invoke it here.
207          */
ensureLogging(Thread t, Throwable e)208         private void ensureLogging(Thread t, Throwable e) {
209             if (!mLoggingHandler.mTriggered) {
210                 try {
211                     mLoggingHandler.uncaughtException(t, e);
212                 } catch (Throwable loggingThrowable) {
213                     // Ignored.
214                 }
215             }
216         }
217     }
218 
219     /**
220      * Common initialization that (unlike {@link #commonInit()} should happen prior to
221      * the Zygote fork.
222      */
preForkInit()223     public static void preForkInit() {
224         if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
225         RuntimeInit.enableDdms();
226         // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
227         // MimeMap.setDefault(DefaultMimeMapFactory.create());
228         /*
229          * Replace libcore's minimal default mapping between MIME types and file
230          * extensions with a mapping that's suitable for Android. Android's mapping
231          * contains many more entries that are derived from IANA registrations but
232          * with several customizations (extensions, overrides).
233          */
234         MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
235     }
236 
237     @UnsupportedAppUsage
commonInit()238     protected static final void commonInit() {
239         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
240 
241         /*
242          * set handlers; these apply to all threads in the VM. Apps can replace
243          * the default handler, but not the pre handler.
244          */
245         LoggingHandler loggingHandler = new LoggingHandler();
246         RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);
247         Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
248 
249         /*
250          * Install a time zone supplier that uses the Android persistent time zone system property.
251          */
252         RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
253 
254         /*
255          * Sets handler for java.util.logging to use Android log facilities.
256          * The odd "new instance-and-then-throw-away" is a mirror of how
257          * the "java.util.logging.config.class" system property works. We
258          * can't use the system property here since the logger has almost
259          * certainly already been initialized.
260          */
261         LogManager.getLogManager().reset();
262         new AndroidConfig();
263 
264         /*
265          * Sets the default HTTP User-Agent used by HttpURLConnection.
266          */
267         String userAgent = getDefaultUserAgent();
268         System.setProperty("http.agent", userAgent);
269 
270         /*
271          * Wire socket tagging to traffic stats.
272          */
273         TrafficStats.attachSocketTagger();
274 
275         initialized = true;
276     }
277 
278     /**
279      * Returns an HTTP user agent of the form
280      * "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MAIN)".
281      */
getDefaultUserAgent()282     private static String getDefaultUserAgent() {
283         StringBuilder result = new StringBuilder(64);
284         result.append("Dalvik/");
285         result.append(System.getProperty("java.vm.version")); // such as 1.1.0
286         result.append(" (Linux; U; Android ");
287 
288         String version = Build.VERSION.RELEASE_OR_CODENAME; // "1.0" or "3.4b5"
289         result.append(version.length() > 0 ? version : "1.0");
290 
291         // add the model for the release build
292         if ("REL".equals(Build.VERSION.CODENAME)) {
293             String model = Build.MODEL;
294             if (model.length() > 0) {
295                 result.append("; ");
296                 result.append(model);
297             }
298         }
299         String id = Build.ID; // "MAIN" or "M4-rc20"
300         if (id.length() > 0) {
301             result.append(" Build/");
302             result.append(id);
303         }
304         result.append(")");
305         return result.toString();
306     }
307 
308     /**
309      * Invokes a static "main(argv[]) method on class "className".
310      * Converts various failing exceptions into RuntimeExceptions, with
311      * the assumption that they will then cause the VM instance to exit.
312      *
313      * @param className Fully-qualified class name
314      * @param argv Argument vector for main()
315      * @param classLoader the classLoader to load {@className} with
316      */
findStaticMain(String className, String[] argv, ClassLoader classLoader)317     protected static Runnable findStaticMain(String className, String[] argv,
318             ClassLoader classLoader) {
319         Class<?> cl;
320 
321         try {
322             cl = Class.forName(className, true, classLoader);
323         } catch (ClassNotFoundException ex) {
324             throw new RuntimeException(
325                     "Missing class when invoking static main " + className,
326                     ex);
327         }
328 
329         Method m;
330         try {
331             m = cl.getMethod("main", new Class[] { String[].class });
332         } catch (NoSuchMethodException ex) {
333             throw new RuntimeException(
334                     "Missing static main on " + className, ex);
335         } catch (SecurityException ex) {
336             throw new RuntimeException(
337                     "Problem getting static main on " + className, ex);
338         }
339 
340         int modifiers = m.getModifiers();
341         if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
342             throw new RuntimeException(
343                     "Main method is not public and static on " + className);
344         }
345 
346         /*
347          * This throw gets caught in ZygoteInit.main(), which responds
348          * by invoking the exception's run() method. This arrangement
349          * clears up all the stack frames that were required in setting
350          * up the process.
351          */
352         return new MethodAndArgsCaller(m, argv);
353     }
354 
355     @UnsupportedAppUsage
main(String[] argv)356     public static final void main(String[] argv) {
357         preForkInit();
358         if (argv.length == 2 && argv[1].equals("application")) {
359             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
360             redirectLogStreams();
361         } else {
362             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
363         }
364 
365         commonInit();
366 
367         /*
368          * Now that we're running in interpreted code, call back into native code
369          * to run the system.
370          */
371         nativeFinishInit();
372 
373         if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
374     }
375 
applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader)376     protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
377             String[] argv, ClassLoader classLoader) {
378         // If the application calls System.exit(), terminate the process
379         // immediately without running any shutdown hooks.  It is not possible to
380         // shutdown an Android application gracefully.  Among other things, the
381         // Android runtime shutdown hooks close the Binder driver, which can cause
382         // leftover running threads to crash before the process actually exits.
383         nativeSetExitWithoutCleanup(true);
384 
385         VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
386         VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
387 
388         final Arguments args = new Arguments(argv);
389 
390         // The end of of the RuntimeInit event (see #zygoteInit).
391         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
392 
393         // Remaining arguments are passed to the start class's static main
394         return findStaticMain(args.startClass, args.startArgs, classLoader);
395     }
396 
397     /**
398      * Redirect System.out and System.err to the Android log.
399      */
400     @android.ravenwood.annotation.RavenwoodReplace
redirectLogStreams()401     public static void redirectLogStreams() {
402         System.out.close();
403         System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
404         System.err.close();
405         System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
406     }
407 
redirectLogStreams$ravenwood()408     public static void redirectLogStreams$ravenwood() {
409         if (sOut$ravenwood != null && sErr$ravenwood != null) {
410             return; // Already initialized.
411         }
412 
413         // Make sure the Log class is loaded and the JNI methods are hooked up,
414         // before redirecting System.out/err.
415         // Otherwise, because ClassLoadHook tries to write to System.out, this would cause
416         // a circular initialization problem and would cause a UnsatisfiedLinkError
417         // on the JNI methods.
418         Log.isLoggable("X", Log.VERBOSE);
419 
420         if (sOut$ravenwood == null) {
421             sOut$ravenwood = System.out;
422             System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
423         }
424         if (sErr$ravenwood == null) {
425             sErr$ravenwood = System.err;
426             System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
427         }
428     }
429 
430     /**
431      * Report a serious error in the current process.  May or may not cause
432      * the process to terminate (depends on system settings).
433      *
434      * @param tag to record with the error
435      * @param t exception describing the error site and conditions
436      */
437     @android.ravenwood.annotation.RavenwoodReplace
wtf(String tag, Throwable t, boolean system)438     public static void wtf(String tag, Throwable t, boolean system) {
439         try {
440             boolean exit = false;
441             final IActivityManager am = ActivityManager.getService();
442             if (am != null) {
443                 exit = am.handleApplicationWtf(
444                         mApplicationObject, tag, system,
445                         new ApplicationErrorReport.ParcelableCrashInfo(t),
446                         Process.myPid());
447             } else {
448                 // Unlikely but possible in early system boot
449                 final ApplicationWtfHandler handler = sDefaultApplicationWtfHandler;
450                 if (handler != null) {
451                     exit = handler.handleApplicationWtf(
452                             mApplicationObject, tag, system,
453                             new ApplicationErrorReport.ParcelableCrashInfo(t),
454                             Process.myPid());
455                 } else {
456                     // Simply log the error
457                     Slog.e(TAG, "Original WTF:", t);
458                 }
459             }
460             if (exit) {
461                 // The Activity Manager has already written us off -- now exit.
462                 Process.killProcess(Process.myPid());
463                 System.exit(10);
464             }
465         } catch (Throwable t2) {
466             if (t2 instanceof DeadObjectException) {
467                 // System process is dead; ignore
468             } else {
469                 Slog.e(TAG, "Error reporting WTF", t2);
470                 Slog.e(TAG, "Original WTF:", t);
471             }
472         }
473     }
474 
wtf$ravenwood(String tag, Throwable t, boolean system)475     public static void wtf$ravenwood(String tag, Throwable t, boolean system) {
476         // We've already emitted to logs, so there's nothing more to do here,
477         // as we don't have a DropBox pipeline configured
478     }
479 
480     /**
481      * Set the default {@link ApplicationWtfHandler}, in case the ActivityManager is not ready yet.
482      */
setDefaultApplicationWtfHandler(final ApplicationWtfHandler handler)483     public static void setDefaultApplicationWtfHandler(final ApplicationWtfHandler handler) {
484         sDefaultApplicationWtfHandler = handler;
485     }
486 
487     /**
488      * The handler to deal with the serious application errors.
489      */
490     public interface ApplicationWtfHandler {
491         /**
492          * @param app object of the crashing app, null for the system server
493          * @param tag reported by the caller
494          * @param system whether this wtf is coming from the system
495          * @param crashInfo describing the context of the error
496          * @param immediateCallerPid the caller Pid
497          * @return true if the process should exit immediately (WTF is fatal)
498          */
handleApplicationWtf(IBinder app, String tag, boolean system, ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid)499         boolean handleApplicationWtf(IBinder app, String tag, boolean system,
500                 ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid);
501     }
502 
503     /**
504      * Set the object identifying this application/process, for reporting VM
505      * errors.
506      */
setApplicationObject(IBinder app)507     public static final void setApplicationObject(IBinder app) {
508         mApplicationObject = app;
509     }
510 
511     @UnsupportedAppUsage
getApplicationObject()512     public static final IBinder getApplicationObject() {
513         return mApplicationObject;
514     }
515 
516     /**
517      * Enable DDMS.
518      */
enableDdms()519     private static void enableDdms() {
520         // Register handlers for DDM messages.
521         android.ddm.DdmRegister.registerHandlers();
522     }
523 
524     /**
525      * Handles argument parsing for args related to the runtime.
526      *
527      * Current recognized args:
528      * <ul>
529      *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
530      * </ul>
531      */
532     static class Arguments {
533         /** first non-option argument */
534         String startClass;
535 
536         /** all following arguments */
537         String[] startArgs;
538 
539         /**
540          * Constructs instance and parses args
541          * @param args runtime command-line args
542          * @throws IllegalArgumentException
543          */
Arguments(String args[])544         Arguments(String args[]) throws IllegalArgumentException {
545             parseArgs(args);
546         }
547 
548         /**
549          * Parses the commandline arguments intended for the Runtime.
550          */
parseArgs(String args[])551         private void parseArgs(String args[])
552                 throws IllegalArgumentException {
553             int curArg = 0;
554             for (; curArg < args.length; curArg++) {
555                 String arg = args[curArg];
556 
557                 if (arg.equals("--")) {
558                     curArg++;
559                     break;
560                 } else if (!arg.startsWith("--")) {
561                     break;
562                 }
563             }
564 
565             if (curArg == args.length) {
566                 throw new IllegalArgumentException("Missing classname argument to RuntimeInit!");
567             }
568 
569             startClass = args[curArg++];
570             startArgs = new String[args.length - curArg];
571             System.arraycopy(args, curArg, startArgs, 0, startArgs.length);
572         }
573     }
574 
575     /**
576      * Helper class which holds a method and arguments and can call them. This is used as part of
577      * a trampoline to get rid of the initial process setup stack frames.
578      */
579     static class MethodAndArgsCaller implements Runnable {
580         /** method to call */
581         private final Method mMethod;
582 
583         /** argument array */
584         private final String[] mArgs;
585 
MethodAndArgsCaller(Method method, String[] args)586         public MethodAndArgsCaller(Method method, String[] args) {
587             mMethod = method;
588             mArgs = args;
589         }
590 
run()591         public void run() {
592             try {
593                 mMethod.invoke(null, new Object[] { mArgs });
594             } catch (IllegalAccessException ex) {
595                 throw new RuntimeException(ex);
596             } catch (InvocationTargetException ex) {
597                 Throwable cause = ex.getCause();
598                 if (cause instanceof RuntimeException) {
599                     throw (RuntimeException) cause;
600                 } else if (cause instanceof Error) {
601                     throw (Error) cause;
602                 }
603                 throw new RuntimeException(ex);
604             }
605         }
606     }
607 }
608