content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.os;
  
  import android.annotation.UnsupportedAppUsage;
  import android.util.TimeUtils;
  import android.util.proto.ProtoOutputStream;
  
  import com.android.internal.annotations.VisibleForTesting;
  
  /**
   *
   * Defines a message containing a description and arbitrary data object that can be
   * sent to a {@link Handler}.  This object contains two extra int fields and an
   * extra object field that allow you to not do allocations in many cases.
   *
   * <p class="note">While the constructor of Message is public, the best way to get
   * one of these is to call {@link #obtain Message.obtain()} or one of the
   * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
   * them from a pool of recycled objects.</p>
   */
  public final class Message implements Parcelable {
      /**
       * User-defined message code so that the recipient can identify
       * what this message is about. Each {@link Handler} has its own name-space
       * for message codes, so you do not need to worry about yours conflicting
       * with other handlers.
       */
      public int what;
  
      /**
       * arg1 and arg2 are lower-cost alternatives to using
       * {@link #setData(Bundle) setData()} if you only need to store a
       * few integer values.
       */
      public int arg1;
  
      /**
       * arg1 and arg2 are lower-cost alternatives to using
       * {@link #setData(Bundle) setData()} if you only need to store a
       * few integer values.
       */
      public int arg2;
  
      /**
       * An arbitrary object to send to the recipient.  When using
       * {@link Messenger} to send the message across processes this can only
       * be non-null if it contains a Parcelable of a framework class (not one
       * implemented by the application).   For other data transfer use
       * {@link #setData}.
       *
       * <p>Note that Parcelable objects here are not supported prior to
       * the {@link android.os.Build.VERSION_CODES#FROYO} release.
       */
      public Object obj;
  
      /**
       * Optional Messenger where replies to this message can be sent.  The
       * semantics of exactly how this is used are up to the sender and
       * receiver.
       */
      public Messenger replyTo;
  
      /**
       * Indicates that the uid is not set;
       *
       * @hide Only for use within the system server.
       */
      public static final int UID_NONE = -1;
  
      /**
       * Optional field indicating the uid that sent the message.  This is
       * only valid for messages posted by a {@link Messenger}; otherwise,
       * it will be -1.
       */
      public int sendingUid = UID_NONE;
  
      /**
       * Optional field indicating the uid that caused this message to be enqueued.
       *
       * @hide Only for use within the system server.
       */
      public int workSourceUid = UID_NONE;
  
      /** 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 */
      /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
  
      /** Flags to clear in the copyFrom method */
      /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
  
      @UnsupportedAppUsage
      /*package*/ int flags;
  
      /**
       * The targeted delivery time of this message. The time-base is
       * {@link SystemClock#uptimeMillis}.
       * @hide Only for use within the tests.
       */
      @UnsupportedAppUsage
      @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
      public long when;
  
      /*package*/ Bundle data;
  
      @UnsupportedAppUsage
      /*package*/ Handler target;
  
      @UnsupportedAppUsage
      /*package*/ Runnable callback;
  
      // sometimes we store linked lists of these things
      @UnsupportedAppUsage
      /*package*/ Message next;
  
  
      /** @hide */
      public static final Object sPoolSync = new Object();
      private static Message sPool;
      private static int sPoolSize = 0;
  
      private static final int MAX_POOL_SIZE = 50;
  
      private static boolean gCheckRecycle = true;
  
      /**
       * Return a new Message instance from the global pool. Allows us to
       * avoid allocating new objects in many cases.
       */
      public static Message obtain() {
          synchronized (sPoolSync) {
              if (sPool != null) {
                  Message m = sPool;
                  sPool = m.next;
                  m.next = null;
                  m.flags = 0; // clear in-use flag
                  sPoolSize--;
                  return m;
              }
          }
          return new Message();
      }
  
      /**
       * Same as {@link #obtain()}, but copies the values of an existing
       * message (including its target) into the new one.
       * @param orig Original message to copy.
       * @return A Message object from the global pool.
       */
      public static Message obtain(Message orig) {
          Message m = obtain();
          m.what = orig.what;
          m.arg1 = orig.arg1;
          m.arg2 = orig.arg2;
          m.obj = orig.obj;
          m.replyTo = orig.replyTo;
          m.sendingUid = orig.sendingUid;
          m.workSourceUid = orig.workSourceUid;
          if (orig.data != null) {
              m.data = new Bundle(orig.data);
          }
          m.target = orig.target;
          m.callback = orig.callback;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
       * @param h  Handler to assign to the returned Message object's <em>target</em> member.
       * @return A Message object from the global pool.
       */
      public static Message obtain(Handler h) {
          Message m = obtain();
          m.target = h;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
       * the Message that is returned.
       * @param h  Handler to assign to the returned Message object's <em>target</em> member.
       * @param callback Runnable that will execute when the message is handled.
       * @return A Message object from the global pool.
       */
      public static Message obtain(Handler h, Runnable callback) {
          Message m = obtain();
          m.target = h;
          m.callback = callback;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
       * <em>what</em> members on the Message.
       * @param h  Value to assign to the <em>target</em> member.
       * @param what  Value to assign to the <em>what</em> member.
       * @return A Message object from the global pool.
       */
      public static Message obtain(Handler h, int what) {
          Message m = obtain();
          m.target = h;
          m.what = what;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
       * members.
       * @param h  The <em>target</em> value to set.
       * @param what  The <em>what</em> value to set.
       * @param obj  The <em>object</em> method to set.
       * @return  A Message object from the global pool.
       */
      public static Message obtain(Handler h, int what, Object obj) {
          Message m = obtain();
          m.target = h;
          m.what = what;
          m.obj = obj;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
       * <em>arg1</em>, and <em>arg2</em> members.
       *
       * @param h  The <em>target</em> value to set.
       * @param what  The <em>what</em> value to set.
       * @param arg1  The <em>arg1</em> value to set.
       * @param arg2  The <em>arg2</em> value to set.
       * @return  A Message object from the global pool.
       */
      public static Message obtain(Handler h, int what, int arg1, int arg2) {
          Message m = obtain();
          m.target = h;
          m.what = what;
          m.arg1 = arg1;
          m.arg2 = arg2;
  
          return m;
      }
  
      /**
       * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
       * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
       *
       * @param h  The <em>target</em> value to set.
       * @param what  The <em>what</em> value to set.
       * @param arg1  The <em>arg1</em> value to set.
       * @param arg2  The <em>arg2</em> value to set.
       * @param obj  The <em>obj</em> value to set.
       * @return  A Message object from the global pool.
       */
      public static Message obtain(Handler h, int what,
              int arg1, int arg2, Object obj) {
          Message m = obtain();
          m.target = h;
          m.what = what;
          m.arg1 = arg1;
          m.arg2 = arg2;
          m.obj = obj;
  
          return m;
      }
  
      /** @hide */
      public static void updateCheckRecycle(int targetSdkVersion) {
          if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
              gCheckRecycle = false;
          }
      }
  
      /**
       * 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() {
          if (isInUse()) {
              if (gCheckRecycle) {
                  throw new IllegalStateException("This message cannot be recycled because it "
                          + "is still in use.");
              }
              return;
          }
          recycleUnchecked();
      }
  
      /**
       * Recycles a Message that may be in-use.
       * Used internally by the MessageQueue and Looper when disposing of queued Messages.
       */
      @UnsupportedAppUsage
      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;
          sendingUid = UID_NONE;
          workSourceUid = UID_NONE;
          when = 0;
          target = null;
          callback = null;
          data = null;
  
          synchronized (sPoolSync) {
              if (sPoolSize < MAX_POOL_SIZE) {
                  next = sPool;
                  sPool = this;
                  sPoolSize++;
              }
          }
      }
  
      /**
       * Make this message like o.  Performs a shallow copy of the data field.
       * Does not copy the linked list fields, nor the timestamp or
       * target/callback of the original message.
       */
      public void copyFrom(Message o) {
          this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
          this.what = o.what;
          this.arg1 = o.arg1;
          this.arg2 = o.arg2;
          this.obj = o.obj;
          this.replyTo = o.replyTo;
          this.sendingUid = o.sendingUid;
          this.workSourceUid = o.workSourceUid;
  
          if (o.data != null) {
              this.data = (Bundle) o.data.clone();
          } else {
              this.data = null;
          }
      }
  
      /**
       * Return the targeted delivery time of this message, in milliseconds.
       */
      public long getWhen() {
          return when;
      }
  
      public void setTarget(Handler target) {
          this.target = target;
      }
  
      /**
       * Retrieve the {@link android.os.Handler Handler} implementation that
       * will receive this message. The object must implement
       * {@link android.os.Handler#handleMessage(android.os.Message)
       * Handler.handleMessage()}. Each Handler has its own name-space for
       * message codes, so you do not need to
       * worry about yours conflicting with other handlers.
       */
      public Handler getTarget() {
          return target;
      }
  
      /**
       * Retrieve callback object that will execute when this message is handled.
       * This object must implement Runnable. This is called by
       * the <em>target</em> {@link Handler} that is receiving this Message to
       * dispatch it.  If
       * not set, the message will be dispatched to the receiving Handler's
       * {@link Handler#handleMessage(Message)}.
       */
      public Runnable getCallback() {
          return callback;
      }
  
      /** @hide */
      @UnsupportedAppUsage
      public Message setCallback(Runnable r) {
          callback = r;
          return this;
      }
  
      /**
       * Obtains a Bundle of arbitrary data associated with this
       * event, lazily creating it if necessary. Set this value by calling
       * {@link #setData(Bundle)}.  Note that when transferring data across
       * processes via {@link Messenger}, you will need to set your ClassLoader
       * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
       * Bundle.setClassLoader()} so that it can instantiate your objects when
       * you retrieve them.
       * @see #peekData()
       * @see #setData(Bundle)
       */
      public Bundle getData() {
          if (data == null) {
              data = new Bundle();
          }
  
          return data;
      }
  
      /**
       * Like getData(), but does not lazily create the Bundle.  A null
       * is returned if the Bundle does not already exist.  See
       * {@link #getData} for further information on this.
       * @see #getData()
       * @see #setData(Bundle)
       */
      public Bundle peekData() {
          return data;
      }
  
      /**
       * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
       * as a lower cost way to send a few simple integer values, if you can.
       * @see #getData()
       * @see #peekData()
       */
      public void setData(Bundle data) {
          this.data = data;
      }
  
      /**
       * Chainable setter for {@link #what}
       *
       * @hide
       */
      public Message setWhat(int what) {
          this.what = what;
          return this;
      }
  
      /**
       * Sends this Message to the Handler specified by {@link #getTarget}.
       * Throws a null pointer exception if this field has not been set.
       */
      public void sendToTarget() {
          target.sendMessage(this);
      }
  
      /**
       * Returns true if the message is asynchronous, meaning that it is not
       * subject to {@link Looper} synchronization barriers.
       *
       * @return True if the message is asynchronous.
       *
       * @see #setAsynchronous(boolean)
       */
      public boolean isAsynchronous() {
          return (flags & FLAG_ASYNCHRONOUS) != 0;
      }
  
      /**
       * Sets whether the message is asynchronous, meaning that it is not
       * subject to {@link Looper} synchronization barriers.
       * <p>
       * Certain operations, such as view invalidation, may introduce synchronization
       * barriers into the {@link Looper}'s message queue to prevent subsequent messages
       * from being delivered until some condition is met.  In the case of view invalidation,
       * messages which are posted after a call to {@link android.view.View#invalidate}
       * are suspended by means of a synchronization barrier until the next frame is
       * ready to be drawn.  The synchronization barrier ensures that the invalidation
       * request is completely handled before resuming.
       * </p><p>
       * Asynchronous messages are exempt from synchronization barriers.  They typically
       * represent interrupts, input events, and other signals that must be handled independently
       * even while other work has been suspended.
       * </p><p>
       * Note that asynchronous messages may be delivered out of order with respect to
       * synchronous messages although they are always delivered in order among themselves.
       * If the relative order of these messages matters then they probably should not be
       * asynchronous in the first place.  Use with caution.
       * </p>
       *
       * @param async True if the message is asynchronous.
       *
       * @see #isAsynchronous()
       */
      public void setAsynchronous(boolean async) {
          if (async) {
              flags |= FLAG_ASYNCHRONOUS;
          } else {
              flags &= ~FLAG_ASYNCHRONOUS;
          }
      }
  
      /*package*/ boolean isInUse() {
          return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
      }
  
      @UnsupportedAppUsage
      /*package*/ void markInUse() {
          flags |= FLAG_IN_USE;
      }
  
      /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
      */
      public Message() {
      }
  
      @Override
      public String toString() {
          return toString(SystemClock.uptimeMillis());
      }
  
      @UnsupportedAppUsage
      String toString(long now) {
          StringBuilder b = new StringBuilder();
          b.append("{ when=");
          TimeUtils.formatDuration(when - now, b);
  
          if (target != null) {
              if (callback != null) {
                  b.append(" callback=");
                  b.append(callback.getClass().getName());
              } else {
                  b.append(" what=");
                  b.append(what);
              }
  
              if (arg1 != 0) {
                  b.append(" arg1=");
                  b.append(arg1);
              }
  
              if (arg2 != 0) {
                  b.append(" arg2=");
                  b.append(arg2);
              }
  
              if (obj != null) {
                  b.append(" obj=");
                  b.append(obj);
              }
  
              b.append(" target=");
              b.append(target.getClass().getName());
          } else {
              b.append(" barrier=");
              b.append(arg1);
          }
  
          b.append(" }");
          return b.toString();
      }
  
      void writeToProto(ProtoOutputStream proto, long fieldId) {
          final long messageToken = proto.start(fieldId);
          proto.write(MessageProto.WHEN, when);
  
          if (target != null) {
              if (callback != null) {
                  proto.write(MessageProto.CALLBACK, callback.getClass().getName());
              } else {
                  proto.write(MessageProto.WHAT, what);
              }
  
              if (arg1 != 0) {
                  proto.write(MessageProto.ARG1, arg1);
              }
  
              if (arg2 != 0) {
                  proto.write(MessageProto.ARG2, arg2);
              }
  
              if (obj != null) {
                  proto.write(MessageProto.OBJ, obj.toString());
              }
  
              proto.write(MessageProto.TARGET, target.getClass().getName());
          } else {
              proto.write(MessageProto.BARRIER, arg1);
          }
  
          proto.end(messageToken);
      }
  
      public static final @android.annotation.NonNull Parcelable.Creator<Message> CREATOR
              = new Parcelable.Creator<Message>() {
          public Message createFromParcel(Parcel source) {
              Message msg = Message.obtain();
              msg.readFromParcel(source);
              return msg;
          }
  
          public Message[] newArray(int size) {
              return new Message[size];
          }
      };
  
      public int describeContents() {
          return 0;
      }
  
      public void writeToParcel(Parcel dest, int flags) {
          if (callback != null) {
              throw new RuntimeException(
                  "Can't marshal callbacks across processes.");
          }
          dest.writeInt(what);
          dest.writeInt(arg1);
          dest.writeInt(arg2);
          if (obj != null) {
              try {
                  Parcelable p = (Parcelable)obj;
                  dest.writeInt(1);
                  dest.writeParcelable(p, flags);
              } catch (ClassCastException e) {
                  throw new RuntimeException(
                      "Can't marshal non-Parcelable objects across processes.");
              }
          } else {
              dest.writeInt(0);
          }
          dest.writeLong(when);
          dest.writeBundle(data);
          Messenger.writeMessengerOrNullToParcel(replyTo, dest);
          dest.writeInt(sendingUid);
          dest.writeInt(workSourceUid);
      }
  
      private void readFromParcel(Parcel source) {
          what = source.readInt();
          arg1 = source.readInt();
          arg2 = source.readInt();
          if (source.readInt() != 0) {
              obj = source.readParcelable(getClass().getClassLoader());
          }
          when = source.readLong();
          data = source.readBundle();
          replyTo = Messenger.readMessengerOrNullFromParcel(source);
          sendingUid = source.readInt();
          workSourceUid = source.readInt();
      }
  }
  