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