Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 727de40c authored by Brad Fitzpatrick's avatar Brad Fitzpatrick
Browse files

More StrictMode work, keeping Binder & BlockGuard's thread-locals in-sync.

Change-Id: Ia67cabcc17a73a0f15907ffea683d06bc41b90e5
parent d6343c26
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -102,6 +102,29 @@ public class Binder implements IBinder {
     */
    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
+51 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+67 −1
Original line number Diff line number Diff line
@@ -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));
+5 −1
Original line number Diff line number Diff line
@@ -58,9 +58,13 @@ public:

    // Writes the RPC header.
    status_t            writeInterfaceToken(const String16& interface);

    // Parses the RPC header, returning true if the interface name
    // in the header matches the expected interface from the caller.
    bool                enforceInterface(const String16& interface) const;
    // If strict_policy_out is non-NULL, the RPC header's StrictMode policy
    // mask is returned.
    bool                enforceInterface(const String16& interface,
                                         int32_t* strict_policy_out = NULL) const;
    bool                checkInterface(IBinder*) const;

    void                freeData();
+2 −2
Original line number Diff line number Diff line
@@ -372,8 +372,8 @@ void IPCThreadState::setStrictModePolicy(int32_t policy)
    mStrictModePolicy = policy;
}


int32_t IPCThreadState::getStrictModePolicy() const {
int32_t IPCThreadState::getStrictModePolicy() const
{
    return mStrictModePolicy;
}

Loading