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> [--] <start class name> <args> 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