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

Commit 9867ed7a authored by Jeff Brown's avatar Jeff Brown
Browse files

Detect invalid uses of Message.

Throw an exception when an application attempts to recycle or
resend messages that are still in-use.

Change-Id: I7096e8b7bd5bec41b7b8ef0c798c55ce3db6827e
parent 454a0384
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -149,7 +149,7 @@ public final class Looper {
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();
            msg.recycleUnchecked();
        }
    }

+41 −20
Original line number Diff line number Diff line
@@ -71,7 +71,14 @@ public final class Message implements Parcelable {
     */
    public Messenger replyTo;

    /** If set message is in use */
    /** If set message is in use.
     * This flag is set when the message is enqueued and remains set while it
     * is delivered and afterwards when it is recycled.  The flag is only cleared
     * when a new message is created or obtained since that is the only time that
     * applications are allowed to modify the contents of the message.
     *
     * It is an error to attempt to enqueue or recycle a message that is already in use.
     */
    /*package*/ static final int FLAG_IN_USE = 1 << 0;

    /** If set message is asynchronous */
@@ -109,6 +116,7 @@ public final class Message implements Parcelable {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
@@ -241,12 +249,38 @@ public final class Message implements Parcelable {
    }

    /**
     * Return a Message instance to the global pool.  You MUST NOT touch
     * the Message after calling this function -- it has effectively been
     * freed.
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     */
    public void recycle() {
        clearForRecycle();
        if (isInUse()) {
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        recycleUnchecked();
    }

    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
@@ -402,19 +436,6 @@ public final class Message implements Parcelable {
        }
    }

    /*package*/ void clearForRecycle() {
        flags = 0;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        when = 0;
        target = null;
        callback = null;
        data = null;
    }

    /*package*/ boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }
+18 −17
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.os;

import android.util.AndroidRuntimeException;
import android.util.Log;
import android.util.Printer;

@@ -169,7 +168,6 @@ public final class MessageQueue {
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
@@ -233,7 +231,7 @@ public final class MessageQueue {

    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit.");
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
@@ -259,6 +257,7 @@ public final class MessageQueue {
        synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;

@@ -303,7 +302,7 @@ public final class MessageQueue {
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;
            }
            p.recycle();
            p.recycleUnchecked();

            // If the loop is quitting then it is already awake.
            // We can assume mPtr != 0 when mQuitting is false.
@@ -314,21 +313,23 @@ public final class MessageQueue {
    }

    boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg + " This message is already in use.");
        }
        if (msg.target == null) {
            throw new AndroidRuntimeException("Message must have a target.");
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                RuntimeException e = new RuntimeException(
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
@@ -424,7 +425,7 @@ public final class MessageQueue {
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycle();
                p.recycleUnchecked();
                p = n;
            }

@@ -435,7 +436,7 @@ public final class MessageQueue {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycle();
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
@@ -458,7 +459,7 @@ public final class MessageQueue {
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycle();
                p.recycleUnchecked();
                p = n;
            }

@@ -469,7 +470,7 @@ public final class MessageQueue {
                    if (n.target == h && n.callback == r
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycle();
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
@@ -492,7 +493,7 @@ public final class MessageQueue {
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycle();
                p.recycleUnchecked();
                p = n;
            }

@@ -502,7 +503,7 @@ public final class MessageQueue {
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycle();
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
@@ -516,7 +517,7 @@ public final class MessageQueue {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycle();
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
@@ -544,7 +545,7 @@ public final class MessageQueue {
                do {
                    p = n;
                    n = p.next;
                    p.recycle();
                    p.recycleUnchecked();
                } while (n != null);
            }
        }