blob: 5f4220369fb36c9c0988ce5896e3c4c26631a8df [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
40#ifdef SH_HISTORY
41#include "shlist.h"
42#include "history.h"
43#endif
44
45enum {
46 IGNORE_DATA,
47 WIPE_DATA,
48 FLASH_DATA
49};
50
51static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
52
Alexey Tarasov31664102009-10-22 02:55:00 +110053void get_my_path(char *s, size_t maxLen);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080054int find_sync_dirs(const char *srcarg,
55 char **android_srcdir_out, char **data_srcdir_out);
56int install_app(transport_type transport, char* serial, int argc, char** argv);
57int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
58
59static const char *gProductOutPath = NULL;
60
61static char *product_file(const char *extra)
62{
63 int n;
64 char *x;
65
66 if (gProductOutPath == NULL) {
67 fprintf(stderr, "adb: Product directory not specified; "
68 "use -p or define ANDROID_PRODUCT_OUT\n");
69 exit(1);
70 }
71
72 n = strlen(gProductOutPath) + strlen(extra) + 2;
73 x = malloc(n);
74 if (x == 0) {
75 fprintf(stderr, "adb: Out of memory (product_file())\n");
76 exit(1);
77 }
78
79 snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
80 return x;
81}
82
83void version(FILE * out) {
84 fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
85 ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
86}
87
88void help()
89{
90 version(stderr);
91
92 fprintf(stderr,
93 "\n"
94 " -d - directs command to the only connected USB device\n"
95 " returns an error if more than one USB device is present.\n"
96 " -e - directs command to the only running emulator.\n"
97 " returns an error if more than one emulator is running.\n"
98 " -s <serial number> - directs command to the USB device or emulator with\n"
Nick Pellydb449262009-05-07 12:48:03 -070099 " the given serial number. Overrides ANDROID_SERIAL\n"
Elliott Hughes31dbed72009-10-07 15:38:53 -0700100 " environment variable.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800101 " -p <product name or path> - simple product name like 'sooner', or\n"
102 " a relative/absolute path to a product\n"
103 " out directory like 'out/target/product/sooner'.\n"
104 " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
105 " environment variable is used, which must\n"
106 " be an absolute path.\n"
107 " devices - list all connected devices\n"
Brian Carlstrom6fcc8012010-03-01 22:54:12 -0800108 " connect <host>:<port> - connect to a device via TCP/IP\n"
109 " disconnect <host>:<port> - disconnect from a TCP/IP device\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110 "\n"
111 "device commands:\n"
112 " adb push <local> <remote> - copy file/dir to device\n"
Joe Onorato00c0eea2010-01-05 13:42:25 -0800113 " adb pull <remote> [<local>] - copy file/dir from device\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800114 " adb sync [ <directory> ] - copy host->device only if changed\n"
Anthony Newnam705c9442010-02-22 08:36:49 -0600115 " (-l means list but don't copy)\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800116 " (see 'adb help all')\n"
117 " adb shell - run remote shell interactively\n"
118 " adb shell <command> - run remote shell command\n"
119 " adb emu <command> - run emulator console command\n"
120 " adb logcat [ <filter-spec> ] - View device log\n"
121 " adb forward <local> <remote> - forward socket connections\n"
122 " forward specs are one of: \n"
123 " tcp:<port>\n"
124 " localabstract:<unix domain socket name>\n"
125 " localreserved:<unix domain socket name>\n"
126 " localfilesystem:<unix domain socket name>\n"
127 " dev:<character device name>\n"
128 " jdwp:<process pid> (remote only)\n"
129 " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
Mike Lockwood0ef3fd02010-02-19 17:53:27 -0500130 " adb install [-l] [-r] [-s] <file> - push this package file to the device and install it\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 " ('-l' means forward-lock the app)\n"
132 " ('-r' means reinstall the app, keeping its data)\n"
Mike Lockwood0ef3fd02010-02-19 17:53:27 -0500133 " ('-s' means install on SD card instead of internal storage)\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134 " adb uninstall [-k] <package> - remove this app package from the device\n"
135 " ('-k' means keep the data and cache directories)\n"
136 " adb bugreport - return all information from the device\n"
137 " that should be included in a bug report.\n"
138 "\n"
139 " adb help - show this help message\n"
140 " adb version - show version num\n"
141 "\n"
142 "DATAOPTS:\n"
143 " (no option) - don't touch the data partition\n"
144 " -w - wipe the data partition\n"
145 " -d - flash the data partition\n"
146 "\n"
147 "scripting:\n"
148 " adb wait-for-device - block until device is online\n"
149 " adb start-server - ensure that there is a server running\n"
150 " adb kill-server - kill the server if it is running\n"
151 " adb get-state - prints: offline | bootloader | device\n"
152 " adb get-serialno - prints: <serial-number>\n"
153 " adb status-window - continuously print device status for a specified device\n"
154 " adb remount - remounts the /system partition on the device read-write\n"
Mike Lockwoodee156622009-08-04 20:37:51 -0400155 " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
Romain Guy311add42009-12-14 14:42:17 -0800156 " adb reboot-bootloader - reboots the device into the bootloader\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700157 " adb root - restarts the adbd daemon with root permissions\n"
Romain Guy311add42009-12-14 14:42:17 -0800158 " adb usb - restarts the adbd daemon listening on USB\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700159 " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800160 "\n"
161 "networking:\n"
162 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
Kenny Rootc9891992009-06-08 14:40:30 -0500163 " Note: you should not automatically start a PPP connection.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800164 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
165 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
166 "\n"
167 "adb sync notes: adb sync [ <directory> ]\n"
168 " <localdir> can be interpreted in several ways:\n"
169 "\n"
170 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
171 "\n"
172 " - If it is \"system\" or \"data\", only the corresponding partition\n"
173 " is updated.\n"
174 );
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 Lockwooddd6b36e2009-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
230#ifdef SH_HISTORY
231int shItemCmp( void *val, void *idata )
232{
233 return( (strcmp( val, idata ) == 0) );
234}
235#endif
236
237static void *stdin_read_thread(void *x)
238{
239 int fd, fdi;
240 unsigned char buf[1024];
241#ifdef SH_HISTORY
242 unsigned char realbuf[1024], *buf_ptr;
243 SHLIST history;
244 SHLIST *item = &history;
245 int cmdlen = 0, ins_flag = 0;
246#endif
247 int r, n;
248 int state = 0;
249
250 int *fds = (int*) x;
251 fd = fds[0];
252 fdi = fds[1];
253 free(fds);
254
255#ifdef SH_HISTORY
256 shListInitList( &history );
257#endif
258 for(;;) {
259 /* fdi is really the client's stdin, so use read, not adb_read here */
260 r = unix_read(fdi, buf, 1024);
261 if(r == 0) break;
262 if(r < 0) {
263 if(errno == EINTR) continue;
264 break;
265 }
266#ifdef SH_HISTORY
267 if( (r == 3) && /* Arrow processing */
268 (memcmp( (void *)buf, SH_ARROW_ANY, 2 ) == 0) ) {
269 switch( buf[2] ) {
270 case SH_ARROW_UP:
271 item = shListGetNextItem( &history, item );
272 break;
273 case SH_ARROW_DOWN:
274 item = shListGetPrevItem( &history, item );
275 break;
276 default:
277 item = NULL;
278 break;
279 }
280 memset( buf, SH_DEL_CHAR, cmdlen );
281 if( item != NULL ) {
282 n = snprintf( (char *)(&buf[cmdlen]), sizeof buf - cmdlen, "%s", (char *)(item->data) );
283 memcpy( realbuf, item->data, n );
284 }
285 else { /* Clean buffer */
286 item = &history;
287 n = 0;
288 }
289 r = n + cmdlen;
290 cmdlen = n;
291 ins_flag = 0;
292 if( r == 0 )
293 continue;
294 }
295 else {
296#endif
297 for(n = 0; n < r; n++){
298 switch(buf[n]) {
299 case '\n':
300#ifdef SH_HISTORY
301 if( ins_flag && (SH_BLANK_CHAR <= realbuf[0]) ) {
302 buf_ptr = malloc(cmdlen + 1);
303 if( buf_ptr != NULL ) {
304 memcpy( buf_ptr, realbuf, cmdlen );
305 buf_ptr[cmdlen] = '\0';
306 if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
307 shListInsFirstItem( &history, (void *)buf_ptr );
308 item = &history;
309 }
310 }
311 }
312 cmdlen = 0;
313 ins_flag = 0;
314#endif
315 state = 1;
316 break;
317 case '\r':
318 state = 1;
319 break;
320 case '~':
321 if(state == 1) state++;
322 break;
323 case '.':
324 if(state == 2) {
325 fprintf(stderr,"\n* disconnect *\n");
326 #ifdef HAVE_TERMIO_H
327 stdin_raw_restore(fdi);
328 #endif
329 exit(0);
330 }
331 default:
332#ifdef SH_HISTORY
333 if( buf[n] == SH_DEL_CHAR ) {
334 if( cmdlen > 0 )
335 cmdlen--;
336 }
337 else {
338 realbuf[cmdlen] = buf[n];
339 cmdlen++;
340 }
341 ins_flag = 1;
342#endif
343 state = 0;
344 }
345 }
346#ifdef SH_HISTORY
347 }
348#endif
349 r = adb_write(fd, buf, r);
350 if(r <= 0) {
351 break;
352 }
353 }
354#ifdef SH_HISTORY
355 shListDelAllItems( &history, (shListFree)free );
356#endif
357 return 0;
358}
359
360int interactive_shell(void)
361{
362 adb_thread_t thr;
363 int fdi, fd;
364 int *fds;
365
366 fd = adb_connect("shell:");
367 if(fd < 0) {
368 fprintf(stderr,"error: %s\n", adb_error());
369 return 1;
370 }
371 fdi = 0; //dup(0);
372
373 fds = malloc(sizeof(int) * 2);
374 fds[0] = fd;
375 fds[1] = fdi;
376
377#ifdef HAVE_TERMIO_H
378 stdin_raw_init(fdi);
379#endif
380 adb_thread_create(&thr, stdin_read_thread, fds);
381 read_and_dump(fd);
382#ifdef HAVE_TERMIO_H
383 stdin_raw_restore(fdi);
384#endif
385 return 0;
386}
387
388
389static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
390{
391 if (serial) {
392 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
393 } else {
394 const char* prefix = "host";
395 if (ttype == kTransportUsb)
396 prefix = "host-usb";
397 else if (ttype == kTransportLocal)
398 prefix = "host-local";
399
400 snprintf(buffer, buflen, "%s:%s", prefix, command);
401 }
402}
403
404static void status_window(transport_type ttype, const char* serial)
405{
406 char command[4096];
407 char *state = 0;
408 char *laststate = 0;
409
410 /* silence stderr */
411#ifdef _WIN32
412 /* XXX: TODO */
413#else
414 int fd;
415 fd = unix_open("/dev/null", O_WRONLY);
416 dup2(fd, 2);
417 adb_close(fd);
418#endif
419
420 format_host_command(command, sizeof command, "get-state", ttype, serial);
421
422 for(;;) {
423 adb_sleep_ms(250);
424
425 if(state) {
426 free(state);
427 state = 0;
428 }
429
430 state = adb_query(command);
431
432 if(state) {
433 if(laststate && !strcmp(state,laststate)){
434 continue;
435 } else {
436 if(laststate) free(laststate);
437 laststate = strdup(state);
438 }
439 }
440
441 printf("%c[2J%c[2H", 27, 27);
442 printf("Android Debug Bridge\n");
443 printf("State: %s\n", state ? state : "offline");
444 fflush(stdout);
445 }
446}
447
448/** duplicate string and quote all \ " ( ) chars + space character. */
449static char *
450dupAndQuote(const char *s)
451{
452 const char *ts;
453 size_t alloc_len;
454 char *ret;
455 char *dest;
456
457 ts = s;
458
459 alloc_len = 0;
460
461 for( ;*ts != '\0'; ts++) {
462 alloc_len++;
463 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
464 alloc_len++;
465 }
466 }
467
468 ret = (char *)malloc(alloc_len + 1);
469
470 ts = s;
471 dest = ret;
472
473 for ( ;*ts != '\0'; ts++) {
474 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
475 *dest++ = '\\';
476 }
477
478 *dest++ = *ts;
479 }
480
481 *dest++ = '\0';
482
483 return ret;
484}
485
486/**
487 * Run ppp in "notty" mode against a resource listed as the first parameter
488 * eg:
489 *
490 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
491 *
492 */
493int ppp(int argc, char **argv)
494{
495#ifdef HAVE_WIN32_PROC
496 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
497 return -1;
498#else
499 char *adb_service_name;
500 pid_t pid;
501 int fd;
502
503 if (argc < 2) {
504 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
505 argv[0]);
506
507 return 1;
508 }
509
510 adb_service_name = argv[1];
511
512 fd = adb_connect(adb_service_name);
513
514 if(fd < 0) {
515 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
516 adb_service_name, adb_error());
517 return 1;
518 }
519
520 pid = fork();
521
522 if (pid < 0) {
523 perror("from fork()");
524 return 1;
525 } else if (pid == 0) {
526 int err;
527 int i;
528 const char **ppp_args;
529
530 // copy args
531 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
532 ppp_args[0] = "pppd";
533 for (i = 2 ; i < argc ; i++) {
534 //argv[2] and beyond become ppp_args[1] and beyond
535 ppp_args[i - 1] = argv[i];
536 }
537 ppp_args[i-1] = NULL;
538
539 // child side
540
541 dup2(fd, STDIN_FILENO);
542 dup2(fd, STDOUT_FILENO);
543 adb_close(STDERR_FILENO);
544 adb_close(fd);
545
546 err = execvp("pppd", (char * const *)ppp_args);
547
548 if (err < 0) {
549 perror("execing pppd");
550 }
551 exit(-1);
552 } else {
553 // parent side
554
555 adb_close(fd);
556 return 0;
557 }
558#endif /* !HAVE_WIN32_PROC */
559}
560
561static int send_shellcommand(transport_type transport, char* serial, char* buf)
562{
563 int fd, ret;
564
565 for(;;) {
566 fd = adb_connect(buf);
567 if(fd >= 0)
568 break;
569 fprintf(stderr,"- waiting for device -\n");
570 adb_sleep_ms(1000);
571 do_cmd(transport, serial, "wait-for-device", 0);
572 }
573
574 read_and_dump(fd);
575 ret = adb_close(fd);
576 if (ret)
577 perror("close");
578
579 return ret;
580}
581
582static int logcat(transport_type transport, char* serial, int argc, char **argv)
583{
584 char buf[4096];
585
586 char *log_tags;
587 char *quoted_log_tags;
588
589 log_tags = getenv("ANDROID_LOG_TAGS");
590 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
591
592 snprintf(buf, sizeof(buf),
593 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
594 quoted_log_tags);
595
596 free(quoted_log_tags);
597
598 argc -= 1;
599 argv += 1;
600 while(argc-- > 0) {
601 char *quoted;
602
603 quoted = dupAndQuote (*argv++);
604
605 strncat(buf, " ", sizeof(buf)-1);
606 strncat(buf, quoted, sizeof(buf)-1);
607 free(quoted);
608 }
609
610 send_shellcommand(transport, serial, buf);
611 return 0;
612}
613
614#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
615static int top_works(const char *top)
616{
617 if (top != NULL && adb_is_absolute_host_path(top)) {
618 char path_buf[PATH_MAX];
619 snprintf(path_buf, sizeof(path_buf),
620 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
621 return access(path_buf, F_OK) == 0;
622 }
623 return 0;
624}
625
626static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
627{
628 strcpy(path_buf, indir);
629 while (1) {
630 if (top_works(path_buf)) {
631 return path_buf;
632 }
633 char *s = adb_dirstop(path_buf);
634 if (s != NULL) {
635 *s = '\0';
636 } else {
637 path_buf[0] = '\0';
638 return NULL;
639 }
640 }
641}
642
643static char *find_top(char path_buf[PATH_MAX])
644{
645 char *top = getenv("ANDROID_BUILD_TOP");
646 if (top != NULL && top[0] != '\0') {
647 if (!top_works(top)) {
648 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
649 return NULL;
650 }
651 } else {
652 top = getenv("TOP");
653 if (top != NULL && top[0] != '\0') {
654 if (!top_works(top)) {
655 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
656 return NULL;
657 }
658 } else {
659 top = NULL;
660 }
661 }
662
663 if (top != NULL) {
664 /* The environment pointed to a top directory that works.
665 */
666 strcpy(path_buf, top);
667 return path_buf;
668 }
669
670 /* The environment didn't help. Walk up the tree from the CWD
671 * to see if we can find the top.
672 */
673 char dir[PATH_MAX];
674 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
675 if (top == NULL) {
676 /* If the CWD isn't under a good-looking top, see if the
677 * executable is.
678 */
Alexey Tarasov31664102009-10-22 02:55:00 +1100679 get_my_path(dir, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800680 top = find_top_from(dir, path_buf);
681 }
682 return top;
683}
684
685/* <hint> may be:
686 * - A simple product name
687 * e.g., "sooner"
688TODO: debug? sooner-debug, sooner:debug?
689 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
690 * e.g., "out/target/product/sooner"
691 * - An absolute path to the PRODUCT_OUT dir
692 * e.g., "/src/device/out/target/product/sooner"
693 *
694 * Given <hint>, try to construct an absolute path to the
695 * ANDROID_PRODUCT_OUT dir.
696 */
697static const char *find_product_out_path(const char *hint)
698{
699 static char path_buf[PATH_MAX];
700
701 if (hint == NULL || hint[0] == '\0') {
702 return NULL;
703 }
704
705 /* If it's already absolute, don't bother doing any work.
706 */
707 if (adb_is_absolute_host_path(hint)) {
708 strcpy(path_buf, hint);
709 return path_buf;
710 }
711
712 /* If there are any slashes in it, assume it's a relative path;
713 * make it absolute.
714 */
715 if (adb_dirstart(hint) != NULL) {
716 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
717 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
718 return NULL;
719 }
720 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
721 fprintf(stderr, "adb: Couldn't assemble path\n");
722 return NULL;
723 }
724 strcat(path_buf, OS_PATH_SEPARATOR_STR);
725 strcat(path_buf, hint);
726 return path_buf;
727 }
728
729 /* It's a string without any slashes. Try to do something with it.
730 *
731 * Try to find the root of the build tree, and build a PRODUCT_OUT
732 * path from there.
733 */
734 char top_buf[PATH_MAX];
735 const char *top = find_top(top_buf);
736 if (top == NULL) {
737 fprintf(stderr, "adb: Couldn't find top of build tree\n");
738 return NULL;
739 }
740//TODO: if we have a way to indicate debug, look in out/debug/target/...
741 snprintf(path_buf, sizeof(path_buf),
742 "%s" OS_PATH_SEPARATOR_STR
743 "out" OS_PATH_SEPARATOR_STR
744 "target" OS_PATH_SEPARATOR_STR
745 "product" OS_PATH_SEPARATOR_STR
746 "%s", top_buf, hint);
747 if (access(path_buf, F_OK) < 0) {
748 fprintf(stderr, "adb: Couldn't find a product dir "
749 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
750 return NULL;
751 }
752 return path_buf;
753}
754
755int adb_commandline(int argc, char **argv)
756{
757 char buf[4096];
758 int no_daemon = 0;
759 int is_daemon = 0;
760 int persist = 0;
761 int r;
762 int quote;
763 transport_type ttype = kTransportAny;
764 char* serial = NULL;
765
766 /* If defined, this should be an absolute path to
767 * the directory containing all of the various system images
768 * for a particular product. If not defined, and the adb
769 * command requires this information, then the user must
770 * specify the path using "-p".
771 */
772 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
773 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
774 gProductOutPath = NULL;
775 }
776 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
777
Nick Pellydb449262009-05-07 12:48:03 -0700778 serial = getenv("ANDROID_SERIAL");
779
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780 /* modifiers and flags */
781 while(argc > 0) {
782 if(!strcmp(argv[0],"nodaemon")) {
783 no_daemon = 1;
784 } else if (!strcmp(argv[0], "fork-server")) {
785 /* this is a special flag used only when the ADB client launches the ADB Server */
786 is_daemon = 1;
787 } else if(!strcmp(argv[0],"persist")) {
788 persist = 1;
789 } else if(!strncmp(argv[0], "-p", 2)) {
790 const char *product = NULL;
791 if (argv[0][2] == '\0') {
792 if (argc < 2) return usage();
793 product = argv[1];
794 argc--;
795 argv++;
796 } else {
797 product = argv[1] + 2;
798 }
799 gProductOutPath = find_product_out_path(product);
800 if (gProductOutPath == NULL) {
801 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
802 product);
803 return usage();
804 }
805 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
806 if (isdigit(argv[0][2])) {
807 serial = argv[0] + 2;
808 } else {
809 if(argc < 2) return usage();
810 serial = argv[1];
811 argc--;
812 argv++;
813 }
814 } else if (!strcmp(argv[0],"-d")) {
815 ttype = kTransportUsb;
816 } else if (!strcmp(argv[0],"-e")) {
817 ttype = kTransportLocal;
818 } else {
819 /* out of recognized modifiers and flags */
820 break;
821 }
822 argc--;
823 argv++;
824 }
825
826 adb_set_transport(ttype, serial);
827
828 if ((argc > 0) && (!strcmp(argv[0],"server"))) {
829 if (no_daemon || is_daemon) {
830 r = adb_main(is_daemon);
831 } else {
832 r = launch_server();
833 }
834 if(r) {
835 fprintf(stderr,"* could not start server *\n");
836 }
837 return r;
838 }
839
840top:
841 if(argc == 0) {
842 return usage();
843 }
844
845 /* adb_connect() commands */
846
847 if(!strcmp(argv[0], "devices")) {
848 char *tmp;
849 snprintf(buf, sizeof buf, "host:%s", argv[0]);
850 tmp = adb_query(buf);
851 if(tmp) {
852 printf("List of devices attached \n");
853 printf("%s\n", tmp);
854 return 0;
855 } else {
856 return 1;
857 }
858 }
859
Mike Lockwood8cf0d592009-10-11 23:04:18 -0400860 if(!strcmp(argv[0], "connect") || !strcmp(argv[0], "disconnect")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700861 char *tmp;
862 if (argc != 2) {
Mike Lockwood8cf0d592009-10-11 23:04:18 -0400863 fprintf(stderr, "Usage: adb %s <host>:<port>\n", argv[0]);
Mike Lockwoodff196702009-08-24 15:58:40 -0700864 return 1;
865 }
866 snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
867 tmp = adb_query(buf);
868 if(tmp) {
869 printf("%s\n", tmp);
870 return 0;
871 } else {
872 return 1;
873 }
874 }
875
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800876 if (!strcmp(argv[0], "emu")) {
877 return adb_send_emulator_command(argc, argv);
878 }
879
880 if(!strcmp(argv[0], "shell")) {
881 int r;
882 int fd;
883
884 if(argc < 2) {
885 return interactive_shell();
886 }
887
888 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
889 argc -= 2;
890 argv += 2;
891 while(argc-- > 0) {
892 strcat(buf, " ");
893
894 /* quote empty strings and strings with spaces */
895 quote = (**argv == 0 || strchr(*argv, ' '));
896 if (quote)
897 strcat(buf, "\"");
898 strcat(buf, *argv++);
899 if (quote)
900 strcat(buf, "\"");
901 }
902
903 for(;;) {
904 fd = adb_connect(buf);
905 if(fd >= 0) {
906 read_and_dump(fd);
907 adb_close(fd);
908 r = 0;
909 } else {
910 fprintf(stderr,"error: %s\n", adb_error());
911 r = -1;
912 }
913
914 if(persist) {
915 fprintf(stderr,"\n- waiting for device -\n");
916 adb_sleep_ms(1000);
917 do_cmd(ttype, serial, "wait-for-device", 0);
918 } else {
919 return r;
920 }
921 }
922 }
923
924 if(!strcmp(argv[0], "kill-server")) {
925 int fd;
926 fd = _adb_connect("host:kill");
927 if(fd == -1) {
928 fprintf(stderr,"* server not running *\n");
929 return 1;
930 }
931 return 0;
932 }
933
Mike Lockwoodff196702009-08-24 15:58:40 -0700934 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guy311add42009-12-14 14:42:17 -0800935 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwoodff196702009-08-24 15:58:40 -0700936 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400937 || !strcmp(argv[0], "root")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700938 char command[100];
Romain Guy311add42009-12-14 14:42:17 -0800939 if (!strcmp(argv[0], "reboot-bootloader"))
940 snprintf(command, sizeof(command), "reboot:bootloader");
941 else if (argc > 1)
Mike Lockwoodff196702009-08-24 15:58:40 -0700942 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwoodee156622009-08-04 20:37:51 -0400943 else
Mike Lockwoodff196702009-08-24 15:58:40 -0700944 snprintf(command, sizeof(command), "%s:", argv[0]);
945 int fd = adb_connect(command);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700946 if(fd >= 0) {
947 read_and_dump(fd);
948 adb_close(fd);
949 return 0;
950 }
951 fprintf(stderr,"error: %s\n", adb_error());
952 return 1;
953 }
954
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400955 if(!strcmp(argv[0], "bugreport")) {
Dan Egnorc130ea72010-01-20 13:50:36 -0800956 if (argc != 1) return usage();
957 do_cmd(ttype, serial, "shell", "bugreport", 0);
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400958 return 0;
959 }
960
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800961 /* adb_command() wrapper commands */
962
963 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
964 char* service = argv[0];
965 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
966 if (ttype == kTransportUsb) {
967 service = "wait-for-usb";
968 } else if (ttype == kTransportLocal) {
969 service = "wait-for-local";
970 } else {
971 service = "wait-for-any";
972 }
973 }
974
975 format_host_command(buf, sizeof buf, service, ttype, serial);
976
977 if (adb_command(buf)) {
978 D("failure: %s *\n",adb_error());
979 fprintf(stderr,"error: %s\n", adb_error());
980 return 1;
981 }
982
983 /* Allow a command to be run after wait-for-device,
984 * e.g. 'adb wait-for-device shell'.
985 */
986 if(argc > 1) {
987 argc--;
988 argv++;
989 goto top;
990 }
991 return 0;
992 }
993
994 if(!strcmp(argv[0], "forward")) {
995 if(argc != 3) return usage();
996 if (serial) {
Mike Lockwood64e99542009-11-28 12:46:13 -0500997 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
998 } else if (ttype == kTransportUsb) {
999 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1000 } else if (ttype == kTransportLocal) {
1001 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001002 } else {
Mike Lockwood64e99542009-11-28 12:46:13 -05001003 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001004 }
1005 if(adb_command(buf)) {
1006 fprintf(stderr,"error: %s\n", adb_error());
1007 return 1;
1008 }
1009 return 0;
1010 }
1011
1012 /* do_sync_*() commands */
1013
1014 if(!strcmp(argv[0], "ls")) {
1015 if(argc != 2) return usage();
1016 return do_sync_ls(argv[1]);
1017 }
1018
1019 if(!strcmp(argv[0], "push")) {
1020 if(argc != 3) return usage();
1021 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1022 }
1023
1024 if(!strcmp(argv[0], "pull")) {
Joe Onorato00c0eea2010-01-05 13:42:25 -08001025 if (argc == 2) {
1026 return do_sync_pull(argv[1], ".");
1027 } else if (argc == 3) {
1028 return do_sync_pull(argv[1], argv[2]);
1029 } else {
1030 return usage();
1031 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001032 }
1033
1034 if(!strcmp(argv[0], "install")) {
1035 if (argc < 2) return usage();
1036 return install_app(ttype, serial, argc, argv);
1037 }
1038
1039 if(!strcmp(argv[0], "uninstall")) {
1040 if (argc < 2) return usage();
1041 return uninstall_app(ttype, serial, argc, argv);
1042 }
1043
1044 if(!strcmp(argv[0], "sync")) {
1045 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnam705c9442010-02-22 08:36:49 -06001046 int listonly = 0;
1047
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001048 int ret;
1049 if(argc < 2) {
1050 /* No local path was specified. */
1051 srcarg = NULL;
Anthony Newnam705c9442010-02-22 08:36:49 -06001052 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1053 listonly = 1;
1054 if (argc == 3) {
1055 srcarg = argv[2];
1056 } else {
1057 srcarg = NULL;
1058 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001059 } else if(argc == 2) {
1060 /* A local path or "android"/"data" arg was specified. */
1061 srcarg = argv[1];
1062 } else {
1063 return usage();
1064 }
1065 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1066 if(ret != 0) return usage();
1067
1068 if(android_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001069 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001070 if(ret == 0 && data_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001071 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001072
1073 free(android_srcpath);
1074 free(data_srcpath);
1075 return ret;
1076 }
1077
1078 /* passthrough commands */
1079
1080 if(!strcmp(argv[0],"get-state") ||
1081 !strcmp(argv[0],"get-serialno"))
1082 {
1083 char *tmp;
1084
1085 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1086 tmp = adb_query(buf);
1087 if(tmp) {
1088 printf("%s\n", tmp);
1089 return 0;
1090 } else {
1091 return 1;
1092 }
1093 }
1094
1095 /* other commands */
1096
1097 if(!strcmp(argv[0],"status-window")) {
1098 status_window(ttype, serial);
1099 return 0;
1100 }
1101
1102 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1103 return logcat(ttype, serial, argc, argv);
1104 }
1105
1106 if(!strcmp(argv[0],"ppp")) {
1107 return ppp(argc, argv);
1108 }
1109
1110 if (!strcmp(argv[0], "start-server")) {
1111 return adb_connect("host:start-server");
1112 }
1113
1114 if (!strcmp(argv[0], "jdwp")) {
1115 int fd = adb_connect("jdwp");
1116 if (fd >= 0) {
1117 read_and_dump(fd);
1118 adb_close(fd);
1119 return 0;
1120 } else {
1121 fprintf(stderr, "error: %s\n", adb_error());
1122 return -1;
1123 }
1124 }
1125
1126 /* "adb /?" is a common idiom under Windows */
1127 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1128 help();
1129 return 0;
1130 }
1131
1132 if(!strcmp(argv[0], "version")) {
1133 version(stdout);
1134 return 0;
1135 }
1136
1137 usage();
1138 return 1;
1139}
1140
1141static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1142{
1143 char *argv[16];
1144 int argc;
1145 va_list ap;
1146
1147 va_start(ap, cmd);
1148 argc = 0;
1149
1150 if (serial) {
1151 argv[argc++] = "-s";
1152 argv[argc++] = serial;
1153 } else if (ttype == kTransportUsb) {
1154 argv[argc++] = "-d";
1155 } else if (ttype == kTransportLocal) {
1156 argv[argc++] = "-e";
1157 }
1158
1159 argv[argc++] = cmd;
1160 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1161 va_end(ap);
1162
1163#if 0
1164 int n;
1165 fprintf(stderr,"argc = %d\n",argc);
1166 for(n = 0; n < argc; n++) {
1167 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1168 }
1169#endif
1170
1171 return adb_commandline(argc, argv);
1172}
1173
1174int find_sync_dirs(const char *srcarg,
1175 char **android_srcdir_out, char **data_srcdir_out)
1176{
1177 char *android_srcdir, *data_srcdir;
1178
1179 if(srcarg == NULL) {
1180 android_srcdir = product_file("system");
1181 data_srcdir = product_file("data");
1182 } else {
1183 /* srcarg may be "data", "system" or NULL.
1184 * if srcarg is NULL, then both data and system are synced
1185 */
1186 if(strcmp(srcarg, "system") == 0) {
1187 android_srcdir = product_file("system");
1188 data_srcdir = NULL;
1189 } else if(strcmp(srcarg, "data") == 0) {
1190 android_srcdir = NULL;
1191 data_srcdir = product_file("data");
1192 } else {
1193 /* It's not "system" or "data".
1194 */
1195 return 1;
1196 }
1197 }
1198
1199 if(android_srcdir_out != NULL)
1200 *android_srcdir_out = android_srcdir;
1201 else
1202 free(android_srcdir);
1203
1204 if(data_srcdir_out != NULL)
1205 *data_srcdir_out = data_srcdir;
1206 else
1207 free(data_srcdir);
1208
1209 return 0;
1210}
1211
1212static int pm_command(transport_type transport, char* serial,
1213 int argc, char** argv)
1214{
1215 char buf[4096];
1216
1217 snprintf(buf, sizeof(buf), "shell:pm");
1218
1219 while(argc-- > 0) {
1220 char *quoted;
1221
1222 quoted = dupAndQuote(*argv++);
1223
1224 strncat(buf, " ", sizeof(buf)-1);
1225 strncat(buf, quoted, sizeof(buf)-1);
1226 free(quoted);
1227 }
1228
1229 send_shellcommand(transport, serial, buf);
1230 return 0;
1231}
1232
1233int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1234{
1235 /* if the user choose the -k option, we refuse to do it until devices are
1236 out with the option to uninstall the remaining data somehow (adb/ui) */
1237 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1238 {
1239 printf(
1240 "The -k option uninstalls the application while retaining the data/cache.\n"
1241 "At the moment, there is no way to remove the remaining data.\n"
1242 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1243 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1244 return -1;
1245 }
1246
1247 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1248 return pm_command(transport, serial, argc, argv);
1249}
1250
1251static int delete_file(transport_type transport, char* serial, char* filename)
1252{
1253 char buf[4096];
1254 char* quoted;
1255
1256 snprintf(buf, sizeof(buf), "shell:rm ");
1257 quoted = dupAndQuote(filename);
1258 strncat(buf, quoted, sizeof(buf)-1);
1259 free(quoted);
1260
1261 send_shellcommand(transport, serial, buf);
1262 return 0;
1263}
1264
1265int install_app(transport_type transport, char* serial, int argc, char** argv)
1266{
1267 struct stat st;
1268 int err;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001269 const char *const DATA_DEST = "/data/local/tmp/%s";
1270 const char *const SD_DEST = "/sdcard/tmp/%s";
1271 const char* where = DATA_DEST;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001272 char to[PATH_MAX];
1273 char* filename = argv[argc - 1];
1274 const char* p;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001275 int i;
1276
1277 for (i = 0; i < argc; i++) {
1278 if (!strcmp(argv[i], "-s"))
1279 where = SD_DEST;
1280 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001281
1282 p = adb_dirstop(filename);
1283 if (p) {
1284 p++;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001285 snprintf(to, sizeof to, where, p);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001286 } else {
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001287 snprintf(to, sizeof to, where, filename);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001288 }
1289 if (p[0] == '\0') {
1290 }
1291
1292 err = stat(filename, &st);
1293 if (err != 0) {
1294 fprintf(stderr, "can't find '%s' to install\n", filename);
1295 return 1;
1296 }
1297 if (!S_ISREG(st.st_mode)) {
1298 fprintf(stderr, "can't install '%s' because it's not a file\n",
1299 filename);
1300 return 1;
1301 }
1302
1303 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1304 /* file in place; tell the Package Manager to install it */
1305 argv[argc - 1] = to; /* destination name, not source location */
1306 pm_command(transport, serial, argc, argv);
1307 delete_file(transport, serial, to);
1308 }
1309
1310 return err;
1311}