blob: 744e847faf30c3885262eec5b7082881c991a337 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 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#define TRACE_TAG TRACE_ADB
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <ctype.h>
22#include <stdarg.h>
23#include <errno.h>
Scott Andersonc7993af2012-05-25 13:55:46 -070024#include <stddef.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080025#include <string.h>
26#include <time.h>
Mike Lockwood1f546e62009-05-25 18:17:55 -040027#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080028
29#include "sysdeps.h"
30#include "adb.h"
Benoit Gobyd5fcafa2012-04-12 12:23:49 -070031#include "adb_auth.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080032
Scott Andersone82c2db2012-05-25 14:10:02 -070033#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
34
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035#if !ADB_HOST
36#include <private/android_filesystem_config.h>
Mike Lockwood5f4b0512009-08-04 20:37:51 -040037#include <linux/capability.h>
38#include <linux/prctl.h>
Jeff Sharkey885342a2012-08-14 21:00:22 -070039#include <sys/mount.h>
Xavier Ducroheta09fbd12009-05-20 17:33:53 -070040#else
41#include "usb_vendors.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042#endif
43
JP Abgrall408fa572011-03-16 15:57:42 -070044#if ADB_TRACE
45ADB_MUTEX_DEFINE( D_lock );
46#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047
48int HOST = 0;
Matt Gumbeld7b33082012-11-14 10:16:17 -080049int gListenAll = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050
Benoit Gobyd5fcafa2012-04-12 12:23:49 -070051static int auth_enabled = 0;
52
Scott Andersone82c2db2012-05-25 14:10:02 -070053#if !ADB_HOST
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080054static const char *adb_device_banner = "device";
Scott Andersone82c2db2012-05-25 14:10:02 -070055#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080056
57void fatal(const char *fmt, ...)
58{
59 va_list ap;
60 va_start(ap, fmt);
61 fprintf(stderr, "error: ");
62 vfprintf(stderr, fmt, ap);
63 fprintf(stderr, "\n");
64 va_end(ap);
65 exit(-1);
66}
67
68void fatal_errno(const char *fmt, ...)
69{
70 va_list ap;
71 va_start(ap, fmt);
72 fprintf(stderr, "error: %s: ", strerror(errno));
73 vfprintf(stderr, fmt, ap);
74 fprintf(stderr, "\n");
75 va_end(ap);
76 exit(-1);
77}
78
79int adb_trace_mask;
80
81/* read a comma/space/colum/semi-column separated list of tags
82 * from the ADB_TRACE environment variable and build the trace
83 * mask from it. note that '1' and 'all' are special cases to
84 * enable all tracing
85 */
86void adb_trace_init(void)
87{
88 const char* p = getenv("ADB_TRACE");
89 const char* q;
90
91 static const struct {
92 const char* tag;
93 int flag;
94 } tags[] = {
95 { "1", 0 },
96 { "all", 0 },
97 { "adb", TRACE_ADB },
98 { "sockets", TRACE_SOCKETS },
99 { "packets", TRACE_PACKETS },
100 { "rwx", TRACE_RWX },
101 { "usb", TRACE_USB },
102 { "sync", TRACE_SYNC },
103 { "sysdeps", TRACE_SYSDEPS },
104 { "transport", TRACE_TRANSPORT },
105 { "jdwp", TRACE_JDWP },
JP Abgrall408fa572011-03-16 15:57:42 -0700106 { "services", TRACE_SERVICES },
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700107 { "auth", TRACE_AUTH },
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800108 { NULL, 0 }
109 };
110
111 if (p == NULL)
112 return;
113
114 /* use a comma/column/semi-colum/space separated list */
115 while (*p) {
116 int len, tagn;
117
118 q = strpbrk(p, " ,:;");
119 if (q == NULL) {
120 q = p + strlen(p);
121 }
122 len = q - p;
123
124 for (tagn = 0; tags[tagn].tag != NULL; tagn++)
125 {
126 int taglen = strlen(tags[tagn].tag);
127
128 if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
129 {
130 int flag = tags[tagn].flag;
131 if (flag == 0) {
132 adb_trace_mask = ~0;
133 return;
134 }
135 adb_trace_mask |= (1 << flag);
136 break;
137 }
138 }
139 p = q;
140 if (*p)
141 p++;
142 }
143}
144
Vladimir Chtchetkine28781b02012-02-27 10:41:53 -0800145#if !ADB_HOST
146/*
147 * Implements ADB tracing inside the emulator.
148 */
149
150#include <stdarg.h>
151
152/*
153 * Redefine open and write for qemu_pipe.h that contains inlined references
154 * to those routines. We will redifine them back after qemu_pipe.h inclusion.
155 */
156
157#undef open
158#undef write
159#define open adb_open
160#define write adb_write
161#include <hardware/qemu_pipe.h>
162#undef open
163#undef write
164#define open ___xxx_open
165#define write ___xxx_write
166
167/* A handle to adb-debug qemud service in the emulator. */
168int adb_debug_qemu = -1;
169
170/* Initializes connection with the adb-debug qemud service in the emulator. */
171static int adb_qemu_trace_init(void)
172{
173 char con_name[32];
174
175 if (adb_debug_qemu >= 0) {
176 return 0;
177 }
178
179 /* adb debugging QEMUD service connection request. */
180 snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
181 adb_debug_qemu = qemu_pipe_open(con_name);
182 return (adb_debug_qemu >= 0) ? 0 : -1;
183}
184
185void adb_qemu_trace(const char* fmt, ...)
186{
187 va_list args;
188 va_start(args, fmt);
189 char msg[1024];
190
191 if (adb_debug_qemu >= 0) {
192 vsnprintf(msg, sizeof(msg), fmt, args);
193 adb_write(adb_debug_qemu, msg, strlen(msg));
194 }
195}
196#endif /* !ADB_HOST */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800197
198apacket *get_apacket(void)
199{
200 apacket *p = malloc(sizeof(apacket));
201 if(p == 0) fatal("failed to allocate an apacket");
202 memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
203 return p;
204}
205
206void put_apacket(apacket *p)
207{
208 free(p);
209}
210
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700211void handle_online(atransport *t)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800212{
213 D("adb: online\n");
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700214 t->online = 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215}
216
217void handle_offline(atransport *t)
218{
219 D("adb: offline\n");
220 //Close the associated usb
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700221 t->online = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222 run_transport_disconnects(t);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223}
224
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700225#if DEBUG_PACKETS
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800226#define DUMPMAX 32
227void print_packet(const char *label, apacket *p)
228{
229 char *tag;
230 char *x;
231 unsigned count;
232
233 switch(p->msg.command){
234 case A_SYNC: tag = "SYNC"; break;
235 case A_CNXN: tag = "CNXN" ; break;
236 case A_OPEN: tag = "OPEN"; break;
237 case A_OKAY: tag = "OKAY"; break;
238 case A_CLSE: tag = "CLSE"; break;
239 case A_WRTE: tag = "WRTE"; break;
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700240 case A_AUTH: tag = "AUTH"; break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800241 default: tag = "????"; break;
242 }
243
244 fprintf(stderr, "%s: %s %08x %08x %04x \"",
245 label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
246 count = p->msg.data_length;
247 x = (char*) p->data;
248 if(count > DUMPMAX) {
249 count = DUMPMAX;
250 tag = "\n";
251 } else {
252 tag = "\"\n";
253 }
254 while(count-- > 0){
255 if((*x >= ' ') && (*x < 127)) {
256 fputc(*x, stderr);
257 } else {
258 fputc('.', stderr);
259 }
260 x++;
261 }
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700262 fputs(tag, stderr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800263}
264#endif
265
266static void send_ready(unsigned local, unsigned remote, atransport *t)
267{
268 D("Calling send_ready \n");
269 apacket *p = get_apacket();
270 p->msg.command = A_OKAY;
271 p->msg.arg0 = local;
272 p->msg.arg1 = remote;
273 send_packet(p, t);
274}
275
276static void send_close(unsigned local, unsigned remote, atransport *t)
277{
278 D("Calling send_close \n");
279 apacket *p = get_apacket();
280 p->msg.command = A_CLSE;
281 p->msg.arg0 = local;
282 p->msg.arg1 = remote;
283 send_packet(p, t);
284}
285
Scott Andersone82c2db2012-05-25 14:10:02 -0700286static size_t fill_connect_data(char *buf, size_t bufsize)
287{
288#if ADB_HOST
289 return snprintf(buf, bufsize, "host::") + 1;
290#else
291 static const char *cnxn_props[] = {
292 "ro.product.name",
293 "ro.product.model",
294 "ro.product.device",
295 };
296 static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
297 int i;
298 size_t remaining = bufsize;
299 size_t len;
300
301 len = snprintf(buf, remaining, "%s::", adb_device_banner);
302 remaining -= len;
303 buf += len;
304 for (i = 0; i < num_cnxn_props; i++) {
305 char value[PROPERTY_VALUE_MAX];
306 property_get(cnxn_props[i], value, "");
307 len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
308 remaining -= len;
309 buf += len;
310 }
311
312 return bufsize - remaining + 1;
313#endif
314}
315
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800316static void send_connect(atransport *t)
317{
318 D("Calling send_connect \n");
319 apacket *cp = get_apacket();
320 cp->msg.command = A_CNXN;
321 cp->msg.arg0 = A_VERSION;
322 cp->msg.arg1 = MAX_PAYLOAD;
Scott Andersone82c2db2012-05-25 14:10:02 -0700323 cp->msg.data_length = fill_connect_data((char *)cp->data,
324 sizeof(cp->data));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800325 send_packet(cp, t);
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700326}
327
328static void send_auth_request(atransport *t)
329{
330 D("Calling send_auth_request\n");
331 apacket *p;
332 int ret;
333
334 ret = adb_auth_generate_token(t->token, sizeof(t->token));
335 if (ret != sizeof(t->token)) {
336 D("Error generating token ret=%d\n", ret);
337 return;
338 }
339
340 p = get_apacket();
341 memcpy(p->data, t->token, ret);
342 p->msg.command = A_AUTH;
343 p->msg.arg0 = ADB_AUTH_TOKEN;
344 p->msg.data_length = ret;
345 send_packet(p, t);
346}
347
348static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
349{
350 D("Calling send_auth_response\n");
351 apacket *p = get_apacket();
352 int ret;
353
354 ret = adb_auth_sign(t->key, token, token_size, p->data);
355 if (!ret) {
356 D("Error signing the token\n");
357 put_apacket(p);
358 return;
359 }
360
361 p->msg.command = A_AUTH;
362 p->msg.arg0 = ADB_AUTH_SIGNATURE;
363 p->msg.data_length = ret;
364 send_packet(p, t);
365}
366
367static void send_auth_publickey(atransport *t)
368{
369 D("Calling send_auth_publickey\n");
370 apacket *p = get_apacket();
371 int ret;
372
373 ret = adb_auth_get_userkey(p->data, sizeof(p->data));
374 if (!ret) {
375 D("Failed to get user public key\n");
376 put_apacket(p);
377 return;
378 }
379
380 p->msg.command = A_AUTH;
381 p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
382 p->msg.data_length = ret;
383 send_packet(p, t);
384}
385
386void adb_auth_verified(atransport *t)
387{
388 handle_online(t);
389 send_connect(t);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800390}
391
392static char *connection_state_name(atransport *t)
393{
394 if (t == NULL) {
395 return "unknown";
396 }
397
398 switch(t->connection_state) {
399 case CS_BOOTLOADER:
400 return "bootloader";
401 case CS_DEVICE:
402 return "device";
403 case CS_OFFLINE:
404 return "offline";
Benoit Goby77e8e582013-01-15 12:36:47 -0800405 case CS_UNAUTHORIZED:
406 return "unauthorized";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800407 default:
408 return "unknown";
409 }
410}
411
Scott Andersone82c2db2012-05-25 14:10:02 -0700412/* qual_overwrite is used to overwrite a qualifier string. dst is a
413 * pointer to a char pointer. It is assumed that if *dst is non-NULL, it
Scott Anderson2ca3e6b2012-05-30 18:11:27 -0700414 * was malloc'ed and needs to freed. *dst will be set to a dup of src.
Scott Andersone82c2db2012-05-25 14:10:02 -0700415 */
416static void qual_overwrite(char **dst, const char *src)
417{
418 if (!dst)
419 return;
420
421 free(*dst);
422 *dst = NULL;
423
424 if (!src || !*src)
425 return;
426
427 *dst = strdup(src);
428}
429
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800430void parse_banner(char *banner, atransport *t)
431{
Scott Andersone82c2db2012-05-25 14:10:02 -0700432 static const char *prop_seps = ";";
433 static const char key_val_sep = '=';
Scott Anderson2ca3e6b2012-05-30 18:11:27 -0700434 char *cp;
435 char *type;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800436
437 D("parse_banner: %s\n", banner);
438 type = banner;
Scott Andersone82c2db2012-05-25 14:10:02 -0700439 cp = strchr(type, ':');
440 if (cp) {
441 *cp++ = 0;
442 /* Nothing is done with second field. */
443 cp = strchr(cp, ':');
444 if (cp) {
445 char *save;
446 char *key;
Scott Anderson1b7a7e82012-06-05 17:54:27 -0700447 key = adb_strtok_r(cp + 1, prop_seps, &save);
Scott Andersone82c2db2012-05-25 14:10:02 -0700448 while (key) {
449 cp = strchr(key, key_val_sep);
450 if (cp) {
451 *cp++ = '\0';
452 if (!strcmp(key, "ro.product.name"))
453 qual_overwrite(&t->product, cp);
454 else if (!strcmp(key, "ro.product.model"))
455 qual_overwrite(&t->model, cp);
456 else if (!strcmp(key, "ro.product.device"))
457 qual_overwrite(&t->device, cp);
458 }
Scott Anderson1b7a7e82012-06-05 17:54:27 -0700459 key = adb_strtok_r(NULL, prop_seps, &save);
Scott Andersone82c2db2012-05-25 14:10:02 -0700460 }
461 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800462 }
463
464 if(!strcmp(type, "bootloader")){
465 D("setting connection_state to CS_BOOTLOADER\n");
466 t->connection_state = CS_BOOTLOADER;
467 update_transports();
468 return;
469 }
470
471 if(!strcmp(type, "device")) {
472 D("setting connection_state to CS_DEVICE\n");
473 t->connection_state = CS_DEVICE;
474 update_transports();
475 return;
476 }
477
478 if(!strcmp(type, "recovery")) {
479 D("setting connection_state to CS_RECOVERY\n");
480 t->connection_state = CS_RECOVERY;
481 update_transports();
482 return;
483 }
484
Doug Zongker447f0612012-01-09 14:54:53 -0800485 if(!strcmp(type, "sideload")) {
486 D("setting connection_state to CS_SIDELOAD\n");
487 t->connection_state = CS_SIDELOAD;
488 update_transports();
489 return;
490 }
491
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800492 t->connection_state = CS_HOST;
493}
494
495void handle_packet(apacket *p, atransport *t)
496{
497 asocket *s;
498
Viral Mehta899913f2010-06-16 18:41:28 +0530499 D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
500 ((char*) (&(p->msg.command)))[1],
501 ((char*) (&(p->msg.command)))[2],
502 ((char*) (&(p->msg.command)))[3]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800503 print_packet("recv", p);
504
505 switch(p->msg.command){
506 case A_SYNC:
507 if(p->msg.arg0){
508 send_packet(p, t);
509 if(HOST) send_connect(t);
510 } else {
511 t->connection_state = CS_OFFLINE;
512 handle_offline(t);
513 send_packet(p, t);
514 }
515 return;
516
517 case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
518 /* XXX verify version, etc */
519 if(t->connection_state != CS_OFFLINE) {
520 t->connection_state = CS_OFFLINE;
521 handle_offline(t);
522 }
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700523
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800524 parse_banner((char*) p->data, t);
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700525
526 if (HOST || !auth_enabled) {
527 handle_online(t);
528 if(!HOST) send_connect(t);
529 } else {
530 send_auth_request(t);
531 }
532 break;
533
534 case A_AUTH:
535 if (p->msg.arg0 == ADB_AUTH_TOKEN) {
Benoit Goby77e8e582013-01-15 12:36:47 -0800536 t->connection_state = CS_UNAUTHORIZED;
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700537 t->key = adb_auth_nextkey(t->key);
538 if (t->key) {
539 send_auth_response(p->data, p->msg.data_length, t);
540 } else {
541 /* No more private keys to try, send the public key */
542 send_auth_publickey(t);
543 }
544 } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
545 if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
546 adb_auth_verified(t);
547 t->failed_auth_attempts = 0;
548 } else {
549 if (t->failed_auth_attempts++ > 10)
550 adb_sleep_ms(1000);
551 send_auth_request(t);
552 }
553 } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
554 adb_auth_confirm_key(p->data, p->msg.data_length, t);
555 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800556 break;
557
558 case A_OPEN: /* OPEN(local-id, 0, "destination") */
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700559 if (t->online) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800560 char *name = (char*) p->data;
561 name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
562 s = create_local_service_socket(name);
563 if(s == 0) {
564 send_close(0, p->msg.arg0, t);
565 } else {
566 s->peer = create_remote_socket(p->msg.arg0, t);
567 s->peer->peer = s;
568 send_ready(s->id, s->peer->id, t);
569 s->ready(s);
570 }
571 }
572 break;
573
574 case A_OKAY: /* READY(local-id, remote-id, "") */
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700575 if (t->online) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800576 if((s = find_local_socket(p->msg.arg1))) {
577 if(s->peer == 0) {
578 s->peer = create_remote_socket(p->msg.arg0, t);
579 s->peer->peer = s;
580 }
581 s->ready(s);
582 }
583 }
584 break;
585
586 case A_CLSE: /* CLOSE(local-id, remote-id, "") */
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700587 if (t->online) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800588 if((s = find_local_socket(p->msg.arg1))) {
589 s->close(s);
590 }
591 }
592 break;
593
594 case A_WRTE:
Benoit Gobyd5fcafa2012-04-12 12:23:49 -0700595 if (t->online) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800596 if((s = find_local_socket(p->msg.arg1))) {
597 unsigned rid = p->msg.arg0;
598 p->len = p->msg.data_length;
599
600 if(s->enqueue(s, p) == 0) {
601 D("Enqueue the socket\n");
602 send_ready(s->id, rid, t);
603 }
604 return;
605 }
606 }
607 break;
608
609 default:
610 printf("handle_packet: what is %08x?!\n", p->msg.command);
611 }
612
613 put_apacket(p);
614}
615
616alistener listener_list = {
617 .next = &listener_list,
618 .prev = &listener_list,
619};
620
621static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
622{
623 asocket *s;
624
625 if(ev & FDE_READ) {
626 struct sockaddr addr;
627 socklen_t alen;
628 int fd;
629
630 alen = sizeof(addr);
631 fd = adb_socket_accept(_fd, &addr, &alen);
632 if(fd < 0) return;
633
634 adb_socket_setbufsize(fd, CHUNK_SIZE);
635
636 s = create_local_socket(fd);
637 if(s) {
638 connect_to_smartsocket(s);
639 return;
640 }
641
642 adb_close(fd);
643 }
644}
645
646static void listener_event_func(int _fd, unsigned ev, void *_l)
647{
648 alistener *l = _l;
649 asocket *s;
650
651 if(ev & FDE_READ) {
652 struct sockaddr addr;
653 socklen_t alen;
654 int fd;
655
656 alen = sizeof(addr);
657 fd = adb_socket_accept(_fd, &addr, &alen);
658 if(fd < 0) return;
659
660 s = create_local_socket(fd);
661 if(s) {
662 s->transport = l->transport;
663 connect_to_remote(s, l->connect_to);
664 return;
665 }
666
667 adb_close(fd);
668 }
669}
670
671static void free_listener(alistener* l)
672{
673 if (l->next) {
674 l->next->prev = l->prev;
675 l->prev->next = l->next;
676 l->next = l->prev = l;
677 }
678
679 // closes the corresponding fd
680 fdevent_remove(&l->fde);
681
682 if (l->local_name)
683 free((char*)l->local_name);
684
685 if (l->connect_to)
686 free((char*)l->connect_to);
687
688 if (l->transport) {
689 remove_transport_disconnect(l->transport, &l->disconnect);
690 }
691 free(l);
692}
693
694static void listener_disconnect(void* _l, atransport* t)
695{
696 alistener* l = _l;
697
698 free_listener(l);
699}
700
701int local_name_to_fd(const char *name)
702{
703 int port;
704
705 if(!strncmp("tcp:", name, 4)){
706 int ret;
707 port = atoi(name + 4);
Matt Gumbeld7b33082012-11-14 10:16:17 -0800708
709 if (gListenAll > 0) {
710 ret = socket_inaddr_any_server(port, SOCK_STREAM);
711 } else {
712 ret = socket_loopback_server(port, SOCK_STREAM);
713 }
714
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800715 return ret;
716 }
717#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
718 // It's non-sensical to support the "reserved" space on the adb host side
719 if(!strncmp(name, "local:", 6)) {
720 return socket_local_server(name + 6,
721 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
722 } else if(!strncmp(name, "localabstract:", 14)) {
723 return socket_local_server(name + 14,
724 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
725 } else if(!strncmp(name, "localfilesystem:", 16)) {
726 return socket_local_server(name + 16,
727 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
728 }
729
730#endif
731 printf("unknown local portname '%s'\n", name);
732 return -1;
733}
734
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100735// Write a single line describing a listener to a user-provided buffer.
736// Appends a trailing zero, even in case of truncation, but the function
737// returns the full line length.
738// If |buffer| is NULL, does not write but returns required size.
739static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
740 // Format is simply:
741 //
742 // <device-serial> " " <local-name> " " <remote-name> "\n"
743 //
744 int local_len = strlen(l->local_name);
745 int connect_len = strlen(l->connect_to);
746 int serial_len = strlen(l->transport->serial);
747
748 if (buffer != NULL) {
749 snprintf(buffer, buffer_len, "%s %s %s\n",
750 l->transport->serial, l->local_name, l->connect_to);
751 }
752 // NOTE: snprintf() on Windows returns -1 in case of truncation, so
753 // return the computed line length instead.
754 return local_len + connect_len + serial_len + 3;
755}
756
757// Write the list of current listeners (network redirections) into a
758// user-provided buffer. Appends a trailing zero, even in case of
759// trunctaion, but return the full size in bytes.
760// If |buffer| is NULL, does not write but returns required size.
761static int format_listeners(char* buf, size_t buflen)
762{
763 alistener* l;
764 int result = 0;
765 for (l = listener_list.next; l != &listener_list; l = l->next) {
766 // Ignore special listeners like those for *smartsocket*
767 if (l->connect_to[0] == '*')
768 continue;
769 int len = format_listener(l, buf, buflen);
770 // Ensure there is space for the trailing zero.
771 result += len;
772 if (buf != NULL) {
773 buf += len;
774 buflen -= len;
775 if (buflen <= 0)
776 break;
777 }
778 }
779 return result;
780}
781
782static int remove_listener(const char *local_name, atransport* transport)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800783{
784 alistener *l;
785
786 for (l = listener_list.next; l != &listener_list; l = l->next) {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100787 if (!strcmp(local_name, l->local_name)) {
788 listener_disconnect(l, l->transport);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800789 return 0;
790 }
791 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800792 return -1;
793}
794
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100795static void remove_all_listeners(void)
796{
797 alistener *l, *l_next;
798 for (l = listener_list.next; l != &listener_list; l = l_next) {
799 l_next = l->next;
800 // Never remove smart sockets.
801 if (l->connect_to[0] == '*')
802 continue;
803 listener_disconnect(l, l->transport);
804 }
805}
806
807// error/status codes for install_listener.
808typedef enum {
809 INSTALL_STATUS_OK = 0,
810 INSTALL_STATUS_INTERNAL_ERROR = -1,
811 INSTALL_STATUS_CANNOT_BIND = -2,
812 INSTALL_STATUS_CANNOT_REBIND = -3,
813} install_status_t;
814
815static install_status_t install_listener(const char *local_name,
816 const char *connect_to,
817 atransport* transport,
818 int no_rebind)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800819{
820 alistener *l;
821
822 //printf("install_listener('%s','%s')\n", local_name, connect_to);
823
824 for(l = listener_list.next; l != &listener_list; l = l->next){
825 if(strcmp(local_name, l->local_name) == 0) {
826 char *cto;
827
828 /* can't repurpose a smartsocket */
829 if(l->connect_to[0] == '*') {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100830 return INSTALL_STATUS_INTERNAL_ERROR;
831 }
832
833 /* can't repurpose a listener if 'no_rebind' is true */
834 if (no_rebind) {
835 return INSTALL_STATUS_CANNOT_REBIND;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800836 }
837
838 cto = strdup(connect_to);
839 if(cto == 0) {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100840 return INSTALL_STATUS_INTERNAL_ERROR;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800841 }
842
843 //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
844 free((void*) l->connect_to);
845 l->connect_to = cto;
846 if (l->transport != transport) {
847 remove_transport_disconnect(l->transport, &l->disconnect);
848 l->transport = transport;
849 add_transport_disconnect(l->transport, &l->disconnect);
850 }
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100851 return INSTALL_STATUS_OK;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800852 }
853 }
854
855 if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
856 if((l->local_name = strdup(local_name)) == 0) goto nomem;
857 if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
858
859
860 l->fd = local_name_to_fd(local_name);
861 if(l->fd < 0) {
862 free((void*) l->local_name);
863 free((void*) l->connect_to);
864 free(l);
865 printf("cannot bind '%s'\n", local_name);
866 return -2;
867 }
868
869 close_on_exec(l->fd);
870 if(!strcmp(l->connect_to, "*smartsocket*")) {
871 fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
872 } else {
873 fdevent_install(&l->fde, l->fd, listener_event_func, l);
874 }
875 fdevent_set(&l->fde, FDE_READ);
876
877 l->next = &listener_list;
878 l->prev = listener_list.prev;
879 l->next->prev = l;
880 l->prev->next = l;
881 l->transport = transport;
882
883 if (transport) {
884 l->disconnect.opaque = l;
885 l->disconnect.func = listener_disconnect;
886 add_transport_disconnect(transport, &l->disconnect);
887 }
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100888 return INSTALL_STATUS_OK;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800889
890nomem:
891 fatal("cannot allocate listener");
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +0100892 return INSTALL_STATUS_INTERNAL_ERROR;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800893}
894
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800895#ifdef HAVE_WIN32_PROC
896static BOOL WINAPI ctrlc_handler(DWORD type)
897{
898 exit(STATUS_CONTROL_C_EXIT);
899 return TRUE;
900}
901#endif
902
903static void adb_cleanup(void)
904{
905 usb_cleanup();
906}
907
908void start_logging(void)
909{
910#ifdef HAVE_WIN32_PROC
911 char temp[ MAX_PATH ];
912 FILE* fnul;
913 FILE* flog;
914
915 GetTempPath( sizeof(temp) - 8, temp );
916 strcat( temp, "adb.log" );
917
918 /* Win32 specific redirections */
919 fnul = fopen( "NUL", "rt" );
920 if (fnul != NULL)
921 stdin[0] = fnul[0];
922
923 flog = fopen( temp, "at" );
924 if (flog == NULL)
925 flog = fnul;
926
927 setvbuf( flog, NULL, _IONBF, 0 );
928
929 stdout[0] = flog[0];
930 stderr[0] = flog[0];
931 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
932#else
933 int fd;
934
935 fd = unix_open("/dev/null", O_RDONLY);
936 dup2(fd, 0);
JP Abgrall408fa572011-03-16 15:57:42 -0700937 adb_close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800938
939 fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
940 if(fd < 0) {
941 fd = unix_open("/dev/null", O_WRONLY);
942 }
943 dup2(fd, 1);
944 dup2(fd, 2);
JP Abgrall408fa572011-03-16 15:57:42 -0700945 adb_close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
947#endif
948}
949
950#if !ADB_HOST
951void start_device_log(void)
952{
953 int fd;
Mike Lockwood1f546e62009-05-25 18:17:55 -0400954 char path[PATH_MAX];
955 struct tm now;
956 time_t t;
957 char value[PROPERTY_VALUE_MAX];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800958
Mike Lockwood1f546e62009-05-25 18:17:55 -0400959 // read the trace mask from persistent property persist.adb.trace_mask
960 // give up if the property is not set or cannot be parsed
961 property_get("persist.adb.trace_mask", value, "");
962 if (sscanf(value, "%x", &adb_trace_mask) != 1)
963 return;
964
965 adb_mkdir("/data/adb", 0775);
966 tzset();
967 time(&t);
968 localtime_r(&t, &now);
969 strftime(path, sizeof(path),
970 "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
971 &now);
972 fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800973 if (fd < 0)
974 return;
975
976 // redirect stdout and stderr to the log file
977 dup2(fd, 1);
978 dup2(fd, 2);
979 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
Benoit Goby95ef8282011-02-01 18:57:41 -0800980 adb_close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800981
982 fd = unix_open("/dev/null", O_RDONLY);
983 dup2(fd, 0);
Benoit Goby95ef8282011-02-01 18:57:41 -0800984 adb_close(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800985}
986#endif
987
988#if ADB_HOST
JP Abgrall571c1362012-12-06 18:18:12 -0800989
990#ifdef WORKAROUND_BUG6558362
991#include <sched.h>
992#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
993void adb_set_affinity(void)
994{
995 cpu_set_t cpu_set;
996 const char* cpunum_str = getenv(AFFINITY_ENVVAR);
997 char* strtol_res;
998 int cpu_num;
999
1000 if (!cpunum_str || !*cpunum_str)
1001 return;
1002 cpu_num = strtol(cpunum_str, &strtol_res, 0);
1003 if (*strtol_res != '\0')
1004 fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
1005
1006 sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
1007 D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
1008 CPU_ZERO(&cpu_set);
1009 CPU_SET(cpu_num, &cpu_set);
1010 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
1011 sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
1012 D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
1013}
1014#endif
1015
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001016int launch_server(int server_port)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001017{
1018#ifdef HAVE_WIN32_PROC
1019 /* we need to start the server in the background */
1020 /* we create a PIPE that will be used to wait for the server's "OK" */
1021 /* message since the pipe handles must be inheritable, we use a */
1022 /* security attribute */
1023 HANDLE pipe_read, pipe_write;
1024 SECURITY_ATTRIBUTES sa;
1025 STARTUPINFO startup;
1026 PROCESS_INFORMATION pinfo;
1027 char program_path[ MAX_PATH ];
1028 int ret;
1029
1030 sa.nLength = sizeof(sa);
1031 sa.lpSecurityDescriptor = NULL;
1032 sa.bInheritHandle = TRUE;
1033
1034 /* create pipe, and ensure its read handle isn't inheritable */
1035 ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
1036 if (!ret) {
1037 fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
1038 return -1;
1039 }
1040
1041 SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
1042
1043 ZeroMemory( &startup, sizeof(startup) );
1044 startup.cb = sizeof(startup);
1045 startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
1046 startup.hStdOutput = pipe_write;
1047 startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1048 startup.dwFlags = STARTF_USESTDHANDLES;
1049
1050 ZeroMemory( &pinfo, sizeof(pinfo) );
1051
1052 /* get path of current program */
1053 GetModuleFileName( NULL, program_path, sizeof(program_path) );
1054
1055 ret = CreateProcess(
1056 program_path, /* program path */
1057 "adb fork-server server",
1058 /* the fork-server argument will set the
1059 debug = 2 in the child */
1060 NULL, /* process handle is not inheritable */
1061 NULL, /* thread handle is not inheritable */
1062 TRUE, /* yes, inherit some handles */
1063 DETACHED_PROCESS, /* the new process doesn't have a console */
1064 NULL, /* use parent's environment block */
1065 NULL, /* use parent's starting directory */
1066 &startup, /* startup info, i.e. std handles */
1067 &pinfo );
1068
1069 CloseHandle( pipe_write );
1070
1071 if (!ret) {
1072 fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
1073 CloseHandle( pipe_read );
1074 return -1;
1075 }
1076
1077 CloseHandle( pinfo.hProcess );
1078 CloseHandle( pinfo.hThread );
1079
1080 /* wait for the "OK\n" message */
1081 {
1082 char temp[3];
1083 DWORD count;
1084
1085 ret = ReadFile( pipe_read, temp, 3, &count, NULL );
1086 CloseHandle( pipe_read );
1087 if ( !ret ) {
1088 fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
1089 return -1;
1090 }
1091 if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
1092 fprintf(stderr, "ADB server didn't ACK\n" );
1093 return -1;
1094 }
1095 }
1096#elif defined(HAVE_FORKEXEC)
1097 char path[PATH_MAX];
1098 int fd[2];
1099
1100 // set up a pipe so the child can tell us when it is ready.
1101 // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
1102 if (pipe(fd)) {
1103 fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
1104 return -1;
1105 }
Alexey Tarasov31664102009-10-22 02:55:00 +11001106 get_my_path(path, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001107 pid_t pid = fork();
1108 if(pid < 0) return -1;
1109
1110 if (pid == 0) {
1111 // child side of the fork
1112
1113 // redirect stderr to the pipe
1114 // we use stderr instead of stdout due to stdout's buffering behavior.
1115 adb_close(fd[0]);
1116 dup2(fd[1], STDERR_FILENO);
1117 adb_close(fd[1]);
1118
Matt Gumbeld7b33082012-11-14 10:16:17 -08001119 char str_port[30];
1120 snprintf(str_port, sizeof(str_port), "%d", server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001121 // child process
Matt Gumbeld7b33082012-11-14 10:16:17 -08001122 int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001123 // this should not return
1124 fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
1125 } else {
1126 // parent side of the fork
1127
1128 char temp[3];
1129
1130 temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
1131 // wait for the "OK\n" message
1132 adb_close(fd[1]);
1133 int ret = adb_read(fd[0], temp, 3);
JP Abgrall408fa572011-03-16 15:57:42 -07001134 int saved_errno = errno;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001135 adb_close(fd[0]);
1136 if (ret < 0) {
JP Abgrall408fa572011-03-16 15:57:42 -07001137 fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001138 return -1;
1139 }
1140 if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
1141 fprintf(stderr, "ADB server didn't ACK\n" );
1142 return -1;
1143 }
1144
1145 setsid();
1146 }
1147#else
1148#error "cannot implement background server start on this platform"
1149#endif
1150 return 0;
1151}
1152#endif
1153
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001154/* Constructs a local name of form tcp:port.
1155 * target_str points to the target string, it's content will be overwritten.
1156 * target_size is the capacity of the target string.
1157 * server_port is the port number to use for the local name.
1158 */
1159void build_local_name(char* target_str, size_t target_size, int server_port)
1160{
1161 snprintf(target_str, target_size, "tcp:%d", server_port);
1162}
1163
Nick Kralevichbd9206b2012-01-19 10:18:59 -08001164#if !ADB_HOST
1165static int should_drop_privileges() {
Nick Kralevich5890fe32012-01-19 13:11:35 -08001166#ifndef ALLOW_ADBD_ROOT
1167 return 1;
1168#else /* ALLOW_ADBD_ROOT */
Nick Kralevichbd9206b2012-01-19 10:18:59 -08001169 int secure = 0;
1170 char value[PROPERTY_VALUE_MAX];
1171
1172 /* run adbd in secure mode if ro.secure is set and
1173 ** we are not in the emulator
1174 */
1175 property_get("ro.kernel.qemu", value, "");
1176 if (strcmp(value, "1") != 0) {
1177 property_get("ro.secure", value, "1");
1178 if (strcmp(value, "1") == 0) {
1179 // don't run as root if ro.secure is set...
1180 secure = 1;
1181
1182 // ... except we allow running as root in userdebug builds if the
1183 // service.adb.root property has been set by the "adb root" command
1184 property_get("ro.debuggable", value, "");
1185 if (strcmp(value, "1") == 0) {
1186 property_get("service.adb.root", value, "");
1187 if (strcmp(value, "1") == 0) {
1188 secure = 0;
1189 }
1190 }
1191 }
1192 }
1193 return secure;
Nick Kralevich5890fe32012-01-19 13:11:35 -08001194#endif /* ALLOW_ADBD_ROOT */
Nick Kralevichbd9206b2012-01-19 10:18:59 -08001195}
1196#endif /* !ADB_HOST */
1197
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001198int adb_main(int is_daemon, int server_port)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001199{
1200#if !ADB_HOST
Mike Lockwood2f38b692009-08-24 15:58:40 -07001201 int port;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001202 char value[PROPERTY_VALUE_MAX];
Nick Kralevicheb68fa82012-04-02 13:00:35 -07001203
1204 umask(000);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001205#endif
1206
1207 atexit(adb_cleanup);
1208#ifdef HAVE_WIN32_PROC
1209 SetConsoleCtrlHandler( ctrlc_handler, TRUE );
1210#elif defined(HAVE_FORKEXEC)
JP Abgrall408fa572011-03-16 15:57:42 -07001211 // No SIGCHLD. Let the service subproc handle its children.
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001212 signal(SIGPIPE, SIG_IGN);
1213#endif
1214
1215 init_transport_registration();
1216
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001217#if ADB_HOST
1218 HOST = 1;
JP Abgrall571c1362012-12-06 18:18:12 -08001219
1220#ifdef WORKAROUND_BUG6558362
1221 if(is_daemon) adb_set_affinity();
1222#endif
Xavier Ducroheta09fbd12009-05-20 17:33:53 -07001223 usb_vendors_init();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001224 usb_init();
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001225 local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
Benoit Gobyd5fcafa2012-04-12 12:23:49 -07001226 adb_auth_init();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001227
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001228 char local_name[30];
1229 build_local_name(local_name, sizeof(local_name), server_port);
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001230 if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001231 exit(1);
1232 }
1233#else
Benoit Gobyd5fcafa2012-04-12 12:23:49 -07001234 property_get("ro.adb.secure", value, "0");
1235 auth_enabled = !strcmp(value, "1");
1236 if (auth_enabled)
1237 adb_auth_init();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001238
Jeff Sharkeyd6d42862012-09-06 13:05:40 -07001239 // Our external storage path may be different than apps, since
1240 // we aren't able to bind mount after dropping root.
1241 const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
1242 if (NULL != adb_external_storage) {
1243 setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
1244 } else {
1245 D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
1246 " unchanged.\n");
1247 }
1248
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001249 /* don't listen on a port (default 5037) if running in secure mode */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001250 /* don't run as root if we are running in secure mode */
Nick Kralevichbd9206b2012-01-19 10:18:59 -08001251 if (should_drop_privileges()) {
Mike Lockwood5f4b0512009-08-04 20:37:51 -04001252 struct __user_cap_header_struct header;
1253 struct __user_cap_data_struct cap;
1254
Nick Kralevich44db9902010-08-27 14:35:07 -07001255 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1256 exit(1);
1257 }
Mike Lockwood5f4b0512009-08-04 20:37:51 -04001258
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001259 /* add extra groups:
1260 ** AID_ADB to access the USB driver
1261 ** AID_LOG to read system logs (adb logcat)
1262 ** AID_INPUT to diagnose input issues (getevent)
1263 ** AID_INET to diagnose network issues (netcfg, ping)
1264 ** AID_GRAPHICS to access the frame buffer
The Android Open Source Project20155492009-03-11 12:12:01 -07001265 ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
Dianne Hackborn50458cf2012-03-07 12:57:14 -08001266 ** AID_SDCARD_R to allow reading from the SD card
Mike Lockwood6a3075c2009-05-25 13:52:00 -04001267 ** AID_SDCARD_RW to allow writing to the SD card
Mike Lockwoodd969faa2010-02-24 16:07:23 -05001268 ** AID_MOUNT to allow unmounting the SD card before rebooting
JP Abgrall61b90bd2011-11-09 10:30:08 -08001269 ** AID_NET_BW_STATS to read out qtaguid statistics
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001270 */
The Android Open Source Project20155492009-03-11 12:12:01 -07001271 gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
Dianne Hackborn50458cf2012-03-07 12:57:14 -08001272 AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
1273 AID_MOUNT, AID_NET_BW_STATS };
Nick Kralevich44db9902010-08-27 14:35:07 -07001274 if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
1275 exit(1);
1276 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001277
1278 /* then switch user and group to "shell" */
Nick Kralevich44db9902010-08-27 14:35:07 -07001279 if (setgid(AID_SHELL) != 0) {
1280 exit(1);
1281 }
1282 if (setuid(AID_SHELL) != 0) {
1283 exit(1);
1284 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001285
Mike Lockwood5f4b0512009-08-04 20:37:51 -04001286 /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
1287 header.version = _LINUX_CAPABILITY_VERSION;
1288 header.pid = 0;
1289 cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
1290 cap.inheritable = 0;
1291 capset(&header, &cap);
1292
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001293 D("Local port disabled\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001294 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001295 char local_name[30];
1296 build_local_name(local_name, sizeof(local_name), server_port);
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001297 if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001298 exit(1);
1299 }
1300 }
1301
Mike J. Chen1dd55c52012-07-20 18:16:21 -07001302 int usb = 0;
1303 if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
Mike Lockwoodcef31a02009-08-26 12:50:22 -07001304 // listen on USB
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001305 usb_init();
Mike J. Chen1dd55c52012-07-20 18:16:21 -07001306 usb = 1;
1307 }
1308
1309 // If one of these properties is set, also listen on that port
1310 // If one of the properties isn't set and we couldn't listen on usb,
1311 // listen on the default port.
1312 property_get("service.adb.tcp.port", value, "");
1313 if (!value[0]) {
1314 property_get("persist.adb.tcp.port", value, "");
1315 }
1316 if (sscanf(value, "%d", &port) == 1 && port > 0) {
1317 printf("using port=%d\n", port);
1318 // listen on TCP port specified by service.adb.tcp.port property
1319 local_init(port);
1320 } else if (!usb) {
Mike Lockwoodcef31a02009-08-26 12:50:22 -07001321 // listen on default port
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001322 local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001323 }
Mike J. Chen1dd55c52012-07-20 18:16:21 -07001324
JP Abgrall408fa572011-03-16 15:57:42 -07001325 D("adb_main(): pre init_jdwp()\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001326 init_jdwp();
JP Abgrall408fa572011-03-16 15:57:42 -07001327 D("adb_main(): post init_jdwp()\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001328#endif
1329
1330 if (is_daemon)
1331 {
1332 // inform our parent that we are up and running.
1333#ifdef HAVE_WIN32_PROC
1334 DWORD count;
1335 WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
1336#elif defined(HAVE_FORKEXEC)
1337 fprintf(stderr, "OK\n");
1338#endif
1339 start_logging();
1340 }
JP Abgrall408fa572011-03-16 15:57:42 -07001341 D("Event loop starting\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001342
1343 fdevent_loop();
1344
1345 usb_cleanup();
1346
1347 return 0;
1348}
1349
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001350#if ADB_HOST
1351void connect_device(char* host, char* buffer, int buffer_size)
1352{
1353 int port, fd;
1354 char* portstr = strchr(host, ':');
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001355 char hostbuf[100];
1356 char serial[100];
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001357
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001358 strncpy(hostbuf, host, sizeof(hostbuf) - 1);
1359 if (portstr) {
Scott Andersonc7993af2012-05-25 13:55:46 -07001360 if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001361 snprintf(buffer, buffer_size, "bad host name %s", host);
1362 return;
1363 }
1364 // zero terminate the host at the point we found the colon
1365 hostbuf[portstr - host] = 0;
1366 if (sscanf(portstr + 1, "%d", &port) == 0) {
1367 snprintf(buffer, buffer_size, "bad port number %s", portstr);
1368 return;
1369 }
1370 } else {
1371 port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001372 }
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001373
1374 snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
1375 if (find_transport(serial)) {
1376 snprintf(buffer, buffer_size, "already connected to %s", serial);
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001377 return;
1378 }
1379
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001380 fd = socket_network_client(hostbuf, port, SOCK_STREAM);
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001381 if (fd < 0) {
1382 snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
1383 return;
1384 }
1385
1386 D("client: connected on remote on fd %d\n", fd);
1387 close_on_exec(fd);
1388 disable_tcp_nagle(fd);
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001389 register_socket_transport(fd, serial, port, 0);
1390 snprintf(buffer, buffer_size, "connected to %s", serial);
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001391}
1392
1393void connect_emulator(char* port_spec, char* buffer, int buffer_size)
1394{
1395 char* port_separator = strchr(port_spec, ',');
1396 if (!port_separator) {
1397 snprintf(buffer, buffer_size,
1398 "unable to parse '%s' as <console port>,<adb port>",
1399 port_spec);
1400 return;
1401 }
1402
1403 // Zero-terminate console port and make port_separator point to 2nd port.
1404 *port_separator++ = 0;
1405 int console_port = strtol(port_spec, NULL, 0);
1406 int adb_port = strtol(port_separator, NULL, 0);
1407 if (!(console_port > 0 && adb_port > 0)) {
1408 *(port_separator - 1) = ',';
1409 snprintf(buffer, buffer_size,
1410 "Invalid port numbers: Expected positive numbers, got '%s'",
1411 port_spec);
1412 return;
1413 }
1414
1415 /* Check if the emulator is already known.
1416 * Note: There's a small but harmless race condition here: An emulator not
1417 * present just yet could be registered by another invocation right
1418 * after doing this check here. However, local_connect protects
1419 * against double-registration too. From here, a better error message
1420 * can be produced. In the case of the race condition, the very specific
1421 * error message won't be shown, but the data doesn't get corrupted. */
1422 atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
1423 if (known_emulator != NULL) {
1424 snprintf(buffer, buffer_size,
1425 "Emulator on port %d already registered.", adb_port);
1426 return;
1427 }
1428
1429 /* Check if more emulators can be registered. Similar unproblematic
1430 * race condition as above. */
1431 int candidate_slot = get_available_local_transport_index();
1432 if (candidate_slot < 0) {
1433 snprintf(buffer, buffer_size, "Cannot accept more emulators.");
1434 return;
1435 }
1436
1437 /* Preconditions met, try to connect to the emulator. */
1438 if (!local_connect_arbitrary_ports(console_port, adb_port)) {
1439 snprintf(buffer, buffer_size,
1440 "Connected to emulator on ports %d,%d", console_port, adb_port);
1441 } else {
1442 snprintf(buffer, buffer_size,
1443 "Could not connect to emulator on ports %d,%d",
1444 console_port, adb_port);
1445 }
1446}
1447#endif
1448
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001449int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
1450{
1451 atransport *transport = NULL;
1452 char buf[4096];
1453
1454 if(!strcmp(service, "kill")) {
1455 fprintf(stderr,"adb server killed by remote request\n");
1456 fflush(stdout);
1457 adb_write(reply_fd, "OKAY", 4);
1458 usb_cleanup();
1459 exit(0);
1460 }
1461
1462#if ADB_HOST
1463 // "transport:" is used for switching transport with a specified serial number
1464 // "transport-usb:" is used for switching transport to the only USB transport
1465 // "transport-local:" is used for switching transport to the only local transport
1466 // "transport-any:" is used for switching transport to the only transport
1467 if (!strncmp(service, "transport", strlen("transport"))) {
1468 char* error_string = "unknown failure";
1469 transport_type type = kTransportAny;
1470
1471 if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
1472 type = kTransportUsb;
1473 } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
1474 type = kTransportLocal;
1475 } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
1476 type = kTransportAny;
1477 } else if (!strncmp(service, "transport:", strlen("transport:"))) {
1478 service += strlen("transport:");
Tom Marlin3175c8e2011-07-27 12:56:14 -05001479 serial = service;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001480 }
1481
1482 transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
1483
1484 if (transport) {
1485 s->transport = transport;
1486 adb_write(reply_fd, "OKAY", 4);
1487 } else {
1488 sendfailmsg(reply_fd, error_string);
1489 }
1490 return 1;
1491 }
1492
1493 // return a list of all connected devices
Scott Andersone109d262012-04-20 11:21:14 -07001494 if (!strncmp(service, "devices", 7)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001495 char buffer[4096];
Scott Andersone109d262012-04-20 11:21:14 -07001496 int use_long = !strcmp(service+7, "-l");
1497 if (use_long || service[7] == 0) {
1498 memset(buf, 0, sizeof(buf));
1499 memset(buffer, 0, sizeof(buffer));
1500 D("Getting device list \n");
1501 list_transports(buffer, sizeof(buffer), use_long);
1502 snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
1503 D("Wrote device list \n");
1504 writex(reply_fd, buf, strlen(buf));
1505 return 0;
1506 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001507 }
1508
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001509 // add a new TCP transport, device or emulator
Mike Lockwood2f38b692009-08-24 15:58:40 -07001510 if (!strncmp(service, "connect:", 8)) {
1511 char buffer[4096];
Mike Lockwood2f38b692009-08-24 15:58:40 -07001512 char* host = service + 8;
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001513 if (!strncmp(host, "emu:", 4)) {
1514 connect_emulator(host + 4, buffer, sizeof(buffer));
1515 } else {
1516 connect_device(host, buffer, sizeof(buffer));
Mike Lockwood2f38b692009-08-24 15:58:40 -07001517 }
Stefan Hilzingerd9d1ca42010-04-26 10:17:43 +01001518 // Send response for emulator and device
Mike Lockwood74d7ff82009-10-11 23:04:18 -04001519 snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
1520 writex(reply_fd, buf, strlen(buf));
1521 return 0;
1522 }
1523
1524 // remove TCP transport
1525 if (!strncmp(service, "disconnect:", 11)) {
1526 char buffer[4096];
1527 memset(buffer, 0, sizeof(buffer));
1528 char* serial = service + 11;
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001529 if (serial[0] == 0) {
1530 // disconnect from all TCP devices
1531 unregister_all_tcp_transports();
Mike Lockwood74d7ff82009-10-11 23:04:18 -04001532 } else {
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -04001533 char hostbuf[100];
1534 // assume port 5555 if no port is specified
1535 if (!strchr(serial, ':')) {
1536 snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
1537 serial = hostbuf;
1538 }
1539 atransport *t = find_transport(serial);
1540
1541 if (t) {
1542 unregister_transport(t);
1543 } else {
1544 snprintf(buffer, sizeof(buffer), "No such device %s", serial);
1545 }
Mike Lockwood74d7ff82009-10-11 23:04:18 -04001546 }
1547
1548 snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
Mike Lockwood2f38b692009-08-24 15:58:40 -07001549 writex(reply_fd, buf, strlen(buf));
1550 return 0;
1551 }
1552
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001553 // returns our value for ADB_SERVER_VERSION
1554 if (!strcmp(service, "version")) {
1555 char version[12];
1556 snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
1557 snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
1558 writex(reply_fd, buf, strlen(buf));
1559 return 0;
1560 }
1561
1562 if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
1563 char *out = "unknown";
1564 transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1565 if (transport && transport->serial) {
1566 out = transport->serial;
1567 }
1568 snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
1569 writex(reply_fd, buf, strlen(buf));
1570 return 0;
1571 }
Scott Andersone109d262012-04-20 11:21:14 -07001572 if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
1573 char *out = "unknown";
1574 transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1575 if (transport && transport->devpath) {
1576 out = transport->devpath;
1577 }
1578 snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
1579 writex(reply_fd, buf, strlen(buf));
1580 return 0;
1581 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001582 // indicates a new emulator instance has started
1583 if (!strncmp(service,"emulator:",9)) {
1584 int port = atoi(service+9);
1585 local_connect(port);
1586 /* we don't even need to send a reply */
1587 return 0;
1588 }
1589#endif // ADB_HOST
1590
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001591 if(!strcmp(service,"list-forward")) {
1592 // Create the list of forward redirections.
1593 char header[9];
1594 int buffer_size = format_listeners(NULL, 0);
1595 // Add one byte for the trailing zero.
1596 char* buffer = malloc(buffer_size+1);
1597 (void) format_listeners(buffer, buffer_size+1);
1598 snprintf(header, sizeof header, "OKAY%04x", buffer_size);
1599 writex(reply_fd, header, 8);
1600 writex(reply_fd, buffer, buffer_size);
1601 free(buffer);
1602 return 0;
1603 }
1604
1605 if (!strcmp(service,"killforward-all")) {
1606 remove_all_listeners();
1607 adb_write(reply_fd, "OKAYOKAY", 8);
1608 return 0;
1609 }
1610
1611 if(!strncmp(service,"forward:",8) ||
1612 !strncmp(service,"killforward:",12)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001613 char *local, *remote, *err;
1614 int r;
1615 atransport *transport;
1616
1617 int createForward = strncmp(service,"kill",4);
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001618 int no_rebind = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001619
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001620 local = strchr(service, ':') + 1;
1621
1622 // Handle forward:norebind:<local>... here
1623 if (createForward && !strncmp(local, "norebind:", 9)) {
1624 no_rebind = 1;
1625 local = strchr(local, ':') + 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001626 }
1627
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001628 remote = strchr(local,';');
1629
1630 if (createForward) {
1631 // Check forward: parameter format: '<local>;<remote>'
1632 if(remote == 0) {
1633 sendfailmsg(reply_fd, "malformed forward spec");
1634 return 0;
1635 }
1636
1637 *remote++ = 0;
1638 if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
1639 sendfailmsg(reply_fd, "malformed forward spec");
1640 return 0;
1641 }
1642 } else {
1643 // Check killforward: parameter format: '<local>'
1644 if (local[0] == 0) {
1645 sendfailmsg(reply_fd, "malformed forward spec");
1646 return 0;
1647 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001648 }
1649
1650 transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
1651 if (!transport) {
1652 sendfailmsg(reply_fd, err);
1653 return 0;
1654 }
1655
1656 if (createForward) {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001657 r = install_listener(local, remote, transport, no_rebind);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001658 } else {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001659 r = remove_listener(local, transport);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001660 }
1661 if(r == 0) {
1662 /* 1st OKAY is connect, 2nd OKAY is status */
1663 writex(reply_fd, "OKAYOKAY", 8);
1664 return 0;
1665 }
1666
1667 if (createForward) {
David 'Digit' Turner0d82fbf2012-11-14 15:01:55 +01001668 const char* message;
1669 switch (r) {
1670 case INSTALL_STATUS_CANNOT_BIND:
1671 message = "cannot bind to socket";
1672 break;
1673 case INSTALL_STATUS_CANNOT_REBIND:
1674 message = "cannot rebind existing socket";
1675 break;
1676 default:
1677 message = "internal error";
1678 }
1679 sendfailmsg(reply_fd, message);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001680 } else {
1681 sendfailmsg(reply_fd, "cannot remove listener");
1682 }
1683 return 0;
1684 }
1685
1686 if(!strncmp(service,"get-state",strlen("get-state"))) {
1687 transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1688 char *state = connection_state_name(transport);
1689 snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
1690 writex(reply_fd, buf, strlen(buf));
1691 return 0;
1692 }
1693 return -1;
1694}
1695
1696#if !ADB_HOST
1697int recovery_mode = 0;
1698#endif
1699
1700int main(int argc, char **argv)
1701{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001702#if ADB_HOST
1703 adb_sysdeps_init();
JP Abgrall408fa572011-03-16 15:57:42 -07001704 adb_trace_init();
1705 D("Handling commandline()\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001706 return adb_commandline(argc - 1, argv + 1);
1707#else
Vladimir Chtchetkine28781b02012-02-27 10:41:53 -08001708 /* If adbd runs inside the emulator this will enable adb tracing via
1709 * adb-debug qemud service in the emulator. */
1710 adb_qemu_trace_init();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001711 if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
1712 adb_device_banner = "recovery";
1713 recovery_mode = 1;
1714 }
Mike Lockwood1f546e62009-05-25 18:17:55 -04001715
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001716 start_device_log();
JP Abgrall408fa572011-03-16 15:57:42 -07001717 D("Handling main()\n");
Stefan Hilzingera84a42e2010-04-19 12:21:12 +01001718 return adb_main(0, DEFAULT_ADB_PORT);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001719#endif
1720}