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