Structure StrictMode violations as Throwables

All violations of StrictMode now inherit from one central Violation
class. This unlocks adding penaltyCallback(Violation).
Parsing strings is no longer required to infer what type of violation
something is.
Violation classes have no need to be loaded in Zygote as only developers
opt-in to this feature and will see violations.

Cross-binder thread violation perf test:
before
2872331
2574093
2481208
after
1938227
1742714
2654538

Bug: 64258734
Test: cts-tradefed run cts-dev --module CtsOsTestCases --test
android.os.cts.StrictModeTest
Change-Id: I1971feb03ff77cf297c940cacee62fadb5b8422c
This commit is contained in:
Kurt Nelson
2017-10-26 18:06:12 -07:00
parent 0075dda825
commit 1bb93bf77c
22 changed files with 557 additions and 249 deletions

View File

@@ -32081,13 +32081,13 @@ package android.os {
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
ctor public StrictMode.ViolationInfo();
ctor public StrictMode.ViolationInfo(java.lang.Throwable, int);
ctor public StrictMode.ViolationInfo(android.os.Parcel);
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
method public int getPolicyMask();
method public java.lang.String getStackTrace();
method public int getViolationBit();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
@@ -32095,7 +32095,6 @@ package android.os {
field public int durationMillis;
field public int numAnimationsRunning;
field public long numInstances;
field public final int policy;
field public java.lang.String[] tags;
field public int violationNumThisLoop;
field public long violationUptimeMillis;

View File

@@ -3340,14 +3340,8 @@ android.os.StrictMode$9
android.os.StrictMode$AndroidBlockGuardPolicy
android.os.StrictMode$AndroidBlockGuardPolicy$1
android.os.StrictMode$AndroidCloseGuardReporter
android.os.StrictMode$InstanceCountViolation
android.os.StrictMode$InstanceTracker
android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
android.os.StrictMode$StrictModeCustomViolation
android.os.StrictMode$StrictModeDiskReadViolation
android.os.StrictMode$StrictModeDiskWriteViolation
android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState

View File

@@ -1865,9 +1865,6 @@ android.os.StrictMode$InstanceCountViolation
android.os.StrictMode$InstanceTracker
android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
android.os.StrictMode$StrictModeDiskReadViolation
android.os.StrictMode$StrictModeDiskWriteViolation
android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState

View File

@@ -27,6 +27,23 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.strictmode.CleartextNetworkViolation;
import android.os.strictmode.ContentUriWithoutPermissionViolation;
import android.os.strictmode.CustomViolation;
import android.os.strictmode.DiskReadViolation;
import android.os.strictmode.DiskWriteViolation;
import android.os.strictmode.FileUriExposedViolation;
import android.os.strictmode.InstanceCountViolation;
import android.os.strictmode.IntentReceiverLeakedViolation;
import android.os.strictmode.LeakedClosableViolation;
import android.os.strictmode.NetworkViolation;
import android.os.strictmode.ResourceMismatchViolation;
import android.os.strictmode.ServiceConnectionLeakedViolation;
import android.os.strictmode.SqliteObjectLeakedViolation;
import android.os.strictmode.UnbufferedIOViolation;
import android.os.strictmode.UntaggedSocketViolation;
import android.os.strictmode.Violation;
import android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Printer;
@@ -156,36 +173,30 @@ public final class StrictMode {
// Byte 1: Thread-policy
/** @hide */
@TestApi
public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
@TestApi public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
/** @hide */
@TestApi
public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
@TestApi public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
/** @hide */
@TestApi
public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
@TestApi public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
/**
* For StrictMode.noteSlowCall()
*
* @hide
*/
@TestApi
public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
@TestApi public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
/**
* For StrictMode.noteResourceMismatch()
*
* @hide
*/
@TestApi
public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
@TestApi public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
/** @hide */
@TestApi
public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
@TestApi public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
private static final int ALL_THREAD_DETECT_BITS =
DETECT_DISK_WRITE
@@ -202,48 +213,40 @@ public final class StrictMode {
*
* @hide
*/
@TestApi
public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
@TestApi
public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
@TestApi
public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
@TestApi public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
@TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS
@@ -354,11 +357,7 @@ public final class StrictMode {
} else {
msg = "StrictMode policy violation:";
}
if (info.hasStackTrace()) {
Log.d(TAG, msg + " " + info.getStackTrace());
} else {
Log.d(TAG, msg + " missing stack trace!");
}
Log.d(TAG, msg + " " + info.getStackTrace());
};
private static volatile ViolationLogger sLogger = LOGCAT_LOGGER;
@@ -991,55 +990,6 @@ public final class StrictMode {
CloseGuard.setEnabled(enabled);
}
/** @hide */
public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeViolation(int policyState, int policyViolated, String message) {
super(policyState, policyViolated, message);
}
}
/** @hide */
public static class StrictModeNetworkViolation extends StrictModeViolation {
public StrictModeNetworkViolation(int policyMask) {
super(policyMask, DETECT_NETWORK, null);
}
}
/** @hide */
private static class StrictModeDiskReadViolation extends StrictModeViolation {
public StrictModeDiskReadViolation(int policyMask) {
super(policyMask, DETECT_DISK_READ, null);
}
}
/** @hide */
private static class StrictModeDiskWriteViolation extends StrictModeViolation {
public StrictModeDiskWriteViolation(int policyMask) {
super(policyMask, DETECT_DISK_WRITE, null);
}
}
/** @hide */
private static class StrictModeCustomViolation extends StrictModeViolation {
public StrictModeCustomViolation(int policyMask, String name) {
super(policyMask, DETECT_CUSTOM, name);
}
}
/** @hide */
private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
}
}
/** @hide */
private static class StrictModeUnbufferedIOViolation extends StrictModeViolation {
public StrictModeUnbufferedIOViolation(int policyMask) {
super(policyMask, DETECT_UNBUFFERED_IO, null);
}
}
/**
* Returns the bitmask of the current thread's policy.
*
@@ -1308,9 +1258,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new DiskWriteViolation());
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1321,10 +1269,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e =
new StrictModeCustomViolation(mPolicyMask, name);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new CustomViolation(name));
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1335,13 +1280,10 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e =
new StrictModeResourceMismatchViolation(mPolicyMask, tag);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new ResourceMismatchViolation(tag));
}
// Part of BlockGuard.Policy; just part of StrictMode:
// Not part of BlockGuard.Policy; just part of StrictMode:
public void onUnbufferedIO() {
if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
return;
@@ -1349,10 +1291,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e =
new StrictModeUnbufferedIOViolation(mPolicyMask);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new UnbufferedIOViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1363,9 +1302,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new DiskReadViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1379,9 +1316,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
e.fillInStackTrace();
startHandlingViolationException(e);
startHandlingViolationException(new NetworkViolation());
}
public void setPolicyMask(int policyMask) {
@@ -1393,8 +1328,8 @@ public final class StrictMode {
// has yet occurred). This sees if we're in an event loop
// thread and, if so, uses it to roughly measure how long the
// violation took.
void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
void startHandlingViolationException(Violation e) {
final ViolationInfo info = new ViolationInfo(e, mPolicyMask);
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
@@ -1423,7 +1358,7 @@ public final class StrictMode {
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
if (looper == null || (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
info.durationMillis = -1; // unknown (redundant, already set)
handleViolation(info);
return;
@@ -1443,7 +1378,7 @@ public final class StrictMode {
}
final IWindowManager windowManager =
(info.policy & PENALTY_FLASH) != 0 ? sWindowManager.get() : null;
info.penaltyEnabled(PENALTY_FLASH) ? sWindowManager.get() : null;
if (windowManager != null) {
try {
windowManager.showStrictModeViolation(true);
@@ -1496,14 +1431,9 @@ public final class StrictMode {
// to people who push/pop temporary policy in regions of code,
// hence the policy being passed around.
void handleViolation(final ViolationInfo info) {
if (info == null || !info.hasStackTrace()) {
Log.wtf(TAG, "unexpected null stacktrace");
return;
}
if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.mPolicy);
if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
if ((info.policy & PENALTY_GATHER) != 0) {
if (info.penaltyEnabled(PENALTY_GATHER)) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
if (violations == null) {
violations = new ArrayList<ViolationInfo>(1);
@@ -1535,7 +1465,7 @@ public final class StrictMode {
long timeSinceLastViolationMillis =
lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime);
if ((info.policy & PENALTY_LOG) != 0
if (info.penaltyEnabled(PENALTY_LOG)
&& timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
sLogger.log(info);
}
@@ -1546,12 +1476,12 @@ public final class StrictMode {
// by the ActivityManagerService remaining set.
int violationMaskSubset = 0;
if ((info.policy & PENALTY_DIALOG) != 0
if (info.penaltyEnabled(PENALTY_DIALOG)
&& timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
violationMaskSubset |= PENALTY_DIALOG;
}
if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) {
violationMaskSubset |= PENALTY_DROPBOX;
}
@@ -1559,7 +1489,7 @@ public final class StrictMode {
violationMaskSubset |= info.getViolationBit();
final int savedPolicyMask = getThreadPolicyMask();
final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
final boolean justDropBox = (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
if (justDropBox) {
// If all we're going to ask the activity manager
// to do is dropbox it (the common case during
@@ -1594,14 +1524,14 @@ public final class StrictMode {
}
}
if ((info.policy & PENALTY_DEATH) != 0) {
if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
executeDeathPenalty(info);
}
}
}
private static void executeDeathPenalty(ViolationInfo info) {
throw new StrictModeViolation(info.policy, info.getViolationBit(), null);
throw new RuntimeException("StrictMode death penalty", info.mViolation);
}
/**
@@ -1648,7 +1578,7 @@ public final class StrictMode {
private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
public void report(String message, Throwable allocationSite) {
onVmPolicyViolation(allocationSite);
onVmPolicyViolation(new LeakedClosableViolation(message, allocationSite));
}
}
@@ -1686,8 +1616,7 @@ public final class StrictMode {
int limit = policy.classInstanceLimit.get(klass);
long instances = instanceCounts[i];
if (instances > limit) {
Throwable tr = new InstanceCountViolation(klass, instances, limit);
onVmPolicyViolation(tr);
onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
}
@@ -1811,24 +1740,22 @@ public final class StrictMode {
/** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
Throwable t = new Throwable(message);
t.setStackTrace(originStack.getStackTrace());
onVmPolicyViolation(t);
onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
/** @hide */
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
onVmPolicyViolation(originStack);
onVmPolicyViolation(new WebViewMethodCalledOnWrongThreadViolation(originStack));
}
/** @hide */
public static void onIntentReceiverLeaked(Throwable originStack) {
onVmPolicyViolation(originStack);
onVmPolicyViolation(new IntentReceiverLeakedViolation(originStack));
}
/** @hide */
public static void onServiceConnectionLeaked(Throwable originStack) {
onVmPolicyViolation(originStack);
onVmPolicyViolation(new ServiceConnectionLeakedViolation(originStack));
}
/** @hide */
@@ -1837,19 +1764,13 @@ public final class StrictMode {
if ((sVmPolicy.mask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
throw new FileUriExposedException(message);
} else {
onVmPolicyViolation(new Throwable(message));
onVmPolicyViolation(new FileUriExposedViolation(message));
}
}
/** @hide */
public static void onContentUriWithoutPermission(Uri uri, String location) {
final String message =
uri
+ " exposed beyond app through "
+ location
+ " without permission grant flags; did you forget"
+ " FLAG_GRANT_READ_URI_PERMISSION?";
onVmPolicyViolation(new Throwable(message));
onVmPolicyViolation(new ContentUriWithoutPermissionViolation(uri, location));
}
/** @hide */
@@ -1881,29 +1802,24 @@ public final class StrictMode {
}
msg += HexDump.dumpHexString(firstPacket).trim() + " ";
final boolean forceDeath = (sVmPolicy.mask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
onVmPolicyViolation(new Throwable(msg), forceDeath);
onVmPolicyViolation(new CleartextNetworkViolation(msg), forceDeath);
}
/** @hide */
public static final String UNTAGGED_SOCKET_VIOLATION_MESSAGE =
"Untagged socket detected; use"
+ " TrafficStats.setThreadSocketTag() to track all network usage";
/** @hide */
public static void onUntaggedSocket() {
onVmPolicyViolation(new Throwable(UNTAGGED_SOCKET_VIOLATION_MESSAGE));
onVmPolicyViolation(new UntaggedSocketViolation());
}
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();
/** @hide */
public static void onVmPolicyViolation(Throwable originStack) {
public static void onVmPolicyViolation(Violation originStack) {
onVmPolicyViolation(originStack, false);
}
/** @hide */
public static void onVmPolicyViolation(Throwable originStack, boolean forceDeath) {
public static void onVmPolicyViolation(Violation originStack, boolean forceDeath) {
final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
@@ -1998,14 +1914,12 @@ public final class StrictMode {
gatheredViolations.set(null);
}
private static class LogStackTrace extends Exception {}
/**
* Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, we here
* read back all the encoded violations.
*/
/* package */ static void readAndHandleBinderCallViolations(Parcel p) {
LogStackTrace localCallSite = new LogStackTrace();
Throwable localCallSite = new Throwable();
final int policyMask = getThreadPolicyMask();
final boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
@@ -2323,8 +2237,7 @@ public final class StrictMode {
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances > limit) {
Throwable tr = new InstanceCountViolation(klass, instances, limit);
onVmPolicyViolation(tr);
onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
@@ -2337,18 +2250,16 @@ public final class StrictMode {
@TestApi
public static final class ViolationInfo implements Parcelable {
/** Stack and violation details. */
@Nullable private final Throwable mThrowable;
private final Violation mViolation;
/** Path leading to a violation that occurred across binder. */
private final Deque<StackTraceElement[]> mBinderStack = new ArrayDeque<>();
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
/** Memoized violation bit. */
private int mViolationBit;
/** The strict mode policy mask at the time of violation. */
public final int policy;
private final int mPolicy;
/** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
@@ -2378,17 +2289,11 @@ public final class StrictMode {
/** If this is a instance count violation, the number of instances in memory, else -1. */
public long numInstances = -1;
/** Create an uninitialized instance of ViolationInfo */
public ViolationInfo() {
mThrowable = null;
policy = 0;
}
/** Create an instance of ViolationInfo initialized from an exception. */
public ViolationInfo(Throwable tr, int policy) {
this.mThrowable = tr;
ViolationInfo(Violation tr, int policy) {
this.mViolation = tr;
this.mPolicy = policy;
violationUptimeMillis = SystemClock.uptimeMillis();
this.policy = policy;
this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
if (broadcastIntent != null) {
@@ -2396,7 +2301,7 @@ public final class StrictMode {
}
ThreadSpanState state = sThisThreadSpanState.get();
if (tr instanceof InstanceCountViolation) {
this.numInstances = ((InstanceCountViolation) tr).mInstances;
this.numInstances = ((InstanceCountViolation) tr).getNumberOfInstances();
}
synchronized (state) {
int spanActiveCount = state.mActiveSize;
@@ -2418,10 +2323,10 @@ public final class StrictMode {
/** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
public String getStackTrace() {
if (mThrowable != null && mStackTrace == null) {
if (mStackTrace == null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 256);
mThrowable.printStackTrace(pw);
mViolation.printStackTrace(pw);
for (StackTraceElement[] traces : mBinderStack) {
pw.append("# via Binder call with stack:\n");
for (StackTraceElement traceElement : traces) {
@@ -2444,20 +2349,21 @@ public final class StrictMode {
*/
@TestApi
public String getViolationDetails() {
if (mThrowable != null) {
return mThrowable.getMessage();
} else {
return "";
}
return mViolation.getMessage();
}
/**
* If this violation has a useful stack trace.
* Policy mask at time of violation.
*
* @hide
*/
public boolean hasStackTrace() {
return mThrowable != null;
@TestApi
public int getPolicyMask() {
return mPolicy;
}
boolean penaltyEnabled(int p) {
return (mPolicy & p) != 0;
}
/**
@@ -2475,37 +2381,47 @@ public final class StrictMode {
*
* @hide
*/
int getViolationBit() {
if (mThrowable == null || mThrowable.getMessage() == null) {
return 0;
}
if (mViolationBit != 0) {
return mViolationBit;
}
String message = mThrowable.getMessage();
int violationIndex = message.indexOf("violation=");
if (violationIndex == -1) {
return 0;
}
int numberStartIndex = violationIndex + "violation=".length();
int numberEndIndex = message.indexOf(' ', numberStartIndex);
if (numberEndIndex == -1) {
numberEndIndex = message.length();
}
String violationString = message.substring(numberStartIndex, numberEndIndex);
try {
mViolationBit = Integer.parseInt(violationString);
return mViolationBit;
} catch (NumberFormatException e) {
return 0;
@TestApi
public int getViolationBit() {
if (mViolation instanceof DiskWriteViolation) {
return DETECT_DISK_WRITE;
} else if (mViolation instanceof DiskReadViolation) {
return DETECT_DISK_READ;
} else if (mViolation instanceof NetworkViolation) {
return DETECT_NETWORK;
} else if (mViolation instanceof CustomViolation) {
return DETECT_CUSTOM;
} else if (mViolation instanceof ResourceMismatchViolation) {
return DETECT_RESOURCE_MISMATCH;
} else if (mViolation instanceof UnbufferedIOViolation) {
return DETECT_UNBUFFERED_IO;
} else if (mViolation instanceof SqliteObjectLeakedViolation) {
return DETECT_VM_CURSOR_LEAKS;
} else if (mViolation instanceof LeakedClosableViolation) {
return DETECT_VM_CLOSABLE_LEAKS;
} else if (mViolation instanceof InstanceCountViolation) {
return DETECT_VM_INSTANCE_LEAKS;
} else if (mViolation instanceof IntentReceiverLeakedViolation) {
return DETECT_VM_REGISTRATION_LEAKS;
} else if (mViolation instanceof ServiceConnectionLeakedViolation) {
return DETECT_VM_REGISTRATION_LEAKS;
} else if (mViolation instanceof FileUriExposedViolation) {
return DETECT_VM_FILE_URI_EXPOSURE;
} else if (mViolation instanceof CleartextNetworkViolation) {
return DETECT_VM_CLEARTEXT_NETWORK;
} else if (mViolation instanceof ContentUriWithoutPermissionViolation) {
return DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
} else if (mViolation instanceof UntaggedSocketViolation) {
return DETECT_VM_UNTAGGED_SOCKET;
}
throw new IllegalStateException("missing violation bit");
}
@Override
public int hashCode() {
int result = 17;
if (mThrowable != null) {
result = 37 * result + mThrowable.hashCode();
if (mViolation != null) {
result = 37 * result + mViolation.hashCode();
}
if (numAnimationsRunning != 0) {
result *= 37;
@@ -2533,7 +2449,7 @@ public final class StrictMode {
* should be removed.
*/
public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
mThrowable = (Throwable) in.readSerializable();
mViolation = (Violation) in.readSerializable();
int binderStackSize = in.readInt();
for (int i = 0; i < binderStackSize; i++) {
StackTraceElement[] traceElements = new StackTraceElement[in.readInt()];
@@ -2550,9 +2466,9 @@ public final class StrictMode {
}
int rawPolicy = in.readInt();
if (unsetGatheringBit) {
policy = rawPolicy & ~PENALTY_GATHER;
mPolicy = rawPolicy & ~PENALTY_GATHER;
} else {
policy = rawPolicy;
mPolicy = rawPolicy;
}
durationMillis = in.readInt();
violationNumThisLoop = in.readInt();
@@ -2566,7 +2482,7 @@ public final class StrictMode {
/** Save a ViolationInfo instance to a parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(mThrowable);
dest.writeSerializable(mViolation);
dest.writeInt(mBinderStack.size());
for (StackTraceElement[] traceElements : mBinderStack) {
dest.writeInt(traceElements.length);
@@ -2578,7 +2494,7 @@ public final class StrictMode {
}
}
int start = dest.dataPosition();
dest.writeInt(policy);
dest.writeInt(mPolicy);
dest.writeInt(durationMillis);
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
@@ -2591,7 +2507,7 @@ public final class StrictMode {
Slog.d(
TAG,
"VIO: policy="
+ policy
+ mPolicy
+ " dur="
+ durationMillis
+ " numLoop="
@@ -2610,10 +2526,8 @@ public final class StrictMode {
/** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
if (mThrowable != null) {
pw.println(prefix + "stackTrace: " + getStackTrace());
}
pw.println(prefix + "policy: " + policy);
pw.println(prefix + "stackTrace: " + getStackTrace());
pw.println(prefix + "policy: " + mPolicy);
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
@@ -2657,27 +2571,6 @@ public final class StrictMode {
};
}
// Dummy throwable, for now, since we don't know when or where the
// leaked instances came from. We might in the future, but for
// now we suppress the stack trace because it's useless and/or
// misleading.
private static class InstanceCountViolation extends Throwable {
private final long mInstances;
private final int mLimit;
private static final StackTraceElement[] FAKE_STACK = {
new StackTraceElement(
"android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
};
public InstanceCountViolation(Class klass, long instances, int limit) {
super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
setStackTrace(FAKE_STACK);
mInstances = instances;
mLimit = limit;
}
}
private static final class InstanceTracker {
private static final HashMap<Class<?>, Integer> sInstanceCounts =
new HashMap<Class<?>, Integer>();

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class CleartextNetworkViolation extends Violation {
public CleartextNetworkViolation(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
import android.net.Uri;
/** @hide */
public final class ContentUriWithoutPermissionViolation extends Violation {
public ContentUriWithoutPermissionViolation(Uri uri, String location) {
super(
uri
+ " exposed beyond app through "
+ location
+ " without permission grant flags; did you forget"
+ " FLAG_GRANT_READ_URI_PERMISSION?");
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class CustomViolation extends Violation {
public CustomViolation(String name) {
super(name);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class DiskReadViolation extends Violation {
public DiskReadViolation() {
super(null);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class DiskWriteViolation extends Violation {
public DiskWriteViolation() {
super(null);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class FileUriExposedViolation extends Violation {
public FileUriExposedViolation(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public class InstanceCountViolation extends Violation {
private final long mInstances;
private static final StackTraceElement[] FAKE_STACK = {
new StackTraceElement(
"android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
};
public InstanceCountViolation(Class klass, long instances, int limit) {
super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
setStackTrace(FAKE_STACK);
mInstances = instances;
}
public long getNumberOfInstances() {
return mInstances;
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class IntentReceiverLeakedViolation extends Violation {
public IntentReceiverLeakedViolation(Throwable originStack) {
super(null);
setStackTrace(originStack.getStackTrace());
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class LeakedClosableViolation extends Violation {
public LeakedClosableViolation(String message, Throwable allocationSite) {
super(message);
initCause(allocationSite);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class NetworkViolation extends Violation {
public NetworkViolation() {
super(null);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class ResourceMismatchViolation extends Violation {
public ResourceMismatchViolation(Object tag) {
super(tag.toString());
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class ServiceConnectionLeakedViolation extends Violation {
public ServiceConnectionLeakedViolation(Throwable originStack) {
super(null);
setStackTrace(originStack.getStackTrace());
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class SqliteObjectLeakedViolation extends Violation {
public SqliteObjectLeakedViolation(String message, Throwable originStack) {
super(message);
initCause(originStack);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class UnbufferedIOViolation extends Violation {
public UnbufferedIOViolation() {
super(null);
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class UntaggedSocketViolation extends Violation {
/** @hide */
public static final String MESSAGE =
"Untagged socket detected; use"
+ " TrafficStats.setThreadSocketTag() to track all network usage";
public UntaggedSocketViolation() {
super(MESSAGE);
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/**
* Root class for all StrictMode violations.
*
* @hide
*/
public abstract class Violation extends Throwable {
protected Violation(String message) {
super(message);
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.strictmode;
/** @hide */
public final class WebViewMethodCalledOnWrongThreadViolation extends Violation {
public WebViewMethodCalledOnWrongThreadViolation(Throwable originStack) {
super(null);
setStackTrace(originStack.getStackTrace());
}
}

View File

@@ -14358,10 +14358,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
sb.append("\n");
if (info.hasStackTrace()) {
sb.append(info.getStackTrace());
sb.append("\n");
}
sb.append(info.getStackTrace());
sb.append("\n");
if (info.getViolationDetails() != null) {
sb.append(info.getViolationDetails());
sb.append("\n");