blob: 460120e8afe21839821079158161eb7233707df3 [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 -080040static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
41
Alexey Tarasov31664102009-10-22 02:55:00 +110042void get_my_path(char *s, size_t maxLen);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043int find_sync_dirs(const char *srcarg,
44 char **android_srcdir_out, char **data_srcdir_out);
45int install_app(transport_type transport, char* serial, int argc, char** argv);
46int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
47
48static const char *gProductOutPath = NULL;
49
50static char *product_file(const char *extra)
51{
52 int n;
53 char *x;
54
55 if (gProductOutPath == NULL) {
56 fprintf(stderr, "adb: Product directory not specified; "
57 "use -p or define ANDROID_PRODUCT_OUT\n");
58 exit(1);
59 }
60
61 n = strlen(gProductOutPath) + strlen(extra) + 2;
62 x = malloc(n);
63 if (x == 0) {
64 fprintf(stderr, "adb: Out of memory (product_file())\n");
65 exit(1);
66 }
67
68 snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
69 return x;
70}
71
72void version(FILE * out) {
73 fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
74 ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
75}
76
77void help()
78{
79 version(stderr);
80
81 fprintf(stderr,
82 "\n"
83 " -d - directs command to the only connected USB device\n"
84 " returns an error if more than one USB device is present.\n"
85 " -e - directs command to the only running emulator.\n"
86 " returns an error if more than one emulator is running.\n"
87 " -s <serial number> - directs command to the USB device or emulator with\n"
Nick Pellydb449262009-05-07 12:48:03 -070088 " the given serial number. Overrides ANDROID_SERIAL\n"
Elliott Hughes31dbed72009-10-07 15:38:53 -070089 " environment variable.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080090 " -p <product name or path> - simple product name like 'sooner', or\n"
91 " a relative/absolute path to a product\n"
92 " out directory like 'out/target/product/sooner'.\n"
93 " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
94 " environment variable is used, which must\n"
95 " be an absolute path.\n"
96 " devices - list all connected devices\n"
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -040097 " connect <host>[:<port>] - connect to a device via TCP/IP\n"
98 " Port 5555 is used by default if no port number is specified.\n"
99 " disconnect [<host>[:<port>]] - disconnect from a TCP/IP device.\n"
100 " Port 5555 is used by default if no port number is specified.\n"
Bernhard Reutner-Fischer6715a432011-04-26 12:46:05 +0200101 " Using this command with no additional arguments\n"
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400102 " will disconnect from all connected TCP/IP devices.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103 "\n"
104 "device commands:\n"
105 " adb push <local> <remote> - copy file/dir to device\n"
Joe Onorato00c0eea2010-01-05 13:42:25 -0800106 " adb pull <remote> [<local>] - copy file/dir from device\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107 " adb sync [ <directory> ] - copy host->device only if changed\n"
Anthony Newnam705c9442010-02-22 08:36:49 -0600108 " (-l means list but don't copy)\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800109 " (see 'adb help all')\n"
110 " adb shell - run remote shell interactively\n"
111 " adb shell <command> - run remote shell command\n"
112 " adb emu <command> - run emulator console command\n"
113 " adb logcat [ <filter-spec> ] - View device log\n"
114 " adb forward <local> <remote> - forward socket connections\n"
115 " forward specs are one of: \n"
116 " tcp:<port>\n"
117 " localabstract:<unix domain socket name>\n"
118 " localreserved:<unix domain socket name>\n"
119 " localfilesystem:<unix domain socket name>\n"
120 " dev:<character device name>\n"
121 " jdwp:<process pid> (remote only)\n"
122 " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
Mike Lockwood0ef3fd02010-02-19 17:53:27 -0500123 " 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 -0800124 " ('-l' means forward-lock the app)\n"
125 " ('-r' means reinstall the app, keeping its data)\n"
Mike Lockwood0ef3fd02010-02-19 17:53:27 -0500126 " ('-s' means install on SD card instead of internal storage)\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800127 " adb uninstall [-k] <package> - remove this app package from the device\n"
128 " ('-k' means keep the data and cache directories)\n"
129 " adb bugreport - return all information from the device\n"
130 " that should be included in a bug report.\n"
131 "\n"
Christopher Tated2f54152011-04-21 12:53:28 -0700132 " adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [<packages...>]\n"
133 " - Write a tarfile backup of the device's data to <file>.\n"
134 " The -f option must come first; if not specified then the data\n"
135 " is written to \"backup.tar\" in the current directory.\n"
136 " (-apk|-noapk enable/disable backup of the .apks themselves\n"
137 " in the tarfile; the default is noapk.)\n"
138 " (-shared|-noshared enable/disable backup of the device's\n"
139 " shared storage / SD card contents; the default is noshared.)\n"
140 " (-all means to back up all installed applications)\n"
141 " (<packages...> is the list of applications to be backed up. If\n"
142 " the -all or -shared flags are passed, then the package\n"
143 " list is optional.)\n"
144 "\n"
Christopher Tate702967a2011-05-17 15:52:54 -0700145 " adb restore <file> - restore device contents from the <file> backup tarfile\n"
146 "\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800147 " adb help - show this help message\n"
148 " adb version - show version num\n"
149 "\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800150 "scripting:\n"
151 " adb wait-for-device - block until device is online\n"
152 " adb start-server - ensure that there is a server running\n"
153 " adb kill-server - kill the server if it is running\n"
154 " adb get-state - prints: offline | bootloader | device\n"
155 " adb get-serialno - prints: <serial-number>\n"
156 " adb status-window - continuously print device status for a specified device\n"
157 " adb remount - remounts the /system partition on the device read-write\n"
Mike Lockwoodee156622009-08-04 20:37:51 -0400158 " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
Romain Guy311add42009-12-14 14:42:17 -0800159 " adb reboot-bootloader - reboots the device into the bootloader\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700160 " adb root - restarts the adbd daemon with root permissions\n"
Romain Guy311add42009-12-14 14:42:17 -0800161 " adb usb - restarts the adbd daemon listening on USB\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700162 " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163 "\n"
164 "networking:\n"
165 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
Kenny Rootc9891992009-06-08 14:40:30 -0500166 " Note: you should not automatically start a PPP connection.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800167 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
168 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
169 "\n"
170 "adb sync notes: adb sync [ <directory> ]\n"
171 " <localdir> can be interpreted in several ways:\n"
172 "\n"
173 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
174 "\n"
175 " - If it is \"system\" or \"data\", only the corresponding partition\n"
176 " is updated.\n"
Timcd643152010-02-16 20:18:29 +0000177 "\n"
178 "environmental variables:\n"
179 " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
180 " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
181 " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
182 " 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 -0800183 );
184}
185
186int usage()
187{
188 help();
189 return 1;
190}
191
192#ifdef HAVE_TERMIO_H
193static struct termios tio_save;
194
195static void stdin_raw_init(int fd)
196{
197 struct termios tio;
198
199 if(tcgetattr(fd, &tio)) return;
200 if(tcgetattr(fd, &tio_save)) return;
201
202 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
203
204 /* no timeout but request at least one character per read */
205 tio.c_cc[VTIME] = 0;
206 tio.c_cc[VMIN] = 1;
207
208 tcsetattr(fd, TCSANOW, &tio);
209 tcflush(fd, TCIFLUSH);
210}
211
212static void stdin_raw_restore(int fd)
213{
214 tcsetattr(fd, TCSANOW, &tio_save);
215 tcflush(fd, TCIFLUSH);
216}
217#endif
218
219static void read_and_dump(int fd)
220{
221 char buf[4096];
222 int len;
223
224 while(fd >= 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700225 D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800226 len = adb_read(fd, buf, 4096);
JP Abgrall408fa572011-03-16 15:57:42 -0700227 D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800228 if(len == 0) {
229 break;
230 }
231
232 if(len < 0) {
233 if(errno == EINTR) continue;
234 break;
235 }
Mike Lockwooddd6b36e2009-09-22 01:18:40 -0400236 fwrite(buf, 1, len, stdout);
237 fflush(stdout);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800238 }
239}
240
Christopher Tated2f54152011-04-21 12:53:28 -0700241static void copy_to_file(int inFd, int outFd) {
242 char buf[4096];
243 int len;
244
245 D("copy_to_file(%d -> %d)\n", inFd, outFd);
246 for (;;) {
247 len = adb_read(inFd, buf, sizeof(buf));
248 if (len == 0) {
249 break;
250 }
251 if (len < 0) {
252 if (errno == EINTR) continue;
253 D("copy_to_file() : error %d\n", errno);
254 break;
255 }
256 adb_write(outFd, buf, len);
257 }
258}
259
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800260static void *stdin_read_thread(void *x)
261{
262 int fd, fdi;
263 unsigned char buf[1024];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800264 int r, n;
265 int state = 0;
266
267 int *fds = (int*) x;
268 fd = fds[0];
269 fdi = fds[1];
270 free(fds);
271
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800272 for(;;) {
273 /* fdi is really the client's stdin, so use read, not adb_read here */
JP Abgrall408fa572011-03-16 15:57:42 -0700274 D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800275 r = unix_read(fdi, buf, 1024);
JP Abgrall408fa572011-03-16 15:57:42 -0700276 D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800277 if(r == 0) break;
278 if(r < 0) {
279 if(errno == EINTR) continue;
280 break;
281 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400282 for(n = 0; n < r; n++){
283 switch(buf[n]) {
284 case '\n':
285 state = 1;
286 break;
287 case '\r':
288 state = 1;
289 break;
290 case '~':
291 if(state == 1) state++;
292 break;
293 case '.':
294 if(state == 2) {
295 fprintf(stderr,"\n* disconnect *\n");
296#ifdef HAVE_TERMIO_H
297 stdin_raw_restore(fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800298#endif
Mike Lockwood67d53582010-05-25 13:40:15 -0400299 exit(0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800300 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400301 default:
302 state = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800303 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800304 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800305 r = adb_write(fd, buf, r);
306 if(r <= 0) {
307 break;
308 }
309 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800310 return 0;
311}
312
313int interactive_shell(void)
314{
315 adb_thread_t thr;
316 int fdi, fd;
317 int *fds;
318
319 fd = adb_connect("shell:");
320 if(fd < 0) {
321 fprintf(stderr,"error: %s\n", adb_error());
322 return 1;
323 }
324 fdi = 0; //dup(0);
325
326 fds = malloc(sizeof(int) * 2);
327 fds[0] = fd;
328 fds[1] = fdi;
329
330#ifdef HAVE_TERMIO_H
331 stdin_raw_init(fdi);
332#endif
333 adb_thread_create(&thr, stdin_read_thread, fds);
334 read_and_dump(fd);
335#ifdef HAVE_TERMIO_H
336 stdin_raw_restore(fdi);
337#endif
338 return 0;
339}
340
341
342static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
343{
344 if (serial) {
345 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
346 } else {
347 const char* prefix = "host";
348 if (ttype == kTransportUsb)
349 prefix = "host-usb";
350 else if (ttype == kTransportLocal)
351 prefix = "host-local";
352
353 snprintf(buffer, buflen, "%s:%s", prefix, command);
354 }
355}
356
357static void status_window(transport_type ttype, const char* serial)
358{
359 char command[4096];
360 char *state = 0;
361 char *laststate = 0;
362
363 /* silence stderr */
364#ifdef _WIN32
365 /* XXX: TODO */
366#else
367 int fd;
368 fd = unix_open("/dev/null", O_WRONLY);
369 dup2(fd, 2);
370 adb_close(fd);
371#endif
372
373 format_host_command(command, sizeof command, "get-state", ttype, serial);
374
375 for(;;) {
376 adb_sleep_ms(250);
377
378 if(state) {
379 free(state);
380 state = 0;
381 }
382
383 state = adb_query(command);
384
385 if(state) {
386 if(laststate && !strcmp(state,laststate)){
387 continue;
388 } else {
389 if(laststate) free(laststate);
390 laststate = strdup(state);
391 }
392 }
393
394 printf("%c[2J%c[2H", 27, 27);
395 printf("Android Debug Bridge\n");
396 printf("State: %s\n", state ? state : "offline");
397 fflush(stdout);
398 }
399}
400
401/** duplicate string and quote all \ " ( ) chars + space character. */
402static char *
403dupAndQuote(const char *s)
404{
405 const char *ts;
406 size_t alloc_len;
407 char *ret;
408 char *dest;
409
410 ts = s;
411
412 alloc_len = 0;
413
414 for( ;*ts != '\0'; ts++) {
415 alloc_len++;
416 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
417 alloc_len++;
418 }
419 }
420
421 ret = (char *)malloc(alloc_len + 1);
422
423 ts = s;
424 dest = ret;
425
426 for ( ;*ts != '\0'; ts++) {
427 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
428 *dest++ = '\\';
429 }
430
431 *dest++ = *ts;
432 }
433
434 *dest++ = '\0';
435
436 return ret;
437}
438
439/**
440 * Run ppp in "notty" mode against a resource listed as the first parameter
441 * eg:
442 *
443 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
444 *
445 */
446int ppp(int argc, char **argv)
447{
448#ifdef HAVE_WIN32_PROC
449 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
450 return -1;
451#else
452 char *adb_service_name;
453 pid_t pid;
454 int fd;
455
456 if (argc < 2) {
457 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
458 argv[0]);
459
460 return 1;
461 }
462
463 adb_service_name = argv[1];
464
465 fd = adb_connect(adb_service_name);
466
467 if(fd < 0) {
468 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
469 adb_service_name, adb_error());
470 return 1;
471 }
472
473 pid = fork();
474
475 if (pid < 0) {
476 perror("from fork()");
477 return 1;
478 } else if (pid == 0) {
479 int err;
480 int i;
481 const char **ppp_args;
482
483 // copy args
484 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
485 ppp_args[0] = "pppd";
486 for (i = 2 ; i < argc ; i++) {
487 //argv[2] and beyond become ppp_args[1] and beyond
488 ppp_args[i - 1] = argv[i];
489 }
490 ppp_args[i-1] = NULL;
491
492 // child side
493
494 dup2(fd, STDIN_FILENO);
495 dup2(fd, STDOUT_FILENO);
496 adb_close(STDERR_FILENO);
497 adb_close(fd);
498
499 err = execvp("pppd", (char * const *)ppp_args);
500
501 if (err < 0) {
502 perror("execing pppd");
503 }
504 exit(-1);
505 } else {
506 // parent side
507
508 adb_close(fd);
509 return 0;
510 }
511#endif /* !HAVE_WIN32_PROC */
512}
513
514static int send_shellcommand(transport_type transport, char* serial, char* buf)
515{
516 int fd, ret;
517
518 for(;;) {
519 fd = adb_connect(buf);
520 if(fd >= 0)
521 break;
522 fprintf(stderr,"- waiting for device -\n");
523 adb_sleep_ms(1000);
524 do_cmd(transport, serial, "wait-for-device", 0);
525 }
526
527 read_and_dump(fd);
528 ret = adb_close(fd);
529 if (ret)
530 perror("close");
531
532 return ret;
533}
534
535static int logcat(transport_type transport, char* serial, int argc, char **argv)
536{
537 char buf[4096];
538
539 char *log_tags;
540 char *quoted_log_tags;
541
542 log_tags = getenv("ANDROID_LOG_TAGS");
543 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
544
545 snprintf(buf, sizeof(buf),
546 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
547 quoted_log_tags);
548
549 free(quoted_log_tags);
550
551 argc -= 1;
552 argv += 1;
553 while(argc-- > 0) {
554 char *quoted;
555
556 quoted = dupAndQuote (*argv++);
557
558 strncat(buf, " ", sizeof(buf)-1);
559 strncat(buf, quoted, sizeof(buf)-1);
560 free(quoted);
561 }
562
563 send_shellcommand(transport, serial, buf);
564 return 0;
565}
566
Christopher Tated2f54152011-04-21 12:53:28 -0700567static int backup(int argc, char** argv) {
568 char buf[4096];
569 const char* filename = "./backup.tar";
570 int fd, outFd;
571
572 if (!strcmp("-f", argv[1])) {
573 if (argc < 3) return usage();
574 filename = argv[2];
575 argc -= 2;
576 argv += 2;
577 }
578
579 outFd = adb_open_mode(filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
580 if (outFd < 0) {
581 fprintf(stderr, "adb: unable to open file %s\n", filename);
582 return -1;
583 }
584
585 snprintf(buf, sizeof(buf), "backup");
586 for (argc--, argv++; argc; argc--, argv++) {
587 strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
588 strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
589 }
590
591 D("backup. filename=%s buf=%s\n", filename, buf);
592 fd = adb_connect(buf);
593 if (fd < 0) {
594 fprintf(stderr, "adb: unable to connect for backup\n");
595 adb_close(outFd);
596 return -1;
597 }
598
599 copy_to_file(fd, outFd);
600
601 adb_close(fd);
602 adb_close(outFd);
603 return 0;
604}
605
Christopher Tate702967a2011-05-17 15:52:54 -0700606static int restore(int argc, char** argv) {
607 const char* filename;
608 int fd, tarFd;
609
610 if (argc != 2) return usage();
611
612 filename = argv[1];
613 tarFd = adb_open(filename, O_RDONLY);
614 if (tarFd < 0) {
615 fprintf(stderr, "adb: unable to open file %s\n", filename);
616 return -1;
617 }
618
619 fd = adb_connect("restore:");
620 if (fd < 0) {
621 fprintf(stderr, "adb: unable to connect for backup\n");
622 adb_close(tarFd);
623 return -1;
624 }
625
626 copy_to_file(tarFd, fd);
627
628 adb_close(fd);
629 adb_close(tarFd);
630 return 0;
631}
632
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800633#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
634static int top_works(const char *top)
635{
636 if (top != NULL && adb_is_absolute_host_path(top)) {
637 char path_buf[PATH_MAX];
638 snprintf(path_buf, sizeof(path_buf),
639 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
640 return access(path_buf, F_OK) == 0;
641 }
642 return 0;
643}
644
645static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
646{
647 strcpy(path_buf, indir);
648 while (1) {
649 if (top_works(path_buf)) {
650 return path_buf;
651 }
652 char *s = adb_dirstop(path_buf);
653 if (s != NULL) {
654 *s = '\0';
655 } else {
656 path_buf[0] = '\0';
657 return NULL;
658 }
659 }
660}
661
662static char *find_top(char path_buf[PATH_MAX])
663{
664 char *top = getenv("ANDROID_BUILD_TOP");
665 if (top != NULL && top[0] != '\0') {
666 if (!top_works(top)) {
667 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
668 return NULL;
669 }
670 } else {
671 top = getenv("TOP");
672 if (top != NULL && top[0] != '\0') {
673 if (!top_works(top)) {
674 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
675 return NULL;
676 }
677 } else {
678 top = NULL;
679 }
680 }
681
682 if (top != NULL) {
683 /* The environment pointed to a top directory that works.
684 */
685 strcpy(path_buf, top);
686 return path_buf;
687 }
688
689 /* The environment didn't help. Walk up the tree from the CWD
690 * to see if we can find the top.
691 */
692 char dir[PATH_MAX];
693 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
694 if (top == NULL) {
695 /* If the CWD isn't under a good-looking top, see if the
696 * executable is.
697 */
Alexey Tarasov31664102009-10-22 02:55:00 +1100698 get_my_path(dir, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800699 top = find_top_from(dir, path_buf);
700 }
701 return top;
702}
703
704/* <hint> may be:
705 * - A simple product name
706 * e.g., "sooner"
707TODO: debug? sooner-debug, sooner:debug?
708 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
709 * e.g., "out/target/product/sooner"
710 * - An absolute path to the PRODUCT_OUT dir
711 * e.g., "/src/device/out/target/product/sooner"
712 *
713 * Given <hint>, try to construct an absolute path to the
714 * ANDROID_PRODUCT_OUT dir.
715 */
716static const char *find_product_out_path(const char *hint)
717{
718 static char path_buf[PATH_MAX];
719
720 if (hint == NULL || hint[0] == '\0') {
721 return NULL;
722 }
723
724 /* If it's already absolute, don't bother doing any work.
725 */
726 if (adb_is_absolute_host_path(hint)) {
727 strcpy(path_buf, hint);
728 return path_buf;
729 }
730
731 /* If there are any slashes in it, assume it's a relative path;
732 * make it absolute.
733 */
734 if (adb_dirstart(hint) != NULL) {
735 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
736 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
737 return NULL;
738 }
739 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
740 fprintf(stderr, "adb: Couldn't assemble path\n");
741 return NULL;
742 }
743 strcat(path_buf, OS_PATH_SEPARATOR_STR);
744 strcat(path_buf, hint);
745 return path_buf;
746 }
747
748 /* It's a string without any slashes. Try to do something with it.
749 *
750 * Try to find the root of the build tree, and build a PRODUCT_OUT
751 * path from there.
752 */
753 char top_buf[PATH_MAX];
754 const char *top = find_top(top_buf);
755 if (top == NULL) {
756 fprintf(stderr, "adb: Couldn't find top of build tree\n");
757 return NULL;
758 }
759//TODO: if we have a way to indicate debug, look in out/debug/target/...
760 snprintf(path_buf, sizeof(path_buf),
761 "%s" OS_PATH_SEPARATOR_STR
762 "out" OS_PATH_SEPARATOR_STR
763 "target" OS_PATH_SEPARATOR_STR
764 "product" OS_PATH_SEPARATOR_STR
765 "%s", top_buf, hint);
766 if (access(path_buf, F_OK) < 0) {
767 fprintf(stderr, "adb: Couldn't find a product dir "
768 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
769 return NULL;
770 }
771 return path_buf;
772}
773
774int adb_commandline(int argc, char **argv)
775{
776 char buf[4096];
777 int no_daemon = 0;
778 int is_daemon = 0;
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100779 int is_server = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780 int persist = 0;
781 int r;
782 int quote;
783 transport_type ttype = kTransportAny;
784 char* serial = NULL;
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100785 char* server_port_str = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800786
787 /* If defined, this should be an absolute path to
788 * the directory containing all of the various system images
789 * for a particular product. If not defined, and the adb
790 * command requires this information, then the user must
791 * specify the path using "-p".
792 */
793 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
794 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
795 gProductOutPath = NULL;
796 }
797 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
798
Nick Pellydb449262009-05-07 12:48:03 -0700799 serial = getenv("ANDROID_SERIAL");
800
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100801 /* Validate and assign the server port */
802 server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
803 int server_port = DEFAULT_ADB_PORT;
804 if (server_port_str && strlen(server_port_str) > 0) {
805 server_port = (int) strtol(server_port_str, NULL, 0);
806 if (server_port <= 0) {
807 fprintf(stderr,
808 "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
809 server_port_str);
810 return usage();
811 }
812 }
813
814 /* modifiers and flags */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800815 while(argc > 0) {
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100816 if(!strcmp(argv[0],"server")) {
817 is_server = 1;
818 } else if(!strcmp(argv[0],"nodaemon")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800819 no_daemon = 1;
820 } else if (!strcmp(argv[0], "fork-server")) {
821 /* this is a special flag used only when the ADB client launches the ADB Server */
822 is_daemon = 1;
823 } else if(!strcmp(argv[0],"persist")) {
824 persist = 1;
825 } else if(!strncmp(argv[0], "-p", 2)) {
826 const char *product = NULL;
827 if (argv[0][2] == '\0') {
828 if (argc < 2) return usage();
829 product = argv[1];
830 argc--;
831 argv++;
832 } else {
833 product = argv[1] + 2;
834 }
835 gProductOutPath = find_product_out_path(product);
836 if (gProductOutPath == NULL) {
837 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
838 product);
839 return usage();
840 }
841 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
842 if (isdigit(argv[0][2])) {
843 serial = argv[0] + 2;
844 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100845 if(argc < 2 || argv[0][2] != '\0') return usage();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800846 serial = argv[1];
847 argc--;
848 argv++;
849 }
850 } else if (!strcmp(argv[0],"-d")) {
851 ttype = kTransportUsb;
852 } else if (!strcmp(argv[0],"-e")) {
853 ttype = kTransportLocal;
854 } else {
855 /* out of recognized modifiers and flags */
856 break;
857 }
858 argc--;
859 argv++;
860 }
861
862 adb_set_transport(ttype, serial);
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100863 adb_set_tcp_specifics(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800864
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100865 if (is_server) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800866 if (no_daemon || is_daemon) {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100867 r = adb_main(is_daemon, server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800868 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100869 r = launch_server(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800870 }
871 if(r) {
872 fprintf(stderr,"* could not start server *\n");
873 }
874 return r;
875 }
876
877top:
878 if(argc == 0) {
879 return usage();
880 }
881
882 /* adb_connect() commands */
883
884 if(!strcmp(argv[0], "devices")) {
885 char *tmp;
886 snprintf(buf, sizeof buf, "host:%s", argv[0]);
887 tmp = adb_query(buf);
888 if(tmp) {
889 printf("List of devices attached \n");
890 printf("%s\n", tmp);
891 return 0;
892 } else {
893 return 1;
894 }
895 }
896
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400897 if(!strcmp(argv[0], "connect")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700898 char *tmp;
899 if (argc != 2) {
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400900 fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
Mike Lockwoodff196702009-08-24 15:58:40 -0700901 return 1;
902 }
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400903 snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
904 tmp = adb_query(buf);
905 if(tmp) {
906 printf("%s\n", tmp);
907 return 0;
908 } else {
909 return 1;
910 }
911 }
912
913 if(!strcmp(argv[0], "disconnect")) {
914 char *tmp;
915 if (argc > 2) {
916 fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
917 return 1;
918 }
919 if (argc == 2) {
920 snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
921 } else {
922 snprintf(buf, sizeof buf, "host:disconnect:");
923 }
Mike Lockwoodff196702009-08-24 15:58:40 -0700924 tmp = adb_query(buf);
925 if(tmp) {
926 printf("%s\n", tmp);
927 return 0;
928 } else {
929 return 1;
930 }
931 }
932
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800933 if (!strcmp(argv[0], "emu")) {
934 return adb_send_emulator_command(argc, argv);
935 }
936
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400937 if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800938 int r;
939 int fd;
940
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400941 char h = (argv[0][0] == 'h');
942
943 if (h) {
944 printf("\x1b[41;33m");
945 fflush(stdout);
946 }
947
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800948 if(argc < 2) {
JP Abgrall408fa572011-03-16 15:57:42 -0700949 D("starting interactive shell\n");
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400950 r = interactive_shell();
951 if (h) {
952 printf("\x1b[0m");
953 fflush(stdout);
954 }
955 return r;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800956 }
957
958 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
959 argc -= 2;
960 argv += 2;
961 while(argc-- > 0) {
962 strcat(buf, " ");
963
964 /* quote empty strings and strings with spaces */
965 quote = (**argv == 0 || strchr(*argv, ' '));
966 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100967 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800968 strcat(buf, *argv++);
969 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100970 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800971 }
972
973 for(;;) {
JP Abgrall408fa572011-03-16 15:57:42 -0700974 D("interactive shell loop. buff=%s\n", buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800975 fd = adb_connect(buf);
976 if(fd >= 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700977 D("about to read_and_dump(fd=%d)\n", fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800978 read_and_dump(fd);
JP Abgrall408fa572011-03-16 15:57:42 -0700979 D("read_and_dump() done.\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800980 adb_close(fd);
981 r = 0;
982 } else {
983 fprintf(stderr,"error: %s\n", adb_error());
984 r = -1;
985 }
986
987 if(persist) {
988 fprintf(stderr,"\n- waiting for device -\n");
989 adb_sleep_ms(1000);
990 do_cmd(ttype, serial, "wait-for-device", 0);
991 } else {
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400992 if (h) {
993 printf("\x1b[0m");
994 fflush(stdout);
995 }
JP Abgrall408fa572011-03-16 15:57:42 -0700996 D("interactive shell loop. return r=%d\n", r);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800997 return r;
998 }
999 }
1000 }
1001
1002 if(!strcmp(argv[0], "kill-server")) {
1003 int fd;
1004 fd = _adb_connect("host:kill");
1005 if(fd == -1) {
1006 fprintf(stderr,"* server not running *\n");
1007 return 1;
1008 }
1009 return 0;
1010 }
1011
Mike Lockwoodff196702009-08-24 15:58:40 -07001012 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guy311add42009-12-14 14:42:17 -08001013 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwoodff196702009-08-24 15:58:40 -07001014 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Mike Lockwoodf56d1b52009-09-03 14:54:58 -04001015 || !strcmp(argv[0], "root")) {
Mike Lockwoodff196702009-08-24 15:58:40 -07001016 char command[100];
Romain Guy311add42009-12-14 14:42:17 -08001017 if (!strcmp(argv[0], "reboot-bootloader"))
1018 snprintf(command, sizeof(command), "reboot:bootloader");
1019 else if (argc > 1)
Mike Lockwoodff196702009-08-24 15:58:40 -07001020 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwoodee156622009-08-04 20:37:51 -04001021 else
Mike Lockwoodff196702009-08-24 15:58:40 -07001022 snprintf(command, sizeof(command), "%s:", argv[0]);
1023 int fd = adb_connect(command);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -07001024 if(fd >= 0) {
1025 read_and_dump(fd);
1026 adb_close(fd);
1027 return 0;
1028 }
1029 fprintf(stderr,"error: %s\n", adb_error());
1030 return 1;
1031 }
1032
Mike Lockwoodf56d1b52009-09-03 14:54:58 -04001033 if(!strcmp(argv[0], "bugreport")) {
Dan Egnorc130ea72010-01-20 13:50:36 -08001034 if (argc != 1) return usage();
1035 do_cmd(ttype, serial, "shell", "bugreport", 0);
Mike Lockwoodf56d1b52009-09-03 14:54:58 -04001036 return 0;
1037 }
1038
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001039 /* adb_command() wrapper commands */
1040
1041 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
1042 char* service = argv[0];
1043 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
1044 if (ttype == kTransportUsb) {
1045 service = "wait-for-usb";
1046 } else if (ttype == kTransportLocal) {
1047 service = "wait-for-local";
1048 } else {
1049 service = "wait-for-any";
1050 }
1051 }
1052
1053 format_host_command(buf, sizeof buf, service, ttype, serial);
1054
1055 if (adb_command(buf)) {
1056 D("failure: %s *\n",adb_error());
1057 fprintf(stderr,"error: %s\n", adb_error());
1058 return 1;
1059 }
1060
1061 /* Allow a command to be run after wait-for-device,
1062 * e.g. 'adb wait-for-device shell'.
1063 */
1064 if(argc > 1) {
1065 argc--;
1066 argv++;
1067 goto top;
1068 }
1069 return 0;
1070 }
1071
1072 if(!strcmp(argv[0], "forward")) {
1073 if(argc != 3) return usage();
1074 if (serial) {
Mike Lockwood64e99542009-11-28 12:46:13 -05001075 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
1076 } else if (ttype == kTransportUsb) {
1077 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1078 } else if (ttype == kTransportLocal) {
1079 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001080 } else {
Mike Lockwood64e99542009-11-28 12:46:13 -05001081 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001082 }
1083 if(adb_command(buf)) {
1084 fprintf(stderr,"error: %s\n", adb_error());
1085 return 1;
1086 }
1087 return 0;
1088 }
1089
1090 /* do_sync_*() commands */
1091
1092 if(!strcmp(argv[0], "ls")) {
1093 if(argc != 2) return usage();
1094 return do_sync_ls(argv[1]);
1095 }
1096
1097 if(!strcmp(argv[0], "push")) {
1098 if(argc != 3) return usage();
1099 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1100 }
1101
1102 if(!strcmp(argv[0], "pull")) {
Joe Onorato00c0eea2010-01-05 13:42:25 -08001103 if (argc == 2) {
1104 return do_sync_pull(argv[1], ".");
1105 } else if (argc == 3) {
1106 return do_sync_pull(argv[1], argv[2]);
1107 } else {
1108 return usage();
1109 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001110 }
1111
1112 if(!strcmp(argv[0], "install")) {
1113 if (argc < 2) return usage();
1114 return install_app(ttype, serial, argc, argv);
1115 }
1116
1117 if(!strcmp(argv[0], "uninstall")) {
1118 if (argc < 2) return usage();
1119 return uninstall_app(ttype, serial, argc, argv);
1120 }
1121
1122 if(!strcmp(argv[0], "sync")) {
1123 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnam705c9442010-02-22 08:36:49 -06001124 int listonly = 0;
1125
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001126 int ret;
1127 if(argc < 2) {
1128 /* No local path was specified. */
1129 srcarg = NULL;
Anthony Newnam705c9442010-02-22 08:36:49 -06001130 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1131 listonly = 1;
1132 if (argc == 3) {
1133 srcarg = argv[2];
1134 } else {
1135 srcarg = NULL;
1136 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001137 } else if(argc == 2) {
1138 /* A local path or "android"/"data" arg was specified. */
1139 srcarg = argv[1];
1140 } else {
1141 return usage();
1142 }
1143 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1144 if(ret != 0) return usage();
1145
1146 if(android_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001147 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001148 if(ret == 0 && data_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001149 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001150
1151 free(android_srcpath);
1152 free(data_srcpath);
1153 return ret;
1154 }
1155
1156 /* passthrough commands */
1157
1158 if(!strcmp(argv[0],"get-state") ||
1159 !strcmp(argv[0],"get-serialno"))
1160 {
1161 char *tmp;
1162
1163 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1164 tmp = adb_query(buf);
1165 if(tmp) {
1166 printf("%s\n", tmp);
1167 return 0;
1168 } else {
1169 return 1;
1170 }
1171 }
1172
1173 /* other commands */
1174
1175 if(!strcmp(argv[0],"status-window")) {
1176 status_window(ttype, serial);
1177 return 0;
1178 }
1179
1180 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1181 return logcat(ttype, serial, argc, argv);
1182 }
1183
1184 if(!strcmp(argv[0],"ppp")) {
1185 return ppp(argc, argv);
1186 }
1187
1188 if (!strcmp(argv[0], "start-server")) {
1189 return adb_connect("host:start-server");
1190 }
1191
Christopher Tated2f54152011-04-21 12:53:28 -07001192 if (!strcmp(argv[0], "backup")) {
1193 return backup(argc, argv);
1194 }
1195
Christopher Tate702967a2011-05-17 15:52:54 -07001196 if (!strcmp(argv[0], "restore")) {
1197 return restore(argc, argv);
1198 }
1199
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001200 if (!strcmp(argv[0], "jdwp")) {
1201 int fd = adb_connect("jdwp");
1202 if (fd >= 0) {
1203 read_and_dump(fd);
1204 adb_close(fd);
1205 return 0;
1206 } else {
1207 fprintf(stderr, "error: %s\n", adb_error());
1208 return -1;
1209 }
1210 }
1211
1212 /* "adb /?" is a common idiom under Windows */
1213 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1214 help();
1215 return 0;
1216 }
1217
1218 if(!strcmp(argv[0], "version")) {
1219 version(stdout);
1220 return 0;
1221 }
1222
1223 usage();
1224 return 1;
1225}
1226
1227static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1228{
1229 char *argv[16];
1230 int argc;
1231 va_list ap;
1232
1233 va_start(ap, cmd);
1234 argc = 0;
1235
1236 if (serial) {
1237 argv[argc++] = "-s";
1238 argv[argc++] = serial;
1239 } else if (ttype == kTransportUsb) {
1240 argv[argc++] = "-d";
1241 } else if (ttype == kTransportLocal) {
1242 argv[argc++] = "-e";
1243 }
1244
1245 argv[argc++] = cmd;
1246 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1247 va_end(ap);
1248
1249#if 0
1250 int n;
1251 fprintf(stderr,"argc = %d\n",argc);
1252 for(n = 0; n < argc; n++) {
1253 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1254 }
1255#endif
1256
1257 return adb_commandline(argc, argv);
1258}
1259
1260int find_sync_dirs(const char *srcarg,
1261 char **android_srcdir_out, char **data_srcdir_out)
1262{
1263 char *android_srcdir, *data_srcdir;
1264
1265 if(srcarg == NULL) {
1266 android_srcdir = product_file("system");
1267 data_srcdir = product_file("data");
1268 } else {
1269 /* srcarg may be "data", "system" or NULL.
1270 * if srcarg is NULL, then both data and system are synced
1271 */
1272 if(strcmp(srcarg, "system") == 0) {
1273 android_srcdir = product_file("system");
1274 data_srcdir = NULL;
1275 } else if(strcmp(srcarg, "data") == 0) {
1276 android_srcdir = NULL;
1277 data_srcdir = product_file("data");
1278 } else {
1279 /* It's not "system" or "data".
1280 */
1281 return 1;
1282 }
1283 }
1284
1285 if(android_srcdir_out != NULL)
1286 *android_srcdir_out = android_srcdir;
1287 else
1288 free(android_srcdir);
1289
1290 if(data_srcdir_out != NULL)
1291 *data_srcdir_out = data_srcdir;
1292 else
1293 free(data_srcdir);
1294
1295 return 0;
1296}
1297
1298static int pm_command(transport_type transport, char* serial,
1299 int argc, char** argv)
1300{
1301 char buf[4096];
1302
1303 snprintf(buf, sizeof(buf), "shell:pm");
1304
1305 while(argc-- > 0) {
1306 char *quoted;
1307
1308 quoted = dupAndQuote(*argv++);
1309
1310 strncat(buf, " ", sizeof(buf)-1);
1311 strncat(buf, quoted, sizeof(buf)-1);
1312 free(quoted);
1313 }
1314
1315 send_shellcommand(transport, serial, buf);
1316 return 0;
1317}
1318
1319int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1320{
1321 /* if the user choose the -k option, we refuse to do it until devices are
1322 out with the option to uninstall the remaining data somehow (adb/ui) */
1323 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1324 {
1325 printf(
1326 "The -k option uninstalls the application while retaining the data/cache.\n"
1327 "At the moment, there is no way to remove the remaining data.\n"
1328 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1329 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1330 return -1;
1331 }
1332
1333 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1334 return pm_command(transport, serial, argc, argv);
1335}
1336
1337static int delete_file(transport_type transport, char* serial, char* filename)
1338{
1339 char buf[4096];
1340 char* quoted;
1341
1342 snprintf(buf, sizeof(buf), "shell:rm ");
1343 quoted = dupAndQuote(filename);
1344 strncat(buf, quoted, sizeof(buf)-1);
1345 free(quoted);
1346
1347 send_shellcommand(transport, serial, buf);
1348 return 0;
1349}
1350
1351int install_app(transport_type transport, char* serial, int argc, char** argv)
1352{
1353 struct stat st;
1354 int err;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001355 const char *const DATA_DEST = "/data/local/tmp/%s";
1356 const char *const SD_DEST = "/sdcard/tmp/%s";
1357 const char* where = DATA_DEST;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001358 char to[PATH_MAX];
1359 char* filename = argv[argc - 1];
1360 const char* p;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001361 int i;
1362
1363 for (i = 0; i < argc; i++) {
1364 if (!strcmp(argv[i], "-s"))
1365 where = SD_DEST;
1366 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001367
1368 p = adb_dirstop(filename);
1369 if (p) {
1370 p++;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001371 snprintf(to, sizeof to, where, p);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001372 } else {
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001373 snprintf(to, sizeof to, where, filename);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001374 }
1375 if (p[0] == '\0') {
1376 }
1377
1378 err = stat(filename, &st);
1379 if (err != 0) {
1380 fprintf(stderr, "can't find '%s' to install\n", filename);
1381 return 1;
1382 }
1383 if (!S_ISREG(st.st_mode)) {
1384 fprintf(stderr, "can't install '%s' because it's not a file\n",
1385 filename);
1386 return 1;
1387 }
1388
1389 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1390 /* file in place; tell the Package Manager to install it */
1391 argv[argc - 1] = to; /* destination name, not source location */
1392 pm_command(transport, serial, argc, argv);
1393 delete_file(transport, serial, to);
1394 }
1395
1396 return err;
1397}