blob: d97e97d0b300ce3feed01ad4bc889fb7a7cac396 [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"
Timcd643152010-02-16 20:18:29 +0000174 "\n"
175 "environmental variables:\n"
176 " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
177 " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
178 " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
179 " 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 -0800180 );
181}
182
183int usage()
184{
185 help();
186 return 1;
187}
188
189#ifdef HAVE_TERMIO_H
190static struct termios tio_save;
191
192static void stdin_raw_init(int fd)
193{
194 struct termios tio;
195
196 if(tcgetattr(fd, &tio)) return;
197 if(tcgetattr(fd, &tio_save)) return;
198
199 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
200
201 /* no timeout but request at least one character per read */
202 tio.c_cc[VTIME] = 0;
203 tio.c_cc[VMIN] = 1;
204
205 tcsetattr(fd, TCSANOW, &tio);
206 tcflush(fd, TCIFLUSH);
207}
208
209static void stdin_raw_restore(int fd)
210{
211 tcsetattr(fd, TCSANOW, &tio_save);
212 tcflush(fd, TCIFLUSH);
213}
214#endif
215
216static void read_and_dump(int fd)
217{
218 char buf[4096];
219 int len;
220
221 while(fd >= 0) {
222 len = adb_read(fd, buf, 4096);
223 if(len == 0) {
224 break;
225 }
226
227 if(len < 0) {
228 if(errno == EINTR) continue;
229 break;
230 }
Mike Lockwooddd6b36e2009-09-22 01:18:40 -0400231 fwrite(buf, 1, len, stdout);
232 fflush(stdout);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800233 }
234}
235
236#ifdef SH_HISTORY
237int shItemCmp( void *val, void *idata )
238{
239 return( (strcmp( val, idata ) == 0) );
240}
241#endif
242
243static void *stdin_read_thread(void *x)
244{
245 int fd, fdi;
246 unsigned char buf[1024];
247#ifdef SH_HISTORY
248 unsigned char realbuf[1024], *buf_ptr;
249 SHLIST history;
250 SHLIST *item = &history;
251 int cmdlen = 0, ins_flag = 0;
252#endif
253 int r, n;
254 int state = 0;
255
256 int *fds = (int*) x;
257 fd = fds[0];
258 fdi = fds[1];
259 free(fds);
260
261#ifdef SH_HISTORY
262 shListInitList( &history );
263#endif
264 for(;;) {
265 /* fdi is really the client's stdin, so use read, not adb_read here */
266 r = unix_read(fdi, buf, 1024);
267 if(r == 0) break;
268 if(r < 0) {
269 if(errno == EINTR) continue;
270 break;
271 }
272#ifdef SH_HISTORY
273 if( (r == 3) && /* Arrow processing */
274 (memcmp( (void *)buf, SH_ARROW_ANY, 2 ) == 0) ) {
275 switch( buf[2] ) {
276 case SH_ARROW_UP:
277 item = shListGetNextItem( &history, item );
278 break;
279 case SH_ARROW_DOWN:
280 item = shListGetPrevItem( &history, item );
281 break;
282 default:
283 item = NULL;
284 break;
285 }
286 memset( buf, SH_DEL_CHAR, cmdlen );
287 if( item != NULL ) {
288 n = snprintf( (char *)(&buf[cmdlen]), sizeof buf - cmdlen, "%s", (char *)(item->data) );
289 memcpy( realbuf, item->data, n );
290 }
291 else { /* Clean buffer */
292 item = &history;
293 n = 0;
294 }
295 r = n + cmdlen;
296 cmdlen = n;
297 ins_flag = 0;
298 if( r == 0 )
299 continue;
300 }
301 else {
302#endif
303 for(n = 0; n < r; n++){
304 switch(buf[n]) {
305 case '\n':
306#ifdef SH_HISTORY
307 if( ins_flag && (SH_BLANK_CHAR <= realbuf[0]) ) {
308 buf_ptr = malloc(cmdlen + 1);
309 if( buf_ptr != NULL ) {
310 memcpy( buf_ptr, realbuf, cmdlen );
311 buf_ptr[cmdlen] = '\0';
312 if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
313 shListInsFirstItem( &history, (void *)buf_ptr );
314 item = &history;
315 }
316 }
317 }
318 cmdlen = 0;
319 ins_flag = 0;
320#endif
321 state = 1;
322 break;
323 case '\r':
324 state = 1;
325 break;
326 case '~':
327 if(state == 1) state++;
328 break;
329 case '.':
330 if(state == 2) {
331 fprintf(stderr,"\n* disconnect *\n");
332 #ifdef HAVE_TERMIO_H
333 stdin_raw_restore(fdi);
334 #endif
335 exit(0);
336 }
337 default:
338#ifdef SH_HISTORY
339 if( buf[n] == SH_DEL_CHAR ) {
340 if( cmdlen > 0 )
341 cmdlen--;
342 }
343 else {
344 realbuf[cmdlen] = buf[n];
345 cmdlen++;
346 }
347 ins_flag = 1;
348#endif
349 state = 0;
350 }
351 }
352#ifdef SH_HISTORY
353 }
354#endif
355 r = adb_write(fd, buf, r);
356 if(r <= 0) {
357 break;
358 }
359 }
360#ifdef SH_HISTORY
361 shListDelAllItems( &history, (shListFree)free );
362#endif
363 return 0;
364}
365
366int interactive_shell(void)
367{
368 adb_thread_t thr;
369 int fdi, fd;
370 int *fds;
371
372 fd = adb_connect("shell:");
373 if(fd < 0) {
374 fprintf(stderr,"error: %s\n", adb_error());
375 return 1;
376 }
377 fdi = 0; //dup(0);
378
379 fds = malloc(sizeof(int) * 2);
380 fds[0] = fd;
381 fds[1] = fdi;
382
383#ifdef HAVE_TERMIO_H
384 stdin_raw_init(fdi);
385#endif
386 adb_thread_create(&thr, stdin_read_thread, fds);
387 read_and_dump(fd);
388#ifdef HAVE_TERMIO_H
389 stdin_raw_restore(fdi);
390#endif
391 return 0;
392}
393
394
395static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
396{
397 if (serial) {
398 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
399 } else {
400 const char* prefix = "host";
401 if (ttype == kTransportUsb)
402 prefix = "host-usb";
403 else if (ttype == kTransportLocal)
404 prefix = "host-local";
405
406 snprintf(buffer, buflen, "%s:%s", prefix, command);
407 }
408}
409
410static void status_window(transport_type ttype, const char* serial)
411{
412 char command[4096];
413 char *state = 0;
414 char *laststate = 0;
415
416 /* silence stderr */
417#ifdef _WIN32
418 /* XXX: TODO */
419#else
420 int fd;
421 fd = unix_open("/dev/null", O_WRONLY);
422 dup2(fd, 2);
423 adb_close(fd);
424#endif
425
426 format_host_command(command, sizeof command, "get-state", ttype, serial);
427
428 for(;;) {
429 adb_sleep_ms(250);
430
431 if(state) {
432 free(state);
433 state = 0;
434 }
435
436 state = adb_query(command);
437
438 if(state) {
439 if(laststate && !strcmp(state,laststate)){
440 continue;
441 } else {
442 if(laststate) free(laststate);
443 laststate = strdup(state);
444 }
445 }
446
447 printf("%c[2J%c[2H", 27, 27);
448 printf("Android Debug Bridge\n");
449 printf("State: %s\n", state ? state : "offline");
450 fflush(stdout);
451 }
452}
453
454/** duplicate string and quote all \ " ( ) chars + space character. */
455static char *
456dupAndQuote(const char *s)
457{
458 const char *ts;
459 size_t alloc_len;
460 char *ret;
461 char *dest;
462
463 ts = s;
464
465 alloc_len = 0;
466
467 for( ;*ts != '\0'; ts++) {
468 alloc_len++;
469 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
470 alloc_len++;
471 }
472 }
473
474 ret = (char *)malloc(alloc_len + 1);
475
476 ts = s;
477 dest = ret;
478
479 for ( ;*ts != '\0'; ts++) {
480 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
481 *dest++ = '\\';
482 }
483
484 *dest++ = *ts;
485 }
486
487 *dest++ = '\0';
488
489 return ret;
490}
491
492/**
493 * Run ppp in "notty" mode against a resource listed as the first parameter
494 * eg:
495 *
496 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
497 *
498 */
499int ppp(int argc, char **argv)
500{
501#ifdef HAVE_WIN32_PROC
502 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
503 return -1;
504#else
505 char *adb_service_name;
506 pid_t pid;
507 int fd;
508
509 if (argc < 2) {
510 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
511 argv[0]);
512
513 return 1;
514 }
515
516 adb_service_name = argv[1];
517
518 fd = adb_connect(adb_service_name);
519
520 if(fd < 0) {
521 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
522 adb_service_name, adb_error());
523 return 1;
524 }
525
526 pid = fork();
527
528 if (pid < 0) {
529 perror("from fork()");
530 return 1;
531 } else if (pid == 0) {
532 int err;
533 int i;
534 const char **ppp_args;
535
536 // copy args
537 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
538 ppp_args[0] = "pppd";
539 for (i = 2 ; i < argc ; i++) {
540 //argv[2] and beyond become ppp_args[1] and beyond
541 ppp_args[i - 1] = argv[i];
542 }
543 ppp_args[i-1] = NULL;
544
545 // child side
546
547 dup2(fd, STDIN_FILENO);
548 dup2(fd, STDOUT_FILENO);
549 adb_close(STDERR_FILENO);
550 adb_close(fd);
551
552 err = execvp("pppd", (char * const *)ppp_args);
553
554 if (err < 0) {
555 perror("execing pppd");
556 }
557 exit(-1);
558 } else {
559 // parent side
560
561 adb_close(fd);
562 return 0;
563 }
564#endif /* !HAVE_WIN32_PROC */
565}
566
567static int send_shellcommand(transport_type transport, char* serial, char* buf)
568{
569 int fd, ret;
570
571 for(;;) {
572 fd = adb_connect(buf);
573 if(fd >= 0)
574 break;
575 fprintf(stderr,"- waiting for device -\n");
576 adb_sleep_ms(1000);
577 do_cmd(transport, serial, "wait-for-device", 0);
578 }
579
580 read_and_dump(fd);
581 ret = adb_close(fd);
582 if (ret)
583 perror("close");
584
585 return ret;
586}
587
588static int logcat(transport_type transport, char* serial, int argc, char **argv)
589{
590 char buf[4096];
591
592 char *log_tags;
593 char *quoted_log_tags;
594
595 log_tags = getenv("ANDROID_LOG_TAGS");
596 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
597
598 snprintf(buf, sizeof(buf),
599 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
600 quoted_log_tags);
601
602 free(quoted_log_tags);
603
604 argc -= 1;
605 argv += 1;
606 while(argc-- > 0) {
607 char *quoted;
608
609 quoted = dupAndQuote (*argv++);
610
611 strncat(buf, " ", sizeof(buf)-1);
612 strncat(buf, quoted, sizeof(buf)-1);
613 free(quoted);
614 }
615
616 send_shellcommand(transport, serial, buf);
617 return 0;
618}
619
620#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
621static int top_works(const char *top)
622{
623 if (top != NULL && adb_is_absolute_host_path(top)) {
624 char path_buf[PATH_MAX];
625 snprintf(path_buf, sizeof(path_buf),
626 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
627 return access(path_buf, F_OK) == 0;
628 }
629 return 0;
630}
631
632static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
633{
634 strcpy(path_buf, indir);
635 while (1) {
636 if (top_works(path_buf)) {
637 return path_buf;
638 }
639 char *s = adb_dirstop(path_buf);
640 if (s != NULL) {
641 *s = '\0';
642 } else {
643 path_buf[0] = '\0';
644 return NULL;
645 }
646 }
647}
648
649static char *find_top(char path_buf[PATH_MAX])
650{
651 char *top = getenv("ANDROID_BUILD_TOP");
652 if (top != NULL && top[0] != '\0') {
653 if (!top_works(top)) {
654 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
655 return NULL;
656 }
657 } else {
658 top = getenv("TOP");
659 if (top != NULL && top[0] != '\0') {
660 if (!top_works(top)) {
661 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
662 return NULL;
663 }
664 } else {
665 top = NULL;
666 }
667 }
668
669 if (top != NULL) {
670 /* The environment pointed to a top directory that works.
671 */
672 strcpy(path_buf, top);
673 return path_buf;
674 }
675
676 /* The environment didn't help. Walk up the tree from the CWD
677 * to see if we can find the top.
678 */
679 char dir[PATH_MAX];
680 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
681 if (top == NULL) {
682 /* If the CWD isn't under a good-looking top, see if the
683 * executable is.
684 */
Alexey Tarasov31664102009-10-22 02:55:00 +1100685 get_my_path(dir, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800686 top = find_top_from(dir, path_buf);
687 }
688 return top;
689}
690
691/* <hint> may be:
692 * - A simple product name
693 * e.g., "sooner"
694TODO: debug? sooner-debug, sooner:debug?
695 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
696 * e.g., "out/target/product/sooner"
697 * - An absolute path to the PRODUCT_OUT dir
698 * e.g., "/src/device/out/target/product/sooner"
699 *
700 * Given <hint>, try to construct an absolute path to the
701 * ANDROID_PRODUCT_OUT dir.
702 */
703static const char *find_product_out_path(const char *hint)
704{
705 static char path_buf[PATH_MAX];
706
707 if (hint == NULL || hint[0] == '\0') {
708 return NULL;
709 }
710
711 /* If it's already absolute, don't bother doing any work.
712 */
713 if (adb_is_absolute_host_path(hint)) {
714 strcpy(path_buf, hint);
715 return path_buf;
716 }
717
718 /* If there are any slashes in it, assume it's a relative path;
719 * make it absolute.
720 */
721 if (adb_dirstart(hint) != NULL) {
722 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
723 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
724 return NULL;
725 }
726 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
727 fprintf(stderr, "adb: Couldn't assemble path\n");
728 return NULL;
729 }
730 strcat(path_buf, OS_PATH_SEPARATOR_STR);
731 strcat(path_buf, hint);
732 return path_buf;
733 }
734
735 /* It's a string without any slashes. Try to do something with it.
736 *
737 * Try to find the root of the build tree, and build a PRODUCT_OUT
738 * path from there.
739 */
740 char top_buf[PATH_MAX];
741 const char *top = find_top(top_buf);
742 if (top == NULL) {
743 fprintf(stderr, "adb: Couldn't find top of build tree\n");
744 return NULL;
745 }
746//TODO: if we have a way to indicate debug, look in out/debug/target/...
747 snprintf(path_buf, sizeof(path_buf),
748 "%s" OS_PATH_SEPARATOR_STR
749 "out" OS_PATH_SEPARATOR_STR
750 "target" OS_PATH_SEPARATOR_STR
751 "product" OS_PATH_SEPARATOR_STR
752 "%s", top_buf, hint);
753 if (access(path_buf, F_OK) < 0) {
754 fprintf(stderr, "adb: Couldn't find a product dir "
755 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
756 return NULL;
757 }
758 return path_buf;
759}
760
761int adb_commandline(int argc, char **argv)
762{
763 char buf[4096];
764 int no_daemon = 0;
765 int is_daemon = 0;
766 int persist = 0;
767 int r;
768 int quote;
769 transport_type ttype = kTransportAny;
770 char* serial = NULL;
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100771 char* server_port_str = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800772
773 /* If defined, this should be an absolute path to
774 * the directory containing all of the various system images
775 * for a particular product. If not defined, and the adb
776 * command requires this information, then the user must
777 * specify the path using "-p".
778 */
779 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
780 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
781 gProductOutPath = NULL;
782 }
783 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
784
Nick Pellydb449262009-05-07 12:48:03 -0700785 serial = getenv("ANDROID_SERIAL");
786
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100787 /* Validate and assign the server port */
788 server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
789 int server_port = DEFAULT_ADB_PORT;
790 if (server_port_str && strlen(server_port_str) > 0) {
791 server_port = (int) strtol(server_port_str, NULL, 0);
792 if (server_port <= 0) {
793 fprintf(stderr,
794 "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
795 server_port_str);
796 return usage();
797 }
798 }
799
800 /* modifiers and flags */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800801 while(argc > 0) {
802 if(!strcmp(argv[0],"nodaemon")) {
803 no_daemon = 1;
804 } else if (!strcmp(argv[0], "fork-server")) {
805 /* this is a special flag used only when the ADB client launches the ADB Server */
806 is_daemon = 1;
807 } else if(!strcmp(argv[0],"persist")) {
808 persist = 1;
809 } else if(!strncmp(argv[0], "-p", 2)) {
810 const char *product = NULL;
811 if (argv[0][2] == '\0') {
812 if (argc < 2) return usage();
813 product = argv[1];
814 argc--;
815 argv++;
816 } else {
817 product = argv[1] + 2;
818 }
819 gProductOutPath = find_product_out_path(product);
820 if (gProductOutPath == NULL) {
821 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
822 product);
823 return usage();
824 }
825 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
826 if (isdigit(argv[0][2])) {
827 serial = argv[0] + 2;
828 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100829 if(argc < 2 || argv[0][2] != '\0') return usage();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800830 serial = argv[1];
831 argc--;
832 argv++;
833 }
834 } else if (!strcmp(argv[0],"-d")) {
835 ttype = kTransportUsb;
836 } else if (!strcmp(argv[0],"-e")) {
837 ttype = kTransportLocal;
838 } else {
839 /* out of recognized modifiers and flags */
840 break;
841 }
842 argc--;
843 argv++;
844 }
845
846 adb_set_transport(ttype, serial);
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100847 adb_set_tcp_specifics(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800848
849 if ((argc > 0) && (!strcmp(argv[0],"server"))) {
850 if (no_daemon || is_daemon) {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100851 r = adb_main(is_daemon, server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800852 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100853 r = launch_server(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800854 }
855 if(r) {
856 fprintf(stderr,"* could not start server *\n");
857 }
858 return r;
859 }
860
861top:
862 if(argc == 0) {
863 return usage();
864 }
865
866 /* adb_connect() commands */
867
868 if(!strcmp(argv[0], "devices")) {
869 char *tmp;
870 snprintf(buf, sizeof buf, "host:%s", argv[0]);
871 tmp = adb_query(buf);
872 if(tmp) {
873 printf("List of devices attached \n");
874 printf("%s\n", tmp);
875 return 0;
876 } else {
877 return 1;
878 }
879 }
880
Mike Lockwood8cf0d592009-10-11 23:04:18 -0400881 if(!strcmp(argv[0], "connect") || !strcmp(argv[0], "disconnect")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700882 char *tmp;
883 if (argc != 2) {
Mike Lockwood8cf0d592009-10-11 23:04:18 -0400884 fprintf(stderr, "Usage: adb %s <host>:<port>\n", argv[0]);
Mike Lockwoodff196702009-08-24 15:58:40 -0700885 return 1;
886 }
887 snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
888 tmp = adb_query(buf);
889 if(tmp) {
890 printf("%s\n", tmp);
891 return 0;
892 } else {
893 return 1;
894 }
895 }
896
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800897 if (!strcmp(argv[0], "emu")) {
898 return adb_send_emulator_command(argc, argv);
899 }
900
901 if(!strcmp(argv[0], "shell")) {
902 int r;
903 int fd;
904
905 if(argc < 2) {
906 return interactive_shell();
907 }
908
909 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
910 argc -= 2;
911 argv += 2;
912 while(argc-- > 0) {
913 strcat(buf, " ");
914
915 /* quote empty strings and strings with spaces */
916 quote = (**argv == 0 || strchr(*argv, ' '));
917 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100918 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800919 strcat(buf, *argv++);
920 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100921 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800922 }
923
924 for(;;) {
925 fd = adb_connect(buf);
926 if(fd >= 0) {
927 read_and_dump(fd);
928 adb_close(fd);
929 r = 0;
930 } else {
931 fprintf(stderr,"error: %s\n", adb_error());
932 r = -1;
933 }
934
935 if(persist) {
936 fprintf(stderr,"\n- waiting for device -\n");
937 adb_sleep_ms(1000);
938 do_cmd(ttype, serial, "wait-for-device", 0);
939 } else {
940 return r;
941 }
942 }
943 }
944
945 if(!strcmp(argv[0], "kill-server")) {
946 int fd;
947 fd = _adb_connect("host:kill");
948 if(fd == -1) {
949 fprintf(stderr,"* server not running *\n");
950 return 1;
951 }
952 return 0;
953 }
954
Mike Lockwoodff196702009-08-24 15:58:40 -0700955 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guy311add42009-12-14 14:42:17 -0800956 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwoodff196702009-08-24 15:58:40 -0700957 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400958 || !strcmp(argv[0], "root")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700959 char command[100];
Romain Guy311add42009-12-14 14:42:17 -0800960 if (!strcmp(argv[0], "reboot-bootloader"))
961 snprintf(command, sizeof(command), "reboot:bootloader");
962 else if (argc > 1)
Mike Lockwoodff196702009-08-24 15:58:40 -0700963 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwoodee156622009-08-04 20:37:51 -0400964 else
Mike Lockwoodff196702009-08-24 15:58:40 -0700965 snprintf(command, sizeof(command), "%s:", argv[0]);
966 int fd = adb_connect(command);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700967 if(fd >= 0) {
968 read_and_dump(fd);
969 adb_close(fd);
970 return 0;
971 }
972 fprintf(stderr,"error: %s\n", adb_error());
973 return 1;
974 }
975
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400976 if(!strcmp(argv[0], "bugreport")) {
Dan Egnorc130ea72010-01-20 13:50:36 -0800977 if (argc != 1) return usage();
978 do_cmd(ttype, serial, "shell", "bugreport", 0);
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400979 return 0;
980 }
981
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800982 /* adb_command() wrapper commands */
983
984 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
985 char* service = argv[0];
986 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
987 if (ttype == kTransportUsb) {
988 service = "wait-for-usb";
989 } else if (ttype == kTransportLocal) {
990 service = "wait-for-local";
991 } else {
992 service = "wait-for-any";
993 }
994 }
995
996 format_host_command(buf, sizeof buf, service, ttype, serial);
997
998 if (adb_command(buf)) {
999 D("failure: %s *\n",adb_error());
1000 fprintf(stderr,"error: %s\n", adb_error());
1001 return 1;
1002 }
1003
1004 /* Allow a command to be run after wait-for-device,
1005 * e.g. 'adb wait-for-device shell'.
1006 */
1007 if(argc > 1) {
1008 argc--;
1009 argv++;
1010 goto top;
1011 }
1012 return 0;
1013 }
1014
1015 if(!strcmp(argv[0], "forward")) {
1016 if(argc != 3) return usage();
1017 if (serial) {
Mike Lockwood64e99542009-11-28 12:46:13 -05001018 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
1019 } else if (ttype == kTransportUsb) {
1020 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1021 } else if (ttype == kTransportLocal) {
1022 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001023 } else {
Mike Lockwood64e99542009-11-28 12:46:13 -05001024 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001025 }
1026 if(adb_command(buf)) {
1027 fprintf(stderr,"error: %s\n", adb_error());
1028 return 1;
1029 }
1030 return 0;
1031 }
1032
1033 /* do_sync_*() commands */
1034
1035 if(!strcmp(argv[0], "ls")) {
1036 if(argc != 2) return usage();
1037 return do_sync_ls(argv[1]);
1038 }
1039
1040 if(!strcmp(argv[0], "push")) {
1041 if(argc != 3) return usage();
1042 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1043 }
1044
1045 if(!strcmp(argv[0], "pull")) {
Joe Onorato00c0eea2010-01-05 13:42:25 -08001046 if (argc == 2) {
1047 return do_sync_pull(argv[1], ".");
1048 } else if (argc == 3) {
1049 return do_sync_pull(argv[1], argv[2]);
1050 } else {
1051 return usage();
1052 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001053 }
1054
1055 if(!strcmp(argv[0], "install")) {
1056 if (argc < 2) return usage();
1057 return install_app(ttype, serial, argc, argv);
1058 }
1059
1060 if(!strcmp(argv[0], "uninstall")) {
1061 if (argc < 2) return usage();
1062 return uninstall_app(ttype, serial, argc, argv);
1063 }
1064
1065 if(!strcmp(argv[0], "sync")) {
1066 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnam705c9442010-02-22 08:36:49 -06001067 int listonly = 0;
1068
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001069 int ret;
1070 if(argc < 2) {
1071 /* No local path was specified. */
1072 srcarg = NULL;
Anthony Newnam705c9442010-02-22 08:36:49 -06001073 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1074 listonly = 1;
1075 if (argc == 3) {
1076 srcarg = argv[2];
1077 } else {
1078 srcarg = NULL;
1079 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001080 } else if(argc == 2) {
1081 /* A local path or "android"/"data" arg was specified. */
1082 srcarg = argv[1];
1083 } else {
1084 return usage();
1085 }
1086 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1087 if(ret != 0) return usage();
1088
1089 if(android_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001090 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001091 if(ret == 0 && data_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001092 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001093
1094 free(android_srcpath);
1095 free(data_srcpath);
1096 return ret;
1097 }
1098
1099 /* passthrough commands */
1100
1101 if(!strcmp(argv[0],"get-state") ||
1102 !strcmp(argv[0],"get-serialno"))
1103 {
1104 char *tmp;
1105
1106 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1107 tmp = adb_query(buf);
1108 if(tmp) {
1109 printf("%s\n", tmp);
1110 return 0;
1111 } else {
1112 return 1;
1113 }
1114 }
1115
1116 /* other commands */
1117
1118 if(!strcmp(argv[0],"status-window")) {
1119 status_window(ttype, serial);
1120 return 0;
1121 }
1122
1123 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1124 return logcat(ttype, serial, argc, argv);
1125 }
1126
1127 if(!strcmp(argv[0],"ppp")) {
1128 return ppp(argc, argv);
1129 }
1130
1131 if (!strcmp(argv[0], "start-server")) {
1132 return adb_connect("host:start-server");
1133 }
1134
1135 if (!strcmp(argv[0], "jdwp")) {
1136 int fd = adb_connect("jdwp");
1137 if (fd >= 0) {
1138 read_and_dump(fd);
1139 adb_close(fd);
1140 return 0;
1141 } else {
1142 fprintf(stderr, "error: %s\n", adb_error());
1143 return -1;
1144 }
1145 }
1146
1147 /* "adb /?" is a common idiom under Windows */
1148 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1149 help();
1150 return 0;
1151 }
1152
1153 if(!strcmp(argv[0], "version")) {
1154 version(stdout);
1155 return 0;
1156 }
1157
1158 usage();
1159 return 1;
1160}
1161
1162static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1163{
1164 char *argv[16];
1165 int argc;
1166 va_list ap;
1167
1168 va_start(ap, cmd);
1169 argc = 0;
1170
1171 if (serial) {
1172 argv[argc++] = "-s";
1173 argv[argc++] = serial;
1174 } else if (ttype == kTransportUsb) {
1175 argv[argc++] = "-d";
1176 } else if (ttype == kTransportLocal) {
1177 argv[argc++] = "-e";
1178 }
1179
1180 argv[argc++] = cmd;
1181 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1182 va_end(ap);
1183
1184#if 0
1185 int n;
1186 fprintf(stderr,"argc = %d\n",argc);
1187 for(n = 0; n < argc; n++) {
1188 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1189 }
1190#endif
1191
1192 return adb_commandline(argc, argv);
1193}
1194
1195int find_sync_dirs(const char *srcarg,
1196 char **android_srcdir_out, char **data_srcdir_out)
1197{
1198 char *android_srcdir, *data_srcdir;
1199
1200 if(srcarg == NULL) {
1201 android_srcdir = product_file("system");
1202 data_srcdir = product_file("data");
1203 } else {
1204 /* srcarg may be "data", "system" or NULL.
1205 * if srcarg is NULL, then both data and system are synced
1206 */
1207 if(strcmp(srcarg, "system") == 0) {
1208 android_srcdir = product_file("system");
1209 data_srcdir = NULL;
1210 } else if(strcmp(srcarg, "data") == 0) {
1211 android_srcdir = NULL;
1212 data_srcdir = product_file("data");
1213 } else {
1214 /* It's not "system" or "data".
1215 */
1216 return 1;
1217 }
1218 }
1219
1220 if(android_srcdir_out != NULL)
1221 *android_srcdir_out = android_srcdir;
1222 else
1223 free(android_srcdir);
1224
1225 if(data_srcdir_out != NULL)
1226 *data_srcdir_out = data_srcdir;
1227 else
1228 free(data_srcdir);
1229
1230 return 0;
1231}
1232
1233static int pm_command(transport_type transport, char* serial,
1234 int argc, char** argv)
1235{
1236 char buf[4096];
1237
1238 snprintf(buf, sizeof(buf), "shell:pm");
1239
1240 while(argc-- > 0) {
1241 char *quoted;
1242
1243 quoted = dupAndQuote(*argv++);
1244
1245 strncat(buf, " ", sizeof(buf)-1);
1246 strncat(buf, quoted, sizeof(buf)-1);
1247 free(quoted);
1248 }
1249
1250 send_shellcommand(transport, serial, buf);
1251 return 0;
1252}
1253
1254int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1255{
1256 /* if the user choose the -k option, we refuse to do it until devices are
1257 out with the option to uninstall the remaining data somehow (adb/ui) */
1258 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1259 {
1260 printf(
1261 "The -k option uninstalls the application while retaining the data/cache.\n"
1262 "At the moment, there is no way to remove the remaining data.\n"
1263 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1264 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1265 return -1;
1266 }
1267
1268 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1269 return pm_command(transport, serial, argc, argv);
1270}
1271
1272static int delete_file(transport_type transport, char* serial, char* filename)
1273{
1274 char buf[4096];
1275 char* quoted;
1276
1277 snprintf(buf, sizeof(buf), "shell:rm ");
1278 quoted = dupAndQuote(filename);
1279 strncat(buf, quoted, sizeof(buf)-1);
1280 free(quoted);
1281
1282 send_shellcommand(transport, serial, buf);
1283 return 0;
1284}
1285
1286int install_app(transport_type transport, char* serial, int argc, char** argv)
1287{
1288 struct stat st;
1289 int err;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001290 const char *const DATA_DEST = "/data/local/tmp/%s";
1291 const char *const SD_DEST = "/sdcard/tmp/%s";
1292 const char* where = DATA_DEST;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001293 char to[PATH_MAX];
1294 char* filename = argv[argc - 1];
1295 const char* p;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001296 int i;
1297
1298 for (i = 0; i < argc; i++) {
1299 if (!strcmp(argv[i], "-s"))
1300 where = SD_DEST;
1301 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001302
1303 p = adb_dirstop(filename);
1304 if (p) {
1305 p++;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001306 snprintf(to, sizeof to, where, p);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001307 } else {
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001308 snprintf(to, sizeof to, where, filename);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001309 }
1310 if (p[0] == '\0') {
1311 }
1312
1313 err = stat(filename, &st);
1314 if (err != 0) {
1315 fprintf(stderr, "can't find '%s' to install\n", filename);
1316 return 1;
1317 }
1318 if (!S_ISREG(st.st_mode)) {
1319 fprintf(stderr, "can't install '%s' because it's not a file\n",
1320 filename);
1321 return 1;
1322 }
1323
1324 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1325 /* file in place; tell the Package Manager to install it */
1326 argv[argc - 1] = to; /* destination name, not source location */
1327 pm_command(transport, serial, argc, argv);
1328 delete_file(transport, serial, to);
1329 }
1330
1331 return err;
1332}