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