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 
    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         if (mSrcHandler != null) {
    466             replyDisconnected(STATUS_SUCCESSFUL);
    467             mSrcHandler = null;
    468         }
    469         // Unlink only when bindService isn't used
    470         if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
    471             mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
    472             mDeathMonitor = null;
    473         }
    474     }
    475 
    476     /**
    477      * Send a message to the destination handler.
    478      *
    479      * @param msg
    480      */
    481     public void sendMessage(Message msg) {
    482         msg.replyTo = mSrcMessenger;
    483         try {
    484             mDstMessenger.send(msg);
    485         } catch (RemoteException e) {
    486             replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
    487         }
    488     }
    489 
    490     /**
    491      * Send a message to the destination handler
    492      *
    493      * @param what
    494      */
    495     public void sendMessage(int what) {
    496         Message msg = Message.obtain();
    497         msg.what = what;
    498         sendMessage(msg);
    499     }
    500 
    501     /**
    502      * Send a message to the destination handler
    503      *
    504      * @param what
    505      * @param arg1
    506      */
    507     public void sendMessage(int what, int arg1) {
    508         Message msg = Message.obtain();
    509         msg.what = what;
    510         msg.arg1 = arg1;
    511         sendMessage(msg);
    512     }
    513 
    514     /**
    515      * Send a message to the destination handler
    516      *
    517      * @param what
    518      * @param arg1
    519      * @param arg2
    520      */
    521     public void sendMessage(int what, int arg1, int arg2) {
    522         Message msg = Message.obtain();
    523         msg.what = what;
    524         msg.arg1 = arg1;
    525         msg.arg2 = arg2;
    526         sendMessage(msg);
    527     }
    528 
    529     /**
    530      * Send a message to the destination handler
    531      *
    532      * @param what
    533      * @param arg1
    534      * @param arg2
    535      * @param obj
    536      */
    537     public void sendMessage(int what, int arg1, int arg2, Object obj) {
    538         Message msg = Message.obtain();
    539         msg.what = what;
    540         msg.arg1 = arg1;
    541         msg.arg2 = arg2;
    542         msg.obj = obj;
    543         sendMessage(msg);
    544     }
    545 
    546     /**
    547      * Send a message to the destination handler
    548      *
    549      * @param what
    550      * @param obj
    551      */
    552     public void sendMessage(int what, Object obj) {
    553         Message msg = Message.obtain();
    554         msg.what = what;
    555         msg.obj = obj;
    556         sendMessage(msg);
    557     }
    558 
    559     /**
    560      * Reply to srcMsg sending dstMsg
    561      *
    562      * @param srcMsg
    563      * @param dstMsg
    564      */
    565     public void replyToMessage(Message srcMsg, Message dstMsg) {
    566         try {
    567             dstMsg.replyTo = mSrcMessenger;
    568             srcMsg.replyTo.send(dstMsg);
    569         } catch (RemoteException e) {
    570             log("TODO: handle replyToMessage RemoteException" + e);
    571             e.printStackTrace();
    572         }
    573     }
    574 
    575     /**
    576      * Reply to srcMsg
    577      *
    578      * @param srcMsg
    579      * @param what
    580      */
    581     public void replyToMessage(Message srcMsg, int what) {
    582         Message msg = Message.obtain();
    583         msg.what = what;
    584         replyToMessage(srcMsg, msg);
    585     }
    586 
    587     /**
    588      * Reply to srcMsg
    589      *
    590      * @param srcMsg
    591      * @param what
    592      * @param arg1
    593      */
    594     public void replyToMessage(Message srcMsg, int what, int arg1) {
    595         Message msg = Message.obtain();
    596         msg.what = what;
    597         msg.arg1 = arg1;
    598         replyToMessage(srcMsg, msg);
    599     }
    600 
    601     /**
    602      * Reply to srcMsg
    603      *
    604      * @param srcMsg
    605      * @param what
    606      * @param arg1
    607      * @param arg2
    608      */
    609     public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) {
    610         Message msg = Message.obtain();
    611         msg.what = what;
    612         msg.arg1 = arg1;
    613         msg.arg2 = arg2;
    614         replyToMessage(srcMsg, msg);
    615     }
    616 
    617     /**
    618      * Reply to srcMsg
    619      *
    620      * @param srcMsg
    621      * @param what
    622      * @param arg1
    623      * @param arg2
    624      * @param obj
    625      */
    626     public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) {
    627         Message msg = Message.obtain();
    628         msg.what = what;
    629         msg.arg1 = arg1;
    630         msg.arg2 = arg2;
    631         msg.obj = obj;
    632         replyToMessage(srcMsg, msg);
    633     }
    634 
    635     /**
    636      * Reply to srcMsg
    637      *
    638      * @param srcMsg
    639      * @param what
    640      * @param obj
    641      */
    642     public void replyToMessage(Message srcMsg, int what, Object obj) {
    643         Message msg = Message.obtain();
    644         msg.what = what;
    645         msg.obj = obj;
    646         replyToMessage(srcMsg, msg);
    647     }
    648 
    649     /**
    650      * Send the Message synchronously.
    651      *
    652      * @param msg to send
    653      * @return reply message or null if an error.
    654      */
    655     public Message sendMessageSynchronously(Message msg) {
    656         Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
    657         return resultMsg;
    658     }
    659 
    660     /**
    661      * Send the Message synchronously.
    662      *
    663      * @param what
    664      * @return reply message or null if an error.
    665      */
    666     public Message sendMessageSynchronously(int what) {
    667         Message msg = Message.obtain();
    668         msg.what = what;
    669         Message resultMsg = sendMessageSynchronously(msg);
    670         return resultMsg;
    671     }
    672 
    673     /**
    674      * Send the Message synchronously.
    675      *
    676      * @param what
    677      * @param arg1
    678      * @return reply message or null if an error.
    679      */
    680     public Message sendMessageSynchronously(int what, int arg1) {
    681         Message msg = Message.obtain();
    682         msg.what = what;
    683         msg.arg1 = arg1;
    684         Message resultMsg = sendMessageSynchronously(msg);
    685         return resultMsg;
    686     }
    687 
    688     /**
    689      * Send the Message synchronously.
    690      *
    691      * @param what
    692      * @param arg1
    693      * @param arg2
    694      * @return reply message or null if an error.
    695      */
    696     public Message sendMessageSynchronously(int what, int arg1, int arg2) {
    697         Message msg = Message.obtain();
    698         msg.what = what;
    699         msg.arg1 = arg1;
    700         msg.arg2 = arg2;
    701         Message resultMsg = sendMessageSynchronously(msg);
    702         return resultMsg;
    703     }
    704 
    705     /**
    706      * Send the Message synchronously.
    707      *
    708      * @param what
    709      * @param arg1
    710      * @param arg2
    711      * @param obj
    712      * @return reply message or null if an error.
    713      */
    714     public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) {
    715         Message msg = Message.obtain();
    716         msg.what = what;
    717         msg.arg1 = arg1;
    718         msg.arg2 = arg2;
    719         msg.obj = obj;
    720         Message resultMsg = sendMessageSynchronously(msg);
    721         return resultMsg;
    722     }
    723 
    724     /**
    725      * Send the Message synchronously.
    726      *
    727      * @param what
    728      * @param obj
    729      * @return reply message or null if an error.
    730      */
    731     public Message sendMessageSynchronously(int what, Object obj) {
    732         Message msg = Message.obtain();
    733         msg.what = what;
    734         msg.obj = obj;
    735         Message resultMsg = sendMessageSynchronously(msg);
    736         return resultMsg;
    737     }
    738 
    739     /**
    740      * Helper class to send messages synchronously
    741      */
    742     private static class SyncMessenger {
    743         /** A stack of SyncMessengers */
    744         private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>();
    745         /** A number of SyncMessengers created */
    746         private static int sCount = 0;
    747         /** The handler thread */
    748         private HandlerThread mHandlerThread;
    749         /** The handler that will receive the result */
    750         private SyncHandler mHandler;
    751         /** The messenger used to send the message */
    752         private Messenger mMessenger;
    753 
    754         /** private constructor */
    755         private SyncMessenger() {
    756         }
    757 
    758         /** Synchronous Handler class */
    759         private class SyncHandler extends Handler {
    760             /** The object used to wait/notify */
    761             private Object mLockObject = new Object();
    762             /** The resulting message */
    763             private Message mResultMsg;
    764 
    765             /** Constructor */
    766             private SyncHandler(Looper looper) {
    767                 super(looper);
    768             }
    769 
    770             /** Handle of the reply message */
    771             @Override
    772             public void handleMessage(Message msg) {
    773                 mResultMsg = Message.obtain();
    774                 mResultMsg.copyFrom(msg);
    775                 synchronized(mLockObject) {
    776                     mLockObject.notify();
    777                 }
    778             }
    779         }
    780 
    781         /**
    782          * @return the SyncMessenger
    783          */
    784         private static SyncMessenger obtain() {
    785             SyncMessenger sm;
    786             synchronized (sStack) {
    787                 if (sStack.isEmpty()) {
    788                     sm = new SyncMessenger();
    789                     sm.mHandlerThread = new HandlerThread("SyncHandler-" + sCount++);
    790                     sm.mHandlerThread.start();
    791                     sm.mHandler = sm.new SyncHandler(sm.mHandlerThread.getLooper());
    792                     sm.mMessenger = new Messenger(sm.mHandler);
    793                 } else {
    794                     sm = sStack.pop();
    795                 }
    796             }
    797             return sm;
    798         }
    799 
    800         /**
    801          * Recycle this object
    802          */
    803         private void recycle() {
    804             synchronized (sStack) {
    805                 sStack.push(this);
    806             }
    807         }
    808 
    809         /**
    810          * Send a message synchronously.
    811          *
    812          * @param msg to send
    813          * @return result message or null if an error occurs
    814          */
    815         private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
    816             SyncMessenger sm = SyncMessenger.obtain();
    817             try {
    818                 if (dstMessenger != null && msg != null) {
    819                     msg.replyTo = sm.mMessenger;
    820                     synchronized (sm.mHandler.mLockObject) {
    821                         dstMessenger.send(msg);
    822                         sm.mHandler.mLockObject.wait();
    823                     }
    824                 } else {
    825                     sm.mHandler.mResultMsg = null;
    826                 }
    827             } catch (InterruptedException e) {
    828                 sm.mHandler.mResultMsg = null;
    829             } catch (RemoteException e) {
    830                 sm.mHandler.mResultMsg = null;
    831             }
    832             Message resultMsg = sm.mHandler.mResultMsg;
    833             sm.recycle();
    834             return resultMsg;
    835         }
    836     }
    837 
    838     /**
    839      * Reply to the src handler that we're half connected.
    840      * see: CMD_CHANNEL_HALF_CONNECTED for message contents
    841      *
    842      * @param status to be stored in msg.arg1
    843      */
    844     private void replyHalfConnected(int status) {
    845         Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
    846         msg.arg1 = status;
    847         msg.obj = this;
    848         msg.replyTo = mDstMessenger;
    849 
    850         /*
    851          * Link to death only when bindService isn't used.
    852          */
    853         if (mConnection == null) {
    854             mDeathMonitor = new DeathMonitor();
    855             try {
    856                 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
    857             } catch (RemoteException e) {
    858                 mDeathMonitor = null;
    859                 // Override status to indicate failure
    860                 msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
    861             }
    862         }
    863 
    864         mSrcHandler.sendMessage(msg);
    865     }
    866 
    867     /**
    868      * Reply to the src handler that we are disconnected
    869      * see: CMD_CHANNEL_DISCONNECTED for message contents
    870      *
    871      * @param status to be stored in msg.arg1
    872      */
    873     private void replyDisconnected(int status) {
    874         Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
    875         msg.arg1 = status;
    876         msg.obj = this;
    877         msg.replyTo = mDstMessenger;
    878         mSrcHandler.sendMessage(msg);
    879     }
    880 
    881 
    882     /**
    883      * ServiceConnection to receive call backs.
    884      */
    885     class AsyncChannelConnection implements ServiceConnection {
    886         AsyncChannelConnection() {
    887         }
    888 
    889         @Override
    890         public void onServiceConnected(ComponentName className, IBinder service) {
    891             mDstMessenger = new Messenger(service);
    892             replyHalfConnected(STATUS_SUCCESSFUL);
    893         }
    894 
    895         @Override
    896         public void onServiceDisconnected(ComponentName className) {
    897             replyDisconnected(STATUS_SUCCESSFUL);
    898         }
    899     }
    900 
    901     /**
    902      * Log the string.
    903      *
    904      * @param s
    905      */
    906     private static void log(String s) {
    907         Slog.d(TAG, s);
    908     }
    909 
    910     private final class DeathMonitor implements IBinder.DeathRecipient {
    911 
    912         DeathMonitor() {
    913         }
    914 
    915         public void binderDied() {
    916             replyDisconnected(STATUS_REMOTE_DISCONNECTION);
    917         }
    918 
    919     }
    920 }
    921