FileDocCategorySizeDatePackage
AsyncChannel.javaAPI DocAndroid 5.1 API30269Thu Mar 12 22:22:10 GMT 2015com.android.internal.util

AsyncChannel

public class AsyncChannel extends Object

An asynchronous channel between two handlers.

The handlers maybe in the same process or in another process. There are two protocol styles that can be used with an AysncChannel. The first is a simple request/reply protocol where the server does not need to know which client is issuing the request.

In a simple request/reply protocol the client/source sends requests to the server/destination. And the server uses the replyToMessage methods. In this usage model there is no need for the destination to use the connect methods. The typical sequence of operations is:

  1. Client calls AsyncChannel#connectSync or Asynchronously:
    1. For an asynchronous half connection client calls AsyncChannel#connect.
  2. Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
  • comm-loop:
  • Client calls AsyncChannel#sendMessage
  • Server processes messages and optionally replies using AsyncChannel#replyToMessage
  • Loop to comm-loop until done
  • When done Client calls {@link AsyncChannel#disconnect}
  • Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel

  • A second usage model is where the server/destination needs to know which client it's connected too. For example the server needs to send unsolicited messages back to the client. Or the server keeps different state for each client. In this model the server will also use the connect methods. The typical sequence of operation is:

    1. Client calls AsyncChannel#fullyConnectSync or Asynchronously:
      1. For an asynchronous full connection it calls AsyncChannel#connect
      2. Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
      3. Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)
    2. Server receives CMD_CHANNEL_FULL_CONNECTION
    3. Server calls AsyncChannel#connected
    4. Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)
    5. Client receives CMD_CHANNEL_FULLY_CONNECTED
    6. comm-loop:
    7. Client/Server uses AsyncChannel#sendMessage/replyToMessage to communicate and perform work
    8. Loop to comm-loop until done
    9. When done Client/Server calls {@link AsyncChannel#disconnect}
    10. Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel
    TODO: Consider simplifying where we have connect and fullyConnect with only one response message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.

    Fields Summary
    private static final String
    TAG
    Log tag
    private static final boolean
    DBG
    Enable to turn on debugging
    private static final int
    BASE
    public static final int
    CMD_CHANNEL_HALF_CONNECTED
    Command sent when the channel is half connected. Half connected means that the channel can be used to send commends to the destination but the destination is unaware that the channel exists. The first command sent to the destination is typically CMD_CHANNEL_FULL_CONNECTION if it is desired to establish a long term connection, but any command maybe sent. msg.arg1 == 0 : STATUS_SUCCESSFUL 1 : STATUS_BINDING_UNSUCCESSFUL msg.obj == the AsyncChannel msg.replyTo == dstMessenger if successful
    public static final int
    CMD_CHANNEL_FULL_CONNECTION
    Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED. This is used to initiate a long term connection with the destination and typically the destination will reply with CMD_CHANNEL_FULLY_CONNECTED. msg.replyTo = srcMessenger.
    public static final int
    CMD_CHANNEL_FULLY_CONNECTED
    Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION. This signifies the acceptance or rejection of the channel by the sender. msg.arg1 == 0 : Accept connection : All other values signify the destination rejected the connection and {@link AsyncChannel#disconnect} would typically be called.
    public static final int
    CMD_CHANNEL_DISCONNECT
    Command sent when one side or the other wishes to disconnect. The sender may or may not be able to receive a reply depending upon the protocol and the state of the connection. The receiver should call {@link AsyncChannel#disconnect} to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED when the channel is closed. msg.replyTo = messenger that is disconnecting
    public static final int
    CMD_CHANNEL_DISCONNECTED
    Command sent when the channel becomes disconnected. This is sent when the channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT. msg.arg1 == 0 : STATUS_SUCCESSFUL 1 : STATUS_BINDING_UNSUCCESSFUL 2 : STATUS_SEND_UNSUCCESSFUL : All other values signify failure and the channel state is indeterminate msg.obj == the AsyncChannel msg.replyTo = messenger disconnecting or null if it was never connected.
    private static final int
    CMD_TO_STRING_COUNT
    private static String[]
    sCmdToString
    public static final int
    STATUS_SUCCESSFUL
    Successful status always 0, !0 is an unsuccessful status
    public static final int
    STATUS_BINDING_UNSUCCESSFUL
    Error attempting to bind on a connect
    public static final int
    STATUS_SEND_UNSUCCESSFUL
    Error attempting to send a message
    public static final int
    STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED
    CMD_FULLY_CONNECTED refused because a connection already exists
    public static final int
    STATUS_REMOTE_DISCONNECTION
    Error indicating abnormal termination of destination messenger
    private AsyncChannelConnection
    mConnection
    Service connection
    private android.content.Context
    mSrcContext
    Context for source
    private android.os.Handler
    mSrcHandler
    Handler for source
    private android.os.Messenger
    mSrcMessenger
    Messenger for source
    private android.os.Messenger
    mDstMessenger
    Messenger for destination
    private DeathMonitor
    mDeathMonitor
    Death Monitor for destination messenger
    Constructors Summary
    public AsyncChannel()
    AsyncChannel constructor

    
               
          
        
    Methods Summary
    protected static java.lang.StringcmdToString(int cmd)

         
            sCmdToString[CMD_CHANNEL_HALF_CONNECTED - BASE] = "CMD_CHANNEL_HALF_CONNECTED";
            sCmdToString[CMD_CHANNEL_FULL_CONNECTION - BASE] = "CMD_CHANNEL_FULL_CONNECTION";
            sCmdToString[CMD_CHANNEL_FULLY_CONNECTED - BASE] = "CMD_CHANNEL_FULLY_CONNECTED";
            sCmdToString[CMD_CHANNEL_DISCONNECT - BASE] = "CMD_CHANNEL_DISCONNECT";
            sCmdToString[CMD_CHANNEL_DISCONNECTED - BASE] = "CMD_CHANNEL_DISCONNECTED";
        
            cmd -= BASE;
            if ((cmd >= 0) && (cmd < sCmdToString.length)) {
                return sCmdToString[cmd];
            } else {
                return null;
            }
        
    public voidconnect(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Handler dstHandler)
    Connect two local Handlers.

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstHandler is the hander to send messages to.

            connect(srcContext, srcHandler, new Messenger(dstHandler));
        
    public voidconnect(AsyncService srcAsyncService, android.os.Messenger dstMessenger)
    Connect service and messenger. Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete. msg.arg1 = status msg.obj = the AsyncChannel

    param
    srcAsyncService
    param
    dstMessenger

            connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger);
        
    public voidconnect(android.content.Context srcContext, android.os.Handler srcHandler, java.lang.String dstPackageName, java.lang.String dstClassName)
    Connect handler to named package/class. Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. msg.arg1 = status msg.obj = the AsyncChannel

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstPackageName is the destination package name
    param
    dstClassName is the fully qualified class name (i.e. contains package name)

            if (DBG) log("connect srcHandler to dst Package & class E");
    
            final class ConnectAsync implements Runnable {
                Context mSrcCtx;
                Handler mSrcHdlr;
                String mDstPackageName;
                String mDstClassName;
    
                ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName,
                        String dstClassName) {
                    mSrcCtx = srcContext;
                    mSrcHdlr = srcHandler;
                    mDstPackageName = dstPackageName;
                    mDstClassName = dstClassName;
                }
    
                @Override
                public void run() {
                    int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
                            mDstClassName);
                    replyHalfConnected(result);
                }
            }
    
            ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName);
            new Thread(ca).start();
    
            if (DBG) log("connect srcHandler to dst Package & class X");
        
    public voidconnect(android.content.Context srcContext, android.os.Handler srcHandler, java.lang.Class klass)
    Connect handler to a class Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. msg.arg1 = status msg.obj = the AsyncChannel

    param
    srcContext
    param
    srcHandler
    param
    klass is the class to send messages to.

            connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName());
        
    public voidconnect(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Messenger dstMessenger)
    Connect handler and messenger. Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. msg.arg1 = status msg.obj = the AsyncChannel

    param
    srcContext
    param
    srcHandler
    param
    dstMessenger

            if (DBG) log("connect srcHandler to the dstMessenger  E");
    
            // We are connected
            connected(srcContext, srcHandler, dstMessenger);
    
            // Tell source we are half connected
            replyHalfConnected(STATUS_SUCCESSFUL);
    
            if (DBG) log("connect srcHandler to the dstMessenger X");
        
    public intconnectSrcHandlerToPackageSync(android.content.Context srcContext, android.os.Handler srcHandler, java.lang.String dstPackageName, java.lang.String dstClassName)
    Connect handler to named package/class synchronously.

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstPackageName is the destination package name
    param
    dstClassName is the fully qualified class name (i.e. contains package name)
    return
    STATUS_SUCCESSFUL on success any other value is an error.

            if (DBG) log("connect srcHandler to dst Package & class E");
    
            mConnection = new AsyncChannelConnection();
    
            /* Initialize the source information */
            mSrcContext = srcContext;
            mSrcHandler = srcHandler;
            mSrcMessenger = new Messenger(srcHandler);
    
            /*
             * Initialize destination information to null they will
             * be initialized when the AsyncChannelConnection#onServiceConnected
             * is called
             */
            mDstMessenger = null;
    
            /* Send intent to create the connection */
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.setClassName(dstPackageName, dstClassName);
            boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
            if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
            return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
        
    public intconnectSync(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Messenger dstMessenger)
    Connect a handler to Messenger synchronously.

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstMessenger is the hander to send messages to.
    return
    STATUS_SUCCESSFUL on success any other value is an error.

            if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");
    
            // We are connected
            connected(srcContext, srcHandler, dstMessenger);
    
            if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
            return STATUS_SUCCESSFUL;
        
    public intconnectSync(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Handler dstHandler)
    connect two local Handlers synchronously.

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstHandler is the hander to send messages to.
    return
    STATUS_SUCCESSFUL on success any other value is an error.

            return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
        
    public voidconnected(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Messenger dstMessenger)
    Connect handler to messenger. This method is typically called when a server receives a CMD_CHANNEL_FULL_CONNECTION request and initializes the internal instance variables to allow communication with the dstMessenger.

    param
    srcContext
    param
    srcHandler
    param
    dstMessenger

            if (DBG) log("connected srcHandler to the dstMessenger  E");
    
            // Initialize source fields
            mSrcContext = srcContext;
            mSrcHandler = srcHandler;
            mSrcMessenger = new Messenger(mSrcHandler);
    
            // Initialize destination fields
            mDstMessenger = dstMessenger;
    
            if (DBG) log("connected srcHandler to the dstMessenger X");
        
    public voiddisconnect()
    Disconnect

            if ((mConnection != null) && (mSrcContext != null)) {
                mSrcContext.unbindService(mConnection);
                mConnection = null;
            }
            try {
                // Send the DISCONNECTED, although it may not be received
                // but its the best we can do.
                Message msg = Message.obtain();
                msg.what = CMD_CHANNEL_DISCONNECTED;
                msg.replyTo = mSrcMessenger;
                mDstMessenger.send(msg);
            } catch(Exception e) {
            }
            // Tell source we're disconnected.
            if (mSrcHandler != null) {
                replyDisconnected(STATUS_SUCCESSFUL);
                mSrcHandler = null;
            }
            // Unlink only when bindService isn't used
            if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
                mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
                mDeathMonitor = null;
            }
        
    public voiddisconnected()
    To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED

            mSrcContext = null;
            mSrcHandler = null;
            mSrcMessenger = null;
            mDstMessenger = null;
            mDeathMonitor = null;
            mConnection = null;
        
    public intfullyConnectSync(android.content.Context srcContext, android.os.Handler srcHandler, android.os.Handler dstHandler)
    Fully connect two local Handlers synchronously.

    param
    srcContext is the context of the source
    param
    srcHandler is the hander to receive CONNECTED & DISCONNECTED messages
    param
    dstHandler is the hander to send messages to.
    return
    STATUS_SUCCESSFUL on success any other value is an error.

            int status = connectSync(srcContext, srcHandler, dstHandler);
            if (status == STATUS_SUCCESSFUL) {
                Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
                status = response.arg1;
            }
            return status;
        
    private static voidlog(java.lang.String s)
    Log the string.

    param
    s

            Slog.d(TAG, s);
        
    private voidreplyDisconnected(int status)
    Reply to the src handler that we are disconnected see: CMD_CHANNEL_DISCONNECTED for message contents

    param
    status to be stored in msg.arg1

            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
            msg.arg1 = status;
            msg.obj = this;
            msg.replyTo = mDstMessenger;
            mSrcHandler.sendMessage(msg);
        
    private voidreplyHalfConnected(int status)
    Reply to the src handler that we're half connected. see: CMD_CHANNEL_HALF_CONNECTED for message contents

    param
    status to be stored in msg.arg1

            Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
            msg.arg1 = status;
            msg.obj = this;
            msg.replyTo = mDstMessenger;
    
            /*
             * Link to death only when bindService isn't used.
             */
            if (mConnection == null) {
                mDeathMonitor = new DeathMonitor();
                try {
                    mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
                } catch (RemoteException e) {
                    mDeathMonitor = null;
                    // Override status to indicate failure
                    msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
                }
            }
    
            mSrcHandler.sendMessage(msg);
        
    public voidreplyToMessage(android.os.Message srcMsg, android.os.Message dstMsg)
    Reply to srcMsg sending dstMsg

    param
    srcMsg
    param
    dstMsg

            try {
                dstMsg.replyTo = mSrcMessenger;
                srcMsg.replyTo.send(dstMsg);
            } catch (RemoteException e) {
                log("TODO: handle replyToMessage RemoteException" + e);
                e.printStackTrace();
            }
        
    public voidreplyToMessage(android.os.Message srcMsg, int what)
    Reply to srcMsg

    param
    srcMsg
    param
    what

            Message msg = Message.obtain();
            msg.what = what;
            replyToMessage(srcMsg, msg);
        
    public voidreplyToMessage(android.os.Message srcMsg, int what, int arg1)
    Reply to srcMsg

    param
    srcMsg
    param
    what
    param
    arg1

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            replyToMessage(srcMsg, msg);
        
    public voidreplyToMessage(android.os.Message srcMsg, int what, int arg1, int arg2)
    Reply to srcMsg

    param
    srcMsg
    param
    what
    param
    arg1
    param
    arg2

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            replyToMessage(srcMsg, msg);
        
    public voidreplyToMessage(android.os.Message srcMsg, int what, int arg1, int arg2, java.lang.Object obj)
    Reply to srcMsg

    param
    srcMsg
    param
    what
    param
    arg1
    param
    arg2
    param
    obj

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            msg.obj = obj;
            replyToMessage(srcMsg, msg);
        
    public voidreplyToMessage(android.os.Message srcMsg, int what, java.lang.Object obj)
    Reply to srcMsg

    param
    srcMsg
    param
    what
    param
    obj

            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            replyToMessage(srcMsg, msg);
        
    public voidsendMessage(android.os.Message msg)
    Send a message to the destination handler.

    param
    msg

            msg.replyTo = mSrcMessenger;
            try {
                mDstMessenger.send(msg);
            } catch (RemoteException e) {
                replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
            }
        
    public voidsendMessage(int what)
    Send a message to the destination handler

    param
    what

            Message msg = Message.obtain();
            msg.what = what;
            sendMessage(msg);
        
    public voidsendMessage(int what, int arg1)
    Send a message to the destination handler

    param
    what
    param
    arg1

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            sendMessage(msg);
        
    public voidsendMessage(int what, int arg1, int arg2)
    Send a message to the destination handler

    param
    what
    param
    arg1
    param
    arg2

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            sendMessage(msg);
        
    public voidsendMessage(int what, int arg1, int arg2, java.lang.Object obj)
    Send a message to the destination handler

    param
    what
    param
    arg1
    param
    arg2
    param
    obj

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            msg.obj = obj;
            sendMessage(msg);
        
    public voidsendMessage(int what, java.lang.Object obj)
    Send a message to the destination handler

    param
    what
    param
    obj

            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            sendMessage(msg);
        
    public android.os.MessagesendMessageSynchronously(android.os.Message msg)
    Send the Message synchronously.

    param
    msg to send
    return
    reply message or null if an error.

            Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
            return resultMsg;
        
    public android.os.MessagesendMessageSynchronously(int what)
    Send the Message synchronously.

    param
    what
    return
    reply message or null if an error.

            Message msg = Message.obtain();
            msg.what = what;
            Message resultMsg = sendMessageSynchronously(msg);
            return resultMsg;
        
    public android.os.MessagesendMessageSynchronously(int what, int arg1)
    Send the Message synchronously.

    param
    what
    param
    arg1
    return
    reply message or null if an error.

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            Message resultMsg = sendMessageSynchronously(msg);
            return resultMsg;
        
    public android.os.MessagesendMessageSynchronously(int what, int arg1, int arg2)
    Send the Message synchronously.

    param
    what
    param
    arg1
    param
    arg2
    return
    reply message or null if an error.

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            Message resultMsg = sendMessageSynchronously(msg);
            return resultMsg;
        
    public android.os.MessagesendMessageSynchronously(int what, int arg1, int arg2, java.lang.Object obj)
    Send the Message synchronously.

    param
    what
    param
    arg1
    param
    arg2
    param
    obj
    return
    reply message or null if an error.

            Message msg = Message.obtain();
            msg.what = what;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            msg.obj = obj;
            Message resultMsg = sendMessageSynchronously(msg);
            return resultMsg;
        
    public android.os.MessagesendMessageSynchronously(int what, java.lang.Object obj)
    Send the Message synchronously.

    param
    what
    param
    obj
    return
    reply message or null if an error.

            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            Message resultMsg = sendMessageSynchronously(msg);
            return resultMsg;