summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@android.com>2010-07-07 16:06:39 -0700
committerBrad Fitzpatrick <bradfitz@android.com>2010-07-15 13:18:05 -0700
commit727de40c6bc7c6521a0542ea9def5d5c7b1c5e06 (patch)
tree0d2f0f400211efbaf131020d7c4d38e647f5bbe3 /core
parentd6343c26b8580f61a257a3045bfa124049201116 (diff)
downloadframeworks_base-727de40c6bc7c6521a0542ea9def5d5c7b1c5e06.zip
frameworks_base-727de40c6bc7c6521a0542ea9def5d5c7b1c5e06.tar.gz
frameworks_base-727de40c6bc7c6521a0542ea9def5d5c7b1c5e06.tar.bz2
More StrictMode work, keeping Binder & BlockGuard's thread-locals in-sync.
Change-Id: Ia67cabcc17a73a0f15907ffea683d06bc41b90e5
Diffstat (limited to 'core')
-rw-r--r--core/java/android/os/Binder.java25
-rw-r--r--core/java/android/os/StrictMode.java51
-rw-r--r--core/jni/android_util_Binder.cpp68
3 files changed, 142 insertions, 2 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index c9df567..4c40982 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -101,7 +101,30 @@ public class Binder implements IBinder {
* @see #clearCallingIdentity
*/
public static final native void restoreCallingIdentity(long token);
-
+
+ /**
+ * Sets the native thread-local StrictMode policy mask.
+ *
+ * <p>The StrictMode settings are kept in two places: a Java-level
+ * threadlocal for libcore/Dalvik, and a native threadlocal (set
+ * here) for propagation via Binder calls. This is a little
+ * unfortunate, but necessary to break otherwise more unfortunate
+ * dependencies either of Dalvik on Android, or Android
+ * native-only code on Dalvik.
+ *
+ * @see StrictMode
+ * @hide
+ */
+ public static final native void setThreadStrictModePolicy(int policyMask);
+
+ /**
+ * Gets the current native thread-local StrictMode policy mask.
+ *
+ * @see #setThreadStrictModePolicy
+ * @hide
+ */
+ public static final native int getThreadStrictModePolicy();
+
/**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 9b18719..f7ad884 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -69,6 +69,17 @@ public final class StrictMode {
*/
public static final int PENALTY_DROPBOX = 0x80;
+ /**
+ * Non-public penalty mode which overrides all the other penalty
+ * bits and signals that we're in a Binder call and we should
+ * ignore the other penalty bits and instead serialize back all
+ * our offending stack traces to the caller to ultimately handle
+ * in the originating process.
+ *
+ * @hide
+ */
+ public static final int PENALTY_GATHER = 0x100;
+
/** @hide */
public static final int PENALTY_MASK =
PENALTY_LOG | PENALTY_DIALOG |
@@ -81,6 +92,19 @@ public final class StrictMode {
* @param policyMask a bitmask of DISALLOW_* and PENALTY_* values.
*/
public static void setThreadBlockingPolicy(final int policyMask) {
+ // In addition to the Java-level thread-local in Dalvik's
+ // BlockGuard, we also need to keep a native thread-local in
+ // Binder in order to propagate the value across Binder calls,
+ // even across native-only processes. The two are kept in
+ // sync via the callback to onStrictModePolicyChange, below.
+ setBlockGuardPolicy(policyMask);
+
+ // And set the Android native version...
+ Binder.setThreadStrictModePolicy(policyMask);
+ }
+
+ // Sets the policy in Dalvik/libcore (BlockGuard)
+ private static void setBlockGuardPolicy(final int policyMask) {
if (policyMask == 0) {
BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
return;
@@ -189,6 +213,11 @@ public final class StrictMode {
new ApplicationErrorReport.CrashInfo(violation);
crashInfo.durationMillis = durationMillis;
+ if ((policy & PENALTY_GATHER) != 0) {
+ Log.d(TAG, "StrictMode violation via Binder call; ignoring for now.");
+ return;
+ }
+
// Not perfect, but fast and good enough for dup suppression.
Integer crashFingerprint = crashInfo.stackTrace.hashCode();
long lastViolationTime = 0;
@@ -227,13 +256,23 @@ public final class StrictMode {
if (violationMask != 0) {
violationMask |= violation.getPolicyViolation();
+ final int savedPolicy = getThreadBlockingPolicy();
try {
+ // First, remove any policy before we call into the Activity Manager,
+ // otherwise we'll infinite recurse as we try to log policy violations
+ // to disk, thus violating policy, thus requiring logging, etc...
+ // We restore the current policy below, in the finally block.
+ setThreadBlockingPolicy(0);
+
ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
RuntimeInit.getApplicationObject(),
violationMask,
new ApplicationErrorReport.CrashInfo(violation));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ } finally {
+ // Restore the policy.
+ setThreadBlockingPolicy(savedPolicy);
}
}
@@ -244,4 +283,16 @@ public final class StrictMode {
}
}
}
+
+ /**
+ * Called from android_util_Binder.cpp's
+ * android_os_Parcel_enforceInterface when an incoming Binder call
+ * requires changing the StrictMode policy mask. The role of this
+ * function is to ask Binder for its current (native) thread-local
+ * policy value and synchronize it to libcore's (Java)
+ * thread-local policy value.
+ */
+ private static void onBinderStrictModePolicyChange(int newPolicy) {
+ setBlockGuardPolicy(newPolicy);
+ }
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d26cd28..040b324 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -134,6 +134,12 @@ static struct parcel_file_descriptor_offsets_t
jmethodID mConstructor;
} gParcelFileDescriptorOffsets;
+static struct strict_mode_callback_offsets_t
+{
+ jclass mClass;
+ jmethodID mCallback;
+} gStrictModeCallbackOffsets;
+
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
@@ -214,6 +220,15 @@ bail:
env->DeleteLocalRef(msgstr);
}
+static void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy)
+{
+ // Call back into android.os.StrictMode#onBinderStrictModePolicyChange
+ // to sync our state back to it. See the comments in StrictMode.java.
+ env->CallStaticVoidMethod(gStrictModeCallbackOffsets.mClass,
+ gStrictModeCallbackOffsets.mCallback,
+ strict_policy);
+}
+
class JavaBBinderHolder;
class JavaBBinder : public BBinder
@@ -253,12 +268,28 @@ protected:
LOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
+ IPCThreadState* thread_state = IPCThreadState::self();
+ const int strict_policy_before = thread_state->getStrictModePolicy();
+
//printf("Transact from %p to Java code sending: ", this);
//data.print();
//printf("\n");
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags);
jthrowable excep = env->ExceptionOccurred();
+
+ // Restore the Java binder thread's state if it changed while
+ // processing a call (as it would if the Parcel's header had a
+ // new policy mask and Parcel.enforceInterface() changed
+ // it...)
+ const int strict_policy_after = thread_state->getStrictModePolicy();
+ if (strict_policy_after != strict_policy_before) {
+ // Our thread-local...
+ thread_state->setStrictModePolicy(strict_policy_before);
+ // And the Java-level thread-local...
+ set_dalvik_blockguard_policy(env, strict_policy_before);
+ }
+
if (excep) {
report_exception(env, excep,
"*** Uncaught remote exception! "
@@ -574,6 +605,16 @@ static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz,
IPCThreadState::self()->restoreCallingIdentity(token);
}
+static void android_os_Binder_setThreadStrictModePolicy(JNIEnv* env, jobject clazz, jint policyMask)
+{
+ IPCThreadState::self()->setStrictModePolicy(policyMask);
+}
+
+static jint android_os_Binder_getThreadStrictModePolicy(JNIEnv* env, jobject clazz)
+{
+ return IPCThreadState::self()->getStrictModePolicy();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -618,6 +659,8 @@ static const JNINativeMethod gBinderMethods[] = {
{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
{ "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
+ { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
+ { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "init", "()V", (void*)android_os_Binder_init },
{ "destroy", "()V", (void*)android_os_Binder_destroy }
@@ -1523,9 +1566,24 @@ static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstri
if (parcel != NULL) {
const jchar* str = env->GetStringCritical(name, 0);
if (str) {
- bool isValid = parcel->enforceInterface(String16(str, env->GetStringLength(name)));
+ const int32_t old_strict_policy =
+ IPCThreadState::self()->getStrictModePolicy();
+ int32_t strict_policy;
+ bool isValid = parcel->enforceInterface(
+ String16(str, env->GetStringLength(name)),
+ &strict_policy);
env->ReleaseStringCritical(name, str);
if (isValid) {
+ if (old_strict_policy != strict_policy) {
+ // Need to keep the Java-level thread-local strict
+ // mode policy in sync for the libcore
+ // enforcements, which involves an upcall back
+ // into Java. (We can't modify the
+ // Parcel.enforceInterface signature, as it's
+ // pseudo-public, and used via AIDL
+ // auto-generation...)
+ set_dalvik_blockguard_policy(env, strict_policy);
+ }
return; // everything was correct -> return silently
}
}
@@ -1611,6 +1669,14 @@ static int int_register_android_os_Parcel(JNIEnv* env)
gParcelOffsets.mOwnObject
= env->GetFieldID(clazz, "mOwnObject", "I");
+ clazz = env->FindClass("android/os/StrictMode");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.StrictMode");
+ gStrictModeCallbackOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gStrictModeCallbackOffsets.mCallback = env->GetStaticMethodID(
+ clazz, "onBinderStrictModePolicyChange", "(I)V");
+ LOG_FATAL_IF(gStrictModeCallbackOffsets.mCallback == NULL,
+ "Unable to find strict mode callback.");
+
return AndroidRuntime::registerNativeMethods(
env, kParcelPathName,
gParcelMethods, NELEM(gParcelMethods));