diff options
author | Brad Fitzpatrick <bradfitz@android.com> | 2010-07-07 16:06:39 -0700 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@android.com> | 2010-07-15 13:18:05 -0700 |
commit | 727de40c6bc7c6521a0542ea9def5d5c7b1c5e06 (patch) | |
tree | 0d2f0f400211efbaf131020d7c4d38e647f5bbe3 /core | |
parent | d6343c26b8580f61a257a3045bfa124049201116 (diff) | |
download | frameworks_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.java | 25 | ||||
-rw-r--r-- | core/java/android/os/StrictMode.java | 51 | ||||
-rw-r--r-- | core/jni/android_util_Binder.cpp | 68 |
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)); |