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