aboutsummaryrefslogtreecommitdiffstats
path: root/android/sdk-controller-socket.h
blob: 03b12f4db794e13379d13cb5b4c75b35cdcfdc4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*
 * 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"

/*
 * 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 packet - 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.
 */

/* Declares SDK controller socket descriptor. */
typedef struct SDKCtlSocket SDKCtlSocket;

/* Declares SDK controller data packet descriptor. */
typedef struct SDKCtlPacket SDKCtlPacket;

/* Declares SDK controller query descriptor. */
typedef struct SDKCtlQuery SDKCtlQuery;

/* 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_connection_cb)(void* client_opaque,
                                                 SDKCtlSocket* sdkctl,
                                                 AsyncIOState status);

/* Defines client's callback set to receive handshake reply from the SdkController
 * service running on the device.
 *
 * Successful handshake means that connection between the client and SDK
 * controller service has been established.
 *
 * Param:
 *  client_opaque - An opaque pointer associated with the client.
 *  sdkctl - Initialized SDKCtlSocket instance.
 *  handshake - Handshake message received from the SDK controller service.
 *  handshake_size - Size of the fandshake message received from the SDK
 *      controller service.
 *  status - Handshake status. Note that handshake, and handshake_size are valid
 *      only if this parameter is set to ASIO_STATE_SUCCEEDED.
 */
typedef void (*on_sdkctl_handshake_cb)(void* client_opaque,
                                       SDKCtlSocket* sdkctl,
                                       void* handshake,
                                       uint32_t handshake_size,
                                       AsyncIOState 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,
                                     SDKCtlPacket* 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);

/********************************************************************************
 *                         SDKCtlPacket API
 ********************************************************************************/

/* References SDKCtlPacket object.
 * Param:
 *  packet - Initialized SDKCtlPacket instance.
 * Return:
 *  Number of outstanding references to the object.
 */
extern int sdkctl_packet_reference(SDKCtlPacket* packet);

/* Releases SDKCtlPacket 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 SDKCtlPacket instance.
 * Return:
 *  Number of outstanding references to the object.
 */
extern int sdkctl_packet_release(SDKCtlPacket* packet);

/********************************************************************************
 *                          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);

/********************************************************************************
 *                          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_connection - A callback to invoke on socket connection events.
 *  on_handshake - A callback to invoke on handshake 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_connection_cb on_connection,
                                       on_sdkctl_handshake_cb on_handshake,
                                       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);

#endif  /* ANDROID_SDKCONTROL_SOCKET_H_ */