StrictMode.java revision 15ba4061116e088d62a7e05a0037f294f31dff06
1/* 2 * Copyright (C) 2010 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 */ 16package android.os; 17 18import android.app.ActivityManagerNative; 19import android.app.ApplicationErrorReport; 20import android.util.Log; 21import android.util.Printer; 22 23import com.android.internal.os.RuntimeInit; 24 25import dalvik.system.BlockGuard; 26 27import java.io.PrintWriter; 28import java.io.StringWriter; 29import java.util.ArrayList; 30import java.util.HashMap; 31 32/** 33 * <p>StrictMode is a developer tool which lets you impose stricter 34 * rules under which your application runs. 35 * 36 * <p>StrictMode is most commonly used to catch accidental disk or 37 * network access on the application's main thread, where UI 38 * operations are received and animations take place. Keeping disk 39 * and network operations off the main thread makes for much smoother, 40 * more responsive applications. 41 * 42 * <p class="note">Note that even though an Android device's disk is 43 * often on flash memory, many devices run a filesystem on top of that 44 * memory with very limited concurrency. It's often the case that 45 * almost all disk accesses are fast, but may in individual cases be 46 * dramatically slower when certain I/O is happening in the background 47 * from other processes. If possible, it's best to assume that such 48 * things are not fast.</p> 49 * 50 * <p>Example code to enable from early in your 51 * {@link android.app.Application}, {@link android.app.Activity}, or 52 * other application component's 53 * {@link android.app.Application#onCreate} method: 54 * 55 * <pre> 56 * public void onCreate() { 57 * if (DEVELOPER_MODE) { 58 * StrictMode.setThreadPolicy(StrictMode.DISALLOW_DISK_WRITE | 59 * StrictMode.DISALLOW_DISK_READ | 60 * StrictMode.DISALLOW_NETWORK | 61 * StrictMode.PENALTY_LOG); 62 * } 63 * super.onCreate(); 64 * } 65 * </pre> 66 * 67 * <p>Then you can watch the output of <code>adb logcat</code> while you 68 * use your application. 69 * 70 * <p>If you find violations that you feel are problematic, there are 71 * a variety of tools to help solve them: threads, {@link android.os.Handler}, 72 * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc. 73 * But don't feel compelled to fix everything that StrictMode finds. In particular, 74 * a lot of disk accesses are often necessary during the normal activity lifecycle. Use 75 * StrictMode to find things you did on accident. Network requests on the UI thread 76 * are almost always a problem, though. 77 * 78 * <p class="note">StrictMode is not a security mechanism and is not 79 * guaranteed to find all disk or network accesses. While it does 80 * propagate its state across process boundaries when doing 81 * {@link android.os.Binder} calls, it's still ultimately a best 82 * effort mechanism. Notably, disk or network access from JNI calls 83 * won't necessarily trigger it. Future versions of Android may catch 84 * more (or fewer) operations, so you should never leave StrictMode 85 * enabled in shipping applications on the Android Market. 86 */ 87public final class StrictMode { 88 private static final String TAG = "StrictMode"; 89 private static final boolean LOG_V = false; 90 91 // Only log a duplicate stack trace to the logs every second. 92 private static final long MIN_LOG_INTERVAL_MS = 1000; 93 94 // Only show an annoying dialog at most every 30 seconds 95 private static final long MIN_DIALOG_INTERVAL_MS = 30000; 96 97 private StrictMode() {} 98 99 /** 100 * Flag for {@link #setThreadPolicy} to signal that you don't intend for this 101 * thread to write to disk. 102 */ 103 public static final int DISALLOW_DISK_WRITE = 0x01; 104 105 /** 106 * Flag for {@link #setThreadPolicy} to signal that you don't intend for this 107 * thread to read from disk. 108 */ 109 public static final int DISALLOW_DISK_READ = 0x02; 110 111 /** 112 * Flag for {@link #setThreadPolicy} to signal that you don't intend for this 113 * thread to access the network. 114 */ 115 public static final int DISALLOW_NETWORK = 0x04; 116 117 /** @hide */ 118 public static final int DISALLOW_MASK = 119 DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK; 120 121 /** 122 * Penalty flag for {@link #setThreadPolicy} to log violations to 123 * the system log, visible with <code>adb logcat</code>. 124 */ 125 public static final int PENALTY_LOG = 0x10; // normal android.util.Log 126 127 /** 128 * Penalty flag for {@link #setThreadPolicy} to show an annoying 129 * dialog to the developer, rate-limited to be only a little 130 * annoying. 131 */ 132 public static final int PENALTY_DIALOG = 0x20; 133 134 /** 135 * Penalty flag for {@link #setThreadPolicy} to crash hard if 136 * policy is violated. 137 */ 138 public static final int PENALTY_DEATH = 0x40; 139 140 /** 141 * Penalty flag for {@link #setThreadPolicy} to log a stacktrace 142 * and timing data to the 143 * {@link android.os.DropBoxManager DropBox} on policy violation. 144 * Intended mostly for platform integrators doing beta user field 145 * data collection. 146 */ 147 public static final int PENALTY_DROPBOX = 0x80; 148 149 /** 150 * Non-public penalty mode which overrides all the other penalty 151 * bits and signals that we're in a Binder call and we should 152 * ignore the other penalty bits and instead serialize back all 153 * our offending stack traces to the caller to ultimately handle 154 * in the originating process. 155 * 156 * This must be kept in sync with the constant in libs/binder/Parcel.cpp 157 * 158 * @hide 159 */ 160 public static final int PENALTY_GATHER = 0x100; 161 162 /** @hide */ 163 public static final int PENALTY_MASK = 164 PENALTY_LOG | PENALTY_DIALOG | 165 PENALTY_DROPBOX | PENALTY_DEATH; 166 167 /** 168 * Log of strict mode violation stack traces that have occurred 169 * during a Binder call, to be serialized back later to the caller 170 * via Parcel.writeNoException() (amusingly) where the caller can 171 * choose how to react. 172 */ 173 private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = 174 new ThreadLocal<ArrayList<ViolationInfo>>() { 175 @Override protected ArrayList<ViolationInfo> initialValue() { 176 // Starts null to avoid unnecessary allocations when 177 // checking whether there are any violations or not in 178 // hasGatheredViolations() below. 179 return null; 180 } 181 }; 182 183 /** 184 * Sets the policy for what actions the current thread isn't 185 * expected to do, as well as the penalty if it does. 186 * 187 * <p>Internally this sets a thread-local integer which is 188 * propagated across cross-process IPC calls, meaning you can 189 * catch violations when a system service or another process 190 * accesses the disk or network on your behalf. 191 * 192 * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values, 193 * e.g. {@link #DISALLOW_DISK_READ}, {@link #DISALLOW_DISK_WRITE}, 194 * {@link #DISALLOW_NETWORK}, {@link #PENALTY_LOG}. 195 */ 196 public static void setThreadPolicy(final int policyMask) { 197 // In addition to the Java-level thread-local in Dalvik's 198 // BlockGuard, we also need to keep a native thread-local in 199 // Binder in order to propagate the value across Binder calls, 200 // even across native-only processes. The two are kept in 201 // sync via the callback to onStrictModePolicyChange, below. 202 setBlockGuardPolicy(policyMask); 203 204 // And set the Android native version... 205 Binder.setThreadStrictModePolicy(policyMask); 206 } 207 208 // Sets the policy in Dalvik/libcore (BlockGuard) 209 private static void setBlockGuardPolicy(final int policyMask) { 210 if (policyMask == 0) { 211 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 212 return; 213 } 214 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 215 if (!(policy instanceof AndroidBlockGuardPolicy)) { 216 BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); 217 } else { 218 AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy; 219 androidPolicy.setPolicyMask(policyMask); 220 } 221 } 222 223 private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException { 224 public StrictModeNetworkViolation(int policyMask) { 225 super(policyMask, DISALLOW_NETWORK); 226 } 227 } 228 229 private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException { 230 public StrictModeDiskReadViolation(int policyMask) { 231 super(policyMask, DISALLOW_DISK_READ); 232 } 233 } 234 235 private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException { 236 public StrictModeDiskWriteViolation(int policyMask) { 237 super(policyMask, DISALLOW_DISK_WRITE); 238 } 239 } 240 241 /** 242 * Returns the bitmask of the current thread's policy. 243 * 244 * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled 245 */ 246 public static int getThreadPolicy() { 247 return BlockGuard.getThreadPolicy().getPolicyMask(); 248 } 249 250 /** 251 * A convenience wrapper around {@link #getThreadPolicy} and 252 * {@link #setThreadPolicy}. Updates the current thread's policy 253 * mask to allow both reading & writing to disk, returning the 254 * old policy so you can restore it at the end of a block. 255 * 256 * @return the old policy mask, to be passed to setThreadPolicy to 257 * restore the policy. 258 */ 259 public static int allowThreadDiskWrites() { 260 int oldPolicy = getThreadPolicy(); 261 int newPolicy = oldPolicy & ~(DISALLOW_DISK_WRITE | DISALLOW_DISK_READ); 262 if (newPolicy != oldPolicy) { 263 setThreadPolicy(newPolicy); 264 } 265 return oldPolicy; 266 } 267 268 /** 269 * A convenience wrapper around {@link #getThreadPolicy} and 270 * {@link #setThreadPolicy}. Updates the current thread's policy 271 * mask to allow reading from disk, returning the old 272 * policy so you can restore it at the end of a block. 273 * 274 * @return the old policy mask, to be passed to setThreadPolicy to 275 * restore the policy. 276 */ 277 public static int allowThreadDiskReads() { 278 int oldPolicy = getThreadPolicy(); 279 int newPolicy = oldPolicy & ~(DISALLOW_DISK_READ); 280 if (newPolicy != oldPolicy) { 281 setThreadPolicy(newPolicy); 282 } 283 return oldPolicy; 284 } 285 286 /** 287 * Enable DropBox logging for debug phone builds. 288 * 289 * @hide 290 */ 291 public static boolean conditionallyEnableDebugLogging() { 292 // For debug builds, log event loop stalls to dropbox for analysis. 293 // Similar logic also appears in ActivityThread.java for system apps. 294 if ("user".equals(Build.TYPE)) { 295 return false; 296 } 297 StrictMode.setThreadPolicy( 298 StrictMode.DISALLOW_DISK_WRITE | 299 StrictMode.DISALLOW_DISK_READ | 300 StrictMode.DISALLOW_NETWORK | 301 StrictMode.PENALTY_DROPBOX); 302 return true; 303 } 304 305 /** 306 * Parses the BlockGuard policy mask out from the Exception's 307 * getMessage() String value. Kinda gross, but least 308 * invasive. :/ 309 * 310 * Input is of form "policy=137 violation=64" 311 * 312 * Returns 0 on failure, which is a valid policy, but not a 313 * valid policy during a violation (else there must've been 314 * some policy in effect to violate). 315 */ 316 private static int parsePolicyFromMessage(String message) { 317 if (message == null || !message.startsWith("policy=")) { 318 return 0; 319 } 320 int spaceIndex = message.indexOf(' '); 321 if (spaceIndex == -1) { 322 return 0; 323 } 324 String policyString = message.substring(7, spaceIndex); 325 try { 326 return Integer.valueOf(policyString).intValue(); 327 } catch (NumberFormatException e) { 328 return 0; 329 } 330 } 331 332 /** 333 * Like parsePolicyFromMessage(), but returns the violation. 334 */ 335 private static int parseViolationFromMessage(String message) { 336 if (message == null) { 337 return 0; 338 } 339 int violationIndex = message.indexOf("violation="); 340 if (violationIndex == -1) { 341 return 0; 342 } 343 String violationString = message.substring(violationIndex + 10); 344 try { 345 return Integer.valueOf(violationString).intValue(); 346 } catch (NumberFormatException e) { 347 return 0; 348 } 349 } 350 351 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 352 private int mPolicyMask; 353 354 // Map from violation stacktrace hashcode -> uptimeMillis of 355 // last violation. No locking needed, as this is only 356 // accessed by the same thread. 357 private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>(); 358 359 public AndroidBlockGuardPolicy(final int policyMask) { 360 mPolicyMask = policyMask; 361 } 362 363 @Override 364 public String toString() { 365 return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask; 366 } 367 368 // Part of BlockGuard.Policy interface: 369 public int getPolicyMask() { 370 return mPolicyMask; 371 } 372 373 // Part of BlockGuard.Policy interface: 374 public void onWriteToDisk() { 375 if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) { 376 return; 377 } 378 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); 379 e.fillInStackTrace(); 380 startHandlingViolationException(e); 381 } 382 383 // Part of BlockGuard.Policy interface: 384 public void onReadFromDisk() { 385 if ((mPolicyMask & DISALLOW_DISK_READ) == 0) { 386 return; 387 } 388 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); 389 e.fillInStackTrace(); 390 startHandlingViolationException(e); 391 } 392 393 // Part of BlockGuard.Policy interface: 394 public void onNetwork() { 395 if ((mPolicyMask & DISALLOW_NETWORK) == 0) { 396 return; 397 } 398 BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); 399 e.fillInStackTrace(); 400 startHandlingViolationException(e); 401 } 402 403 public void setPolicyMask(int policyMask) { 404 mPolicyMask = policyMask; 405 } 406 407 // Start handling a violation that just started and hasn't 408 // actually run yet (e.g. no disk write or network operation 409 // has yet occurred). This sees if we're in an event loop 410 // thread and, if so, uses it to roughly measure how long the 411 // violation took. 412 void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) { 413 final ViolationInfo info = new ViolationInfo(e, e.getPolicy()); 414 info.violationUptimeMillis = SystemClock.uptimeMillis(); 415 handleViolationWithTimingAttempt(info); 416 } 417 418 private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = 419 new ThreadLocal<ArrayList<ViolationInfo>>() { 420 @Override protected ArrayList<ViolationInfo> initialValue() { 421 return new ArrayList<ViolationInfo>(); 422 } 423 }; 424 425 // Attempts to fill in the provided ViolationInfo's 426 // durationMillis field if this thread has a Looper we can use 427 // to measure with. We measure from the time of violation 428 // until the time the looper is idle again (right before 429 // the next epoll_wait) 430 void handleViolationWithTimingAttempt(final ViolationInfo info) { 431 Looper looper = Looper.myLooper(); 432 433 // Without a Looper, we're unable to time how long the 434 // violation takes place. This case should be rare, as 435 // most users will care about timing violations that 436 // happen on their main UI thread. Note that this case is 437 // also hit when a violation takes place in a Binder 438 // thread, in "gather" mode. In this case, the duration 439 // of the violation is computed by the ultimate caller and 440 // its Looper, if any. 441 // TODO: if in gather mode, ignore Looper.myLooper() and always 442 // go into this immediate mode? 443 if (looper == null) { 444 info.durationMillis = -1; // unknown (redundant, already set) 445 handleViolation(info); 446 return; 447 } 448 449 MessageQueue queue = Looper.myQueue(); 450 final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); 451 if (records.size() >= 10) { 452 // Not worth measuring. Too many offenses in one loop. 453 return; 454 } 455 records.add(info); 456 if (records.size() > 1) { 457 // There's already been a violation this loop, so we've already 458 // registered an idle handler to process the list of violations 459 // at the end of this Looper's loop. 460 return; 461 } 462 463 queue.addIdleHandler(new MessageQueue.IdleHandler() { 464 public boolean queueIdle() { 465 long loopFinishTime = SystemClock.uptimeMillis(); 466 for (int n = 0; n < records.size(); ++n) { 467 ViolationInfo v = records.get(n); 468 v.violationNumThisLoop = n + 1; 469 v.durationMillis = 470 (int) (loopFinishTime - v.violationUptimeMillis); 471 handleViolation(v); 472 } 473 records.clear(); 474 return false; // remove this idle handler from the array 475 } 476 }); 477 } 478 479 // Note: It's possible (even quite likely) that the 480 // thread-local policy mask has changed from the time the 481 // violation fired and now (after the violating code ran) due 482 // to people who push/pop temporary policy in regions of code, 483 // hence the policy being passed around. 484 void handleViolation(final ViolationInfo info) { 485 if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) { 486 Log.wtf(TAG, "unexpected null stacktrace"); 487 return; 488 } 489 490 if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy); 491 492 if ((info.policy & PENALTY_GATHER) != 0) { 493 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 494 if (violations == null) { 495 violations = new ArrayList<ViolationInfo>(1); 496 gatheredViolations.set(violations); 497 } else if (violations.size() >= 5) { 498 // Too many. In a loop or something? Don't gather them all. 499 return; 500 } 501 for (ViolationInfo previous : violations) { 502 if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) { 503 // Duplicate. Don't log. 504 return; 505 } 506 } 507 violations.add(info); 508 return; 509 } 510 511 // Not perfect, but fast and good enough for dup suppression. 512 Integer crashFingerprint = info.crashInfo.stackTrace.hashCode(); 513 long lastViolationTime = 0; 514 if (mLastViolationTime.containsKey(crashFingerprint)) { 515 lastViolationTime = mLastViolationTime.get(crashFingerprint); 516 } 517 long now = SystemClock.uptimeMillis(); 518 mLastViolationTime.put(crashFingerprint, now); 519 long timeSinceLastViolationMillis = lastViolationTime == 0 ? 520 Long.MAX_VALUE : (now - lastViolationTime); 521 522 if ((info.policy & PENALTY_LOG) != 0 && 523 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 524 if (info.durationMillis != -1) { 525 Log.d(TAG, "StrictMode policy violation; ~duration=" + 526 info.durationMillis + " ms: " + info.crashInfo.stackTrace); 527 } else { 528 Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace); 529 } 530 } 531 532 // The violationMask, passed to ActivityManager, is a 533 // subset of the original StrictMode policy bitmask, with 534 // only the bit violated and penalty bits to be executed 535 // by the ActivityManagerService remaining set. 536 int violationMaskSubset = 0; 537 538 if ((info.policy & PENALTY_DIALOG) != 0 && 539 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 540 violationMaskSubset |= PENALTY_DIALOG; 541 } 542 543 if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { 544 violationMaskSubset |= PENALTY_DROPBOX; 545 } 546 547 if (violationMaskSubset != 0) { 548 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); 549 violationMaskSubset |= violationBit; 550 final int savedPolicy = getThreadPolicy(); 551 try { 552 // First, remove any policy before we call into the Activity Manager, 553 // otherwise we'll infinite recurse as we try to log policy violations 554 // to disk, thus violating policy, thus requiring logging, etc... 555 // We restore the current policy below, in the finally block. 556 setThreadPolicy(0); 557 558 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 559 RuntimeInit.getApplicationObject(), 560 violationMaskSubset, 561 info); 562 } catch (RemoteException e) { 563 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 564 } finally { 565 // Restore the policy. 566 setThreadPolicy(savedPolicy); 567 } 568 } 569 570 if ((info.policy & PENALTY_DEATH) != 0) { 571 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); 572 Process.killProcess(Process.myPid()); 573 System.exit(10); 574 } 575 } 576 } 577 578 /** 579 * Called from Parcel.writeNoException() 580 */ 581 /* package */ static boolean hasGatheredViolations() { 582 return gatheredViolations.get() != null; 583 } 584 585 /** 586 * Called from Parcel.writeException(), so we drop this memory and 587 * don't incorrectly attribute it to the wrong caller on the next 588 * Binder call on this thread. 589 */ 590 /* package */ static void clearGatheredViolations() { 591 gatheredViolations.set(null); 592 } 593 594 /** 595 * Called from Parcel.writeNoException() 596 */ 597 /* package */ static void writeGatheredViolationsToParcel(Parcel p) { 598 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 599 if (violations == null) { 600 p.writeInt(0); 601 } else { 602 p.writeInt(violations.size()); 603 for (int i = 0; i < violations.size(); ++i) { 604 violations.get(i).writeToParcel(p, 0 /* unused flags? */); 605 } 606 if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size()); 607 violations.clear(); // somewhat redundant, as we're about to null the threadlocal 608 } 609 gatheredViolations.set(null); 610 } 611 612 private static class LogStackTrace extends Exception {} 613 614 /** 615 * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, 616 * we here read back all the encoded violations. 617 */ 618 /* package */ static void readAndHandleBinderCallViolations(Parcel p) { 619 // Our own stack trace to append 620 StringWriter sw = new StringWriter(); 621 new LogStackTrace().printStackTrace(new PrintWriter(sw)); 622 String ourStack = sw.toString(); 623 624 int policyMask = getThreadPolicy(); 625 boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; 626 627 int numViolations = p.readInt(); 628 for (int i = 0; i < numViolations; ++i) { 629 if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); 630 ViolationInfo info = new ViolationInfo(p, !currentlyGathering); 631 info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; 632 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 633 if (policy instanceof AndroidBlockGuardPolicy) { 634 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); 635 } 636 } 637 } 638 639 /** 640 * Called from android_util_Binder.cpp's 641 * android_os_Parcel_enforceInterface when an incoming Binder call 642 * requires changing the StrictMode policy mask. The role of this 643 * function is to ask Binder for its current (native) thread-local 644 * policy value and synchronize it to libcore's (Java) 645 * thread-local policy value. 646 */ 647 private static void onBinderStrictModePolicyChange(int newPolicy) { 648 setBlockGuardPolicy(newPolicy); 649 } 650 651 /** 652 * Parcelable that gets sent in Binder call headers back to callers 653 * to report violations that happened during a cross-process call. 654 * 655 * @hide 656 */ 657 public static class ViolationInfo { 658 /** 659 * Stack and other stuff info. 660 */ 661 public final ApplicationErrorReport.CrashInfo crashInfo; 662 663 /** 664 * The strict mode policy mask at the time of violation. 665 */ 666 public final int policy; 667 668 /** 669 * The wall time duration of the violation, when known. -1 when 670 * not known. 671 */ 672 public int durationMillis = -1; 673 674 /** 675 * Which violation number this was (1-based) since the last Looper loop, 676 * from the perspective of the root caller (if it crossed any processes 677 * via Binder calls). The value is 0 if the root caller wasn't on a Looper 678 * thread. 679 */ 680 public int violationNumThisLoop; 681 682 /** 683 * The time (in terms of SystemClock.uptimeMillis()) that the 684 * violation occurred. 685 */ 686 public long violationUptimeMillis; 687 688 /** 689 * Create an uninitialized instance of ViolationInfo 690 */ 691 public ViolationInfo() { 692 crashInfo = null; 693 policy = 0; 694 } 695 696 /** 697 * Create an instance of ViolationInfo initialized from an exception. 698 */ 699 public ViolationInfo(Throwable tr, int policy) { 700 crashInfo = new ApplicationErrorReport.CrashInfo(tr); 701 violationUptimeMillis = SystemClock.uptimeMillis(); 702 this.policy = policy; 703 } 704 705 /** 706 * Create an instance of ViolationInfo initialized from a Parcel. 707 */ 708 public ViolationInfo(Parcel in) { 709 this(in, false); 710 } 711 712 /** 713 * Create an instance of ViolationInfo initialized from a Parcel. 714 * 715 * @param unsetGatheringBit if true, the caller is the root caller 716 * and the gathering penalty should be removed. 717 */ 718 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 719 crashInfo = new ApplicationErrorReport.CrashInfo(in); 720 int rawPolicy = in.readInt(); 721 if (unsetGatheringBit) { 722 policy = rawPolicy & ~PENALTY_GATHER; 723 } else { 724 policy = rawPolicy; 725 } 726 durationMillis = in.readInt(); 727 violationNumThisLoop = in.readInt(); 728 violationUptimeMillis = in.readLong(); 729 } 730 731 /** 732 * Save a ViolationInfo instance to a parcel. 733 */ 734 public void writeToParcel(Parcel dest, int flags) { 735 crashInfo.writeToParcel(dest, flags); 736 dest.writeInt(policy); 737 dest.writeInt(durationMillis); 738 dest.writeInt(violationNumThisLoop); 739 dest.writeLong(violationUptimeMillis); 740 } 741 742 743 /** 744 * Dump a ViolationInfo instance to a Printer. 745 */ 746 public void dump(Printer pw, String prefix) { 747 crashInfo.dump(pw, prefix); 748 pw.println(prefix + "policy: " + policy); 749 if (durationMillis != -1) { 750 pw.println(prefix + "durationMillis: " + durationMillis); 751 } 752 if (violationNumThisLoop != 0) { 753 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 754 } 755 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 756 } 757 758 } 759} 760