blob: e58a4e21ccc5d0bf38f4ecd94a5807a201f03fa0 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SDKCONTROL_SOCKET_H_
#define ANDROID_SDKCONTROL_SOCKET_H_
#include "android/async-socket.h"
#include "android/async-utils.h"
/*
* Contains declaration of an API that encapsulates communication protocol with
* SdkController running on an Android device.
*
* SdkController is used to provide:
*
* - Realistic sensor emulation.
* - Multi-touch emulation.
* - Open for other types of emulation.
*
* The idea behind this type of emulation is such that there is an actual
* Android device that is connected via USB to the host running the emulator.
* On the device there is an SdkController service running that enables
* communication between an Android application that gathers information required
* by the emulator, and transmits that info to the emulator.
*
* SdkController service on the device, and SDKCtlSocket API implemented here
* implement the exchange protocol between an Android application, and emulation
* engine running inside the emulator.
*
* In turn, the exchange protocol is implemented on top of asynchronous socket
* communication (abstracted in AsyncSocket protocol implemented in
* android/async-socket.*). It means that connection, and all data transfer
* (both, in, and out) are completely asynchronous, and results of each operation
* are reported through callbacks.
*
* Essentially, this entire API implements two types of protocols:
*
* - Connection protocol.
* - Data exchange protocol.
*
* 1. Connection protocol.
*
* Connecting to SdkController service on the attached device can be broken down
* into two phases:
* - Connecting to a TCP socket.
* - Sending a "handshake" query to the SdkController.
*
* 1.1. Connecting to the socket.
*
* TCP socket connection with SdkController is enabled by using adb port
* forwarding. SdkController is always listening to a local abstract socket named
* 'android.sdk.controller', so to enable connecting to it from the host, run
*
* adb forward tcp:<port> localabstract: android.sdk.controller
*
* After that TCP socket for the requested port can be used to connect to
* SdkController, and connecting to it is no different than connecting to any
* socket server. Except for one thing: adb port forwarding is implemented in
* such a way, that socket_connect will always succeed, even if there is no
* server listening to that port on the other side of connection. Moreover,
* even socked_send will succeed in this case, so the only way to ensure that
* SdkController in deed is listening is to exchange a handshake with it:
* Fortunatelly, an attempt to read from forwarded TCP port on condition that
* there is no listener on the oher side will fail.
*
* 1.2. Handshake query.
*
* Handshake query is a special type of query that SDKCtlSocket sends to the
* SdkController upon successful socket connection. This query served two
* purposes:
* - Informs the SdkController about host endianness. This information is
* important, because SdkController needs it in order to format its messages
* with proper endianness.
* - Ensures that SdkController is in deed listening on the other side of the
* connected socket.
*
* Connection with SdkController is considered to be successfuly established when
* SdkController responds to the handshake query, thus, completing the connection.
*
* 2. Data exchange protocol.
*
* As it was mentioned above, all data transfer in this API is completely
* asynchronous, and result of each data transfer is reported via callbacks.
* This also complicates destruction of data involved in exchange, since in an
* asynchronous environment it's hard to control the lifespan of an object, its
* owner, and who and when is responsible to free resources allocated for the
* transfer. To address this issue, all the descriptors that this API operates
* with are referenced on use / released after use, and get freed when reference
* counter for them drops to zero, indicating that there is no component that is
* interested in that particular descriptor.
*
* There are three types of data in the exchange protocol:
* - A message - the simplest type of data that doesn't require any replies.
* - A query - A message that require a reply, and
* - A query reply - A message that delivers query reply.
*/
/* Default TCP port to use for connection with SDK controller. */
#define SDKCTL_DEFAULT_TCP_PORT 1970
/* Declares SDK controller socket descriptor. */
typedef struct SDKCtlSocket SDKCtlSocket;
/* Declares SDK controller message descriptor. */
typedef struct SDKCtlMessage SDKCtlMessage;
/* Declares SDK controller query descriptor. */
typedef struct SDKCtlQuery SDKCtlQuery;
/* Declares SDK controller direct packet descriptor.
* Direct packet (unlike message, or query packets) doesn't contain data buffer,
* but rather references message, or query data allocated by the client.
*/
typedef struct SDKCtlDirectPacket SDKCtlDirectPacket;
/* Defines client's callback set to monitor SDK controller socket connection.
*
* SDKCtlSocket will invoke this callback when connection to TCP port is
* established, but before handshake query is processed. The client should use
* on_sdkctl_handshake_cb to receive notification about an operational connection
* with SdkController.
*
* The main purpose of this callback for the client is to monitor connection
* state: in addition to TCP port connection, this callback will be invoked when
* connection with the port is lost.
*
* Param:
* client_opaque - An opaque pointer associated with the client.
* sdkctl - Initialized SDKCtlSocket instance.
* status - Socket connection status. Can be one of these:
* - ASIO_STATE_SUCCEEDED : Socket is connected to the port.
* - ASIO_STATE_FAILED : Connection attempt has failed, or connection with
* the port is lost.
* Return:
* One of the AsyncIOAction values.
*/
typedef AsyncIOAction (*on_sdkctl_socket_connection_cb)(void* client_opaque,
SDKCtlSocket* sdkctl,
AsyncIOState status);
/* Enumerates port connection statuses passed to port connection callback.
*/
typedef enum SdkCtlPortStatus {
/* Service-side port has connected to the socket. */
SDKCTL_PORT_DISCONNECTED,
/* Service-side port has disconnected from the socket. */
SDKCTL_PORT_CONNECTED,
/* Service-side port has enabled emulation */
SDKCTL_PORT_ENABLED,
/* Service-side port has disabled emulation */
SDKCTL_PORT_DISABLED,
/* Handshake request has succeeded, and service-side port is connected. */
SDKCTL_HANDSHAKE_CONNECTED,
/* Handshake request has succeeded, but service-side port is not connected. */
SDKCTL_HANDSHAKE_NO_PORT,
/* Handshake request has failed due to port duplication. */
SDKCTL_HANDSHAKE_DUP,
/* Handshake request has failed on an unknown query. */
SDKCTL_HANDSHAKE_UNKNOWN_QUERY,
/* Handshake request has failed on an unknown response. */
SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE,
} SdkCtlPortStatus;
/* Defines client's callback set to receive port connection status.
*
* Port connection is different than socket connection, and indicates whether
* or not a service-side port that provides requested emulation functionality is
* hooked up with the connected socket. For instance, multi-touch port may be
* inactive at the time when socket is connected. So, there is a successful
* socket connection, but there is no service at the device end that provides
* multi-touch functionality. So, for multi-touch example, this callback will be
* invoked when multi-touch port at the device end becomes active, and hooks up
* with the socket that was connected before.
*
* Param:
* client_opaque - An opaque pointer associated with the client.
* sdkctl - Initialized SDKCtlSocket instance.
* status - Port connection status.
*/
typedef void (*on_sdkctl_port_connection_cb)(void* client_opaque,
SDKCtlSocket* sdkctl,
SdkCtlPortStatus status);
/* Defines a message notification callback.
* Param:
* client_opaque - An opaque pointer associated with the client.
* sdkctl - Initialized SDKCtlSocket instance.
* message - Descriptor for received message. Note that message descriptor will
* be released upon exit from this callback (thus, could be freed along
* with message data). If the client is interested in working with that
* message after the callback returns, it should reference the message
* descriptor in this callback.
* msg_type - Message type.
* msg_data, msg_size - Message data.
*/
typedef void (*on_sdkctl_message_cb)(void* client_opaque,
SDKCtlSocket* sdkctl,
SDKCtlMessage* message,
int msg_type,
void* msg_data,
int msg_size);
/* Defines query completion callback.
* Param:
* query_opaque - An opaque pointer associated with the query by the client.
* query - Query descriptor. Note that query descriptor will be released upon
* exit from this callback (thus, could be freed along with query data). If
* the client is interested in working with that query after the callback
* returns, it should reference the query descriptor in this callback.
* status - Query status. Can be one of these:
* - ASIO_STATE_CONTINUES : Query data has been transmitted to the service,
* and query is now waiting for response.
* - ASIO_STATE_SUCCEEDED : Query has been successfully completed.
* - ASIO_STATE_FAILED : Query has failed on an I/O.
* - ASIO_STATE_TIMED_OUT : Deadline set for the query has expired.
* - ASIO_STATE_CANCELLED : Query has been cancelled due to socket
* disconnection.
* Return:
* One of the AsyncIOAction values.
*/
typedef AsyncIOAction (*on_sdkctl_query_cb)(void* query_opaque,
SDKCtlQuery* query,
AsyncIOState status);
/* Defines direct packet completion callback.
* Param:
* opaque - An opaque pointer associated with the direct packet by the client.
* packet - Packet descriptor. Note that packet descriptor will be released
* upon exit from this callback (thus, could be freed). If the client is
* interested in working with that packet after the callback returns, it
* should reference the packet descriptor in this callback.
* status - Packet status. Can be one of these:
* - ASIO_STATE_SUCCEEDED : Packet has been successfully sent.
* - ASIO_STATE_FAILED : Packet has failed on an I/O.
* - ASIO_STATE_CANCELLED : Packet has been cancelled due to socket
* disconnection.
* Return:
* One of the AsyncIOAction values.
*/
typedef AsyncIOAction (*on_sdkctl_direct_cb)(void* opaque,
SDKCtlDirectPacket* packet,
AsyncIOState status);
/********************************************************************************
* SDKCtlDirectPacket API
********************************************************************************/
/* Creates new SDKCtlDirectPacket descriptor.
* Param:
* sdkctl - Initialized SDKCtlSocket instance to create a direct packet for.
* Return:
* Referenced SDKCtlDirectPacket instance.
*/
extern SDKCtlDirectPacket* sdkctl_direct_packet_new(SDKCtlSocket* sdkctl);
/* References SDKCtlDirectPacket object.
* Param:
* packet - Initialized SDKCtlDirectPacket instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_direct_packet_reference(SDKCtlDirectPacket* packet);
/* Releases SDKCtlDirectPacket object.
* Note that upon exiting from this routine the object might be destroyed, even
* if this routine returns value other than zero.
* Param:
* packet - Initialized SDKCtlDirectPacket instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_direct_packet_release(SDKCtlDirectPacket* packet);
/* Sends direct packet.
* Param:
* packet - Packet descriptor for the direct packet to send.
* data - Data to send with the packet. Must be fully initialized message, or
* query header.
* cb, cb_opaque - Callback to invoke on packet transmission events.
*/
extern void sdkctl_direct_packet_send(SDKCtlDirectPacket* packet,
void* data,
on_sdkctl_direct_cb cb,
void* cb_opaque);
/********************************************************************************
* SDKCtlMessage API
********************************************************************************/
/* References SDKCtlMessage object.
* Param:
* msg - Initialized SDKCtlMessage instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_message_reference(SDKCtlMessage* msg);
/* Releases SDKCtlMessage object.
* Note that upon exiting from this routine the object might be destroyed, even
* if this routine returns value other than zero.
* Param:
* msg - Initialized SDKCtlMessage instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_message_release(SDKCtlMessage* msg);
/* Builds and sends a message to the device.
* Param:
* sdkctl - SDKCtlSocket instance for the message.
* msg_type - Defines message type.
* data - Message data. Can be NULL if there is no data associated with the
* message.
* size - Byte size of the data buffer.
* Return:
* Referenced SDKCtlQuery descriptor.
*/
extern SDKCtlMessage* sdkctl_message_send(SDKCtlSocket* sdkctl,
int msg_type,
const void* data,
uint32_t size);
/* Gets message header size */
extern int sdkctl_message_get_header_size(void);
/* Initializes message header.
* Param:
* msg - Beginning of the message packet.
* msg_type - Message type.
* msg_size - Message data size.
*/
extern void sdkctl_init_message_header(void* msg, int msg_type, int msg_size);
/********************************************************************************
* SDKCtlQuery API
********************************************************************************/
/* Creates, and partially initializes query descriptor.
* Note that returned descriptor is referenced, and it must be eventually
* released with a call to sdkctl_query_release.
* Param:
* sdkctl - SDKCtlSocket instance for the query.
* query_type - Defines query type.
* in_data_size Size of the query's input buffer (data to be sent with this
* query). Note that buffer for query data will be allocated along with the
* query descriptor. Use sdkctl_query_get_buffer_in to get address of data
* buffer for this query.
* Return:
* Referenced SDKCtlQuery descriptor.
*/
extern SDKCtlQuery* sdkctl_query_new(SDKCtlSocket* sdkctl,
int query_type,
uint32_t in_data_size);
/* Creates, and fully initializes query descriptor.
* Note that returned descriptor is referenced, and it must be eventually
* released with a call to sdkctl_query_release.
* Param:
* sdkctl - SDKCtlSocket instance for the query.
* query_type - Defines query type.
* in_data_size Size of the query's input buffer (data to be sent with this
* query). Note that buffer for query data will be allocated along with the
* query descriptor. Use sdkctl_query_get_buffer_in to get address of data
* buffer for this query.
* in_data - Data to initialize query's input buffer with.
* response_buffer - Contains address of the buffer addressing preallocated
* response buffer on the way in, and address of the buffer containing query
* response on query completion. If this parameter is NULL, the API will
* allocate its own query response buffer, which is going to be freed after
* query completion.
* response_size - Contains size of preallocated response buffer on the way in,
* and size of the received response on query completion. Can be NULL.
* query_cb - A callback to monitor query state.
* query_opaque - An opaque pointer associated with the query.
* Return:
* Referenced SDKCtlQuery descriptor.
*/
extern SDKCtlQuery* sdkctl_query_new_ex(SDKCtlSocket* sdkctl,
int query_type,
uint32_t in_data_size,
const void* in_data,
void** response_buffer,
uint32_t* response_size,
on_sdkctl_query_cb query_cb,
void* query_opaque);
/* Sends query to SDK controller.
* Param:
* query - Query to send. Note that this must be a fully initialized query
* descriptor.
* to - Milliseconds to allow for the query to complete. Negative value means
* "forever".
*/
extern void sdkctl_query_send(SDKCtlQuery* query, int to);
/* Creates, fully initializes query descriptor, and sends the query to SDK
* controller.
* Note that returned descriptor is referenced, and it must be eventually
* released with a call to sdkctl_query_release.
* Param:
* sdkctl - SDKCtlSocket instance for the query.
* query_type - Defines query type.
* in_data_size Size of the query's input buffer (data to be sent with this
* query). Note that buffer for query data will be allocated along with the
* query descriptor. Use sdkctl_query_get_buffer_in to get address of data
* buffer for this query.
* in_data - Data to initialize query's input buffer with.
* response_buffer - Contains address of the buffer addressing preallocated
* response buffer on the way in, and address of the buffer containing query
* response on query completion. If this parameter is NULL, the API will
* allocate its own query response buffer, which is going to be freed after
* query completion.
* response_size - Contains size of preallocated response buffer on the way in,
* and size of the received response on query completion. Can be NULL.
* query_cb - A callback to monitor query state.
* query_opaque - An opaque pointer associated with the query.
* to - Milliseconds to allow for the query to complete. Negative value means
* "forever".
* Return:
* Referenced SDKCtlQuery descriptor for the query that has been sent.
*/
extern SDKCtlQuery* sdkctl_query_build_and_send(SDKCtlSocket* sdkctl,
int query_type,
uint32_t in_data_size,
const void* in_data,
void** response_buffer,
uint32_t* response_size,
on_sdkctl_query_cb query_cb,
void* query_opaque,
int to);
/* References SDKCtlQuery object.
* Param:
* query - Initialized SDKCtlQuery instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_query_reference(SDKCtlQuery* query);
/* Releases SDKCtlQuery object.
* Note that upon exit from this routine the object might be destroyed, even if
* this routine returns value other than zero.
* Param:
* query - Initialized SDKCtlQuery instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_query_release(SDKCtlQuery* query);
/* Gets address of query's input data buffer (data to be send).
* Param:
* query - Query to get data buffer for.
* Return:
* Address of query's input data buffer.
*/
extern void* sdkctl_query_get_buffer_in(SDKCtlQuery* query);
/* Gets address of query's output data buffer (response data).
* Param:
* query - Query to get data buffer for.
* Return:
* Address of query's output data buffer.
*/
extern void* sdkctl_query_get_buffer_out(SDKCtlQuery* query);
/********************************************************************************
* SDKCtlSocket API
********************************************************************************/
/* Creates an SDK controller socket descriptor.
* Param:
* reconnect_to - Timeout before trying to reconnect, or retry connection
* attempts after disconnection, or on connection failures.
* service_name - Name of the SdkController service for this socket (such as
* 'sensors', 'milti-touch', etc.)
* on_socket_connection - A callback to invoke on socket connection events.
* on_port_connection - A callback to invoke on port connection events.
* on_message - A callback to invoke when a message is received from the SDK
* controller.
* opaque - An opaque pointer to associate with the socket.
* Return:
* Initialized SDKCtlSocket instance on success, or NULL on failure.
*/
extern SDKCtlSocket* sdkctl_socket_new(int reconnect_to,
const char* service_name,
on_sdkctl_socket_connection_cb on_socket_connection,
on_sdkctl_port_connection_cb on_port_connection,
on_sdkctl_message_cb on_message,
void* opaque);
/* Improves throughput by recycling memory allocated for buffers transferred via
* this API.
*
* In many cases data exchanged between SDK controller sides are small, and,
* although may come quite often, are coming in a sequential manner. For instance,
* sensor service on the device may send us sensor updates every 20ms, one after
* another. For such data traffic it makes perfect sense to recycle memory
* allocated for the previous sensor update, rather than to free it just to
* reallocate same buffer in 20ms. This routine sets properties of the recycler
* for the given SDK controller connection. Recycling includes memory allocated
* for all types of data transferred in this API: packets, and queries.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* data_size - Size of buffer to allocate for each data block.
* max_recycled_num - Maximum number of allocated buffers to keep in the
* recycler.
*/
extern void sdkctl_init_recycler(SDKCtlSocket* sdkctl,
uint32_t data_size,
int max_recycled_num);
/* References SDKCtlSocket object.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_socket_reference(SDKCtlSocket* sdkctl);
/* Releases SDKCtlSocket object.
* Note that upon exit from this routine the object might be destroyed, even if
* this routine returns value other than zero.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Number of outstanding references to the object.
*/
extern int sdkctl_socket_release(SDKCtlSocket* sdkctl);
/* Asynchronously connects to SDK controller.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* port - TCP port to connect the socket to.
* retry_to - Number of milliseconds to wait before retrying a failed
* connection attempt.
*/
extern void sdkctl_socket_connect(SDKCtlSocket* sdkctl, int port, int retry_to);
/* Asynchronously reconnects to SDK controller.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* port - TCP port to reconnect the socket to.
* retry_to - Number of milliseconds to wait before reconnecting. Same timeout
* will be used for retrying a failed connection attempt.
*/
extern void sdkctl_socket_reconnect(SDKCtlSocket* sdkctl, int port, int retry_to);
/* Disconnects from SDK controller.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
*/
extern void sdkctl_socket_disconnect(SDKCtlSocket* sdkctl);
/* Checks if SDK controller socket is connected.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Boolean: 1 if socket is connected, 0 if socket is not connected.
*/
extern int sdkctl_socket_is_connected(SDKCtlSocket* sdkctl);
/* Checks if SDK controller port is ready for emulation.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Boolean: 1 if port is ready, 0 if port is not ready.
*/
extern int sdkctl_socket_is_port_ready(SDKCtlSocket* sdkctl);
/* Gets status of the SDK controller port for this socket.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Status of the SDK controller port for this socket.
*/
extern SdkCtlPortStatus sdkctl_socket_get_port_status(SDKCtlSocket* sdkctl);
/* Checks if handshake was successful.
* Param:
* sdkctl - Initialized SDKCtlSocket instance.
* Return:
* Boolean: 1 if handshake was successful, 0 if handshake was not successful.
*/
extern int sdkctl_socket_is_handshake_ok(SDKCtlSocket* sdkctl);
#endif /* ANDROID_SDKCONTROL_SOCKET_H_ */