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