blob: bc518072ef9a42f29b9eb78046a3bd08aa43747f [file] [log] [blame]
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -08001/*
2 * Copyright (C) 2011 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#include "qemu-common.h"
18#include "android/globals.h" /* for android_hw */
19#include "android/hw-qemud.h"
20#include "android/utils/misc.h"
21#include "android/utils/system.h"
22#include "android/utils/debug.h"
23#include "android/adb-server.h"
24#include "android/adb-qemud.h"
25
26#define E(...) derror(__VA_ARGS__)
27#define W(...) dwarning(__VA_ARGS__)
28#define D(...) VERBOSE_PRINT(adbclient,__VA_ARGS__)
29#define D_ACTIVE VERBOSE_CHECK(adbclient)
30#define QB(b, s) quote_bytes((const char*)b, (s < 32) ? s : 32)
31
32#define SERVICE_NAME "adb"
33
34/* Enumerates ADB client state values. */
35typedef enum AdbClientState {
36 /* Waiting on a connection from ADB host. */
37 ADBC_STATE_WAIT_ON_HOST,
38 /* ADB host is connected. Waiting on the transport initialization completion
39 * in the guest. */
40 ADBC_STATE_HOST_CONNECTED,
41 /* Connection between ADB host and ADB guest is fully established. */
42 ADBC_STATE_CONNECTED,
43 /* ADB host has been disconnected. */
44 ADBC_STATE_HOST_DISCONNECTED,
45 /* ADB guest has been disconnected. */
46 ADBC_STATE_GUEST_DISCONNECTED,
47} AdbClientState;
48
49/* ADB client descriptor. */
50typedef struct AdbClient AdbClient;
51struct AdbClient {
52 /* Opaque pointer returned from adb_server_register_guest API. */
53 void* opaque;
54 /* QEMUD client pipe for this client. */
55 QemudClient* qemud_client;
56 /* Connection state. */
57 AdbClientState state;
58};
59
60/********************************************************************************
61 * ADB host communication.
62 *******************************************************************************/
63
64/* A callback that is invoked when the host is connected.
65 * Param:
66 * opaque - AdbClient instance.
67 * connection - An opaque pointer that identifies connection with the ADB host.
68 */
69static void
70_adb_on_host_connected(void* opaque, void* connection)
71{
72 AdbClient* const adb_client = (AdbClient*)opaque;
73
74 if (adb_client->state == ADBC_STATE_WAIT_ON_HOST) {
75 D("ADB client %p(o=%p) is connected to the host %p",
76 adb_client, adb_client->opaque, connection);
77
78 /* Bump the state up. */
79 adb_client->state = ADBC_STATE_HOST_CONNECTED;
80
81 /* Notify the ADB guest that host has been connected.This will unblock
82 * the guest from a 'read', then guest will register the transport, and
83 * will send 'setart' request, indicating that it is ready to receive
84 * data from the host. */
85 qemud_client_send(adb_client->qemud_client, (const uint8_t*)"ok", 2);
86 } else {
87 D("Unexpected ADB host connection while state is %d", adb_client->state);
88 }
89}
90
91/* A callback that is invoked when the host gets disconnected.
92 * Param:
93 * opaque - AdbClient instance.
94 * connection - An opaque pointer that identifies connection with the ADB host.
95 */
96static void
97_adb_on_host_disconnect(void* opaque, void* connection)
98{
99 AdbClient* const adb_client = (AdbClient*)opaque;
100
101 D("ADB client %p(o=%p) is disconnected from the host %p",
102 adb_client, adb_client->opaque, connection);
103 adb_client->state = ADBC_STATE_HOST_DISCONNECTED;
104}
105
106/* A callback that is invoked when the host sends data.
107 * Param:
108 * opaque - AdbClient instance.
109 * connection - An opaque pointer that identifies connection with the ADB host.
110 * buff, size - Buffer containing the host data.
111 */
112static void
113_adb_on_host_data(void* opaque, void* connection, const void* buff, int size)
114{
115 AdbClient* const adb_client = (AdbClient*)opaque;
116 D("ADB client %p(o=%p) received from the host %p %d bytes in %s",
117 adb_client, adb_client->opaque, connection, size, QB(buff, size));
118
119 if (adb_client->state == ADBC_STATE_CONNECTED) {
120 /* Dispatch data down to the guest. */
121 qemud_client_send(adb_client->qemud_client, (const uint8_t*)buff, size);
122 } else {
123 D("Unexpected data from ADB host %p while client %p(o=%p) is in state %d",
124 connection, adb_client, adb_client->opaque, adb_client->state);
125 }
126}
127
128/* ADB guest API required for adb_server_register_guest */
129static AdbGuestRoutines _adb_client_routines = {
130 /* A callback that is invoked when the host is connected. */
131 _adb_on_host_connected,
132 /* A callback that is invoked when the host gets disconnected. */
133 _adb_on_host_disconnect,
134 /* A callback that is invoked when the host sends data. */
135 _adb_on_host_data,
136};
137
138/********************************************************************************
139 * ADB guest communication.
140 *******************************************************************************/
141
142/* Allocates AdbClient instance. */
143static AdbClient*
144_adb_client_new(void)
145{
146 AdbClient* adb_client;
147
148 ANEW0(adb_client);
149
150 return adb_client;
151}
152
153/* Frees AdbClient instance, allocated with _adb_client_new */
154static void
155_adb_client_free(AdbClient* adb_client)
156{
157 if (adb_client != NULL) {
158 free(adb_client);
159 }
160}
161
162/* A callback that is invoked when ADB guest sends data to the service.
163 * Param:
164 * opaque - AdbClient instance.
165 * msg, msglen - Message received from the ADB guest.
166 * client - adb QEMUD client.
167 */
168static void
169_adb_client_recv(void* opaque, uint8_t* msg, int msglen, QemudClient* client)
170{
171 AdbClient* const adb_client = (AdbClient*)opaque;
172
173 D("ADB client %p(o=%p) received from guest %d bytes in %s",
174 adb_client, adb_client->opaque, msglen, QB(msg, msglen));
175
176 /* Properly dispatch the message, depending on the client state. */
177 switch (adb_client->state) {
178 case ADBC_STATE_CONNECTED:
179 /* Connection is fully established. Dispatch the message to the
180 * host. */
181 adb_server_on_guest_message(adb_client->opaque, msg, msglen);
182 break;
183
184 case ADBC_STATE_WAIT_ON_HOST:
185 /* At this state the only message that is allowed is 'accept' */
186 if (msglen == 6 && !memcmp(msg, "accept", 6)) {
187 /* Register ADB guest connection with the ADB server. */
188 adb_client->opaque =
189 adb_server_register_guest(adb_client, &_adb_client_routines);
190 if (adb_client->opaque == NULL) {
191 D("Unable to register ADB guest with the ADB server.");
192 /* KO the guest. */
193 qemud_client_send(adb_client->qemud_client,
194 (const uint8_t*)"ko", 2);
195 }
196 } else {
197 D("Unexpected guest request while waiting on ADB host to connect.");
198 }
199 break;
200
201 case ADBC_STATE_HOST_CONNECTED:
202 /* At this state the only message that is allowed is 'start' */
203 if (msglen == 5 && !memcmp(msg, "start", 5)) {
204 adb_client->state = ADBC_STATE_CONNECTED;
205 adb_server_complete_connection(adb_client->opaque);
206 } else {
207 D("Unexpected request while waiting on connection to start.");
208 }
209 break;
210
211 default:
212 D("Unexpected ADB guest request '%s' while client state is %d.",
213 QB(msg, msglen), adb_client->state);
214 break;
215 }
216}
217
218/* A callback that is invoked when ADB guest disconnects from the service. */
219static void
220_adb_client_close(void* opaque)
221{
222 AdbClient* const adb_client = (AdbClient*)opaque;
223
224 D("ADB client %p(o=%p) is disconnected from the guest.",
225 adb_client, adb_client->opaque);
226 adb_client->state = ADBC_STATE_GUEST_DISCONNECTED;
227 if (adb_client->opaque != NULL) {
228 /* Close connection with the host. */
229 adb_server_on_guest_closed(adb_client->opaque);
230 }
231 _adb_client_free(adb_client);
232}
233
234/* A callback that is invoked when ADB daemon running inside the guest connects
235 * to the service.
236 * Client parameters are ignored here. Typically they contain the ADB port number
237 * which is always 5555 for the device / emulated system.
238 */
239static QemudClient*
240_adb_service_connect(void* opaque,
241 QemudService* serv,
242 int channel,
243 const char* client_param)
244{
245 /* Create new QEMUD client for the connection with ADB daemon. */
246 AdbClient* const adb_client = _adb_client_new();
247
248 D("Connecting ADB guest: '%s'", client_param ? client_param : "<null>");
249 adb_client->qemud_client =
250 qemud_client_new(serv, channel, client_param, adb_client,
251 _adb_client_recv, _adb_client_close, NULL, NULL);
252 if (adb_client->qemud_client == NULL) {
253 D("Unable to create QEMUD client for ADB guest.");
254 _adb_client_free(adb_client);
255 return NULL;
256 }
257
258 return adb_client->qemud_client;
259}
260
261/********************************************************************************
262 * ADB service API.
263 *******************************************************************************/
264
265void
266android_adb_service_init(void)
267{
268static int _inited = 0;
269
270 if (!adb_server_is_initialized()) {
271 return;
272 }
273
274 if (!_inited) {
275 QemudService* serv = qemud_service_register(SERVICE_NAME, 0, NULL,
276 _adb_service_connect,
277 NULL, NULL);
278 if (serv == NULL) {
279 derror("%s: Could not register '%s' service",
280 __FUNCTION__, SERVICE_NAME);
281 return;
282 }
283 D("%s: Registered '%s' qemud service", __FUNCTION__, SERVICE_NAME);
284 }
285}