blob: d1eba5adf99d431e328a18dbdd4849b336844be6 [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#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include <unistd.h>
22#include <limits.h>
23#include <stdarg.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <ctype.h>
27#include <assert.h>
28
29#include "sysdeps.h"
30
31#ifdef HAVE_TERMIO_H
32#include <termios.h>
33#endif
34
35#define TRACE_TAG TRACE_ADB
36#include "adb.h"
37#include "adb_client.h"
38#include "file_sync_service.h"
39
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040enum {
41 IGNORE_DATA,
42 WIPE_DATA,
43 FLASH_DATA
44};
45
46static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
47
Alexey Tarasov31664102009-10-22 02:55:00 +110048void get_my_path(char *s, size_t maxLen);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049int find_sync_dirs(const char *srcarg,
50 char **android_srcdir_out, char **data_srcdir_out);
51int install_app(transport_type transport, char* serial, int argc, char** argv);
52int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
53
54static const char *gProductOutPath = NULL;
55
56static char *product_file(const char *extra)
57{
58 int n;
59 char *x;
60
61 if (gProductOutPath == NULL) {
62 fprintf(stderr, "adb: Product directory not specified; "
63 "use -p or define ANDROID_PRODUCT_OUT\n");
64 exit(1);
65 }
66
67 n = strlen(gProductOutPath) + strlen(extra) + 2;
68 x = malloc(n);
69 if (x == 0) {
70 fprintf(stderr, "adb: Out of memory (product_file())\n");
71 exit(1);
72 }
73
74 snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
75 return x;
76}
77
78void version(FILE * out) {
79 fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
80 ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
81}
82
83void help()
84{
85 version(stderr);
86
87 fprintf(stderr,
88 "\n"
89 " -d - directs command to the only connected USB device\n"
90 " returns an error if more than one USB device is present.\n"
91 " -e - directs command to the only running emulator.\n"
92 " returns an error if more than one emulator is running.\n"
93 " -s <serial number> - directs command to the USB device or emulator with\n"
Nick Pelly22048ef2009-05-07 12:48:03 -070094 " the given serial number. Overrides ANDROID_SERIAL\n"
95 " envivornment variable.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096 " -p <product name or path> - simple product name like 'sooner', or\n"
97 " a relative/absolute path to a product\n"
98 " out directory like 'out/target/product/sooner'.\n"
99 " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
100 " environment variable is used, which must\n"
101 " be an absolute path.\n"
102 " devices - list all connected devices\n"
Brian Carlstrom805c4a72010-03-01 22:54:12 -0800103 " connect <host>:<port> - connect to a device via TCP/IP\n"
104 " disconnect <host>:<port> - disconnect from a TCP/IP device\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800105 "\n"
106 "device commands:\n"
107 " adb push <local> <remote> - copy file/dir to device\n"
Joe Onorato8071a4b2010-01-05 13:42:25 -0800108 " adb pull <remote> [<local>] - copy file/dir from device\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800109 " adb sync [ <directory> ] - copy host->device only if changed\n"
Anthony Newnam705c9442010-02-22 08:36:49 -0600110 " (-l means list but don't copy)\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800111 " (see 'adb help all')\n"
112 " adb shell - run remote shell interactively\n"
113 " adb shell <command> - run remote shell command\n"
114 " adb emu <command> - run emulator console command\n"
115 " adb logcat [ <filter-spec> ] - View device log\n"
116 " adb forward <local> <remote> - forward socket connections\n"
117 " forward specs are one of: \n"
118 " tcp:<port>\n"
119 " localabstract:<unix domain socket name>\n"
120 " localreserved:<unix domain socket name>\n"
121 " localfilesystem:<unix domain socket name>\n"
122 " dev:<character device name>\n"
123 " jdwp:<process pid> (remote only)\n"
124 " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
125 " adb install [-l] [-r] <file> - push this package file to the device and install it\n"
126 " ('-l' means forward-lock the app)\n"
127 " ('-r' means reinstall the app, keeping its data)\n"
128 " adb uninstall [-k] <package> - remove this app package from the device\n"
129 " ('-k' means keep the data and cache directories)\n"
130 " adb bugreport - return all information from the device\n"
131 " that should be included in a bug report.\n"
132 "\n"
133 " adb help - show this help message\n"
134 " adb version - show version num\n"
135 "\n"
136 "DATAOPTS:\n"
137 " (no option) - don't touch the data partition\n"
138 " -w - wipe the data partition\n"
139 " -d - flash the data partition\n"
140 "\n"
141 "scripting:\n"
142 " adb wait-for-device - block until device is online\n"
143 " adb start-server - ensure that there is a server running\n"
144 " adb kill-server - kill the server if it is running\n"
145 " adb get-state - prints: offline | bootloader | device\n"
146 " adb get-serialno - prints: <serial-number>\n"
147 " adb status-window - continuously print device status for a specified device\n"
148 " adb remount - remounts the /system partition on the device read-write\n"
Mike Lockwood5f4b0512009-08-04 20:37:51 -0400149 " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
Romain Guya48d43a2009-12-14 14:42:17 -0800150 " adb reboot-bootloader - reboots the device into the bootloader\n"
Mike Lockwood2f38b692009-08-24 15:58:40 -0700151 " adb root - restarts the adbd daemon with root permissions\n"
Romain Guya48d43a2009-12-14 14:42:17 -0800152 " adb usb - restarts the adbd daemon listening on USB\n"
Mike Lockwood2f38b692009-08-24 15:58:40 -0700153 " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 "\n"
155 "networking:\n"
156 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
Kenny Root417a3232009-06-08 14:40:30 -0500157 " Note: you should not automatically start a PPP connection.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800158 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
159 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
160 "\n"
161 "adb sync notes: adb sync [ <directory> ]\n"
162 " <localdir> can be interpreted in several ways:\n"
163 "\n"
164 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
165 "\n"
166 " - If it is \"system\" or \"data\", only the corresponding partition\n"
167 " is updated.\n"
Timcd643152010-02-16 20:18:29 +0000168 "\n"
169 "environmental variables:\n"
170 " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
171 " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
172 " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
173 " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800174 );
175}
176
177int usage()
178{
179 help();
180 return 1;
181}
182
183#ifdef HAVE_TERMIO_H
184static struct termios tio_save;
185
186static void stdin_raw_init(int fd)
187{
188 struct termios tio;
189
190 if(tcgetattr(fd, &tio)) return;
191 if(tcgetattr(fd, &tio_save)) return;
192
193 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
194
195 /* no timeout but request at least one character per read */
196 tio.c_cc[VTIME] = 0;
197 tio.c_cc[VMIN] = 1;
198
199 tcsetattr(fd, TCSANOW, &tio);
200 tcflush(fd, TCIFLUSH);
201}
202
203static void stdin_raw_restore(int fd)
204{
205 tcsetattr(fd, TCSANOW, &tio_save);
206 tcflush(fd, TCIFLUSH);
207}
208#endif
209
210static void read_and_dump(int fd)
211{
212 char buf[4096];
213 int len;
214
215 while(fd >= 0) {
216 len = adb_read(fd, buf, 4096);
217 if(len == 0) {
218 break;
219 }
220
221 if(len < 0) {
222 if(errno == EINTR) continue;
223 break;
224 }
Mike Lockwoodc519c002009-09-22 01:18:40 -0400225 fwrite(buf, 1, len, stdout);
226 fflush(stdout);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800227 }
228}
229
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230static void *stdin_read_thread(void *x)
231{
232 int fd, fdi;
233 unsigned char buf[1024];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234 int r, n;
235 int state = 0;
236
237 int *fds = (int*) x;
238 fd = fds[0];
239 fdi = fds[1];
240 free(fds);
241
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242 for(;;) {
243 /* fdi is really the client's stdin, so use read, not adb_read here */
244 r = unix_read(fdi, buf, 1024);
245 if(r == 0) break;
246 if(r < 0) {
247 if(errno == EINTR) continue;
248 break;
249 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400250 for(n = 0; n < r; n++){
251 switch(buf[n]) {
252 case '\n':
253 state = 1;
254 break;
255 case '\r':
256 state = 1;
257 break;
258 case '~':
259 if(state == 1) state++;
260 break;
261 case '.':
262 if(state == 2) {
263 fprintf(stderr,"\n* disconnect *\n");
264#ifdef HAVE_TERMIO_H
265 stdin_raw_restore(fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266#endif
Mike Lockwood67d53582010-05-25 13:40:15 -0400267 exit(0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800268 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400269 default:
270 state = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800271 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800272 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800273 r = adb_write(fd, buf, r);
274 if(r <= 0) {
275 break;
276 }
277 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800278 return 0;
279}
280
281int interactive_shell(void)
282{
283 adb_thread_t thr;
284 int fdi, fd;
285 int *fds;
286
287 fd = adb_connect("shell:");
288 if(fd < 0) {
289 fprintf(stderr,"error: %s\n", adb_error());
290 return 1;
291 }
292 fdi = 0; //dup(0);
293
294 fds = malloc(sizeof(int) * 2);
295 fds[0] = fd;
296 fds[1] = fdi;
297
298#ifdef HAVE_TERMIO_H
299 stdin_raw_init(fdi);
300#endif
301 adb_thread_create(&thr, stdin_read_thread, fds);
302 read_and_dump(fd);
303#ifdef HAVE_TERMIO_H
304 stdin_raw_restore(fdi);
305#endif
306 return 0;
307}
308
309
310static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
311{
312 if (serial) {
313 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
314 } else {
315 const char* prefix = "host";
316 if (ttype == kTransportUsb)
317 prefix = "host-usb";
318 else if (ttype == kTransportLocal)
319 prefix = "host-local";
320
321 snprintf(buffer, buflen, "%s:%s", prefix, command);
322 }
323}
324
325static void status_window(transport_type ttype, const char* serial)
326{
327 char command[4096];
328 char *state = 0;
329 char *laststate = 0;
330
331 /* silence stderr */
332#ifdef _WIN32
333 /* XXX: TODO */
334#else
335 int fd;
336 fd = unix_open("/dev/null", O_WRONLY);
337 dup2(fd, 2);
338 adb_close(fd);
339#endif
340
341 format_host_command(command, sizeof command, "get-state", ttype, serial);
342
343 for(;;) {
344 adb_sleep_ms(250);
345
346 if(state) {
347 free(state);
348 state = 0;
349 }
350
351 state = adb_query(command);
352
353 if(state) {
354 if(laststate && !strcmp(state,laststate)){
355 continue;
356 } else {
357 if(laststate) free(laststate);
358 laststate = strdup(state);
359 }
360 }
361
362 printf("%c[2J%c[2H", 27, 27);
363 printf("Android Debug Bridge\n");
364 printf("State: %s\n", state ? state : "offline");
365 fflush(stdout);
366 }
367}
368
369/** duplicate string and quote all \ " ( ) chars + space character. */
370static char *
371dupAndQuote(const char *s)
372{
373 const char *ts;
374 size_t alloc_len;
375 char *ret;
376 char *dest;
377
378 ts = s;
379
380 alloc_len = 0;
381
382 for( ;*ts != '\0'; ts++) {
383 alloc_len++;
384 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
385 alloc_len++;
386 }
387 }
388
389 ret = (char *)malloc(alloc_len + 1);
390
391 ts = s;
392 dest = ret;
393
394 for ( ;*ts != '\0'; ts++) {
395 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
396 *dest++ = '\\';
397 }
398
399 *dest++ = *ts;
400 }
401
402 *dest++ = '\0';
403
404 return ret;
405}
406
407/**
408 * Run ppp in "notty" mode against a resource listed as the first parameter
409 * eg:
410 *
411 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
412 *
413 */
414int ppp(int argc, char **argv)
415{
416#ifdef HAVE_WIN32_PROC
417 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
418 return -1;
419#else
420 char *adb_service_name;
421 pid_t pid;
422 int fd;
423
424 if (argc < 2) {
425 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
426 argv[0]);
427
428 return 1;
429 }
430
431 adb_service_name = argv[1];
432
433 fd = adb_connect(adb_service_name);
434
435 if(fd < 0) {
436 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
437 adb_service_name, adb_error());
438 return 1;
439 }
440
441 pid = fork();
442
443 if (pid < 0) {
444 perror("from fork()");
445 return 1;
446 } else if (pid == 0) {
447 int err;
448 int i;
449 const char **ppp_args;
450
451 // copy args
452 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
453 ppp_args[0] = "pppd";
454 for (i = 2 ; i < argc ; i++) {
455 //argv[2] and beyond become ppp_args[1] and beyond
456 ppp_args[i - 1] = argv[i];
457 }
458 ppp_args[i-1] = NULL;
459
460 // child side
461
462 dup2(fd, STDIN_FILENO);
463 dup2(fd, STDOUT_FILENO);
464 adb_close(STDERR_FILENO);
465 adb_close(fd);
466
467 err = execvp("pppd", (char * const *)ppp_args);
468
469 if (err < 0) {
470 perror("execing pppd");
471 }
472 exit(-1);
473 } else {
474 // parent side
475
476 adb_close(fd);
477 return 0;
478 }
479#endif /* !HAVE_WIN32_PROC */
480}
481
482static int send_shellcommand(transport_type transport, char* serial, char* buf)
483{
484 int fd, ret;
485
486 for(;;) {
487 fd = adb_connect(buf);
488 if(fd >= 0)
489 break;
490 fprintf(stderr,"- waiting for device -\n");
491 adb_sleep_ms(1000);
492 do_cmd(transport, serial, "wait-for-device", 0);
493 }
494
495 read_and_dump(fd);
496 ret = adb_close(fd);
497 if (ret)
498 perror("close");
499
500 return ret;
501}
502
503static int logcat(transport_type transport, char* serial, int argc, char **argv)
504{
505 char buf[4096];
506
507 char *log_tags;
508 char *quoted_log_tags;
509
510 log_tags = getenv("ANDROID_LOG_TAGS");
511 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
512
513 snprintf(buf, sizeof(buf),
514 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
515 quoted_log_tags);
516
517 free(quoted_log_tags);
518
519 argc -= 1;
520 argv += 1;
521 while(argc-- > 0) {
522 char *quoted;
523
524 quoted = dupAndQuote (*argv++);
525
526 strncat(buf, " ", sizeof(buf)-1);
527 strncat(buf, quoted, sizeof(buf)-1);
528 free(quoted);
529 }
530
531 send_shellcommand(transport, serial, buf);
532 return 0;
533}
534
535#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
536static int top_works(const char *top)
537{
538 if (top != NULL && adb_is_absolute_host_path(top)) {
539 char path_buf[PATH_MAX];
540 snprintf(path_buf, sizeof(path_buf),
541 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
542 return access(path_buf, F_OK) == 0;
543 }
544 return 0;
545}
546
547static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
548{
549 strcpy(path_buf, indir);
550 while (1) {
551 if (top_works(path_buf)) {
552 return path_buf;
553 }
554 char *s = adb_dirstop(path_buf);
555 if (s != NULL) {
556 *s = '\0';
557 } else {
558 path_buf[0] = '\0';
559 return NULL;
560 }
561 }
562}
563
564static char *find_top(char path_buf[PATH_MAX])
565{
566 char *top = getenv("ANDROID_BUILD_TOP");
567 if (top != NULL && top[0] != '\0') {
568 if (!top_works(top)) {
569 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
570 return NULL;
571 }
572 } else {
573 top = getenv("TOP");
574 if (top != NULL && top[0] != '\0') {
575 if (!top_works(top)) {
576 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
577 return NULL;
578 }
579 } else {
580 top = NULL;
581 }
582 }
583
584 if (top != NULL) {
585 /* The environment pointed to a top directory that works.
586 */
587 strcpy(path_buf, top);
588 return path_buf;
589 }
590
591 /* The environment didn't help. Walk up the tree from the CWD
592 * to see if we can find the top.
593 */
594 char dir[PATH_MAX];
595 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
596 if (top == NULL) {
597 /* If the CWD isn't under a good-looking top, see if the
598 * executable is.
599 */
Alexey Tarasov31664102009-10-22 02:55:00 +1100600 get_my_path(dir, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800601 top = find_top_from(dir, path_buf);
602 }
603 return top;
604}
605
606/* <hint> may be:
607 * - A simple product name
608 * e.g., "sooner"
609TODO: debug? sooner-debug, sooner:debug?
610 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
611 * e.g., "out/target/product/sooner"
612 * - An absolute path to the PRODUCT_OUT dir
613 * e.g., "/src/device/out/target/product/sooner"
614 *
615 * Given <hint>, try to construct an absolute path to the
616 * ANDROID_PRODUCT_OUT dir.
617 */
618static const char *find_product_out_path(const char *hint)
619{
620 static char path_buf[PATH_MAX];
621
622 if (hint == NULL || hint[0] == '\0') {
623 return NULL;
624 }
625
626 /* If it's already absolute, don't bother doing any work.
627 */
628 if (adb_is_absolute_host_path(hint)) {
629 strcpy(path_buf, hint);
630 return path_buf;
631 }
632
633 /* If there are any slashes in it, assume it's a relative path;
634 * make it absolute.
635 */
636 if (adb_dirstart(hint) != NULL) {
637 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
638 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
639 return NULL;
640 }
641 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
642 fprintf(stderr, "adb: Couldn't assemble path\n");
643 return NULL;
644 }
645 strcat(path_buf, OS_PATH_SEPARATOR_STR);
646 strcat(path_buf, hint);
647 return path_buf;
648 }
649
650 /* It's a string without any slashes. Try to do something with it.
651 *
652 * Try to find the root of the build tree, and build a PRODUCT_OUT
653 * path from there.
654 */
655 char top_buf[PATH_MAX];
656 const char *top = find_top(top_buf);
657 if (top == NULL) {
658 fprintf(stderr, "adb: Couldn't find top of build tree\n");
659 return NULL;
660 }
661//TODO: if we have a way to indicate debug, look in out/debug/target/...
662 snprintf(path_buf, sizeof(path_buf),
663 "%s" OS_PATH_SEPARATOR_STR
664 "out" OS_PATH_SEPARATOR_STR
665 "target" OS_PATH_SEPARATOR_STR
666 "product" OS_PATH_SEPARATOR_STR
667 "%s", top_buf, hint);
668 if (access(path_buf, F_OK) < 0) {
669 fprintf(stderr, "adb: Couldn't find a product dir "
670 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
671 return NULL;
672 }
673 return path_buf;
674}
675
676int adb_commandline(int argc, char **argv)
677{
678 char buf[4096];
679 int no_daemon = 0;
680 int is_daemon = 0;
681 int persist = 0;
682 int r;
683 int quote;
684 transport_type ttype = kTransportAny;
685 char* serial = NULL;
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100686 char* server_port_str = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800687
688 /* If defined, this should be an absolute path to
689 * the directory containing all of the various system images
690 * for a particular product. If not defined, and the adb
691 * command requires this information, then the user must
692 * specify the path using "-p".
693 */
694 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
695 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
696 gProductOutPath = NULL;
697 }
698 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
699
Nick Pelly22048ef2009-05-07 12:48:03 -0700700 serial = getenv("ANDROID_SERIAL");
701
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100702 /* Validate and assign the server port */
703 server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
704 int server_port = DEFAULT_ADB_PORT;
705 if (server_port_str && strlen(server_port_str) > 0) {
706 server_port = (int) strtol(server_port_str, NULL, 0);
707 if (server_port <= 0) {
708 fprintf(stderr,
709 "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
710 server_port_str);
711 return usage();
712 }
713 }
714
715 /* modifiers and flags */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800716 while(argc > 0) {
717 if(!strcmp(argv[0],"nodaemon")) {
718 no_daemon = 1;
719 } else if (!strcmp(argv[0], "fork-server")) {
720 /* this is a special flag used only when the ADB client launches the ADB Server */
721 is_daemon = 1;
722 } else if(!strcmp(argv[0],"persist")) {
723 persist = 1;
724 } else if(!strncmp(argv[0], "-p", 2)) {
725 const char *product = NULL;
726 if (argv[0][2] == '\0') {
727 if (argc < 2) return usage();
728 product = argv[1];
729 argc--;
730 argv++;
731 } else {
732 product = argv[1] + 2;
733 }
734 gProductOutPath = find_product_out_path(product);
735 if (gProductOutPath == NULL) {
736 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
737 product);
738 return usage();
739 }
740 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
741 if (isdigit(argv[0][2])) {
742 serial = argv[0] + 2;
743 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100744 if(argc < 2 || argv[0][2] != '\0') return usage();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800745 serial = argv[1];
746 argc--;
747 argv++;
748 }
749 } else if (!strcmp(argv[0],"-d")) {
750 ttype = kTransportUsb;
751 } else if (!strcmp(argv[0],"-e")) {
752 ttype = kTransportLocal;
753 } else {
754 /* out of recognized modifiers and flags */
755 break;
756 }
757 argc--;
758 argv++;
759 }
760
761 adb_set_transport(ttype, serial);
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100762 adb_set_tcp_specifics(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800763
764 if ((argc > 0) && (!strcmp(argv[0],"server"))) {
765 if (no_daemon || is_daemon) {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100766 r = adb_main(is_daemon, server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800767 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100768 r = launch_server(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800769 }
770 if(r) {
771 fprintf(stderr,"* could not start server *\n");
772 }
773 return r;
774 }
775
776top:
777 if(argc == 0) {
778 return usage();
779 }
780
781 /* adb_connect() commands */
782
783 if(!strcmp(argv[0], "devices")) {
784 char *tmp;
785 snprintf(buf, sizeof buf, "host:%s", argv[0]);
786 tmp = adb_query(buf);
787 if(tmp) {
788 printf("List of devices attached \n");
789 printf("%s\n", tmp);
790 return 0;
791 } else {
792 return 1;
793 }
794 }
795
Mike Lockwood74d7ff82009-10-11 23:04:18 -0400796 if(!strcmp(argv[0], "connect") || !strcmp(argv[0], "disconnect")) {
Mike Lockwood2f38b692009-08-24 15:58:40 -0700797 char *tmp;
798 if (argc != 2) {
Mike Lockwood74d7ff82009-10-11 23:04:18 -0400799 fprintf(stderr, "Usage: adb %s <host>:<port>\n", argv[0]);
Mike Lockwood2f38b692009-08-24 15:58:40 -0700800 return 1;
801 }
802 snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
803 tmp = adb_query(buf);
804 if(tmp) {
805 printf("%s\n", tmp);
806 return 0;
807 } else {
808 return 1;
809 }
810 }
811
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800812 if (!strcmp(argv[0], "emu")) {
813 return adb_send_emulator_command(argc, argv);
814 }
815
816 if(!strcmp(argv[0], "shell")) {
817 int r;
818 int fd;
819
820 if(argc < 2) {
821 return interactive_shell();
822 }
823
824 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
825 argc -= 2;
826 argv += 2;
827 while(argc-- > 0) {
828 strcat(buf, " ");
829
830 /* quote empty strings and strings with spaces */
831 quote = (**argv == 0 || strchr(*argv, ' '));
832 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100833 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800834 strcat(buf, *argv++);
835 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100836 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 }
838
839 for(;;) {
840 fd = adb_connect(buf);
841 if(fd >= 0) {
842 read_and_dump(fd);
843 adb_close(fd);
844 r = 0;
845 } else {
846 fprintf(stderr,"error: %s\n", adb_error());
847 r = -1;
848 }
849
850 if(persist) {
851 fprintf(stderr,"\n- waiting for device -\n");
852 adb_sleep_ms(1000);
853 do_cmd(ttype, serial, "wait-for-device", 0);
854 } else {
855 return r;
856 }
857 }
858 }
859
860 if(!strcmp(argv[0], "kill-server")) {
861 int fd;
862 fd = _adb_connect("host:kill");
863 if(fd == -1) {
864 fprintf(stderr,"* server not running *\n");
865 return 1;
866 }
867 return 0;
868 }
869
Mike Lockwood2f38b692009-08-24 15:58:40 -0700870 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guya48d43a2009-12-14 14:42:17 -0800871 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwood2f38b692009-08-24 15:58:40 -0700872 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Xavier Ducrohetf71c7112009-08-25 20:16:14 -0700873 || !strcmp(argv[0], "root")) {
Mike Lockwood2f38b692009-08-24 15:58:40 -0700874 char command[100];
Romain Guya48d43a2009-12-14 14:42:17 -0800875 if (!strcmp(argv[0], "reboot-bootloader"))
876 snprintf(command, sizeof(command), "reboot:bootloader");
877 else if (argc > 1)
Mike Lockwood2f38b692009-08-24 15:58:40 -0700878 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwood5f4b0512009-08-04 20:37:51 -0400879 else
Mike Lockwood2f38b692009-08-24 15:58:40 -0700880 snprintf(command, sizeof(command), "%s:", argv[0]);
881 int fd = adb_connect(command);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700882 if(fd >= 0) {
883 read_and_dump(fd);
884 adb_close(fd);
885 return 0;
886 }
887 fprintf(stderr,"error: %s\n", adb_error());
888 return 1;
889 }
890
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800891 if(!strcmp(argv[0], "bugreport")) {
Dan Egnor7eced2b2010-01-20 13:50:36 -0800892 if (argc != 1) return usage();
893 do_cmd(ttype, serial, "shell", "bugreport", 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800894 return 0;
895 }
896
897 /* adb_command() wrapper commands */
898
899 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
900 char* service = argv[0];
901 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
902 if (ttype == kTransportUsb) {
903 service = "wait-for-usb";
904 } else if (ttype == kTransportLocal) {
905 service = "wait-for-local";
906 } else {
907 service = "wait-for-any";
908 }
909 }
910
911 format_host_command(buf, sizeof buf, service, ttype, serial);
912
913 if (adb_command(buf)) {
914 D("failure: %s *\n",adb_error());
915 fprintf(stderr,"error: %s\n", adb_error());
916 return 1;
917 }
918
919 /* Allow a command to be run after wait-for-device,
920 * e.g. 'adb wait-for-device shell'.
921 */
922 if(argc > 1) {
923 argc--;
924 argv++;
925 goto top;
926 }
927 return 0;
928 }
929
930 if(!strcmp(argv[0], "forward")) {
931 if(argc != 3) return usage();
932 if (serial) {
Mike Lockwooda59387b2009-11-28 12:46:13 -0500933 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
934 } else if (ttype == kTransportUsb) {
935 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
936 } else if (ttype == kTransportLocal) {
937 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800938 } else {
Mike Lockwooda59387b2009-11-28 12:46:13 -0500939 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800940 }
941 if(adb_command(buf)) {
942 fprintf(stderr,"error: %s\n", adb_error());
943 return 1;
944 }
945 return 0;
946 }
947
948 /* do_sync_*() commands */
949
950 if(!strcmp(argv[0], "ls")) {
951 if(argc != 2) return usage();
952 return do_sync_ls(argv[1]);
953 }
954
955 if(!strcmp(argv[0], "push")) {
956 if(argc != 3) return usage();
957 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
958 }
959
960 if(!strcmp(argv[0], "pull")) {
Joe Onorato8071a4b2010-01-05 13:42:25 -0800961 if (argc == 2) {
962 return do_sync_pull(argv[1], ".");
963 } else if (argc == 3) {
964 return do_sync_pull(argv[1], argv[2]);
965 } else {
966 return usage();
967 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800968 }
969
970 if(!strcmp(argv[0], "install")) {
971 if (argc < 2) return usage();
972 return install_app(ttype, serial, argc, argv);
973 }
974
975 if(!strcmp(argv[0], "uninstall")) {
976 if (argc < 2) return usage();
977 return uninstall_app(ttype, serial, argc, argv);
978 }
979
980 if(!strcmp(argv[0], "sync")) {
981 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnam705c9442010-02-22 08:36:49 -0600982 int listonly = 0;
983
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800984 int ret;
985 if(argc < 2) {
986 /* No local path was specified. */
987 srcarg = NULL;
Anthony Newnam705c9442010-02-22 08:36:49 -0600988 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
989 listonly = 1;
990 if (argc == 3) {
991 srcarg = argv[2];
992 } else {
993 srcarg = NULL;
994 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800995 } else if(argc == 2) {
996 /* A local path or "android"/"data" arg was specified. */
997 srcarg = argv[1];
998 } else {
999 return usage();
1000 }
1001 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1002 if(ret != 0) return usage();
1003
1004 if(android_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001005 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001006 if(ret == 0 && data_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001007 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001008
1009 free(android_srcpath);
1010 free(data_srcpath);
1011 return ret;
1012 }
1013
1014 /* passthrough commands */
1015
1016 if(!strcmp(argv[0],"get-state") ||
1017 !strcmp(argv[0],"get-serialno"))
1018 {
1019 char *tmp;
1020
1021 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1022 tmp = adb_query(buf);
1023 if(tmp) {
1024 printf("%s\n", tmp);
1025 return 0;
1026 } else {
1027 return 1;
1028 }
1029 }
1030
1031 /* other commands */
1032
1033 if(!strcmp(argv[0],"status-window")) {
1034 status_window(ttype, serial);
1035 return 0;
1036 }
1037
1038 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1039 return logcat(ttype, serial, argc, argv);
1040 }
1041
1042 if(!strcmp(argv[0],"ppp")) {
1043 return ppp(argc, argv);
1044 }
1045
1046 if (!strcmp(argv[0], "start-server")) {
1047 return adb_connect("host:start-server");
1048 }
1049
1050 if (!strcmp(argv[0], "jdwp")) {
1051 int fd = adb_connect("jdwp");
1052 if (fd >= 0) {
1053 read_and_dump(fd);
1054 adb_close(fd);
1055 return 0;
1056 } else {
1057 fprintf(stderr, "error: %s\n", adb_error());
1058 return -1;
1059 }
1060 }
1061
1062 /* "adb /?" is a common idiom under Windows */
1063 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1064 help();
1065 return 0;
1066 }
1067
1068 if(!strcmp(argv[0], "version")) {
1069 version(stdout);
1070 return 0;
1071 }
1072
1073 usage();
1074 return 1;
1075}
1076
1077static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1078{
1079 char *argv[16];
1080 int argc;
1081 va_list ap;
1082
1083 va_start(ap, cmd);
1084 argc = 0;
1085
1086 if (serial) {
1087 argv[argc++] = "-s";
1088 argv[argc++] = serial;
1089 } else if (ttype == kTransportUsb) {
1090 argv[argc++] = "-d";
1091 } else if (ttype == kTransportLocal) {
1092 argv[argc++] = "-e";
1093 }
1094
1095 argv[argc++] = cmd;
1096 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1097 va_end(ap);
1098
1099#if 0
1100 int n;
1101 fprintf(stderr,"argc = %d\n",argc);
1102 for(n = 0; n < argc; n++) {
1103 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1104 }
1105#endif
1106
1107 return adb_commandline(argc, argv);
1108}
1109
1110int find_sync_dirs(const char *srcarg,
1111 char **android_srcdir_out, char **data_srcdir_out)
1112{
1113 char *android_srcdir, *data_srcdir;
1114
1115 if(srcarg == NULL) {
1116 android_srcdir = product_file("system");
1117 data_srcdir = product_file("data");
1118 } else {
1119 /* srcarg may be "data", "system" or NULL.
1120 * if srcarg is NULL, then both data and system are synced
1121 */
1122 if(strcmp(srcarg, "system") == 0) {
1123 android_srcdir = product_file("system");
1124 data_srcdir = NULL;
1125 } else if(strcmp(srcarg, "data") == 0) {
1126 android_srcdir = NULL;
1127 data_srcdir = product_file("data");
1128 } else {
1129 /* It's not "system" or "data".
1130 */
1131 return 1;
1132 }
1133 }
1134
1135 if(android_srcdir_out != NULL)
1136 *android_srcdir_out = android_srcdir;
1137 else
1138 free(android_srcdir);
1139
1140 if(data_srcdir_out != NULL)
1141 *data_srcdir_out = data_srcdir;
1142 else
1143 free(data_srcdir);
1144
1145 return 0;
1146}
1147
1148static int pm_command(transport_type transport, char* serial,
1149 int argc, char** argv)
1150{
1151 char buf[4096];
1152
1153 snprintf(buf, sizeof(buf), "shell:pm");
1154
1155 while(argc-- > 0) {
1156 char *quoted;
1157
1158 quoted = dupAndQuote(*argv++);
1159
1160 strncat(buf, " ", sizeof(buf)-1);
1161 strncat(buf, quoted, sizeof(buf)-1);
1162 free(quoted);
1163 }
1164
1165 send_shellcommand(transport, serial, buf);
1166 return 0;
1167}
1168
1169int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1170{
1171 /* if the user choose the -k option, we refuse to do it until devices are
1172 out with the option to uninstall the remaining data somehow (adb/ui) */
1173 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1174 {
1175 printf(
1176 "The -k option uninstalls the application while retaining the data/cache.\n"
1177 "At the moment, there is no way to remove the remaining data.\n"
1178 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1179 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1180 return -1;
1181 }
1182
1183 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1184 return pm_command(transport, serial, argc, argv);
1185}
1186
1187static int delete_file(transport_type transport, char* serial, char* filename)
1188{
1189 char buf[4096];
1190 char* quoted;
1191
1192 snprintf(buf, sizeof(buf), "shell:rm ");
1193 quoted = dupAndQuote(filename);
1194 strncat(buf, quoted, sizeof(buf)-1);
1195 free(quoted);
1196
1197 send_shellcommand(transport, serial, buf);
1198 return 0;
1199}
1200
1201int install_app(transport_type transport, char* serial, int argc, char** argv)
1202{
1203 struct stat st;
1204 int err;
1205 const char *const WHERE = "/data/local/tmp/%s";
1206 char to[PATH_MAX];
1207 char* filename = argv[argc - 1];
1208 const char* p;
1209
1210 p = adb_dirstop(filename);
1211 if (p) {
1212 p++;
1213 snprintf(to, sizeof to, WHERE, p);
1214 } else {
1215 snprintf(to, sizeof to, WHERE, filename);
1216 }
1217 if (p[0] == '\0') {
1218 }
1219
1220 err = stat(filename, &st);
1221 if (err != 0) {
1222 fprintf(stderr, "can't find '%s' to install\n", filename);
1223 return 1;
1224 }
1225 if (!S_ISREG(st.st_mode)) {
1226 fprintf(stderr, "can't install '%s' because it's not a file\n",
1227 filename);
1228 return 1;
1229 }
1230
1231 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1232 /* file in place; tell the Package Manager to install it */
1233 argv[argc - 1] = to; /* destination name, not source location */
1234 pm_command(transport, serial, argc, argv);
1235 delete_file(transport, serial, to);
1236 }
1237
1238 return err;
1239}