system/core
Révision | 74159657687aadab4c82e4fd7e7a54d16c045d95 (tree) |
---|---|
l'heure | 2012-01-11 09:03:17 |
Auteur | Vladimir Chtchetkine <vchtchetkine@goog...> |
Commiter | Vladimir Chtchetkine |
Cherry-picked from c13daef7b on master. Do not merge.
Use QEMU pipe for ADB communication when running in emulator.
Change-Id: I7934b6272c2a9825d244ce76ff65dbce6e54ebff
@@ -185,6 +185,114 @@ static void *server_socket_thread(void * arg) | ||
185 | 185 | return 0; |
186 | 186 | } |
187 | 187 | |
188 | +/* | |
189 | + * Redefine open and write for qemu_pipe.h that contains inlined references | |
190 | + * to those routines. We will redifine them back after qemu_pipe.h inclusion. | |
191 | + */ | |
192 | +#undef open | |
193 | +#undef write | |
194 | +#define open adb_open | |
195 | +#define write adb_write | |
196 | +#include <hardware/qemu_pipe.h> | |
197 | +#undef open | |
198 | +#undef write | |
199 | +#define open ___xxx_open | |
200 | +#define write ___xxx_write | |
201 | + | |
202 | +/* A worker thread that monitors host connections, and registers a transport for | |
203 | + * every new host connection. This thread replaces server_socket_thread on | |
204 | + * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD | |
205 | + * pipe to communicate with adbd daemon inside the guest. This is done in order | |
206 | + * to provide more robust communication channel between ADB host and guest. The | |
207 | + * main issue with server_socket_thread approach is that it runs on top of TCP, | |
208 | + * and thus is sensitive to network disruptions. For instance, the | |
209 | + * ConnectionManager may decide to reset all network connections, in which case | |
210 | + * the connection between ADB host and guest will be lost. To make ADB traffic | |
211 | + * independent from the network, we use here 'adb' QEMUD service to transfer data | |
212 | + * between the host, and the guest. See external/qemu/android/adb-*.* that | |
213 | + * implements the emulator's side of the protocol. Another advantage of using | |
214 | + * QEMUD approach is that ADB will be up much sooner, since it doesn't depend | |
215 | + * anymore on network being set up. | |
216 | + * The guest side of the protocol contains the following phases: | |
217 | + * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service | |
218 | + * is opened, and it becomes clear whether or not emulator supports that | |
219 | + * protocol. | |
220 | + * - Wait for the ADB host to create connection with the guest. This is done by | |
221 | + * sending an 'accept' request to the adb QEMUD service, and waiting on | |
222 | + * response. | |
223 | + * - When new ADB host connection is accepted, the connection with adb QEMUD | |
224 | + * service is registered as the transport, and a 'start' request is sent to the | |
225 | + * adb QEMUD service, indicating that the guest is ready to receive messages. | |
226 | + * Note that the guest will ignore messages sent down from the emulator before | |
227 | + * the transport registration is completed. That's why we need to send the | |
228 | + * 'start' request after the transport is registered. | |
229 | + */ | |
230 | +static void *qemu_socket_thread(void * arg) | |
231 | +{ | |
232 | +/* 'accept' request to the adb QEMUD service. */ | |
233 | +static const char _accept_req[] = "accept"; | |
234 | +/* 'start' request to the adb QEMUD service. */ | |
235 | +static const char _start_req[] = "start"; | |
236 | +/* 'ok' reply from the adb QEMUD service. */ | |
237 | +static const char _ok_resp[] = "ok"; | |
238 | + | |
239 | + const int port = (int)arg; | |
240 | + int res, fd; | |
241 | + char tmp[256]; | |
242 | + char con_name[32]; | |
243 | + | |
244 | + D("transport: qemu_socket_thread() starting\n"); | |
245 | + | |
246 | + /* adb QEMUD service connection request. */ | |
247 | + snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port); | |
248 | + | |
249 | + /* Connect to the adb QEMUD service. */ | |
250 | + fd = qemu_pipe_open(con_name); | |
251 | + if (fd < 0) { | |
252 | + /* This could be an older version of the emulator, that doesn't | |
253 | + * implement adb QEMUD service. Fall back to the old TCP way. */ | |
254 | + adb_thread_t thr; | |
255 | + D("adb service is not available. Falling back to TCP socket.\n"); | |
256 | + adb_thread_create(&thr, server_socket_thread, arg); | |
257 | + return 0; | |
258 | + } | |
259 | + | |
260 | + for(;;) { | |
261 | + /* | |
262 | + * Wait till the host creates a new connection. | |
263 | + */ | |
264 | + | |
265 | + /* Send the 'accept' request. */ | |
266 | + res = adb_write(fd, _accept_req, strlen(_accept_req)); | |
267 | + if (res == strlen(_accept_req)) { | |
268 | + /* Wait for the response. In the response we expect 'ok' on success, | |
269 | + * or 'ko' on failure. */ | |
270 | + res = adb_read(fd, tmp, sizeof(tmp)); | |
271 | + if (res != 2 || memcmp(tmp, _ok_resp, 2)) { | |
272 | + D("Accepting ADB host connection has failed.\n"); | |
273 | + adb_close(fd); | |
274 | + } else { | |
275 | + /* Host is connected. Register the transport, and start the | |
276 | + * exchange. */ | |
277 | + register_socket_transport(fd, "host", port, 1); | |
278 | + adb_write(fd, _start_req, strlen(_start_req)); | |
279 | + } | |
280 | + | |
281 | + /* Prepare for accepting of the next ADB host connection. */ | |
282 | + fd = qemu_pipe_open(con_name); | |
283 | + if (fd < 0) { | |
284 | + D("adb service become unavailable.\n"); | |
285 | + return 0; | |
286 | + } | |
287 | + } else { | |
288 | + D("Unable to send the '%s' request to ADB service.\n", _accept_req); | |
289 | + return 0; | |
290 | + } | |
291 | + } | |
292 | + D("transport: qemu_socket_thread() exiting\n"); | |
293 | + return 0; | |
294 | +} | |
295 | + | |
188 | 296 | void local_init(int port) |
189 | 297 | { |
190 | 298 | adb_thread_t thr; |
@@ -193,7 +301,17 @@ void local_init(int port) | ||
193 | 301 | if(HOST) { |
194 | 302 | func = client_socket_thread; |
195 | 303 | } else { |
196 | - func = server_socket_thread; | |
304 | + /* For the adbd daemon in the system image we need to distinguish | |
305 | + * between the device, and the emulator. */ | |
306 | + char is_qemu[PROPERTY_VALUE_MAX]; | |
307 | + property_get("ro.kernel.qemu", is_qemu, ""); | |
308 | + if (!strcmp(is_qemu, "1")) { | |
309 | + /* Running inside the emulator: use QEMUD pipe as the transport. */ | |
310 | + func = qemu_socket_thread; | |
311 | + } else { | |
312 | + /* Running inside the device: use TCP socket as the transport. */ | |
313 | + func = server_socket_thread; | |
314 | + } | |
197 | 315 | } |
198 | 316 | |
199 | 317 | D("transport: local %s init\n", HOST ? "client" : "server"); |