Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2012 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 /*
     18  * Encapsulates exchange protocol between the emulator, and an Android device
     19  * that is connected to the host via USB. The communication is established over
     20  * a TCP port forwarding, enabled by ADB.
     21  */
     22 
     23 #include "qemu-common.h"
     24 #include "android/async-utils.h"
     25 #include "android/utils/debug.h"
     26 #include "android/async-socket-connector.h"
     27 #include "android/async-socket.h"
     28 #include "android/sdk-controller-socket.h"
     29 #include "utils/panic.h"
     30 #include "iolooper.h"
     31 
     32 #define  E(...)    derror(__VA_ARGS__)
     33 #define  W(...)    dwarning(__VA_ARGS__)
     34 #define  D(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
     35 #define  D_ACTIVE  VERBOSE_CHECK(sdkctlsocket)
     36 
     37 #define TRACE_ON    1
     38 
     39 #if TRACE_ON
     40 #define  T(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
     41 #else
     42 #define  T(...)
     43 #endif
     44 
     45 /* Recycling memory descriptor. */
     46 typedef struct SDKCtlRecycled SDKCtlRecycled;
     47 struct SDKCtlRecycled {
     48     union {
     49         /* Next recycled descriptor (while listed in recycler). */
     50         SDKCtlRecycled* next;
     51         /* Allocated memory size (while outside of the recycler). */
     52         uint32_t        size;
     53     };
     54 };
     55 
     56 /********************************************************************************
     57  *                      SDKCtlPacket declarations
     58  *******************************************************************************/
     59 
     60 /*
     61  * Types of the packets of data sent via SDK controller socket.
     62  */
     63 
     64 /* The packet is a message. */
     65 #define SDKCTL_PACKET_MESSAGE           1
     66 /* The packet is a query. */
     67 #define SDKCTL_PACKET_QUERY             2
     68 /* The packet is a response to a query. */
     69 #define SDKCTL_PACKET_QUERY_RESPONSE    3
     70 
     71 /* Data packet descriptor.
     72  *
     73  * All packets, sent and received via SDK controller socket begin with this
     74  * header, with packet data immediately following this header.
     75  */
     76 typedef struct SDKCtlPacketHeader {
     77     /* Total size of the data to transfer with this packet, including this
     78      * header. The transferring data should immediatelly follow this header. */
     79     int     size;
     80     /* Encodes packet type. See SDKCTL_PACKET_XXX for the list of packet types
     81      * used by SDK controller. */
     82     int     type;
     83 } SDKCtlPacketHeader;
     84 
     85 /* Packet descriptor, allocated by this API for data packets to be sent to SDK
     86  * controller service on the device.
     87  *
     88  * When packet descriptors are allocated by this API, they are allocated large
     89  * enough to contain this header, and packet data to send to the service,
     90  * immediately following this descriptor.
     91  */
     92 struct SDKCtlPacket {
     93     /* Supports recycling. Don't put anything in front: recycler expects this
     94      * to be the first field in recyclable descriptor. */
     95     SDKCtlRecycled      recycling;
     96 
     97     /* Next packet in the list of packets to send. */
     98     SDKCtlPacket*       next;
     99     /* SDK controller socket that transmits this packet. */
    100     SDKCtlSocket*       sdkctl;
    101     /* Number of outstanding references to the packet. */
    102     int                 ref_count;
    103 
    104     /* Common packet header. Packet data immediately follows this header, so it
    105      * must be last field in SDKCtlPacket descriptor. */
    106     SDKCtlPacketHeader  header;
    107 };
    108 
    109 /********************************************************************************
    110  *                      SDKCtlQuery declarations
    111  *******************************************************************************/
    112 
    113 /*
    114  * Types of queries sent via SDK controller socket.
    115  */
    116 
    117 /* Handshake query.
    118  * This query is sent to SDK controller service as part of the connection
    119  * protocol implementation.
    120  */
    121 #define SDKCTL_QUERY_HANDSHAKE          -1
    122 
    123 /* Query packet descriptor.
    124  *
    125  * All queries, sent and received via SDK controller socket begin with this
    126  * header, with query data immediately following this header.
    127  */
    128 typedef struct SDKCtlQueryHeader {
    129     /* Data packet header for this query. */
    130     SDKCtlPacketHeader  packet;
    131     /* A unique query identifier. This ID is used to track the query in the
    132      * asynchronous environment in whcih SDK controller socket operates. */
    133     int                 query_id;
    134     /* Query type. See SDKCTL_QUERY_XXX for the list of query types used by SDK
    135      * controller. */
    136     int                 query_type;
    137 } SDKCtlQueryHeader;
    138 
    139 /* Query descriptor, allocated by this API for queries to be sent to SDK
    140  * controller service on the device.
    141  *
    142  * When query descriptors are allocated by this API, they are allocated large
    143  * enough to contain this header, and query data to send to the service,
    144  * immediately following this descriptor.
    145  */
    146 struct SDKCtlQuery {
    147     /* Supports recycling. Don't put anything in front: recycler expects this
    148      * to be the first field in recyclable descriptor. */
    149     SDKCtlRecycled          recycling;
    150 
    151     /* Next query in the list of active, or recycled queries. */
    152     SDKCtlQuery*            next;
    153     /* A timer to run time out on this query after it has been sent. */
    154     LoopTimer               timer[1];
    155     /* Absolute time for this query's deadline. This is the value that query's
    156      * timer is set for after query has been transmitted to the service. */
    157     Duration                deadline;
    158     /* SDK controller socket that owns the query. */
    159     SDKCtlSocket*           sdkctl;
    160     /* A callback to invoke on query state changes. */
    161     on_sdkctl_query_cb      query_cb;
    162     /* An opaque pointer associated with this query. */
    163     void*                   query_opaque;
    164     /* Points to an address of a buffer where to save query response. */
    165     void**                  response_buffer;
    166     /* Points to a variable containing size of the response buffer (on the way in),
    167      * or actual query response size (when query is completed). */
    168     uint32_t*               response_size;
    169     /* Internal response buffer, allocated if query creator didn't provide its
    170      * own. This field is valid only if response_buffer field is NULL, or is
    171      * pointing to this field. */
    172     void*                   internal_resp_buffer;
    173     /* Internal response buffer size This field is valid only if response_size
    174      * field is NULL, or is pointing to this field. */
    175     uint32_t                internal_resp_size;
    176     /* Number of outstanding references to the query. */
    177     int                     ref_count;
    178 
    179     /* Common packet header. Query data immediately follows this header, so it
    180      * must be last field in SDKCtlQuery descriptor. */
    181     SDKCtlQueryHeader       header;
    182 };
    183 
    184 /* Query reply descriptor.
    185  *
    186  * All replies to a query, sent and received via SDK controller socket begin with
    187  * this header, with query reply data immediately following this header.
    188  */
    189 typedef struct SDKCtlQueryReplyHeader {
    190     /* Data packet header for this reply. */
    191     SDKCtlPacketHeader  packet;
    192 
    193     /* An identifier for the query that is addressed with this reply. */
    194     int                 query_id;
    195 } SDKCtlQueryReplyHeader;
    196 
    197 /********************************************************************************
    198  *                      SDK Control Socket declarations
    199  *******************************************************************************/
    200 
    201 /* Enumerates SDKCtlSocket states. */
    202 typedef enum SDKCtlSocketState {
    203     /* Socket is disconnected from SDK controller. */
    204     SDKCTL_SOCKET_DISCONNECTED,
    205     /* Connection to SDK controller is in progress. */
    206     SDKCTL_SOCKET_CONNECTING,
    207     /* Socket is connected to an SDK controller service. */
    208     SDKCTL_SOCKET_CONNECTED
    209 } SDKCtlSocketState;
    210 
    211 /* Enumerates SDKCtlSocket I/O dispatcher states. */
    212 typedef enum SDKCtlIODispatcherState {
    213     /* I/O dispatcher expects a packet header. */
    214     SDKCTL_IODISP_EXPECT_HEADER,
    215     /* I/O dispatcher expects packet data. */
    216     SDKCTL_IODISP_EXPECT_DATA,
    217     /* I/O dispatcher expects query response header. */
    218     SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER,
    219     /* I/O dispatcher expects query response data. */
    220     SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA,
    221 } SDKCtlIODispatcherState;
    222 
    223 /* SDKCtlSocket I/O dispatcher descriptor. */
    224 typedef struct SDKCtlIODispatcher {
    225     /* SDKCtlSocket instance for this dispatcher. */
    226     SDKCtlSocket*               sdkctl;
    227     /* Dispatcher state. */
    228     SDKCtlIODispatcherState     state;
    229     /* Unites all types of headers used in SDK controller data exchange. */
    230     union {
    231         /* Common packet header. */
    232         SDKCtlPacketHeader      header;
    233         /* Header for a query packet. */
    234         SDKCtlQueryHeader       query_header;
    235         /* Header for a query response packet. */
    236         SDKCtlQueryReplyHeader  query_reply_header;
    237     };
    238     /* Descriptor of a packet packet received from SDK controller. */
    239     SDKCtlPacket*               packet;
    240     /* A query for which a reply is currently being received. */
    241     SDKCtlQuery*                current_query;
    242 } SDKCtlIODispatcher;
    243 
    244 /* SDK controller socket descriptor. */
    245 struct SDKCtlSocket {
    246     /* SDK controller socket state */
    247     SDKCtlSocketState           state;
    248     /* I/O dispatcher for the socket. */
    249     SDKCtlIODispatcher          io_dispatcher;
    250     /* Asynchronous socket connected to SDK Controller on the device. */
    251     AsyncSocket*                as;
    252     /* Client callback that monitors this socket connection. */
    253     on_sdkctl_connection_cb     on_connection;
    254     /* A callback to invoke when handshake message is received from the
    255      * SDK controller. */
    256     on_sdkctl_handshake_cb      on_handshake;
    257     /* A callback to invoke when a message is received from the SDK controller. */
    258     on_sdkctl_message_cb        on_message;
    259     /* An opaque pointer associated with this socket. */
    260     void*                       opaque;
    261     /* Name of an SDK controller service this socket is connected to. */
    262     char*                       service_name;
    263     /* I/O looper for timers. */
    264     Looper*                     looper;
    265     /* Head of the active query list. */
    266     SDKCtlQuery*                query_head;
    267     /* Tail of the active query list. */
    268     SDKCtlQuery*                query_tail;
    269     /* Query ID generator that gets incremented for each new query. */
    270     int                         next_query_id;
    271     /* Timeout before trying to reconnect after disconnection. */
    272     int                         reconnect_to;
    273     /* Number of outstanding references to this descriptor. */
    274     int                         ref_count;
    275     /* Head of the recycled memory */
    276     SDKCtlRecycled*             recycler;
    277     /* Recyclable block size. */
    278     uint32_t                    recycler_block_size;
    279     /* Maximum number of blocks to recycle. */
    280     int                         recycler_max;
    281     /* Number of blocs in the recycler. */
    282     int                         recycler_count;
    283 };
    284 
    285 /********************************************************************************
    286  *                      SDKCtlSocket recycling management
    287  *******************************************************************************/
    288 
    289 /* Gets a recycled block for a given SDKCtlSocket, or allocates new memory
    290  * block. */
    291 static void*
    292 _sdkctl_socket_alloc_recycler(SDKCtlSocket* sdkctl, uint32_t size)
    293 {
    294     SDKCtlRecycled* block = NULL;
    295 
    296     if (sdkctl->recycler != NULL && size <= sdkctl->recycler_block_size) {
    297         /* There are blocks in the recycler, and requested size fits. */
    298         block = sdkctl->recycler;
    299         sdkctl->recycler = block->next;
    300         block->size = sdkctl->recycler_block_size;
    301         sdkctl->recycler_count--;
    302     } else if (size <= sdkctl->recycler_block_size) {
    303         /* There are no blocks in the recycler, but requested size fits. */
    304         block = malloc(sdkctl->recycler_block_size);
    305         if (block == NULL) {
    306             APANIC("SDKCtl %s: Unable to allocate %d bytes block",
    307                    sdkctl->service_name, sdkctl->recycler_block_size);
    308         }
    309         block->size = sdkctl->recycler_block_size;
    310     } else {
    311         /* Requested size doesn't fit the recycler. */
    312         block = malloc(size);
    313         if (block == NULL) {
    314             APANIC("SDKCtl %s: Unable to allocate %d bytes block",
    315                    sdkctl->service_name, size);
    316         }
    317         block->size = size;
    318     }
    319 
    320     return block;
    321 }
    322 
    323 /* Recycles, or frees a block of memory for a given SDKCtlSocket. */
    324 static void
    325 _sdkctl_socket_free_recycler(SDKCtlSocket* sdkctl, void* mem)
    326 {
    327     SDKCtlRecycled* block = (SDKCtlRecycled*)mem;
    328 
    329     if (sdkctl->recycler_count == sdkctl->recycler_max ||
    330         block->size != sdkctl->recycler_block_size) {
    331         /* Recycler is full, or block cannot be recycled. */
    332         free(mem);
    333         return;
    334     }
    335 
    336     block->next = sdkctl->recycler;
    337     sdkctl->recycler = block;
    338     sdkctl->recycler_count++;
    339 }
    340 
    341 /* Empties the recycler for a given SDKCtlSocket. */
    342 static void
    343 _sdkctl_socket_empty_recycler(SDKCtlSocket* sdkctl)
    344 {
    345     SDKCtlRecycled* block = sdkctl->recycler;
    346     while (block != NULL) {
    347         void* to_free = block;
    348         block = block->next;
    349         free(to_free);
    350     }
    351     sdkctl->recycler = NULL;
    352     sdkctl->recycler_count = 0;
    353 }
    354 
    355 /********************************************************************************
    356  *                      SDKCtlSocket query list management
    357  *******************************************************************************/
    358 
    359 /* Adds a query to the list of active queries.
    360  * Param:
    361  *  sdkctl - SDKCtlSocket instance for the query.
    362  *  query - Query to add to the list.
    363  */
    364 static void
    365 _sdkctl_socket_add_query(SDKCtlQuery* query)
    366 {
    367     SDKCtlSocket* const sdkctl = query->sdkctl;
    368     if (sdkctl->query_head == NULL) {
    369         sdkctl->query_head = sdkctl->query_tail = query;
    370     } else {
    371         sdkctl->query_tail->next = query;
    372         sdkctl->query_tail = query;
    373     }
    374 
    375     /* Keep the query referenced while it's in the list. */
    376     sdkctl_query_reference(query);
    377 }
    378 
    379 /* Removes a query from the list of active queries.
    380  * Param:
    381  *  query - Query to remove from the list of active queries.
    382  * Return:
    383  *  Boolean: 1 if query has been removed, or 0 if query has not been found in the
    384  *  list of active queries.
    385  */
    386 static int
    387 _sdkctl_socket_remove_query(SDKCtlQuery* query)
    388 {
    389     SDKCtlSocket* const sdkctl = query->sdkctl;
    390     SDKCtlQuery* prev = NULL;
    391     SDKCtlQuery* head = sdkctl->query_head;
    392 
    393     /* Quick check: the query could be currently handled by dispatcher. */
    394     if (sdkctl->io_dispatcher.current_query == query) {
    395         /* Release the query from dispatcher. */
    396         sdkctl_query_release(query);
    397         sdkctl->io_dispatcher.current_query = NULL;
    398         return 1;
    399     }
    400 
    401     /* Remove query from the list. */
    402     while (head != NULL && query != head) {
    403         prev = head;
    404         head = head->next;
    405     }
    406     if (head != NULL) {
    407         if (prev == NULL) {
    408             /* Query is at the head of the list. */
    409             assert(query == sdkctl->query_head);
    410             sdkctl->query_head = query->next;
    411         } else {
    412             /* Query is in the middle / at the end of the list. */
    413             assert(query != sdkctl->query_head);
    414             prev->next = query->next;
    415         }
    416         if (sdkctl->query_tail == query) {
    417             /* Query is at the tail of the list. */
    418             assert(query->next == NULL);
    419             sdkctl->query_tail = prev;
    420         }
    421         query->next = NULL;
    422 
    423         /* Release query that is now removed from the list. Note that query
    424          * passed to this routine should hold an extra reference, owned by the
    425          * caller. */
    426         sdkctl_query_release(query);
    427         return 1;
    428     } else {
    429         D("%s: Query %p is not found in the list.", sdkctl->service_name, query);
    430         return 0;
    431     }
    432 }
    433 
    434 /* Removes a query (based on query ID) from the list of active queries.
    435  * Param:
    436  *  sdkctl - SDKCtlSocket instance that owns the query.
    437  *  query_id - Identifies the query to remove.
    438  * Return:
    439  *  A query removed from the list of active queries, or NULL if query with the
    440  *  given ID has not been found in the list.
    441  */
    442 static SDKCtlQuery*
    443 _sdkctl_socket_remove_query_id(SDKCtlSocket* sdkctl, int query_id)
    444 {
    445     SDKCtlQuery* prev = NULL;
    446     SDKCtlQuery* head = sdkctl->query_head;
    447 
    448     /* Quick check: the query could be currently handled by dispatcher. */
    449     if (sdkctl->io_dispatcher.current_query != NULL &&
    450         sdkctl->io_dispatcher.current_query->header.query_id == query_id) {
    451         /* Release the query from dispatcher. */
    452         SDKCtlQuery* const query = sdkctl->io_dispatcher.current_query;
    453         sdkctl->io_dispatcher.current_query = NULL;
    454         return query;
    455     }
    456 
    457     /* Remove query from the list. */
    458     while (head != NULL && head->header.query_id != query_id) {
    459         prev = head;
    460         head = head->next;
    461     }
    462     if (head != NULL) {
    463         /* Query is found in the list. */
    464         SDKCtlQuery* const query = head;
    465         if (prev == NULL) {
    466             /* Query is at the head of the list. */
    467             assert(query == sdkctl->query_head);
    468             sdkctl->query_head = query->next;
    469         } else {
    470             /* Query is in the middle, or at the end of the list. */
    471             assert(query != sdkctl->query_head);
    472             prev->next = query->next;
    473         }
    474         if (sdkctl->query_tail == query) {
    475             /* Query is at the tail of the list. */
    476             assert(query->next == NULL);
    477             sdkctl->query_tail = prev;
    478         }
    479         query->next = NULL;
    480         return query;
    481     } else {
    482         D("%s: Query ID %d is not found in the list.",
    483           sdkctl->service_name, query_id);
    484         return NULL;
    485     }
    486 }
    487 
    488 /* Pulls the first query from the list of active queries.
    489  * Param:
    490  *  sdkctl - SDKCtlSocket instance that owns the query.
    491  * Return:
    492  *  A query removed pulled from the list of active queries, or NULL if query
    493  *  list is empty.
    494  */
    495 static SDKCtlQuery*
    496 _sdkctl_socket_pull_first_query(SDKCtlSocket* sdkctl)
    497 {
    498     SDKCtlQuery* const query = sdkctl->query_head;
    499 
    500     if (query != NULL) {
    501         sdkctl->query_head = query->next;
    502         if (sdkctl->query_head == NULL) {
    503             sdkctl->query_tail = NULL;
    504         }
    505     }
    506     return query;
    507 }
    508 
    509 /* Generates new query ID for the given SDKCtl. */
    510 static int
    511 _sdkctl_socket_next_query_id(SDKCtlSocket* sdkctl)
    512 {
    513     return ++sdkctl->next_query_id;
    514 }
    515 
    516 /********************************************************************************
    517  *                      SDKCtlPacket implementation
    518  *******************************************************************************/
    519 
    520 /* Alocates a packet. */
    521 static SDKCtlPacket*
    522 _sdkctl_packet_new(SDKCtlSocket* sdkctl, int size, int type)
    523 {
    524     const uint32_t total_size = sizeof(SDKCtlPacket) + size;
    525     SDKCtlPacket* const packet = _sdkctl_socket_alloc_recycler(sdkctl, total_size);
    526 
    527     packet->sdkctl      = sdkctl;
    528     packet->ref_count   = 1;
    529     packet->header.size = size;
    530     packet->header.type = type;
    531 
    532     /* Refence SDKCTlSocket that owns this packet. */
    533     sdkctl_socket_reference(sdkctl);
    534 
    535     return packet;
    536 }
    537 
    538 /* Frees a packet. */
    539 static void
    540 _sdkctl_packet_free(SDKCtlPacket* packet)
    541 {
    542     SDKCtlSocket* const sdkctl = packet->sdkctl;
    543 
    544     /* Free allocated resources. */
    545     _sdkctl_socket_free_recycler(packet->sdkctl, packet);
    546 
    547     /* Release SDKCTlSocket that owned this packet. */
    548     sdkctl_socket_release(sdkctl);
    549 }
    550 
    551 int
    552 sdkctl_packet_reference(SDKCtlPacket* packet)
    553 {
    554     assert(packet->ref_count > 0);
    555     packet->ref_count++;
    556     return packet->ref_count;
    557 }
    558 
    559 int
    560 sdkctl_packet_release(SDKCtlPacket* packet)
    561 {
    562     assert(packet->ref_count > 0);
    563     packet->ref_count--;
    564     if (packet->ref_count == 0) {
    565         /* Last reference has been dropped. Destroy this object. */
    566         _sdkctl_packet_free(packet);
    567         return 0;
    568     }
    569     return packet->ref_count;
    570 }
    571 
    572 /********************************************************************************
    573  *                    SDKCtlQuery implementation
    574  *******************************************************************************/
    575 
    576 /* Frees query descriptor. */
    577 static void
    578 _sdkctl_query_free(SDKCtlQuery* query)
    579 {
    580     if (query != NULL) {
    581         SDKCtlSocket* const sdkctl = query->sdkctl;
    582         T("SDKCtl %s: Query %p ID %d is freed.",
    583           sdkctl->service_name, query, query->header.query_id);
    584 
    585         /* Free allocated resources. */
    586         if (query->internal_resp_buffer != NULL &&
    587             (query->response_buffer == NULL ||
    588              query->response_buffer == &query->internal_resp_buffer)) {
    589             free(query->internal_resp_buffer);
    590         }
    591 
    592         loopTimer_done(query->timer);
    593         _sdkctl_socket_free_recycler(sdkctl, query);
    594 
    595         /* Release socket that owned this query. */
    596         sdkctl_socket_release(sdkctl);
    597     }
    598 }
    599 
    600 /* Cancels timeout for the query.
    601  *
    602  * For the simplicity of implementation, the dispatcher will cancel query timer
    603  * when query response data begins to flow in. If we let the timer to expire at
    604  * that stage, we will end up with data flowing in without real place to
    605  * accomodate it.
    606  */
    607 static void
    608 _sdkctl_query_cancel_timeout(SDKCtlQuery* query)
    609 {
    610     loopTimer_stop(query->timer);
    611 
    612     T("SDKCtl %s: Query %p ID %d deadline is cancelled.",
    613       query->sdkctl->service_name, query, query->header.query_id);
    614 }
    615 
    616 /*
    617  * Query I/O callbacks.
    618  */
    619 
    620 /* Callback that is invoked by the I/O dispatcher when query is successfuly
    621  * completed (i.e. response to the query is received).
    622  */
    623 static void
    624 _on_sdkctl_query_completed(SDKCtlQuery* query)
    625 {
    626     T("SDKCtl %s: Query %p ID %d is completed.",
    627       query->sdkctl->service_name, query, query->header.query_id);
    628 
    629     /* Cancel deadline, and inform the client about query completion. */
    630     _sdkctl_query_cancel_timeout(query);
    631     query->query_cb(query->query_opaque, query, ASIO_STATE_SUCCEEDED);
    632 }
    633 
    634 /* A callback that is invoked on query cancellation. */
    635 static void
    636 _on_sdkctl_query_cancelled(SDKCtlQuery* query)
    637 {
    638     /*
    639      * Query cancellation means that SDK controller is disconnected. In turn,
    640      * this means that SDK controller socket will handle disconnection in its
    641      * connection callback. So, at this point all we need to do here is to inform
    642      * the client, and then unlist the query.
    643      */
    644 
    645     /* Cancel deadline, and inform the client about query cancellation. */
    646     _sdkctl_query_cancel_timeout(query);
    647     query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
    648 }
    649 
    650 /* A timer callback that is invoked on query timeout.
    651  * Param:
    652  *  opaque - SDKCtlQuery instance.
    653  */
    654 static void
    655 _on_skdctl_query_timeout(void* opaque)
    656 {
    657     SDKCtlQuery* const query = (SDKCtlQuery*)opaque;
    658 
    659     D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out at %lld",
    660       query->sdkctl->service_name, query, query->header.query_id,
    661       query->deadline, async_socket_deadline(query->sdkctl->as, 0));
    662 
    663     /* Reference the query while we're in this callback. */
    664     sdkctl_query_reference(query);
    665 
    666     /* Inform the client about deadline expiration. Note that client may
    667      * extend the deadline, and retry the query. */
    668     const AsyncIOAction action =
    669         query->query_cb(query->query_opaque, query, ASIO_STATE_TIMED_OUT);
    670 
    671     /* For actions other than retry we will destroy the query. */
    672     if (action != ASIO_ACTION_RETRY) {
    673         _sdkctl_socket_remove_query(query);
    674     }
    675 
    676     sdkctl_query_release(query);
    677 }
    678 
    679 /* A callback that is invoked when query has been sent to the SDK controller
    680  * service. */
    681 static void
    682 _on_sdkctl_query_sent(SDKCtlQuery* query)
    683 {
    684     T("SDKCtl %s: sent %d bytes of query %p ID %d of type %d",
    685       query->sdkctl->service_name, query->header.packet.size, query,
    686       query->header.query_id, query->header.query_type);
    687 
    688     /* Inform the client about the event. */
    689     query->query_cb(query->query_opaque, query, ASIO_STATE_CONTINUES);
    690 
    691     /* Set a timer to expire at query's deadline, and let the response to come
    692      * through the dispatcher loop. */
    693     loopTimer_startAbsolute(query->timer, query->deadline);
    694 }
    695 
    696 /* An I/O callback invoked on query transmission.
    697  * Param:
    698  *  io_opaque SDKCtlQuery instance of the query that's being sent with this I/O.
    699  *  asio - Write I/O descriptor.
    700  *  status - I/O status.
    701  */
    702 static AsyncIOAction
    703 _on_sdkctl_query_send_io(void* io_opaque,
    704                          AsyncSocketIO* asio,
    705                          AsyncIOState status)
    706 {
    707     SDKCtlQuery* const query = (SDKCtlQuery*)io_opaque;
    708     AsyncIOAction action = ASIO_ACTION_DONE;
    709 
    710     /* Reference the query while we're in this callback. */
    711     sdkctl_query_reference(query);
    712 
    713     if (status == ASIO_STATE_SUCCEEDED) {
    714         /* Query has been sent to the service. */
    715         _on_sdkctl_query_sent(query);
    716 
    717         sdkctl_query_release(query);
    718 
    719         return ASIO_ACTION_DONE;
    720     }
    721 
    722     /* Lets see what's going on with query transmission. */
    723     switch (status) {
    724         case ASIO_STATE_CANCELLED:
    725             T("SDKCtl %s: Query %p ID %d is cancelled in %s I/O.",
    726               query->sdkctl->service_name, query, query->header.query_id,
    727               async_socket_io_is_read(asio) ? "READ" : "WRITE");
    728             /* Remove the query from the list of active queries. */
    729             _sdkctl_socket_remove_query(query);
    730             _on_sdkctl_query_cancelled(query);
    731             break;
    732 
    733         case ASIO_STATE_TIMED_OUT:
    734             D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out in %s I/O at %lld",
    735               query->sdkctl->service_name, query, query->header.query_id,
    736               query->deadline, async_socket_io_is_read(asio) ? "READ" : "WRITE",
    737               async_socket_deadline(query->sdkctl->as, 0));
    738             /* Invoke query's callback. */
    739             action = query->query_cb(query->query_opaque, query, status);
    740             /* For actions other than retry we need to stop the query. */
    741             if (action != ASIO_ACTION_RETRY) {
    742                 _sdkctl_socket_remove_query(query);
    743             }
    744             break;
    745 
    746         case ASIO_STATE_FAILED:
    747             T("SDKCtl %s: Query %p ID %d failed in %s I/O: %d -> %s",
    748               query->sdkctl->service_name, query, query->header.query_id,
    749               async_socket_io_is_read(asio) ? "READ" : "WRITE",
    750               errno, strerror(errno));
    751             /* Invoke query's callback. Note that we will let the client to
    752              * decide what to do on I/O failure. */
    753             action = query->query_cb(query->query_opaque, query, status);
    754             /* For actions other than retry we need to stop the query. */
    755             if (action != ASIO_ACTION_RETRY) {
    756                 _sdkctl_socket_remove_query(query);
    757             }
    758             break;
    759 
    760         case ASIO_STATE_FINISHED:
    761             /* Time to disassociate with the I/O. */
    762             sdkctl_query_release(query);
    763             break;
    764 
    765         default:
    766             /* Transitional state. */
    767             break;
    768     }
    769 
    770     sdkctl_query_release(query);
    771 
    772     return action;
    773 }
    774 
    775 /********************************************************************************
    776  *                    SDKCtlQuery public API implementation
    777  ********************************************************************************/
    778 
    779 SDKCtlQuery*
    780 sdkctl_query_new(SDKCtlSocket* sdkctl, int query_type, uint32_t in_data_size)
    781 {
    782     const uint32_t total_size = sizeof(SDKCtlQuery) + in_data_size;
    783 
    784     SDKCtlQuery* const query = _sdkctl_socket_alloc_recycler(sdkctl, total_size);
    785     query->next                 = NULL;
    786     query->sdkctl               = sdkctl;
    787     query->response_buffer      = NULL;
    788     query->response_size        = NULL;
    789     query->internal_resp_buffer = NULL;
    790     query->internal_resp_size   = 0;
    791     query->query_cb             = NULL;
    792     query->query_opaque         = NULL;
    793     query->deadline             = DURATION_INFINITE;
    794     query->ref_count            = 1;
    795     query->header.packet.size   = sizeof(SDKCtlQueryHeader) + in_data_size;
    796     query->header.packet.type   = SDKCTL_PACKET_QUERY;
    797     query->header.query_id      = _sdkctl_socket_next_query_id(sdkctl);
    798     query->header.query_type    = query_type;
    799 
    800     /* Initialize timer to fire up on query deadline expiration. */
    801     loopTimer_init(query->timer, sdkctl->looper, _on_skdctl_query_timeout, query);
    802 
    803     /* Reference socket that owns this query. */
    804     sdkctl_socket_reference(sdkctl);
    805 
    806     T("SDKCtl %s: Query %p ID %d type %d is created for %d bytes of data.",
    807       query->sdkctl->service_name, query, query->header.query_id,
    808       query_type, in_data_size);
    809 
    810     return query;
    811 }
    812 
    813 SDKCtlQuery*
    814 sdkctl_query_new_ex(SDKCtlSocket* sdkctl,
    815                     int query_type,
    816                     uint32_t in_data_size,
    817                     const void* in_data,
    818                     void** response_buffer,
    819                     uint32_t* response_size,
    820                     on_sdkctl_query_cb query_cb,
    821                     void* query_opaque)
    822 {
    823     SDKCtlQuery* const query = sdkctl_query_new(sdkctl, query_type, in_data_size);
    824 
    825     query->response_buffer  = response_buffer;
    826     if (query->response_buffer == NULL) {
    827         /* Creator didn't supply a buffer. Use internal one instead. */
    828         query->response_buffer = &query->internal_resp_buffer;
    829         query->internal_resp_buffer = NULL;
    830     }
    831     query->response_size    = response_size;
    832     if (query->response_size == NULL) {
    833         /* Creator didn't supply a buffer for response size. Use internal one
    834          * instead. */
    835         query->response_size = &query->internal_resp_size;
    836         query->internal_resp_size = 0;
    837     }
    838     query->query_cb         = query_cb;
    839     query->query_opaque     = query_opaque;
    840     /* Init query's input buffer. */
    841     if (in_data_size != 0 && in_data != NULL) {
    842         memcpy(query + 1, in_data, in_data_size);
    843     }
    844 
    845     return query;
    846 }
    847 
    848 void
    849 sdkctl_query_send(SDKCtlQuery* query, int to)
    850 {
    851     SDKCtlSocket* const sdkctl = query->sdkctl;
    852 
    853     /* Initialize the deadline. */
    854     query->deadline = async_socket_deadline(query->sdkctl->as, to);
    855 
    856     /* List the query in the list of active queries. */
    857     _sdkctl_socket_add_query(query);
    858 
    859     /* Reference query associated with write I/O. */
    860     sdkctl_query_reference(query);
    861 
    862     /* Transmit the query to SDK controller. */
    863     async_socket_write_abs(sdkctl->as, &query->header, query->header.packet.size,
    864                            _on_sdkctl_query_send_io, query, query->deadline);
    865 
    866     T("SDKCtl %s: Query %p ID %d type %d is sent with deadline at %lld",
    867       query->sdkctl->service_name, query, query->header.query_id,
    868       query->header.query_type, query->deadline);
    869 }
    870 
    871 SDKCtlQuery*
    872 sdkctl_query_build_and_send(SDKCtlSocket* sdkctl,
    873                             int query_type,
    874                             uint32_t in_data_size,
    875                             const void* in_data,
    876                             void** response_buffer,
    877                             uint32_t* response_size,
    878                             on_sdkctl_query_cb query_cb,
    879                             void* query_opaque,
    880                             int to)
    881 {
    882     SDKCtlQuery* const query =
    883         sdkctl_query_new_ex(sdkctl, query_type, in_data_size, in_data,
    884                             response_buffer, response_size, query_cb,
    885                             query_opaque);
    886     sdkctl_query_send(query, to);
    887     return query;
    888 }
    889 
    890 int
    891 sdkctl_query_reference(SDKCtlQuery* query)
    892 {
    893     assert(query->ref_count > 0);
    894     query->ref_count++;
    895     return query->ref_count;
    896 }
    897 
    898 int
    899 sdkctl_query_release(SDKCtlQuery* query)
    900 {
    901     assert(query->ref_count > 0);
    902     query->ref_count--;
    903     if (query->ref_count == 0) {
    904         /* Last reference has been dropped. Destroy this object. */
    905         _sdkctl_query_free(query);
    906         return 0;
    907     }
    908     return query->ref_count;
    909 }
    910 
    911 /********************************************************************************
    912  *                      SDKCtlPacket implementation
    913  *******************************************************************************/
    914 
    915 /* A packet has been received from SDK controller. */
    916 static void
    917 _on_sdkctl_packet_received(SDKCtlSocket* sdkctl, SDKCtlPacket* packet)
    918 {
    919     T("SDKCtl %s: Received packet size: %d, type: %d",
    920       sdkctl->service_name, packet->header.size, packet->header.type);
    921 
    922     /* Dispatch received packet to the client. */
    923     sdkctl->on_message(sdkctl->opaque, sdkctl, packet, packet->header.type,
    924                        packet + 1, packet->header.size - sizeof(SDKCtlPacketHeader));
    925 }
    926 
    927 /********************************************************************************
    928  *                      SDKCtlIODispatcher implementation
    929  *******************************************************************************/
    930 
    931 /* An I/O callback invoked when data gets received from the socket.
    932  * Param:
    933  *  io_opaque SDKCtlIODispatcher instance associated with the reader.
    934  *  asio - Read I/O descriptor.
    935  *  status - I/O status.
    936  */
    937 static AsyncIOAction _on_sdkctl_io_dispatcher_io(void* io_opaque,
    938                                                  AsyncSocketIO* asio,
    939                                                  AsyncIOState status);
    940 
    941 /* Starts I/O dispatcher for SDK controller socket. */
    942 static void
    943 _sdkctl_io_dispatcher_start(SDKCtlSocket* sdkctl) {
    944     SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
    945 
    946     dispatcher->state           = SDKCTL_IODISP_EXPECT_HEADER;
    947     dispatcher->sdkctl          = sdkctl;
    948     dispatcher->packet          = NULL;
    949     dispatcher->current_query   = NULL;
    950 
    951     /* Register a packet header reader with the socket. */
    952     async_socket_read_rel(dispatcher->sdkctl->as, &dispatcher->header,
    953                           sizeof(SDKCtlPacketHeader), _on_sdkctl_io_dispatcher_io,
    954                           dispatcher, -1);
    955 }
    956 
    957 /* Resets I/O dispatcher for SDK controller socket. */
    958 static void
    959 _sdkctl_io_dispatcher_reset(SDKCtlSocket* sdkctl) {
    960     SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
    961 
    962     /* Cancel current query. */
    963     if (dispatcher->current_query != NULL) {
    964         SDKCtlQuery* const query = dispatcher->current_query;
    965         dispatcher->current_query = NULL;
    966         _on_sdkctl_query_cancelled(query);
    967         sdkctl_query_release(query);
    968     }
    969 
    970     /* Free packet data buffer. */
    971     if (dispatcher->packet != NULL) {
    972         sdkctl_packet_release(dispatcher->packet);
    973         dispatcher->packet = NULL;
    974     }
    975 
    976     /* Reset dispatcher state. */
    977     dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
    978 }
    979 
    980 /*
    981  * I/O dispatcher callbacks.
    982  */
    983 
    984 /* A callback that is invoked when a failure occurred while dispatcher was
    985  * reading data from the socket.
    986  */
    987 static void
    988 _on_io_dispatcher_io_failure(SDKCtlIODispatcher* dispatcher,
    989                              AsyncSocketIO* asio)
    990 {
    991     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
    992 
    993     D("SDKCtl %s: Dispatcher I/O failure: %d -> %s",
    994       sdkctl->service_name, errno, strerror(errno));
    995 
    996     /* We treat all I/O failures same way we treat disconnection. Just cancel
    997      * everything, disconnect, and let the client to decide what to do next. */
    998     sdkctl_socket_disconnect(sdkctl);
    999 
   1000     /* Report disconnection to the client, and let it restore connection in this
   1001      * callback. */
   1002     sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
   1003 }
   1004 
   1005 /* A callback that is invoked when dispatcher's reader has been cancelled. */
   1006 static void
   1007 _on_io_dispatcher_io_cancelled(SDKCtlIODispatcher* dispatcher,
   1008                                AsyncSocketIO* asio)
   1009 {
   1010     T("SDKCtl %s: Dispatcher I/O cancelled.", dispatcher->sdkctl->service_name);
   1011 
   1012     /* If we're in the middle of receiving query reply we need to cancel the
   1013      * query. */
   1014     if (dispatcher->current_query != NULL) {
   1015         SDKCtlQuery* const query = dispatcher->current_query;
   1016         dispatcher->current_query = NULL;
   1017         _on_sdkctl_query_cancelled(query);
   1018         sdkctl_query_release(query);
   1019     }
   1020 
   1021     /* Discard packet data we've received so far. */
   1022     if (dispatcher->packet != NULL) {
   1023         sdkctl_packet_release(dispatcher->packet);
   1024         dispatcher->packet = NULL;
   1025     }
   1026 }
   1027 
   1028 /* A generic packet header has been received by I/O dispatcher. */
   1029 static AsyncIOAction
   1030 _on_io_dispatcher_packet_header(SDKCtlIODispatcher* dispatcher,
   1031                                 AsyncSocketIO* asio)
   1032 {
   1033     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
   1034 
   1035     T("SDKCtl %s: Packet header type %d, size %d is received.",
   1036       dispatcher->sdkctl->service_name, dispatcher->header.type,
   1037       dispatcher->header.size);
   1038 
   1039     /* Here we have three choices for the packet, that define the rest of
   1040      * the data that follow it:
   1041      * - Regular packet,
   1042      * - Response to a query that has been sent to SDK controller,
   1043      * - A query from SDK controller.
   1044      * Update the state accordingly, and initiate reading of the
   1045      * remaining of the packet.
   1046      */
   1047      if (dispatcher->header.type == SDKCTL_PACKET_QUERY_RESPONSE) {
   1048         /* This is a response to the query. Before receiving response data we
   1049          * need to locate the relevant query, and use its response buffer to read
   1050          * the data. For that we need to obtain query ID firts. So, initiate
   1051          * reading of the remaining part of SDKCtlQueryReplyHeader. */
   1052         dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER;
   1053         async_socket_read_rel(sdkctl->as, &dispatcher->query_reply_header.query_id,
   1054                               sizeof(SDKCtlQueryReplyHeader) - sizeof(SDKCtlPacketHeader),
   1055                              _on_sdkctl_io_dispatcher_io, dispatcher, -1);
   1056     } else {
   1057         /* For regular packets, as well as queries, we simply allocate buffer,
   1058          * that fits the entire packet, and read the remainder of the data in
   1059          * there. */
   1060         dispatcher->state = SDKCTL_IODISP_EXPECT_DATA;
   1061         dispatcher->packet =
   1062             _sdkctl_packet_new(sdkctl, dispatcher->header.size,
   1063                                dispatcher->header.type);
   1064         /* Initiate reading of the packet data. */
   1065         async_socket_read_rel(sdkctl->as, dispatcher->packet + 1,
   1066                               dispatcher->header.size - sizeof(SDKCtlPacketHeader),
   1067                               _on_sdkctl_io_dispatcher_io, dispatcher, -1);
   1068     }
   1069 
   1070     return ASIO_ACTION_DONE;
   1071 }
   1072 
   1073 /* A generic packet has been received by I/O dispatcher. */
   1074 static AsyncIOAction
   1075 _on_io_dispatcher_packet(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
   1076 {
   1077     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
   1078 
   1079     T("SDKCtl %s: Packet type %d, size %d is received.",
   1080       dispatcher->sdkctl->service_name, dispatcher->header.type,
   1081       dispatcher->header.size);
   1082 
   1083     _on_sdkctl_packet_received(sdkctl, dispatcher->packet);
   1084     sdkctl_packet_release(dispatcher->packet);
   1085     dispatcher->packet = NULL;
   1086 
   1087     /* Get ready for the next I/O cycle. */
   1088     dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
   1089     async_socket_read_rel(sdkctl->as, &dispatcher->header, sizeof(SDKCtlPacketHeader),
   1090                           _on_sdkctl_io_dispatcher_io, dispatcher, -1);
   1091     return ASIO_ACTION_DONE;
   1092 }
   1093 
   1094 /* A query reply header has been received by I/O dispatcher. */
   1095 static AsyncIOAction
   1096 _on_io_dispatcher_query_reply_header(SDKCtlIODispatcher* dispatcher,
   1097                                      AsyncSocketIO* asio)
   1098 {
   1099     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
   1100     SDKCtlQuery* query;
   1101 
   1102     T("SDKCtl %s: Query reply header is received for query ID %d",
   1103       dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
   1104 
   1105     /* Pull the query out of the list of active queries. It's the dispatcher that
   1106      * owns this query now. */
   1107     dispatcher->current_query =
   1108         _sdkctl_socket_remove_query_id(sdkctl, dispatcher->query_reply_header.query_id);
   1109     query = dispatcher->current_query;
   1110 
   1111     if (query == NULL) {
   1112         D("%s: Query #%d is not found by dispatcher",
   1113           dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
   1114 
   1115         /* Query is not found. Just read the remainder of reply up in the air,
   1116          * and then discard when it's over. */
   1117         dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
   1118         dispatcher->packet =
   1119             _sdkctl_packet_new(sdkctl, dispatcher->header.size,
   1120                                dispatcher->header.type);
   1121         /* Copy query reply info to the packet. */
   1122         memcpy(&dispatcher->packet->header, &dispatcher->query_reply_header,
   1123                sizeof(SDKCtlQueryReplyHeader));
   1124         async_socket_read_rel(sdkctl->as, &dispatcher->query_header + 1,
   1125                               dispatcher->header.size - sizeof(SDKCtlQueryReplyHeader),
   1126                              _on_sdkctl_io_dispatcher_io, dispatcher, -1);
   1127     } else {
   1128         /* Prepare to receive query reply. For the simplicity sake, cancel query
   1129          * time out, so it doesn't expire on us while we're in the middle of
   1130          * receiving query's reply. */
   1131         _sdkctl_query_cancel_timeout(query);
   1132 
   1133         /* Adjust the reply buffer set for the query (if needed). */
   1134         const uint32_t query_data_size =
   1135             dispatcher->header.size - sizeof(SDKCtlQueryReplyHeader);
   1136         if (*query->response_size < query_data_size) {
   1137             *query->response_buffer = malloc(query_data_size);
   1138             if (*query->response_buffer == NULL) {
   1139                 APANIC("%s: Unable to allocate %d bytes for query response",
   1140                        sdkctl->service_name, query_data_size);
   1141             }
   1142         }
   1143         /* Save the actual query response size. */
   1144         *query->response_size = query_data_size;
   1145 
   1146         /* Start reading query response. */
   1147         dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
   1148         async_socket_read_rel(sdkctl->as, *query->response_buffer,
   1149                               *query->response_size, _on_sdkctl_io_dispatcher_io,
   1150                               dispatcher, -1);
   1151     }
   1152 
   1153     return ASIO_ACTION_DONE;
   1154 }
   1155 
   1156 /* A query reply header has been received by I/O dispatcher. */
   1157 static AsyncIOAction
   1158 _on_io_dispatcher_query_reply(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
   1159 {
   1160     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
   1161     SDKCtlQuery* const query = dispatcher->current_query;
   1162     dispatcher->current_query = NULL;
   1163 
   1164     if (query != NULL) {
   1165         _ANDROID_ASSERT(query->header.query_id == dispatcher->query_reply_header.query_id,
   1166                         "SDKCtl %s: Query ID mismatch in I/O dispatcher",
   1167                         sdkctl->service_name);
   1168         T("SDKCtl %s: Query reply is received for query %p ID %d. Reply size is %d",
   1169           dispatcher->sdkctl->service_name, query, query->header.query_id,
   1170           *query->response_size);
   1171 
   1172         /* Complete the query, and release it from the dispatcher. */
   1173         _on_sdkctl_query_completed(query);
   1174         sdkctl_query_release(query);
   1175     } else {
   1176         /* This was "read up in the air" for a cancelled query. Just discard the
   1177          * read data. */
   1178         if (dispatcher->packet != NULL) {
   1179             sdkctl_packet_release(dispatcher->packet);
   1180             dispatcher->packet = NULL;
   1181         }
   1182     }
   1183 
   1184     /* Get ready for the next I/O cycle. */
   1185     dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
   1186     async_socket_read_rel(sdkctl->as, &dispatcher->header, sizeof(SDKCtlPacketHeader),
   1187                           _on_sdkctl_io_dispatcher_io, dispatcher, -1);
   1188     return ASIO_ACTION_DONE;
   1189 }
   1190 
   1191 /* An I/O callback invoked when data gets received from the socket.
   1192  * This is main I/O dispatcher loop.
   1193  * Param:
   1194  *  io_opaque SDKCtlIODispatcher instance associated with the reader.
   1195  *  asio - Read I/O descriptor.
   1196  *  status - I/O status.
   1197  */
   1198 static AsyncIOAction
   1199 _on_sdkctl_io_dispatcher_io(void* io_opaque,
   1200                             AsyncSocketIO* asio,
   1201                             AsyncIOState status)
   1202 {
   1203     AsyncIOAction action = ASIO_ACTION_DONE;
   1204     SDKCtlIODispatcher* const dispatcher = (SDKCtlIODispatcher*)io_opaque;
   1205     SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
   1206 
   1207     /* Reference SDKCtlSocket while we're in this callback. */
   1208     sdkctl_socket_reference(sdkctl);
   1209 
   1210     if (status != ASIO_STATE_SUCCEEDED) {
   1211         /* Something going on with I/O other than receiving data.. */
   1212         switch (status) {
   1213             case ASIO_STATE_STARTED:
   1214                 /* Data has started flowing in. Cancel timeout on I/O that has
   1215                  * started, so we can complete the current state of the
   1216                  * dispatcher without interruptions other than I/O failures. */
   1217                 async_socket_io_cancel_time_out(asio);
   1218                 break;
   1219 
   1220             case ASIO_STATE_FAILED:
   1221                 /* I/O failure has occurred. Handle the failure. */
   1222                 _on_io_dispatcher_io_failure(dispatcher, asio);
   1223                 break;
   1224 
   1225             case ASIO_STATE_TIMED_OUT:
   1226                  /* The way I/O dispatcher is implemented, this should never
   1227                   * happen, because dispatcher doesn't set I/O expiration time
   1228                   * when registering its readers. */
   1229                 _ANDROID_ASSERT(0,
   1230                     "SDKCtl %s: We should never receive ASIO_STATE_TIMED_OUT in SDKCtl I/O dispatcher.",
   1231                     sdkctl->service_name);
   1232                 break;
   1233 
   1234             case ASIO_STATE_CANCELLED:
   1235                 /* Cancellation means that we're in the middle of handling
   1236                  * disconnection. Sooner or later, this dispatcher will be reset,
   1237                  * so we don't really care about keeping its state at this point.
   1238                  */
   1239                 _on_io_dispatcher_io_cancelled(dispatcher, asio);
   1240                 break;
   1241 
   1242             case ASIO_STATE_FINISHED:
   1243                 break;
   1244 
   1245             default:
   1246                 _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O status %d in the dispatcher",
   1247                                 sdkctl->service_name, status);
   1248                 /* Handle this as protocol failure. */
   1249                 errno = EINVAL;
   1250                 _on_io_dispatcher_io_failure(dispatcher, asio);
   1251                 action = ASIO_ACTION_ABORT;
   1252                 break;
   1253         }
   1254 
   1255         sdkctl_socket_release(sdkctl);
   1256 
   1257         return action;
   1258     }
   1259 
   1260     /* Requested data has been read. Handle the chunk depending on dispatcher's
   1261      * state. */
   1262     switch (dispatcher->state) {
   1263         case SDKCTL_IODISP_EXPECT_HEADER:
   1264             /* A generic packet header is received. */
   1265             action = _on_io_dispatcher_packet_header(dispatcher, asio);
   1266             break;
   1267 
   1268         case SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER:
   1269             /* Query reply header is received. */
   1270             action = _on_io_dispatcher_query_reply_header(dispatcher, asio);
   1271             break;
   1272 
   1273         case SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA:
   1274             /* Query reply is received. Complete the query. */
   1275             action = _on_io_dispatcher_query_reply(dispatcher, asio);
   1276             break;
   1277 
   1278         case SDKCTL_IODISP_EXPECT_DATA:
   1279             /* A generic packet is received. */
   1280             action = _on_io_dispatcher_packet(dispatcher, asio);
   1281             break;
   1282 
   1283         default:
   1284             _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O dispacher state %d",
   1285                             sdkctl->service_name, dispatcher->state);
   1286             break;
   1287     }
   1288 
   1289     sdkctl_socket_release(sdkctl);
   1290 
   1291     return action;
   1292 }
   1293 
   1294 /********************************************************************************
   1295  *                       SDKCtlSocket internals.
   1296  *******************************************************************************/
   1297 
   1298 /* Cancels all queries that is active on this socket. */
   1299 static void
   1300 _sdkctl_socket_cancel_all_queries(SDKCtlSocket* sdkctl)
   1301 {
   1302     SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
   1303     SDKCtlQuery* query;
   1304 
   1305     /* Cancel query that is being completed in dispatcher. */
   1306     if (dispatcher->current_query != NULL) {
   1307         SDKCtlQuery* const query = dispatcher->current_query;
   1308         dispatcher->current_query = NULL;
   1309         _on_sdkctl_query_cancelled(query);
   1310         sdkctl_query_release(query);
   1311     }
   1312 
   1313     /* One by one empty query list cancelling pulled queries. */
   1314     query = _sdkctl_socket_pull_first_query(sdkctl);
   1315     while (query != NULL) {
   1316         _sdkctl_query_cancel_timeout(query);
   1317         query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
   1318         sdkctl_query_release(query);
   1319         query = _sdkctl_socket_pull_first_query(sdkctl);
   1320     }
   1321 }
   1322 
   1323 /* Cancels all packets that is active on this socket. */
   1324 static void
   1325 _sdkctl_socket_cancel_all_packets(SDKCtlSocket* sdkctl)
   1326 {
   1327 }
   1328 
   1329 /* Cancels all I/O that is active on this socket. */
   1330 static void
   1331 _sdkctl_socket_cancel_all_io(SDKCtlSocket* sdkctl)
   1332 {
   1333     /* Cancel all queries, and packets that are active for this I/O. */
   1334     _sdkctl_socket_cancel_all_queries(sdkctl);
   1335     _sdkctl_socket_cancel_all_packets(sdkctl);
   1336 }
   1337 
   1338 /* Disconnects AsyncSocket for SDKCtlSocket. */
   1339 static void
   1340 _sdkctl_socket_disconnect_socket(SDKCtlSocket* sdkctl)
   1341 {
   1342     if (sdkctl->as != NULL) {
   1343         /* Disconnect the socket. This will trigger I/O cancellation callbacks. */
   1344         async_socket_disconnect(sdkctl->as);
   1345 
   1346         /* Cancel all I/O that is active on this socket. */
   1347         _sdkctl_socket_cancel_all_io(sdkctl);
   1348 
   1349         /* Reset I/O dispatcher. */
   1350         _sdkctl_io_dispatcher_reset(sdkctl);
   1351     }
   1352 
   1353     sdkctl->state = SDKCTL_SOCKET_DISCONNECTED;
   1354 }
   1355 
   1356 /* Frees SDKCtlSocket instance. */
   1357 static void
   1358 _sdkctl_socket_free(SDKCtlSocket* sdkctl)
   1359 {
   1360     if (sdkctl != NULL) {
   1361         /* Disconnect, and release the socket. */
   1362         if (sdkctl->as != NULL) {
   1363             async_socket_disconnect(sdkctl->as);
   1364             async_socket_release(sdkctl->as);
   1365         }
   1366 
   1367         /* Free allocated resources. */
   1368         if (sdkctl->looper != NULL) {
   1369             looper_free(sdkctl->looper);
   1370         }
   1371         if (sdkctl->service_name != NULL) {
   1372             free(sdkctl->service_name);
   1373         }
   1374         _sdkctl_socket_empty_recycler(sdkctl);
   1375 
   1376         AFREE(sdkctl);
   1377     }
   1378 }
   1379 
   1380 /********************************************************************************
   1381  *                    SDK Control Socket connection callbacks.
   1382  *******************************************************************************/
   1383 
   1384 /* Initiates handshake query when SDK controller socket is connected. */
   1385 static void _sdkctl_do_handshake(SDKCtlSocket* sdkctl);
   1386 
   1387 /* A socket connection is established.
   1388  * Here we will start I/O dispatcher, and will initiate a handshake with
   1389  * the SdkController service for this socket. */
   1390 static AsyncIOAction
   1391 _on_async_socket_connected(SDKCtlSocket* sdkctl)
   1392 {
   1393     D("SDKCtl %s: Socket is connected.", sdkctl->service_name);
   1394 
   1395     /* Notify the client that connection is established. */
   1396     const AsyncIOAction action =
   1397         sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_SUCCEEDED);
   1398 
   1399     if (action == ASIO_ACTION_DONE) {
   1400         /* Initialize, and start main I/O dispatcher. */
   1401         _sdkctl_io_dispatcher_start(sdkctl);
   1402 
   1403         /* Initiate handshake. */
   1404         _sdkctl_do_handshake(sdkctl);
   1405 
   1406         return action;
   1407     } else {
   1408         /* Client didn't like something about this connection. */
   1409         return action;
   1410     }
   1411 }
   1412 
   1413 /* Handles lost connection with SdkController service. */
   1414 static AsyncIOAction
   1415 _on_async_socket_disconnected(SDKCtlSocket* sdkctl)
   1416 {
   1417     D("SDKCtl %s: Socket has been disconnected.", sdkctl->service_name);
   1418 
   1419     _sdkctl_socket_disconnect_socket(sdkctl);
   1420 
   1421     AsyncIOAction action = sdkctl->on_connection(sdkctl->opaque, sdkctl,
   1422                                                  ASIO_STATE_FAILED);
   1423     if (action == ASIO_ACTION_DONE) {
   1424         /* Default action for disconnect is to reestablish the connection. */
   1425         action = ASIO_ACTION_RETRY;
   1426     }
   1427     if (action == ASIO_ACTION_RETRY) {
   1428         sdkctl->state = SDKCTL_SOCKET_CONNECTING;
   1429     }
   1430     return action;
   1431 }
   1432 
   1433 /* An entry point for all socket connection events.
   1434  * Here we will dispatch connection events to appropriate handlers.
   1435  * Param:
   1436  *  client_opaque - SDKCtlSocket isntance.
   1437  */
   1438 static AsyncIOAction
   1439 _on_async_socket_connection(void* client_opaque,
   1440                             AsyncSocket* as,
   1441                             AsyncIOState status)
   1442 {
   1443     AsyncIOAction action = ASIO_ACTION_DONE;
   1444     SDKCtlSocket* const sdkctl = (SDKCtlSocket*)client_opaque;
   1445 
   1446     /* Reference the socket while in this callback. */
   1447     sdkctl_socket_reference(sdkctl);
   1448 
   1449     switch (status) {
   1450         case ASIO_STATE_SUCCEEDED:
   1451             sdkctl->state = SDKCTL_SOCKET_CONNECTED;
   1452             _on_async_socket_connected(sdkctl);
   1453             break;
   1454 
   1455         case ASIO_STATE_FAILED:
   1456             if (sdkctl->state == SDKCTL_SOCKET_CONNECTED) {
   1457                 /* This is disconnection condition. */
   1458                 action = _on_async_socket_disconnected(sdkctl);
   1459             } else {
   1460                 /* An error has occurred while attempting to connect to socket.
   1461                  * Lets try again... */
   1462                 action = ASIO_ACTION_RETRY;
   1463             }
   1464             break;
   1465 
   1466         case ASIO_STATE_RETRYING:
   1467         default:
   1468             action = ASIO_ACTION_RETRY;
   1469             break;
   1470     }
   1471 
   1472     sdkctl_socket_release(sdkctl);
   1473 
   1474     return action;
   1475 }
   1476 
   1477 /********************************************************************************
   1478  *                      SDK Control Socket public API
   1479  *******************************************************************************/
   1480 
   1481 SDKCtlSocket*
   1482 sdkctl_socket_new(int reconnect_to,
   1483                   const char* service_name,
   1484                   on_sdkctl_connection_cb on_connection,
   1485                   on_sdkctl_handshake_cb on_handshake,
   1486                   on_sdkctl_message_cb on_message,
   1487                   void* opaque)
   1488 {
   1489     SDKCtlSocket* sdkctl;
   1490     ANEW0(sdkctl);
   1491 
   1492     sdkctl->state               = SDKCTL_SOCKET_DISCONNECTED;
   1493     sdkctl->opaque              = opaque;
   1494     sdkctl->service_name        = ASTRDUP(service_name);
   1495     sdkctl->on_connection       = on_connection;
   1496     sdkctl->on_handshake        = on_handshake;
   1497     sdkctl->on_message          = on_message;
   1498     sdkctl->reconnect_to        = reconnect_to;
   1499     sdkctl->as                  = NULL;
   1500     sdkctl->next_query_id       = 0;
   1501     sdkctl->query_head          = sdkctl->query_tail = NULL;
   1502     sdkctl->ref_count           = 1;
   1503     sdkctl->recycler            = NULL;
   1504     sdkctl->recycler_block_size = 0;
   1505     sdkctl->recycler_max        = 0;
   1506     sdkctl->recycler_count      = 0;
   1507 
   1508     sdkctl->looper = looper_newCore();
   1509     if (sdkctl->looper == NULL) {
   1510         E("Unable to create I/O looper for SDKCtl socket '%s'",
   1511           service_name);
   1512         on_connection(opaque, sdkctl, ASIO_STATE_FAILED);
   1513         _sdkctl_socket_free(sdkctl);
   1514         return NULL;
   1515     }
   1516 
   1517     return sdkctl;
   1518 }
   1519 
   1520 int sdkctl_socket_reference(SDKCtlSocket* sdkctl)
   1521 {
   1522     assert(sdkctl->ref_count > 0);
   1523     sdkctl->ref_count++;
   1524     return sdkctl->ref_count;
   1525 }
   1526 
   1527 int
   1528 sdkctl_socket_release(SDKCtlSocket* sdkctl)
   1529 {
   1530     assert(sdkctl->ref_count > 0);
   1531     sdkctl->ref_count--;
   1532     if (sdkctl->ref_count == 0) {
   1533         /* Last reference has been dropped. Destroy this object. */
   1534         _sdkctl_socket_free(sdkctl);
   1535         return 0;
   1536     }
   1537     return sdkctl->ref_count;
   1538 }
   1539 
   1540 void
   1541 sdkctl_init_recycler(SDKCtlSocket* sdkctl,
   1542                      uint32_t data_size,
   1543                      int max_recycled_num)
   1544 {
   1545     if (sdkctl->recycler != NULL) {
   1546         D("SDKCtl %s: Recycler is already initialized. Ignoring recycler init.",
   1547           sdkctl->service_name);
   1548         return;
   1549     }
   1550 
   1551     /* SDKCtlQuery is max descriptor sizeof. */
   1552     data_size += sizeof(SDKCtlQuery);
   1553 
   1554     sdkctl->recycler_block_size = data_size;
   1555     sdkctl->recycler_max        = max_recycled_num;
   1556     sdkctl->recycler_count      = 0;
   1557 }
   1558 
   1559 void
   1560 sdkctl_socket_connect(SDKCtlSocket* sdkctl, int port, int retry_to)
   1561 {
   1562     T("SDKCtl %s: Handling connect request to port %d, retrying in %dms...",
   1563       sdkctl->service_name, port, retry_to);
   1564 
   1565     sdkctl->state = SDKCTL_SOCKET_CONNECTING;
   1566     sdkctl->as = async_socket_new(port, sdkctl->reconnect_to,
   1567                                   _on_async_socket_connection, sdkctl,
   1568                                   sdkctl->looper);
   1569     if (sdkctl->as == NULL) {
   1570         E("Unable to allocate AsyncSocket for SDKCtl socket '%s'",
   1571            sdkctl->service_name);
   1572         sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
   1573     } else {
   1574         async_socket_connect(sdkctl->as, retry_to);
   1575     }
   1576 }
   1577 
   1578 void
   1579 sdkctl_socket_reconnect(SDKCtlSocket* sdkctl, int port, int retry_to)
   1580 {
   1581     T("SDKCtl %s: Handling reconnection request to port %d, retrying in %dms...",
   1582       sdkctl->service_name, port, retry_to);
   1583 
   1584     _sdkctl_socket_disconnect_socket(sdkctl);
   1585 
   1586     if (sdkctl->as == NULL) {
   1587         sdkctl_socket_connect(sdkctl, port, retry_to);
   1588     } else {
   1589         sdkctl->state = SDKCTL_SOCKET_CONNECTING;
   1590         async_socket_reconnect(sdkctl->as, retry_to);
   1591     }
   1592 }
   1593 
   1594 void
   1595 sdkctl_socket_disconnect(SDKCtlSocket* sdkctl)
   1596 {
   1597     T("SDKCtl %s: Handling disconnect request.", sdkctl->service_name);
   1598 
   1599     _sdkctl_socket_disconnect_socket(sdkctl);
   1600 }
   1601 
   1602 
   1603 /********************************************************************************
   1604  *                       Handshake query
   1605  *******************************************************************************/
   1606 
   1607 /* A callback that is ivoked on handshake I/O events. */
   1608 static AsyncIOAction
   1609 _on_handshake_io(void* query_opaque,
   1610                  SDKCtlQuery* query,
   1611                  AsyncIOState status)
   1612 {
   1613     SDKCtlSocket* const sdkctl = (SDKCtlSocket*)query_opaque;
   1614 
   1615     if (status == ASIO_STATE_SUCCEEDED) {
   1616         D("SDKCtl %s: %d bytes of handshake reply is received.",
   1617           sdkctl->service_name, *query->response_size);
   1618 
   1619         /* Handshake is received. Inform the client. */
   1620         sdkctl->on_handshake(sdkctl->opaque, sdkctl, *query->response_buffer,
   1621                              *query->response_size, status);
   1622     } else {
   1623         /* Something is going on with the handshake... */
   1624         switch (status) {
   1625             case ASIO_STATE_FAILED:
   1626             case ASIO_STATE_TIMED_OUT:
   1627             case ASIO_STATE_CANCELLED:
   1628               D("SDKCtl %s: Handshake failed: I/O state %d. Error: %d -> %s",
   1629                 sdkctl->service_name, status, errno, strerror(errno));
   1630                 sdkctl->on_handshake(sdkctl->opaque, sdkctl,
   1631                                      *query->response_buffer,
   1632                                      *query->response_size, status);
   1633                 break;
   1634 
   1635             default:
   1636                 break;
   1637         }
   1638     }
   1639     return ASIO_ACTION_DONE;
   1640 }
   1641 
   1642 static AsyncIOAction
   1643 _on_sdkctl_endianness_io(void* io_opaque,
   1644                          AsyncSocketIO* asio,
   1645                          AsyncIOState status) {
   1646     SDKCtlSocket* const sdkctl = (SDKCtlSocket*)io_opaque;
   1647 
   1648     if (status == ASIO_STATE_SUCCEEDED) {
   1649         /* Now it's time to initiate handshake message. */
   1650         D("SDKCtl %s: Sending handshake query...", sdkctl->service_name);
   1651         SDKCtlQuery* query =
   1652             sdkctl_query_build_and_send(sdkctl, SDKCTL_QUERY_HANDSHAKE,
   1653                                         strlen(sdkctl->service_name),
   1654                                         sdkctl->service_name, NULL, NULL,
   1655                                         _on_handshake_io, sdkctl, 3000);
   1656         sdkctl_query_release(query);
   1657         return ASIO_ACTION_DONE;
   1658     } else {
   1659         /* Something is going on with the endianness... */
   1660         switch (status) {
   1661                 case ASIO_STATE_FAILED:
   1662                 case ASIO_STATE_TIMED_OUT:
   1663                 case ASIO_STATE_CANCELLED:
   1664                   D("SDKCtl %s: endianness failed: I/O state %d. Error: %d -> %s",
   1665                     sdkctl->service_name, status, errno, strerror(errno));
   1666                     sdkctl->on_handshake(sdkctl->opaque, sdkctl, NULL, 0, status);
   1667                     break;
   1668 
   1669                 default:
   1670                     break;
   1671         }
   1672     }
   1673     return ASIO_ACTION_DONE;
   1674 }
   1675 
   1676 static void
   1677 _sdkctl_do_handshake(SDKCtlSocket* sdkctl)
   1678 {
   1679 #ifndef HOST_WORDS_BIGENDIAN
   1680 static const char _host_end = 0;
   1681 #else
   1682 static const char _host_end = 1;
   1683 #endif
   1684 
   1685     D("SDKCtl %s: Sending endianness: %d...", sdkctl->service_name, _host_end);
   1686 
   1687     /* Before we can send any structured data to the SDK controller we need to
   1688      * report endianness of the host. */
   1689     async_socket_write_rel(sdkctl->as, &_host_end, 1,
   1690                            _on_sdkctl_endianness_io, sdkctl, 3000);
   1691 }
   1692