Message.java revision 9867ed7aa98f5a719db4b50c39a290bc0ef38123
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
19import android.util.TimeUtils;
20
21/**
22 *
23 * Defines a message containing a description and arbitrary data object that can be
24 * sent to a {@link Handler}.  This object contains two extra int fields and an
25 * extra object field that allow you to not do allocations in many cases.
26 *
27 * <p class="note">While the constructor of Message is public, the best way to get
28 * one of these is to call {@link #obtain Message.obtain()} or one of the
29 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
30 * them from a pool of recycled objects.</p>
31 */
32public final class Message implements Parcelable {
33    /**
34     * User-defined message code so that the recipient can identify
35     * what this message is about. Each {@link Handler} has its own name-space
36     * for message codes, so you do not need to worry about yours conflicting
37     * with other handlers.
38     */
39    public int what;
40
41    /**
42     * arg1 and arg2 are lower-cost alternatives to using
43     * {@link #setData(Bundle) setData()} if you only need to store a
44     * few integer values.
45     */
46    public int arg1;
47
48    /**
49     * arg1 and arg2 are lower-cost alternatives to using
50     * {@link #setData(Bundle) setData()} if you only need to store a
51     * few integer values.
52     */
53    public int arg2;
54
55    /**
56     * An arbitrary object to send to the recipient.  When using
57     * {@link Messenger} to send the message across processes this can only
58     * be non-null if it contains a Parcelable of a framework class (not one
59     * implemented by the application).   For other data transfer use
60     * {@link #setData}.
61     *
62     * <p>Note that Parcelable objects here are not supported prior to
63     * the {@link android.os.Build.VERSION_CODES#FROYO} release.
64     */
65    public Object obj;
66
67    /**
68     * Optional Messenger where replies to this message can be sent.  The
69     * semantics of exactly how this is used are up to the sender and
70     * receiver.
71     */
72    public Messenger replyTo;
73
74    /** If set message is in use.
75     * This flag is set when the message is enqueued and remains set while it
76     * is delivered and afterwards when it is recycled.  The flag is only cleared
77     * when a new message is created or obtained since that is the only time that
78     * applications are allowed to modify the contents of the message.
79     *
80     * It is an error to attempt to enqueue or recycle a message that is already in use.
81     */
82    /*package*/ static final int FLAG_IN_USE = 1 << 0;
83
84    /** If set message is asynchronous */
85    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
86
87    /** Flags to clear in the copyFrom method */
88    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
89
90    /*package*/ int flags;
91
92    /*package*/ long when;
93
94    /*package*/ Bundle data;
95
96    /*package*/ Handler target;
97
98    /*package*/ Runnable callback;
99
100    // sometimes we store linked lists of these things
101    /*package*/ Message next;
102
103    private static final Object sPoolSync = new Object();
104    private static Message sPool;
105    private static int sPoolSize = 0;
106
107    private static final int MAX_POOL_SIZE = 50;
108
109    /**
110     * Return a new Message instance from the global pool. Allows us to
111     * avoid allocating new objects in many cases.
112     */
113    public static Message obtain() {
114        synchronized (sPoolSync) {
115            if (sPool != null) {
116                Message m = sPool;
117                sPool = m.next;
118                m.next = null;
119                m.flags = 0; // clear in-use flag
120                sPoolSize--;
121                return m;
122            }
123        }
124        return new Message();
125    }
126
127    /**
128     * Same as {@link #obtain()}, but copies the values of an existing
129     * message (including its target) into the new one.
130     * @param orig Original message to copy.
131     * @return A Message object from the global pool.
132     */
133    public static Message obtain(Message orig) {
134        Message m = obtain();
135        m.what = orig.what;
136        m.arg1 = orig.arg1;
137        m.arg2 = orig.arg2;
138        m.obj = orig.obj;
139        m.replyTo = orig.replyTo;
140        if (orig.data != null) {
141            m.data = new Bundle(orig.data);
142        }
143        m.target = orig.target;
144        m.callback = orig.callback;
145
146        return m;
147    }
148
149    /**
150     * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
151     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
152     * @return A Message object from the global pool.
153     */
154    public static Message obtain(Handler h) {
155        Message m = obtain();
156        m.target = h;
157
158        return m;
159    }
160
161    /**
162     * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
163     * the Message that is returned.
164     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
165     * @param callback Runnable that will execute when the message is handled.
166     * @return A Message object from the global pool.
167     */
168    public static Message obtain(Handler h, Runnable callback) {
169        Message m = obtain();
170        m.target = h;
171        m.callback = callback;
172
173        return m;
174    }
175
176    /**
177     * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
178     * <em>what</em> members on the Message.
179     * @param h  Value to assign to the <em>target</em> member.
180     * @param what  Value to assign to the <em>what</em> member.
181     * @return A Message object from the global pool.
182     */
183    public static Message obtain(Handler h, int what) {
184        Message m = obtain();
185        m.target = h;
186        m.what = what;
187
188        return m;
189    }
190
191    /**
192     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
193     * members.
194     * @param h  The <em>target</em> value to set.
195     * @param what  The <em>what</em> value to set.
196     * @param obj  The <em>object</em> method to set.
197     * @return  A Message object from the global pool.
198     */
199    public static Message obtain(Handler h, int what, Object obj) {
200        Message m = obtain();
201        m.target = h;
202        m.what = what;
203        m.obj = obj;
204
205        return m;
206    }
207
208    /**
209     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
210     * <em>arg1</em>, and <em>arg2</em> members.
211     *
212     * @param h  The <em>target</em> value to set.
213     * @param what  The <em>what</em> value to set.
214     * @param arg1  The <em>arg1</em> value to set.
215     * @param arg2  The <em>arg2</em> value to set.
216     * @return  A Message object from the global pool.
217     */
218    public static Message obtain(Handler h, int what, int arg1, int arg2) {
219        Message m = obtain();
220        m.target = h;
221        m.what = what;
222        m.arg1 = arg1;
223        m.arg2 = arg2;
224
225        return m;
226    }
227
228    /**
229     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
230     * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
231     *
232     * @param h  The <em>target</em> value to set.
233     * @param what  The <em>what</em> value to set.
234     * @param arg1  The <em>arg1</em> value to set.
235     * @param arg2  The <em>arg2</em> value to set.
236     * @param obj  The <em>obj</em> value to set.
237     * @return  A Message object from the global pool.
238     */
239    public static Message obtain(Handler h, int what,
240            int arg1, int arg2, Object obj) {
241        Message m = obtain();
242        m.target = h;
243        m.what = what;
244        m.arg1 = arg1;
245        m.arg2 = arg2;
246        m.obj = obj;
247
248        return m;
249    }
250
251    /**
252     * Return a Message instance to the global pool.
253     * <p>
254     * You MUST NOT touch the Message after calling this function because it has
255     * effectively been freed.  It is an error to recycle a message that is currently
256     * enqueued or that is in the process of being delivered to a Handler.
257     * </p>
258     */
259    public void recycle() {
260        if (isInUse()) {
261            throw new IllegalStateException("This message cannot be recycled because it "
262                    + "is still in use.");
263        }
264        recycleUnchecked();
265    }
266
267    /**
268     * Recycles a Message that may be in-use.
269     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
270     */
271    void recycleUnchecked() {
272        // Mark the message as in use while it remains in the recycled object pool.
273        // Clear out all other details.
274        flags = FLAG_IN_USE;
275        what = 0;
276        arg1 = 0;
277        arg2 = 0;
278        obj = null;
279        replyTo = null;
280        when = 0;
281        target = null;
282        callback = null;
283        data = null;
284
285        synchronized (sPoolSync) {
286            if (sPoolSize < MAX_POOL_SIZE) {
287                next = sPool;
288                sPool = this;
289                sPoolSize++;
290            }
291        }
292    }
293
294    /**
295     * Make this message like o.  Performs a shallow copy of the data field.
296     * Does not copy the linked list fields, nor the timestamp or
297     * target/callback of the original message.
298     */
299    public void copyFrom(Message o) {
300        this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
301        this.what = o.what;
302        this.arg1 = o.arg1;
303        this.arg2 = o.arg2;
304        this.obj = o.obj;
305        this.replyTo = o.replyTo;
306
307        if (o.data != null) {
308            this.data = (Bundle) o.data.clone();
309        } else {
310            this.data = null;
311        }
312    }
313
314    /**
315     * Return the targeted delivery time of this message, in milliseconds.
316     */
317    public long getWhen() {
318        return when;
319    }
320
321    public void setTarget(Handler target) {
322        this.target = target;
323    }
324
325    /**
326     * Retrieve the a {@link android.os.Handler Handler} implementation that
327     * will receive this message. The object must implement
328     * {@link android.os.Handler#handleMessage(android.os.Message)
329     * Handler.handleMessage()}. Each Handler has its own name-space for
330     * message codes, so you do not need to
331     * worry about yours conflicting with other handlers.
332     */
333    public Handler getTarget() {
334        return target;
335    }
336
337    /**
338     * Retrieve callback object that will execute when this message is handled.
339     * This object must implement Runnable. This is called by
340     * the <em>target</em> {@link Handler} that is receiving this Message to
341     * dispatch it.  If
342     * not set, the message will be dispatched to the receiving Handler's
343     * {@link Handler#handleMessage(Message Handler.handleMessage())}.
344     */
345    public Runnable getCallback() {
346        return callback;
347    }
348
349    /**
350     * Obtains a Bundle of arbitrary data associated with this
351     * event, lazily creating it if necessary. Set this value by calling
352     * {@link #setData(Bundle)}.  Note that when transferring data across
353     * processes via {@link Messenger}, you will need to set your ClassLoader
354     * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
355     * Bundle.setClassLoader()} so that it can instantiate your objects when
356     * you retrieve them.
357     * @see #peekData()
358     * @see #setData(Bundle)
359     */
360    public Bundle getData() {
361        if (data == null) {
362            data = new Bundle();
363        }
364
365        return data;
366    }
367
368    /**
369     * Like getData(), but does not lazily create the Bundle.  A null
370     * is returned if the Bundle does not already exist.  See
371     * {@link #getData} for further information on this.
372     * @see #getData()
373     * @see #setData(Bundle)
374     */
375    public Bundle peekData() {
376        return data;
377    }
378
379    /**
380     * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
381     * as a lower cost way to send a few simple integer values, if you can.
382     * @see #getData()
383     * @see #peekData()
384     */
385    public void setData(Bundle data) {
386        this.data = data;
387    }
388
389    /**
390     * Sends this Message to the Handler specified by {@link #getTarget}.
391     * Throws a null pointer exception if this field has not been set.
392     */
393    public void sendToTarget() {
394        target.sendMessage(this);
395    }
396
397    /**
398     * Returns true if the message is asynchronous.
399     *
400     * Asynchronous messages represent interrupts or events that do not require global ordering
401     * with represent to synchronous messages.  Asynchronous messages are not subject to
402     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
403     *
404     * @return True if the message is asynchronous.
405     *
406     * @see #setAsynchronous(boolean)
407     * @see MessageQueue#enqueueSyncBarrier(long)
408     * @see MessageQueue#removeSyncBarrier(int)
409     *
410     * @hide
411     */
412    public boolean isAsynchronous() {
413        return (flags & FLAG_ASYNCHRONOUS) != 0;
414    }
415
416    /**
417     * Sets whether the message is asynchronous.
418     *
419     * Asynchronous messages represent interrupts or events that do not require global ordering
420     * with represent to synchronous messages.  Asynchronous messages are not subject to
421     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
422     *
423     * @param async True if the message is asynchronous.
424     *
425     * @see #isAsynchronous()
426     * @see MessageQueue#enqueueSyncBarrier(long)
427     * @see MessageQueue#removeSyncBarrier(int)
428     *
429     * @hide
430     */
431    public void setAsynchronous(boolean async) {
432        if (async) {
433            flags |= FLAG_ASYNCHRONOUS;
434        } else {
435            flags &= ~FLAG_ASYNCHRONOUS;
436        }
437    }
438
439    /*package*/ boolean isInUse() {
440        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
441    }
442
443    /*package*/ void markInUse() {
444        flags |= FLAG_IN_USE;
445    }
446
447    /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
448    */
449    public Message() {
450    }
451
452    @Override
453    public String toString() {
454        return toString(SystemClock.uptimeMillis());
455    }
456
457    String toString(long now) {
458        StringBuilder b = new StringBuilder();
459        b.append("{ when=");
460        TimeUtils.formatDuration(when - now, b);
461
462        if (target != null) {
463            if (callback != null) {
464                b.append(" callback=");
465                b.append(callback.getClass().getName());
466            } else {
467                b.append(" what=");
468                b.append(what);
469            }
470
471            if (arg1 != 0) {
472                b.append(" arg1=");
473                b.append(arg1);
474            }
475
476            if (arg2 != 0) {
477                b.append(" arg2=");
478                b.append(arg2);
479            }
480
481            if (obj != null) {
482                b.append(" obj=");
483                b.append(obj);
484            }
485
486            b.append(" target=");
487            b.append(target.getClass().getName());
488        } else {
489            b.append(" barrier=");
490            b.append(arg1);
491        }
492
493        b.append(" }");
494        return b.toString();
495    }
496
497    public static final Parcelable.Creator<Message> CREATOR
498            = new Parcelable.Creator<Message>() {
499        public Message createFromParcel(Parcel source) {
500            Message msg = Message.obtain();
501            msg.readFromParcel(source);
502            return msg;
503        }
504
505        public Message[] newArray(int size) {
506            return new Message[size];
507        }
508    };
509
510    public int describeContents() {
511        return 0;
512    }
513
514    public void writeToParcel(Parcel dest, int flags) {
515        if (callback != null) {
516            throw new RuntimeException(
517                "Can't marshal callbacks across processes.");
518        }
519        dest.writeInt(what);
520        dest.writeInt(arg1);
521        dest.writeInt(arg2);
522        if (obj != null) {
523            try {
524                Parcelable p = (Parcelable)obj;
525                dest.writeInt(1);
526                dest.writeParcelable(p, flags);
527            } catch (ClassCastException e) {
528                throw new RuntimeException(
529                    "Can't marshal non-Parcelable objects across processes.");
530            }
531        } else {
532            dest.writeInt(0);
533        }
534        dest.writeLong(when);
535        dest.writeBundle(data);
536        Messenger.writeMessengerOrNullToParcel(replyTo, dest);
537    }
538
539    private void readFromParcel(Parcel source) {
540        what = source.readInt();
541        arg1 = source.readInt();
542        arg2 = source.readInt();
543        if (source.readInt() != 0) {
544            obj = source.readParcelable(getClass().getClassLoader());
545        }
546        when = source.readLong();
547        data = source.readBundle();
548        replyTo = Messenger.readMessengerOrNullFromParcel(source);
549    }
550}
551