Home | History | Annotate | Download | only in util
      1 /**
      2  * Copyright (C) 2010 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 
     17 package com.android.internal.util;
     18 
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.ServiceConnection;
     23 import android.os.Handler;
     24 import android.os.HandlerThread;
     25 import android.os.IBinder;
     26 import android.os.Looper;
     27 import android.os.Message;
     28 import android.os.Messenger;
     29 import android.os.RemoteException;
     30 import android.util.Slog;
     31 
     32 import java.util.Stack;
     33 
     34 /**
     35  * <p>An asynchronous channel between two handlers.</p>
     36  *
     37  * <p>The handlers maybe in the same process or in another process. There
     38  * are two protocol styles that can be used with an AysncChannel. The
     39  * first is a simple request/reply protocol where the server does
     40  * not need to know which client is issuing the request.</p>
     41  *
     42  * <p>In a simple request/reply protocol the client/source sends requests to the
     43  * server/destination. And the server uses the replyToMessage methods.
     44  * In this usage model there is no need for the destination to
     45  * use the connect methods. The typical sequence of operations is:</p>
     46  *<ol>
     47  *   <li>Client calls AsyncChannel#connectSync or Asynchronously:</li>
     48  *      <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol>
     49  *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
     50  *      </ol>
     51  *   <li><code>comm-loop:</code></li>
     52  *   <li>Client calls AsyncChannel#sendMessage</li>
     53  *   <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage
     54  *   <li>Loop to <code>comm-loop</code> until done</li>
     55  *   <li>When done Client calls {@link AsyncChannel#disconnect}</li>
     56  *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
     57  *</ol>
     58  *<br/>
     59  * <p>A second usage model is where the server/destination needs to know
     60  * which client it's connected too. For example the server needs to
     61  * send unsolicited messages back to the client. Or the server keeps
     62  * different state for each client. In this model the server will also
     63  * use the connect methods. The typical sequence of operation is:</p>
     64  *<ol>
     65  *   <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li>
     66  *      <ol>For an asynchronous full connection it calls AsyncChannel#connect</li>
     67  *          <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
     68  *          <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
     69  *      </ol>
     70  *   <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
     71  *   <li>Server calls AsyncChannel#connected</li>
     72  *   <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
     73  *   <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
     74  *   <li><code>comm-loop:</code></li>
     75  *   <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
     76  *       to communicate and perform work</li>
     77  *   <li>Loop to <code>comm-loop</code> until done</li>
     78  *   <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li>
     79  *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
     80  *</ol>
     81  *
     82  * TODO: Consider simplifying where we have connect and fullyConnect with only one response
     83  * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and
     84  * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.
     85  */
     86 public class AsyncChannel {
     87     /** Log tag */
     88     private static final String TAG = "AsyncChannel";
     89 
     90     /** Enable to turn on debugging */
     91     private static final boolean DBG = false;
     92 
     93     private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
     94 
     95     /**
     96      * Command sent when the channel is half connected. Half connected
     97      * means that the channel can be used to send commends to the destination
     98      * but the destination is unaware that the channel exists. The first
     99      * command sent to the destination is typically CMD_CHANNEL_FULL_CONNECTION if
    100      * it is desired to establish a long term connection, but any command maybe
    101      * sent.
    102      *
    103      * msg.arg1 == 0 : STATUS_SUCCESSFUL
    104      *             1 : STATUS_BINDING_UNSUCCESSFUL
    105      * msg.obj  == the AsyncChannel
    106      * msg.replyTo == dstMessenger if successful
    107      */
    108     public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
    109 
    110     /**
    111      * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED.
    112      * This is used to initiate a long term connection with the destination and
    113      * typically the destination will reply with CMD_CHANNEL_FULLY_CONNECTED.
    114      *
    115      * msg.replyTo = srcMessenger.
    116      */
    117     public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
    118 
    119     /**
    120      * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION.
    121      * This signifies the acceptance or rejection of the channel by the sender.
    122      *
    123      * msg.arg1 == 0 : Accept connection
    124      *               : All other values signify the destination rejected the connection
    125      *                 and {@link AsyncChannel#disconnect} would typically be called.
    126      */
    127     public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
    128 
    129     /**
    130      * Command sent when one side or the other wishes to disconnect. The sender
    131      * may or may not be able to receive a reply depending upon the protocol and
    132      * the state of the connection. The receiver should call {@link AsyncChannel#disconnect}
    133      * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED
    134      * when the channel is closed.
    135      *
    136      * msg.replyTo = messenger that is disconnecting
    137      */
    138     public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
    139 
    140     /**
    141      * Command sent when the channel becomes disconnected. This is sent when the
    142      * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT.
    143      *
    144      * msg.arg1 == 0 : STATUS_SUCCESSFUL
    145      *             1 : STATUS_BINDING_UNSUCCESSFUL
    146      *             2 : STATUS_SEND_UNSUCCESSFUL
    147      *               : All other values signify failure and the channel state is indeterminate
    148      * msg.obj  == the AsyncChannel
    149      * msg.replyTo = messenger disconnecting or null if it was never connected.
    150      */
    151     public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
    152 
    153     private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED - BASE + 1;
    154     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    155     static {
    156         sCmdToString[CMD_CHANNEL_HALF_CONNECTED - BASE] = "CMD_CHANNEL_HALF_CONNECTED";
    157         sCmdToString[CMD_CHANNEL_FULL_CONNECTION - BASE] = "CMD_CHANNEL_FULL_CONNECTION";
    158         sCmdToString[CMD_CHANNEL_FULLY_CONNECTED - BASE] = "CMD_CHANNEL_FULLY_CONNECTED";
    159         sCmdToString[CMD_CHANNEL_DISCONNECT - BASE] = "CMD_CHANNEL_DISCONNECT";
    160         sCmdToString[CMD_CHANNEL_DISCONNECTED - BASE] = "CMD_CHANNEL_DISCONNECTED";
    161     }
    162     protected static String cmdToString(int cmd) {
    163         cmd -= BASE;
    164         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
    165             return sCmdToString[cmd];
    166         } else {
    167             return null;
    168         }
    169     }
    170 
    171     /** Successful status always 0, !0 is an unsuccessful status */
    172     public static final int STATUS_SUCCESSFUL = 0;
    173 
    174     /** Error attempting to bind on a connect */
    175     public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
    176 
    177     /** Error attempting to send a message */
    178     public static final int STATUS_SEND_UNSUCCESSFUL = 2;
    179 
    180     /** CMD_FULLY_CONNECTED refused because a connection already exists*/
    181     public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
    182 
    183     /** Error indicating abnormal termination of destination messenger */
    184     public static final int STATUS_REMOTE_DISCONNECTION = 4;
    185 
    186     /** Service connection */
    187     private AsyncChannelConnection mConnection;
    188 
    189     /** Context for source */
    190     private Context mSrcContext;
    191 
    192     /** Handler for source */
    193     private Handler mSrcHandler;
    194 
    195     /** Messenger for source */
    196     private Messenger mSrcMessenger;
    197 
    198     /** Messenger for destination */
    199     private Messenger mDstMessenger;
    200 
    201     /** Death Monitor for destination messenger */
    202     private DeathMonitor mDeathMonitor;
    203 
    204     /**
    205      * AsyncChannel constructor
    206      */
    207     public AsyncChannel() {
    208     }
    209 
    210     /**
    211      * Connect handler to named package/class synchronously.
    212      *
    213      * @param srcContext is the context of the source
    214      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    215      *            messages
    216      * @param dstPackageName is the destination package name
    217      * @param dstClassName is the fully qualified class name (i.e. contains
    218      *            package name)
    219      *
    220      * @return STATUS_SUCCESSFUL on success any other value is an error.
    221      */
    222     public int connectSrcHandlerToPackageSync(
    223             Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
    224         if (DBG) log("connect srcHandler to dst Package & class E");
    225 
    226         mConnection = new AsyncChannelConnection();
    227 
    228         /* Initialize the source information */
    229         mSrcContext = srcContext;
    230         mSrcHandler = srcHandler;
    231         mSrcMessenger = new Messenger(srcHandler);
    232 
    233         /*
    234          * Initialize destination information to null they will
    235          * be initialized when the AsyncChannelConnection#onServiceConnected
    236          * is called
    237          */
    238         mDstMessenger = null;
    239 
    240         /* Send intent to create the connection */
    241         Intent intent = new Intent(Intent.ACTION_MAIN);
    242         intent.setClassName(dstPackageName, dstClassName);
    243         boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    244         if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
    245         return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
    246     }
    247 
    248     /**
    249      * Connect a handler to Messenger synchronously.
    250      *
    251      * @param srcContext is the context of the source
    252      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    253      *            messages
    254      * @param dstMessenger is the hander to send messages to.
    255      *
    256      * @return STATUS_SUCCESSFUL on success any other value is an error.
    257      */
    258     public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    259         if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");
    260 
    261         // We are connected
    262         connected(srcContext, srcHandler, dstMessenger);
    263 
    264         if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
    265         return STATUS_SUCCESSFUL;
    266     }
    267 
    268     /**
    269      * connect two local Handlers synchronously.
    270      *
    271      * @param srcContext is the context of the source
    272      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    273      *            messages
    274      * @param dstHandler is the hander to send messages to.
    275      *
    276      * @return STATUS_SUCCESSFUL on success any other value is an error.
    277      */
    278     public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
    279         return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
    280     }
    281 
    282     /**
    283      * Fully connect two local Handlers synchronously.
    284      *
    285      * @param srcContext is the context of the source
    286      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    287      *            messages
    288      * @param dstHandler is the hander to send messages to.
    289      *
    290      * @return STATUS_SUCCESSFUL on success any other value is an error.
    291      */
    292     public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
    293         int status = connectSync(srcContext, srcHandler, dstHandler);
    294         if (status == STATUS_SUCCESSFUL) {
    295             Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
    296             status = response.arg1;
    297         }
    298         return status;
    299     }
    300 
    301     /**
    302      * Connect handler to named package/class.
    303      *
    304      * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
    305      *      msg.arg1 = status
    306      *      msg.obj = the AsyncChannel
    307      *
    308      * @param srcContext is the context of the source
    309      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    310      *            messages
    311      * @param dstPackageName is the destination package name
    312      * @param dstClassName is the fully qualified class name (i.e. contains
    313      *            package name)
    314      */
    315     public void connect(Context srcContext, Handler srcHandler, String dstPackageName,
    316             String dstClassName) {
    317         if (DBG) log("connect srcHandler to dst Package & class E");
    318 
    319         final class ConnectAsync implements Runnable {
    320             Context mSrcCtx;
    321             Handler mSrcHdlr;
    322             String mDstPackageName;
    323             String mDstClassName;
    324 
    325             ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName,
    326                     String dstClassName) {
    327                 mSrcCtx = srcContext;
    328                 mSrcHdlr = srcHandler;
    329                 mDstPackageName = dstPackageName;
    330                 mDstClassName = dstClassName;
    331             }
    332 
    333             @Override
    334             public void run() {
    335                 int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
    336                         mDstClassName);
    337                 replyHalfConnected(result);
    338             }
    339         }
    340 
    341         ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName);
    342         new Thread(ca).start();
    343 
    344         if (DBG) log("connect srcHandler to dst Package & class X");
    345     }
    346 
    347     /**
    348      * Connect handler to a class
    349      *
    350      * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
    351      *      msg.arg1 = status
    352      *      msg.obj = the AsyncChannel
    353      *
    354      * @param srcContext
    355      * @param srcHandler
    356      * @param klass is the class to send messages to.
    357      */
    358     public void connect(Context srcContext, Handler srcHandler, Class<?> klass) {
    359         connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName());
    360     }
    361 
    362     /**
    363      * Connect handler and messenger.
    364      *
    365      * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
    366      *      msg.arg1 = status
    367      *      msg.obj = the AsyncChannel
    368      *
    369      * @param srcContext
    370      * @param srcHandler
    371      * @param dstMessenger
    372      */
    373     public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    374         if (DBG) log("connect srcHandler to the dstMessenger  E");
    375 
    376         // We are connected
    377         connected(srcContext, srcHandler, dstMessenger);
    378 
    379         // Tell source we are half connected
    380         replyHalfConnected(STATUS_SUCCESSFUL);
    381 
    382         if (DBG) log("connect srcHandler to the dstMessenger X");
    383     }
    384 
    385     /**
    386      * Connect handler to messenger. This method is typically called
    387      * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
    388      * and initializes the internal instance variables to allow communication
    389      * with the dstMessenger.
    390      *
    391      * @param srcContext
    392      * @param srcHandler
    393      * @param dstMessenger
    394      */
    395     public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    396         if (DBG) log("connected srcHandler to the dstMessenger  E");
    397 
    398         // Initialize source fields
    399         mSrcContext = srcContext;
    400         mSrcHandler = srcHandler;
    401         mSrcMessenger = new Messenger(mSrcHandler);
    402 
    403         // Initialize destination fields
    404         mDstMessenger = dstMessenger;
    405         linkToDeathMonitor();
    406         if (DBG) log("connected srcHandler to the dstMessenger X");
    407     }
    408 
    409     /**
    410      * Connect two local Handlers.
    411      *
    412      * @param srcContext is the context of the source
    413      * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
    414      *            messages
    415      * @param dstHandler is the hander to send messages to.
    416      */
    417     public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) {
    418         connect(srcContext, srcHandler, new Messenger(dstHandler));
    419     }
    420 
    421     /**
    422      * Connect service and messenger.
    423      *
    424      * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete.
    425      *      msg.arg1 = status
    426      *      msg.obj = the AsyncChannel
    427      *
    428      * @param srcAsyncService
    429      * @param dstMessenger
    430      */
    431     public void connect(AsyncService srcAsyncService, Messenger dstMessenger) {
    432         connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger);
    433     }
    434 
    435     /**
    436      * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED
    437      */
    438     public void disconnected() {
    439         mSrcContext = null;
    440         mSrcHandler = null;
    441         mSrcMessenger = null;
    442         mDstMessenger = null;
    443         mDeathMonitor = null;
    444         mConnection = null;
    445     }
    446 
    447     /**
    448      * Disconnect
    449      */
    450     public void disconnect() {
    451         if ((mConnection != null) && (mSrcContext != null)) {
    452             mSrcContext.unbindService(mConnection);
    453             mConnection = null;
    454         }
    455         try {
    456             // Send the DISCONNECTED, although it may not be received
    457             // but its the best we can do.
    458             Message msg = Message.obtain();
    459             msg.what = CMD_CHANNEL_DISCONNECTED;
    460             msg.replyTo = mSrcMessenger;
    461             mDstMessenger.send(msg);
    462         } catch(Exception e) {
    463         }
    464         // Tell source we're disconnected.
    465         replyDisconnected(STATUS_SUCCESSFUL);
    466         mSrcHandler = null;
    467         // Unlink only when bindService isn't used
    468         if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
    469             mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
    470             mDeathMonitor = null;
    471         }
    472     }
    473 
    474     /**
    475      * Send a message to the destination handler.
    476      *
    477      * @param msg
    478      */
    479     public void sendMessage(Message msg) {
    480         msg.replyTo = mSrcMessenger;
    481         try {
    482             mDstMessenger.send(msg);
    483         } catch (RemoteException e) {
    484             replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
    485         }
    486     }
    487 
    488     /**
    489      * Send a message to the destination handler
    490      *
    491      * @param what
    492      */
    493     public void sendMessage(int what) {
    494         Message msg = Message.obtain();
    495         msg.what = what;
    496         sendMessage(msg);
    497     }
    498 
    499     /**
    500      * Send a message to the destination handler
    501      *
    502      * @param what
    503      * @param arg1
    504      */
    505     public void sendMessage(int what, int arg1) {
    506         Message msg = Message.obtain();
    507         msg.what = what;
    508         msg.arg1 = arg1;
    509         sendMessage(msg);
    510     }
    511 
    512     /**
    513      * Send a message to the destination handler
    514      *
    515      * @param what
    516      * @param arg1
    517      * @param arg2
    518      */
    519     public void sendMessage(int what, int arg1, int arg2) {
    520         Message msg = Message.obtain();
    521         msg.what = what;
    522         msg.arg1 = arg1;
    523         msg.arg2 = arg2;
    524         sendMessage(msg);
    525     }
    526 
    527     /**
    528      * Send a message to the destination handler
    529      *
    530      * @param what
    531      * @param arg1
    532      * @param arg2
    533      * @param obj
    534      */
    535     public void sendMessage(int what, int arg1, int arg2, Object obj) {
    536         Message msg = Message.obtain();
    537         msg.what = what;
    538         msg.arg1 = arg1;
    539         msg.arg2 = arg2;
    540         msg.obj = obj;
    541         sendMessage(msg);
    542     }
    543 
    544     /**
    545      * Send a message to the destination handler
    546      *
    547      * @param what
    548      * @param obj
    549      */
    550     public void sendMessage(int what, Object obj) {
    551         Message msg = Message.obtain();
    552         msg.what = what;
    553         msg.obj = obj;
    554         sendMessage(msg);
    555     }
    556 
    557     /**
    558      * Reply to srcMsg sending dstMsg
    559      *
    560      * @param srcMsg
    561      * @param dstMsg
    562      */
    563     public void replyToMessage(Message srcMsg, Message dstMsg) {
    564         try {
    565             dstMsg.replyTo = mSrcMessenger;
    566             srcMsg.replyTo.send(dstMsg);
    567         } catch (RemoteException e) {
    568             log("TODO: handle replyToMessage RemoteException" + e);
    569             e.printStackTrace();
    570         }
    571     }
    572 
    573     /**
    574      * Reply to srcMsg
    575      *
    576      * @param srcMsg
    577      * @param what
    578      */
    579     public void replyToMessage(Message srcMsg, int what) {
    580         Message msg = Message.obtain();
    581         msg.what = what;
    582         replyToMessage(srcMsg, msg);
    583     }
    584 
    585     /**
    586      * Reply to srcMsg
    587      *
    588      * @param srcMsg
    589      * @param what
    590      * @param arg1
    591      */
    592     public void replyToMessage(Message srcMsg, int what, int arg1) {
    593         Message msg = Message.obtain();
    594         msg.what = what;
    595         msg.arg1 = arg1;
    596         replyToMessage(srcMsg, msg);
    597     }
    598 
    599     /**
    600      * Reply to srcMsg
    601      *
    602      * @param srcMsg
    603      * @param what
    604      * @param arg1
    605      * @param arg2
    606      */
    607     public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) {
    608         Message msg = Message.obtain();
    609         msg.what = what;
    610         msg.arg1 = arg1;
    611         msg.arg2 = arg2;
    612         replyToMessage(srcMsg, msg);
    613     }
    614 
    615     /**
    616      * Reply to srcMsg
    617      *
    618      * @param srcMsg
    619      * @param what
    620      * @param arg1
    621      * @param arg2
    622      * @param obj
    623      */
    624     public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) {
    625         Message msg = Message.obtain();
    626         msg.what = what;
    627         msg.arg1 = arg1;
    628         msg.arg2 = arg2;
    629         msg.obj = obj;
    630         replyToMessage(srcMsg, msg);
    631     }
    632 
    633     /**
    634      * Reply to srcMsg
    635      *
    636      * @param srcMsg
    637      * @param what
    638      * @param obj
    639      */
    640     public void replyToMessage(Message srcMsg, int what, Object obj) {
    641         Message msg = Message.obtain();
    642         msg.what = what;
    643         msg.obj = obj;
    644         replyToMessage(srcMsg, msg);
    645     }
    646 
    647     /**
    648      * Send the Message synchronously.
    649      *
    650      * @param msg to send
    651      * @return reply message or null if an error.
    652      */
    653     public Message sendMessageSynchronously(Message msg) {
    654         Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
    655         return resultMsg;
    656     }
    657 
    658     /**
    659      * Send the Message synchronously.
    660      *
    661      * @param what
    662      * @return reply message or null if an error.
    663      */
    664     public Message sendMessageSynchronously(int what) {
    665         Message msg = Message.obtain();
    666         msg.what = what;
    667         Message resultMsg = sendMessageSynchronously(msg);
    668         return resultMsg;
    669     }
    670 
    671     /**
    672      * Send the Message synchronously.
    673      *
    674      * @param what
    675      * @param arg1
    676      * @return reply message or null if an error.
    677      */
    678     public Message sendMessageSynchronously(int what, int arg1) {
    679         Message msg = Message.obtain();
    680         msg.what = what;
    681         msg.arg1 = arg1;
    682         Message resultMsg = sendMessageSynchronously(msg);
    683         return resultMsg;
    684     }
    685 
    686     /**
    687      * Send the Message synchronously.
    688      *
    689      * @param what
    690      * @param arg1
    691      * @param arg2
    692      * @return reply message or null if an error.
    693      */
    694     public Message sendMessageSynchronously(int what, int arg1, int arg2) {
    695         Message msg = Message.obtain();
    696         msg.what = what;
    697         msg.arg1 = arg1;
    698         msg.arg2 = arg2;
    699         Message resultMsg = sendMessageSynchronously(msg);
    700         return resultMsg;
    701     }
    702 
    703     /**
    704      * Send the Message synchronously.
    705      *
    706      * @param what
    707      * @param arg1
    708      * @param arg2
    709      * @param obj
    710      * @return reply message or null if an error.
    711      */
    712     public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) {
    713         Message msg = Message.obtain();
    714         msg.what = what;
    715         msg.arg1 = arg1;
    716         msg.arg2 = arg2;
    717         msg.obj = obj;
    718         Message resultMsg = sendMessageSynchronously(msg);
    719         return resultMsg;
    720     }
    721 
    722     /**
    723      * Send the Message synchronously.
    724      *
    725      * @param what
    726      * @param obj
    727      * @return reply message or null if an error.
    728      */
    729     public Message sendMessageSynchronously(int what, Object obj) {
    730         Message msg = Message.obtain();
    731         msg.what = what;
    732         msg.obj = obj;
    733         Message resultMsg = sendMessageSynchronously(msg);
    734         return resultMsg;
    735     }
    736 
    737     /**
    738      * Helper class to send messages synchronously
    739      */
    740     private static class SyncMessenger {
    741         /** A stack of SyncMessengers */
    742         private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>();
    743         /** A number of SyncMessengers created */
    744         private static int sCount = 0;
    745         /** The handler thread */
    746         private HandlerThread mHandlerThread;
    747         /** The handler that will receive the result */
    748         private SyncHandler mHandler;
    749         /** The messenger used to send the message */
    750         private Messenger mMessenger;
    751 
    752         /** private constructor */
    753         private SyncMessenger() {
    754         }
    755 
    756         /** Synchronous Handler class */
    757         private class SyncHandler extends Handler {
    758             /** The object used to wait/notify */
    759             private Object mLockObject = new Object();
    760             /** The resulting message */
    761             private Message mResultMsg;
    762 
    763             /** Constructor */
    764             private SyncHandler(Looper looper) {
    765                 super(looper);
    766             }
    767 
    768             /** Handle of the reply message */
    769             @Override
    770             public void handleMessage(Message msg) {
    771                 mResultMsg = Message.obtain();
    772                 mResultMsg.copyFrom(msg);
    773                 synchronized(mLockObject) {
    774                     mLockObject.notify();
    775                 }
    776             }
    777         }
    778 
    779         /**
    780          * @return the SyncMessenger
    781          */
    782         private static SyncMessenger obtain() {
    783             SyncMessenger sm;
    784             synchronized (sStack) {
    785                 if (sStack.isEmpty()) {
    786                     sm = new SyncMessenger();
    787                     sm.mHandlerThread = new HandlerThread("SyncHandler-" + sCount++);
    788                     sm.mHandlerThread.start();
    789                     sm.mHandler = sm.new SyncHandler(sm.mHandlerThread.getLooper());
    790                     sm.mMessenger = new Messenger(sm.mHandler);
    791                 } else {
    792                     sm = sStack.pop();
    793                 }
    794             }
    795             return sm;
    796         }
    797 
    798         /**
    799          * Recycle this object
    800          */
    801         private void recycle() {
    802             synchronized (sStack) {
    803                 sStack.push(this);
    804             }
    805         }
    806 
    807         /**
    808          * Send a message synchronously.
    809          *
    810          * @param msg to send
    811          * @return result message or null if an error occurs
    812          */
    813         private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
    814             SyncMessenger sm = SyncMessenger.obtain();
    815             try {
    816                 if (dstMessenger != null && msg != null) {
    817                     msg.replyTo = sm.mMessenger;
    818                     synchronized (sm.mHandler.mLockObject) {
    819                         dstMessenger.send(msg);
    820                         sm.mHandler.mLockObject.wait();
    821                     }
    822                 } else {
    823                     sm.mHandler.mResultMsg = null;
    824                 }
    825             } catch (InterruptedException e) {
    826                 sm.mHandler.mResultMsg = null;
    827             } catch (RemoteException e) {
    828                 sm.mHandler.mResultMsg = null;
    829             }
    830             Message resultMsg = sm.mHandler.mResultMsg;
    831             sm.recycle();
    832             return resultMsg;
    833         }
    834     }
    835 
    836     /**
    837      * Reply to the src handler that we're half connected.
    838      * see: CMD_CHANNEL_HALF_CONNECTED for message contents
    839      *
    840      * @param status to be stored in msg.arg1
    841      */
    842     private void replyHalfConnected(int status) {
    843         Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
    844         msg.arg1 = status;
    845         msg.obj = this;
    846         msg.replyTo = mDstMessenger;
    847         if (!linkToDeathMonitor()) {
    848             // Override status to indicate failure
    849             msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
    850         }
    851 
    852         mSrcHandler.sendMessage(msg);
    853     }
    854 
    855     /**
    856      * Link to death monitor for destination messenger. Returns true if successfully binded to
    857      * destination messenger; false otherwise.
    858      */
    859     private boolean linkToDeathMonitor() {
    860         // Link to death only when bindService isn't used and not already linked.
    861         if (mConnection == null && mDeathMonitor == null) {
    862             mDeathMonitor = new DeathMonitor();
    863             try {
    864                 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
    865             } catch (RemoteException e) {
    866                 mDeathMonitor = null;
    867                 return false;
    868             }
    869         }
    870         return true;
    871     }
    872 
    873     /**
    874      * Reply to the src handler that we are disconnected
    875      * see: CMD_CHANNEL_DISCONNECTED for message contents
    876      *
    877      * @param status to be stored in msg.arg1
    878      */
    879     private void replyDisconnected(int status) {
    880         // Can't reply if already disconnected. Avoid NullPointerException.
    881         if (mSrcHandler == null) return;
    882         Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
    883         msg.arg1 = status;
    884         msg.obj = this;
    885         msg.replyTo = mDstMessenger;
    886         mSrcHandler.sendMessage(msg);
    887     }
    888 
    889 
    890     /**
    891      * ServiceConnection to receive call backs.
    892      */
    893     class AsyncChannelConnection implements ServiceConnection {
    894         AsyncChannelConnection() {
    895         }
    896 
    897         @Override
    898         public void onServiceConnected(ComponentName className, IBinder service) {
    899             mDstMessenger = new Messenger(service);
    900             replyHalfConnected(STATUS_SUCCESSFUL);
    901         }
    902 
    903         @Override
    904         public void onServiceDisconnected(ComponentName className) {
    905             replyDisconnected(STATUS_SUCCESSFUL);
    906         }
    907     }
    908 
    909     /**
    910      * Log the string.
    911      *
    912      * @param s
    913      */
    914     private static void log(String s) {
    915         Slog.d(TAG, s);
    916     }
    917 
    918     private final class DeathMonitor implements IBinder.DeathRecipient {
    919 
    920         DeathMonitor() {
    921         }
    922 
    923         public void binderDied() {
    924             replyDisconnected(STATUS_REMOTE_DISCONNECTION);
    925         }
    926 
    927     }
    928 }
    929