blob: f8cdbf490e4b8d35b65d2ba2853b9effb4ff0dc2 [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"
101 " Using this ocmmand with no additional arguments\n"
102 " 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"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145 " adb help - show this help message\n"
146 " adb version - show version num\n"
147 "\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800148 "scripting:\n"
149 " adb wait-for-device - block until device is online\n"
150 " adb start-server - ensure that there is a server running\n"
151 " adb kill-server - kill the server if it is running\n"
152 " adb get-state - prints: offline | bootloader | device\n"
153 " adb get-serialno - prints: <serial-number>\n"
154 " adb status-window - continuously print device status for a specified device\n"
155 " adb remount - remounts the /system partition on the device read-write\n"
Mike Lockwoodee156622009-08-04 20:37:51 -0400156 " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
Romain Guy311add42009-12-14 14:42:17 -0800157 " adb reboot-bootloader - reboots the device into the bootloader\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700158 " adb root - restarts the adbd daemon with root permissions\n"
Romain Guy311add42009-12-14 14:42:17 -0800159 " adb usb - restarts the adbd daemon listening on USB\n"
Mike Lockwoodff196702009-08-24 15:58:40 -0700160 " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800161 "\n"
162 "networking:\n"
163 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
Kenny Rootc9891992009-06-08 14:40:30 -0500164 " Note: you should not automatically start a PPP connection.\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
166 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
167 "\n"
168 "adb sync notes: adb sync [ <directory> ]\n"
169 " <localdir> can be interpreted in several ways:\n"
170 "\n"
171 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
172 "\n"
173 " - If it is \"system\" or \"data\", only the corresponding partition\n"
174 " is updated.\n"
Timcd643152010-02-16 20:18:29 +0000175 "\n"
176 "environmental variables:\n"
177 " ADB_TRACE - Print debug information. A comma separated list of the following values\n"
178 " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
179 " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
180 " 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 -0800181 );
182}
183
184int usage()
185{
186 help();
187 return 1;
188}
189
190#ifdef HAVE_TERMIO_H
191static struct termios tio_save;
192
193static void stdin_raw_init(int fd)
194{
195 struct termios tio;
196
197 if(tcgetattr(fd, &tio)) return;
198 if(tcgetattr(fd, &tio_save)) return;
199
200 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
201
202 /* no timeout but request at least one character per read */
203 tio.c_cc[VTIME] = 0;
204 tio.c_cc[VMIN] = 1;
205
206 tcsetattr(fd, TCSANOW, &tio);
207 tcflush(fd, TCIFLUSH);
208}
209
210static void stdin_raw_restore(int fd)
211{
212 tcsetattr(fd, TCSANOW, &tio_save);
213 tcflush(fd, TCIFLUSH);
214}
215#endif
216
217static void read_and_dump(int fd)
218{
219 char buf[4096];
220 int len;
221
222 while(fd >= 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700223 D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224 len = adb_read(fd, buf, 4096);
JP Abgrall408fa572011-03-16 15:57:42 -0700225 D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800226 if(len == 0) {
227 break;
228 }
229
230 if(len < 0) {
231 if(errno == EINTR) continue;
232 break;
233 }
Mike Lockwooddd6b36e2009-09-22 01:18:40 -0400234 fwrite(buf, 1, len, stdout);
235 fflush(stdout);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800236 }
237}
238
Christopher Tated2f54152011-04-21 12:53:28 -0700239static void copy_to_file(int inFd, int outFd) {
240 char buf[4096];
241 int len;
242
243 D("copy_to_file(%d -> %d)\n", inFd, outFd);
244 for (;;) {
245 len = adb_read(inFd, buf, sizeof(buf));
246 if (len == 0) {
247 break;
248 }
249 if (len < 0) {
250 if (errno == EINTR) continue;
251 D("copy_to_file() : error %d\n", errno);
252 break;
253 }
254 adb_write(outFd, buf, len);
255 }
256}
257
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800258static void *stdin_read_thread(void *x)
259{
260 int fd, fdi;
261 unsigned char buf[1024];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800262 int r, n;
263 int state = 0;
264
265 int *fds = (int*) x;
266 fd = fds[0];
267 fdi = fds[1];
268 free(fds);
269
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800270 for(;;) {
271 /* fdi is really the client's stdin, so use read, not adb_read here */
JP Abgrall408fa572011-03-16 15:57:42 -0700272 D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800273 r = unix_read(fdi, buf, 1024);
JP Abgrall408fa572011-03-16 15:57:42 -0700274 D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800275 if(r == 0) break;
276 if(r < 0) {
277 if(errno == EINTR) continue;
278 break;
279 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400280 for(n = 0; n < r; n++){
281 switch(buf[n]) {
282 case '\n':
283 state = 1;
284 break;
285 case '\r':
286 state = 1;
287 break;
288 case '~':
289 if(state == 1) state++;
290 break;
291 case '.':
292 if(state == 2) {
293 fprintf(stderr,"\n* disconnect *\n");
294#ifdef HAVE_TERMIO_H
295 stdin_raw_restore(fdi);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800296#endif
Mike Lockwood67d53582010-05-25 13:40:15 -0400297 exit(0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800298 }
Mike Lockwood67d53582010-05-25 13:40:15 -0400299 default:
300 state = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800302 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800303 r = adb_write(fd, buf, r);
304 if(r <= 0) {
305 break;
306 }
307 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800308 return 0;
309}
310
311int interactive_shell(void)
312{
313 adb_thread_t thr;
314 int fdi, fd;
315 int *fds;
316
317 fd = adb_connect("shell:");
318 if(fd < 0) {
319 fprintf(stderr,"error: %s\n", adb_error());
320 return 1;
321 }
322 fdi = 0; //dup(0);
323
324 fds = malloc(sizeof(int) * 2);
325 fds[0] = fd;
326 fds[1] = fdi;
327
328#ifdef HAVE_TERMIO_H
329 stdin_raw_init(fdi);
330#endif
331 adb_thread_create(&thr, stdin_read_thread, fds);
332 read_and_dump(fd);
333#ifdef HAVE_TERMIO_H
334 stdin_raw_restore(fdi);
335#endif
336 return 0;
337}
338
339
340static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
341{
342 if (serial) {
343 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
344 } else {
345 const char* prefix = "host";
346 if (ttype == kTransportUsb)
347 prefix = "host-usb";
348 else if (ttype == kTransportLocal)
349 prefix = "host-local";
350
351 snprintf(buffer, buflen, "%s:%s", prefix, command);
352 }
353}
354
355static void status_window(transport_type ttype, const char* serial)
356{
357 char command[4096];
358 char *state = 0;
359 char *laststate = 0;
360
361 /* silence stderr */
362#ifdef _WIN32
363 /* XXX: TODO */
364#else
365 int fd;
366 fd = unix_open("/dev/null", O_WRONLY);
367 dup2(fd, 2);
368 adb_close(fd);
369#endif
370
371 format_host_command(command, sizeof command, "get-state", ttype, serial);
372
373 for(;;) {
374 adb_sleep_ms(250);
375
376 if(state) {
377 free(state);
378 state = 0;
379 }
380
381 state = adb_query(command);
382
383 if(state) {
384 if(laststate && !strcmp(state,laststate)){
385 continue;
386 } else {
387 if(laststate) free(laststate);
388 laststate = strdup(state);
389 }
390 }
391
392 printf("%c[2J%c[2H", 27, 27);
393 printf("Android Debug Bridge\n");
394 printf("State: %s\n", state ? state : "offline");
395 fflush(stdout);
396 }
397}
398
399/** duplicate string and quote all \ " ( ) chars + space character. */
400static char *
401dupAndQuote(const char *s)
402{
403 const char *ts;
404 size_t alloc_len;
405 char *ret;
406 char *dest;
407
408 ts = s;
409
410 alloc_len = 0;
411
412 for( ;*ts != '\0'; ts++) {
413 alloc_len++;
414 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
415 alloc_len++;
416 }
417 }
418
419 ret = (char *)malloc(alloc_len + 1);
420
421 ts = s;
422 dest = ret;
423
424 for ( ;*ts != '\0'; ts++) {
425 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
426 *dest++ = '\\';
427 }
428
429 *dest++ = *ts;
430 }
431
432 *dest++ = '\0';
433
434 return ret;
435}
436
437/**
438 * Run ppp in "notty" mode against a resource listed as the first parameter
439 * eg:
440 *
441 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
442 *
443 */
444int ppp(int argc, char **argv)
445{
446#ifdef HAVE_WIN32_PROC
447 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
448 return -1;
449#else
450 char *adb_service_name;
451 pid_t pid;
452 int fd;
453
454 if (argc < 2) {
455 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
456 argv[0]);
457
458 return 1;
459 }
460
461 adb_service_name = argv[1];
462
463 fd = adb_connect(adb_service_name);
464
465 if(fd < 0) {
466 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
467 adb_service_name, adb_error());
468 return 1;
469 }
470
471 pid = fork();
472
473 if (pid < 0) {
474 perror("from fork()");
475 return 1;
476 } else if (pid == 0) {
477 int err;
478 int i;
479 const char **ppp_args;
480
481 // copy args
482 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
483 ppp_args[0] = "pppd";
484 for (i = 2 ; i < argc ; i++) {
485 //argv[2] and beyond become ppp_args[1] and beyond
486 ppp_args[i - 1] = argv[i];
487 }
488 ppp_args[i-1] = NULL;
489
490 // child side
491
492 dup2(fd, STDIN_FILENO);
493 dup2(fd, STDOUT_FILENO);
494 adb_close(STDERR_FILENO);
495 adb_close(fd);
496
497 err = execvp("pppd", (char * const *)ppp_args);
498
499 if (err < 0) {
500 perror("execing pppd");
501 }
502 exit(-1);
503 } else {
504 // parent side
505
506 adb_close(fd);
507 return 0;
508 }
509#endif /* !HAVE_WIN32_PROC */
510}
511
512static int send_shellcommand(transport_type transport, char* serial, char* buf)
513{
514 int fd, ret;
515
516 for(;;) {
517 fd = adb_connect(buf);
518 if(fd >= 0)
519 break;
520 fprintf(stderr,"- waiting for device -\n");
521 adb_sleep_ms(1000);
522 do_cmd(transport, serial, "wait-for-device", 0);
523 }
524
525 read_and_dump(fd);
526 ret = adb_close(fd);
527 if (ret)
528 perror("close");
529
530 return ret;
531}
532
533static int logcat(transport_type transport, char* serial, int argc, char **argv)
534{
535 char buf[4096];
536
537 char *log_tags;
538 char *quoted_log_tags;
539
540 log_tags = getenv("ANDROID_LOG_TAGS");
541 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
542
543 snprintf(buf, sizeof(buf),
544 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
545 quoted_log_tags);
546
547 free(quoted_log_tags);
548
549 argc -= 1;
550 argv += 1;
551 while(argc-- > 0) {
552 char *quoted;
553
554 quoted = dupAndQuote (*argv++);
555
556 strncat(buf, " ", sizeof(buf)-1);
557 strncat(buf, quoted, sizeof(buf)-1);
558 free(quoted);
559 }
560
561 send_shellcommand(transport, serial, buf);
562 return 0;
563}
564
Christopher Tated2f54152011-04-21 12:53:28 -0700565static int backup(int argc, char** argv) {
566 char buf[4096];
567 const char* filename = "./backup.tar";
568 int fd, outFd;
569
570 if (!strcmp("-f", argv[1])) {
571 if (argc < 3) return usage();
572 filename = argv[2];
573 argc -= 2;
574 argv += 2;
575 }
576
577 outFd = adb_open_mode(filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
578 if (outFd < 0) {
579 fprintf(stderr, "adb: unable to open file %s\n", filename);
580 return -1;
581 }
582
583 snprintf(buf, sizeof(buf), "backup");
584 for (argc--, argv++; argc; argc--, argv++) {
585 strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
586 strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
587 }
588
589 D("backup. filename=%s buf=%s\n", filename, buf);
590 fd = adb_connect(buf);
591 if (fd < 0) {
592 fprintf(stderr, "adb: unable to connect for backup\n");
593 adb_close(outFd);
594 return -1;
595 }
596
597 copy_to_file(fd, outFd);
598
599 adb_close(fd);
600 adb_close(outFd);
601 return 0;
602}
603
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800604#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
605static int top_works(const char *top)
606{
607 if (top != NULL && adb_is_absolute_host_path(top)) {
608 char path_buf[PATH_MAX];
609 snprintf(path_buf, sizeof(path_buf),
610 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
611 return access(path_buf, F_OK) == 0;
612 }
613 return 0;
614}
615
616static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
617{
618 strcpy(path_buf, indir);
619 while (1) {
620 if (top_works(path_buf)) {
621 return path_buf;
622 }
623 char *s = adb_dirstop(path_buf);
624 if (s != NULL) {
625 *s = '\0';
626 } else {
627 path_buf[0] = '\0';
628 return NULL;
629 }
630 }
631}
632
633static char *find_top(char path_buf[PATH_MAX])
634{
635 char *top = getenv("ANDROID_BUILD_TOP");
636 if (top != NULL && top[0] != '\0') {
637 if (!top_works(top)) {
638 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
639 return NULL;
640 }
641 } else {
642 top = getenv("TOP");
643 if (top != NULL && top[0] != '\0') {
644 if (!top_works(top)) {
645 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
646 return NULL;
647 }
648 } else {
649 top = NULL;
650 }
651 }
652
653 if (top != NULL) {
654 /* The environment pointed to a top directory that works.
655 */
656 strcpy(path_buf, top);
657 return path_buf;
658 }
659
660 /* The environment didn't help. Walk up the tree from the CWD
661 * to see if we can find the top.
662 */
663 char dir[PATH_MAX];
664 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
665 if (top == NULL) {
666 /* If the CWD isn't under a good-looking top, see if the
667 * executable is.
668 */
Alexey Tarasov31664102009-10-22 02:55:00 +1100669 get_my_path(dir, PATH_MAX);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800670 top = find_top_from(dir, path_buf);
671 }
672 return top;
673}
674
675/* <hint> may be:
676 * - A simple product name
677 * e.g., "sooner"
678TODO: debug? sooner-debug, sooner:debug?
679 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
680 * e.g., "out/target/product/sooner"
681 * - An absolute path to the PRODUCT_OUT dir
682 * e.g., "/src/device/out/target/product/sooner"
683 *
684 * Given <hint>, try to construct an absolute path to the
685 * ANDROID_PRODUCT_OUT dir.
686 */
687static const char *find_product_out_path(const char *hint)
688{
689 static char path_buf[PATH_MAX];
690
691 if (hint == NULL || hint[0] == '\0') {
692 return NULL;
693 }
694
695 /* If it's already absolute, don't bother doing any work.
696 */
697 if (adb_is_absolute_host_path(hint)) {
698 strcpy(path_buf, hint);
699 return path_buf;
700 }
701
702 /* If there are any slashes in it, assume it's a relative path;
703 * make it absolute.
704 */
705 if (adb_dirstart(hint) != NULL) {
706 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
707 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
708 return NULL;
709 }
710 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
711 fprintf(stderr, "adb: Couldn't assemble path\n");
712 return NULL;
713 }
714 strcat(path_buf, OS_PATH_SEPARATOR_STR);
715 strcat(path_buf, hint);
716 return path_buf;
717 }
718
719 /* It's a string without any slashes. Try to do something with it.
720 *
721 * Try to find the root of the build tree, and build a PRODUCT_OUT
722 * path from there.
723 */
724 char top_buf[PATH_MAX];
725 const char *top = find_top(top_buf);
726 if (top == NULL) {
727 fprintf(stderr, "adb: Couldn't find top of build tree\n");
728 return NULL;
729 }
730//TODO: if we have a way to indicate debug, look in out/debug/target/...
731 snprintf(path_buf, sizeof(path_buf),
732 "%s" OS_PATH_SEPARATOR_STR
733 "out" OS_PATH_SEPARATOR_STR
734 "target" OS_PATH_SEPARATOR_STR
735 "product" OS_PATH_SEPARATOR_STR
736 "%s", top_buf, hint);
737 if (access(path_buf, F_OK) < 0) {
738 fprintf(stderr, "adb: Couldn't find a product dir "
739 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
740 return NULL;
741 }
742 return path_buf;
743}
744
745int adb_commandline(int argc, char **argv)
746{
747 char buf[4096];
748 int no_daemon = 0;
749 int is_daemon = 0;
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100750 int is_server = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800751 int persist = 0;
752 int r;
753 int quote;
754 transport_type ttype = kTransportAny;
755 char* serial = NULL;
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100756 char* server_port_str = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800757
758 /* If defined, this should be an absolute path to
759 * the directory containing all of the various system images
760 * for a particular product. If not defined, and the adb
761 * command requires this information, then the user must
762 * specify the path using "-p".
763 */
764 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
765 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
766 gProductOutPath = NULL;
767 }
768 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
769
Nick Pellydb449262009-05-07 12:48:03 -0700770 serial = getenv("ANDROID_SERIAL");
771
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100772 /* Validate and assign the server port */
773 server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
774 int server_port = DEFAULT_ADB_PORT;
775 if (server_port_str && strlen(server_port_str) > 0) {
776 server_port = (int) strtol(server_port_str, NULL, 0);
777 if (server_port <= 0) {
778 fprintf(stderr,
779 "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
780 server_port_str);
781 return usage();
782 }
783 }
784
785 /* modifiers and flags */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800786 while(argc > 0) {
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100787 if(!strcmp(argv[0],"server")) {
788 is_server = 1;
789 } else if(!strcmp(argv[0],"nodaemon")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800790 no_daemon = 1;
791 } else if (!strcmp(argv[0], "fork-server")) {
792 /* this is a special flag used only when the ADB client launches the ADB Server */
793 is_daemon = 1;
794 } else if(!strcmp(argv[0],"persist")) {
795 persist = 1;
796 } else if(!strncmp(argv[0], "-p", 2)) {
797 const char *product = NULL;
798 if (argv[0][2] == '\0') {
799 if (argc < 2) return usage();
800 product = argv[1];
801 argc--;
802 argv++;
803 } else {
804 product = argv[1] + 2;
805 }
806 gProductOutPath = find_product_out_path(product);
807 if (gProductOutPath == NULL) {
808 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
809 product);
810 return usage();
811 }
812 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
813 if (isdigit(argv[0][2])) {
814 serial = argv[0] + 2;
815 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100816 if(argc < 2 || argv[0][2] != '\0') return usage();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800817 serial = argv[1];
818 argc--;
819 argv++;
820 }
821 } else if (!strcmp(argv[0],"-d")) {
822 ttype = kTransportUsb;
823 } else if (!strcmp(argv[0],"-e")) {
824 ttype = kTransportLocal;
825 } else {
826 /* out of recognized modifiers and flags */
827 break;
828 }
829 argc--;
830 argv++;
831 }
832
833 adb_set_transport(ttype, serial);
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100834 adb_set_tcp_specifics(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800835
David 'Digit' Turner305b4b02011-01-31 14:23:56 +0100836 if (is_server) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 if (no_daemon || is_daemon) {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100838 r = adb_main(is_daemon, server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800839 } else {
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100840 r = launch_server(server_port);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800841 }
842 if(r) {
843 fprintf(stderr,"* could not start server *\n");
844 }
845 return r;
846 }
847
848top:
849 if(argc == 0) {
850 return usage();
851 }
852
853 /* adb_connect() commands */
854
855 if(!strcmp(argv[0], "devices")) {
856 char *tmp;
857 snprintf(buf, sizeof buf, "host:%s", argv[0]);
858 tmp = adb_query(buf);
859 if(tmp) {
860 printf("List of devices attached \n");
861 printf("%s\n", tmp);
862 return 0;
863 } else {
864 return 1;
865 }
866 }
867
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400868 if(!strcmp(argv[0], "connect")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700869 char *tmp;
870 if (argc != 2) {
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400871 fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
Mike Lockwoodff196702009-08-24 15:58:40 -0700872 return 1;
873 }
Mike Lockwoodcbbe79a2010-05-24 10:44:35 -0400874 snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
875 tmp = adb_query(buf);
876 if(tmp) {
877 printf("%s\n", tmp);
878 return 0;
879 } else {
880 return 1;
881 }
882 }
883
884 if(!strcmp(argv[0], "disconnect")) {
885 char *tmp;
886 if (argc > 2) {
887 fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
888 return 1;
889 }
890 if (argc == 2) {
891 snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
892 } else {
893 snprintf(buf, sizeof buf, "host:disconnect:");
894 }
Mike Lockwoodff196702009-08-24 15:58:40 -0700895 tmp = adb_query(buf);
896 if(tmp) {
897 printf("%s\n", tmp);
898 return 0;
899 } else {
900 return 1;
901 }
902 }
903
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800904 if (!strcmp(argv[0], "emu")) {
905 return adb_send_emulator_command(argc, argv);
906 }
907
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400908 if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800909 int r;
910 int fd;
911
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400912 char h = (argv[0][0] == 'h');
913
914 if (h) {
915 printf("\x1b[41;33m");
916 fflush(stdout);
917 }
918
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800919 if(argc < 2) {
JP Abgrall408fa572011-03-16 15:57:42 -0700920 D("starting interactive shell\n");
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400921 r = interactive_shell();
922 if (h) {
923 printf("\x1b[0m");
924 fflush(stdout);
925 }
926 return r;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800927 }
928
929 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
930 argc -= 2;
931 argv += 2;
932 while(argc-- > 0) {
933 strcat(buf, " ");
934
935 /* quote empty strings and strings with spaces */
936 quote = (**argv == 0 || strchr(*argv, ' '));
937 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100938 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800939 strcat(buf, *argv++);
940 if (quote)
Stefan Hilzingera84a42e2010-04-19 12:21:12 +0100941 strcat(buf, "\"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800942 }
943
944 for(;;) {
JP Abgrall408fa572011-03-16 15:57:42 -0700945 D("interactive shell loop. buff=%s\n", buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946 fd = adb_connect(buf);
947 if(fd >= 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700948 D("about to read_and_dump(fd=%d)\n", fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800949 read_and_dump(fd);
JP Abgrall408fa572011-03-16 15:57:42 -0700950 D("read_and_dump() done.\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800951 adb_close(fd);
952 r = 0;
953 } else {
954 fprintf(stderr,"error: %s\n", adb_error());
955 r = -1;
956 }
957
958 if(persist) {
959 fprintf(stderr,"\n- waiting for device -\n");
960 adb_sleep_ms(1000);
961 do_cmd(ttype, serial, "wait-for-device", 0);
962 } else {
Daniel Sandlerff91ab82010-08-19 01:10:18 -0400963 if (h) {
964 printf("\x1b[0m");
965 fflush(stdout);
966 }
JP Abgrall408fa572011-03-16 15:57:42 -0700967 D("interactive shell loop. return r=%d\n", r);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800968 return r;
969 }
970 }
971 }
972
973 if(!strcmp(argv[0], "kill-server")) {
974 int fd;
975 fd = _adb_connect("host:kill");
976 if(fd == -1) {
977 fprintf(stderr,"* server not running *\n");
978 return 1;
979 }
980 return 0;
981 }
982
Mike Lockwoodff196702009-08-24 15:58:40 -0700983 if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
Romain Guy311add42009-12-14 14:42:17 -0800984 || !strcmp(argv[0], "reboot-bootloader")
Mike Lockwoodff196702009-08-24 15:58:40 -0700985 || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
Mike Lockwoodf56d1b52009-09-03 14:54:58 -0400986 || !strcmp(argv[0], "root")) {
Mike Lockwoodff196702009-08-24 15:58:40 -0700987 char command[100];
Romain Guy311add42009-12-14 14:42:17 -0800988 if (!strcmp(argv[0], "reboot-bootloader"))
989 snprintf(command, sizeof(command), "reboot:bootloader");
990 else if (argc > 1)
Mike Lockwoodff196702009-08-24 15:58:40 -0700991 snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
Mike Lockwoodee156622009-08-04 20:37:51 -0400992 else
Mike Lockwoodff196702009-08-24 15:58:40 -0700993 snprintf(command, sizeof(command), "%s:", argv[0]);
994 int fd = adb_connect(command);
The Android Open Source Projecte037fd72009-03-13 13:04:37 -0700995 if(fd >= 0) {
996 read_and_dump(fd);
997 adb_close(fd);
998 return 0;
999 }
1000 fprintf(stderr,"error: %s\n", adb_error());
1001 return 1;
1002 }
1003
Mike Lockwoodf56d1b52009-09-03 14:54:58 -04001004 if(!strcmp(argv[0], "bugreport")) {
Dan Egnorc130ea72010-01-20 13:50:36 -08001005 if (argc != 1) return usage();
1006 do_cmd(ttype, serial, "shell", "bugreport", 0);
Mike Lockwoodf56d1b52009-09-03 14:54:58 -04001007 return 0;
1008 }
1009
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001010 /* adb_command() wrapper commands */
1011
1012 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
1013 char* service = argv[0];
1014 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
1015 if (ttype == kTransportUsb) {
1016 service = "wait-for-usb";
1017 } else if (ttype == kTransportLocal) {
1018 service = "wait-for-local";
1019 } else {
1020 service = "wait-for-any";
1021 }
1022 }
1023
1024 format_host_command(buf, sizeof buf, service, ttype, serial);
1025
1026 if (adb_command(buf)) {
1027 D("failure: %s *\n",adb_error());
1028 fprintf(stderr,"error: %s\n", adb_error());
1029 return 1;
1030 }
1031
1032 /* Allow a command to be run after wait-for-device,
1033 * e.g. 'adb wait-for-device shell'.
1034 */
1035 if(argc > 1) {
1036 argc--;
1037 argv++;
1038 goto top;
1039 }
1040 return 0;
1041 }
1042
1043 if(!strcmp(argv[0], "forward")) {
1044 if(argc != 3) return usage();
1045 if (serial) {
Mike Lockwood64e99542009-11-28 12:46:13 -05001046 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
1047 } else if (ttype == kTransportUsb) {
1048 snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
1049 } else if (ttype == kTransportLocal) {
1050 snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001051 } else {
Mike Lockwood64e99542009-11-28 12:46:13 -05001052 snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001053 }
1054 if(adb_command(buf)) {
1055 fprintf(stderr,"error: %s\n", adb_error());
1056 return 1;
1057 }
1058 return 0;
1059 }
1060
1061 /* do_sync_*() commands */
1062
1063 if(!strcmp(argv[0], "ls")) {
1064 if(argc != 2) return usage();
1065 return do_sync_ls(argv[1]);
1066 }
1067
1068 if(!strcmp(argv[0], "push")) {
1069 if(argc != 3) return usage();
1070 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
1071 }
1072
1073 if(!strcmp(argv[0], "pull")) {
Joe Onorato00c0eea2010-01-05 13:42:25 -08001074 if (argc == 2) {
1075 return do_sync_pull(argv[1], ".");
1076 } else if (argc == 3) {
1077 return do_sync_pull(argv[1], argv[2]);
1078 } else {
1079 return usage();
1080 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001081 }
1082
1083 if(!strcmp(argv[0], "install")) {
1084 if (argc < 2) return usage();
1085 return install_app(ttype, serial, argc, argv);
1086 }
1087
1088 if(!strcmp(argv[0], "uninstall")) {
1089 if (argc < 2) return usage();
1090 return uninstall_app(ttype, serial, argc, argv);
1091 }
1092
1093 if(!strcmp(argv[0], "sync")) {
1094 char *srcarg, *android_srcpath, *data_srcpath;
Anthony Newnam705c9442010-02-22 08:36:49 -06001095 int listonly = 0;
1096
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001097 int ret;
1098 if(argc < 2) {
1099 /* No local path was specified. */
1100 srcarg = NULL;
Anthony Newnam705c9442010-02-22 08:36:49 -06001101 } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
1102 listonly = 1;
1103 if (argc == 3) {
1104 srcarg = argv[2];
1105 } else {
1106 srcarg = NULL;
1107 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001108 } else if(argc == 2) {
1109 /* A local path or "android"/"data" arg was specified. */
1110 srcarg = argv[1];
1111 } else {
1112 return usage();
1113 }
1114 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1115 if(ret != 0) return usage();
1116
1117 if(android_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001118 ret = do_sync_sync(android_srcpath, "/system", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001119 if(ret == 0 && data_srcpath != NULL)
Anthony Newnam705c9442010-02-22 08:36:49 -06001120 ret = do_sync_sync(data_srcpath, "/data", listonly);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001121
1122 free(android_srcpath);
1123 free(data_srcpath);
1124 return ret;
1125 }
1126
1127 /* passthrough commands */
1128
1129 if(!strcmp(argv[0],"get-state") ||
1130 !strcmp(argv[0],"get-serialno"))
1131 {
1132 char *tmp;
1133
1134 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1135 tmp = adb_query(buf);
1136 if(tmp) {
1137 printf("%s\n", tmp);
1138 return 0;
1139 } else {
1140 return 1;
1141 }
1142 }
1143
1144 /* other commands */
1145
1146 if(!strcmp(argv[0],"status-window")) {
1147 status_window(ttype, serial);
1148 return 0;
1149 }
1150
1151 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1152 return logcat(ttype, serial, argc, argv);
1153 }
1154
1155 if(!strcmp(argv[0],"ppp")) {
1156 return ppp(argc, argv);
1157 }
1158
1159 if (!strcmp(argv[0], "start-server")) {
1160 return adb_connect("host:start-server");
1161 }
1162
Christopher Tated2f54152011-04-21 12:53:28 -07001163 if (!strcmp(argv[0], "backup")) {
1164 return backup(argc, argv);
1165 }
1166
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001167 if (!strcmp(argv[0], "jdwp")) {
1168 int fd = adb_connect("jdwp");
1169 if (fd >= 0) {
1170 read_and_dump(fd);
1171 adb_close(fd);
1172 return 0;
1173 } else {
1174 fprintf(stderr, "error: %s\n", adb_error());
1175 return -1;
1176 }
1177 }
1178
1179 /* "adb /?" is a common idiom under Windows */
1180 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1181 help();
1182 return 0;
1183 }
1184
1185 if(!strcmp(argv[0], "version")) {
1186 version(stdout);
1187 return 0;
1188 }
1189
1190 usage();
1191 return 1;
1192}
1193
1194static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1195{
1196 char *argv[16];
1197 int argc;
1198 va_list ap;
1199
1200 va_start(ap, cmd);
1201 argc = 0;
1202
1203 if (serial) {
1204 argv[argc++] = "-s";
1205 argv[argc++] = serial;
1206 } else if (ttype == kTransportUsb) {
1207 argv[argc++] = "-d";
1208 } else if (ttype == kTransportLocal) {
1209 argv[argc++] = "-e";
1210 }
1211
1212 argv[argc++] = cmd;
1213 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1214 va_end(ap);
1215
1216#if 0
1217 int n;
1218 fprintf(stderr,"argc = %d\n",argc);
1219 for(n = 0; n < argc; n++) {
1220 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1221 }
1222#endif
1223
1224 return adb_commandline(argc, argv);
1225}
1226
1227int find_sync_dirs(const char *srcarg,
1228 char **android_srcdir_out, char **data_srcdir_out)
1229{
1230 char *android_srcdir, *data_srcdir;
1231
1232 if(srcarg == NULL) {
1233 android_srcdir = product_file("system");
1234 data_srcdir = product_file("data");
1235 } else {
1236 /* srcarg may be "data", "system" or NULL.
1237 * if srcarg is NULL, then both data and system are synced
1238 */
1239 if(strcmp(srcarg, "system") == 0) {
1240 android_srcdir = product_file("system");
1241 data_srcdir = NULL;
1242 } else if(strcmp(srcarg, "data") == 0) {
1243 android_srcdir = NULL;
1244 data_srcdir = product_file("data");
1245 } else {
1246 /* It's not "system" or "data".
1247 */
1248 return 1;
1249 }
1250 }
1251
1252 if(android_srcdir_out != NULL)
1253 *android_srcdir_out = android_srcdir;
1254 else
1255 free(android_srcdir);
1256
1257 if(data_srcdir_out != NULL)
1258 *data_srcdir_out = data_srcdir;
1259 else
1260 free(data_srcdir);
1261
1262 return 0;
1263}
1264
1265static int pm_command(transport_type transport, char* serial,
1266 int argc, char** argv)
1267{
1268 char buf[4096];
1269
1270 snprintf(buf, sizeof(buf), "shell:pm");
1271
1272 while(argc-- > 0) {
1273 char *quoted;
1274
1275 quoted = dupAndQuote(*argv++);
1276
1277 strncat(buf, " ", sizeof(buf)-1);
1278 strncat(buf, quoted, sizeof(buf)-1);
1279 free(quoted);
1280 }
1281
1282 send_shellcommand(transport, serial, buf);
1283 return 0;
1284}
1285
1286int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1287{
1288 /* if the user choose the -k option, we refuse to do it until devices are
1289 out with the option to uninstall the remaining data somehow (adb/ui) */
1290 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1291 {
1292 printf(
1293 "The -k option uninstalls the application while retaining the data/cache.\n"
1294 "At the moment, there is no way to remove the remaining data.\n"
1295 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1296 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1297 return -1;
1298 }
1299
1300 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1301 return pm_command(transport, serial, argc, argv);
1302}
1303
1304static int delete_file(transport_type transport, char* serial, char* filename)
1305{
1306 char buf[4096];
1307 char* quoted;
1308
1309 snprintf(buf, sizeof(buf), "shell:rm ");
1310 quoted = dupAndQuote(filename);
1311 strncat(buf, quoted, sizeof(buf)-1);
1312 free(quoted);
1313
1314 send_shellcommand(transport, serial, buf);
1315 return 0;
1316}
1317
1318int install_app(transport_type transport, char* serial, int argc, char** argv)
1319{
1320 struct stat st;
1321 int err;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001322 const char *const DATA_DEST = "/data/local/tmp/%s";
1323 const char *const SD_DEST = "/sdcard/tmp/%s";
1324 const char* where = DATA_DEST;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001325 char to[PATH_MAX];
1326 char* filename = argv[argc - 1];
1327 const char* p;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001328 int i;
1329
1330 for (i = 0; i < argc; i++) {
1331 if (!strcmp(argv[i], "-s"))
1332 where = SD_DEST;
1333 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001334
1335 p = adb_dirstop(filename);
1336 if (p) {
1337 p++;
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001338 snprintf(to, sizeof to, where, p);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001339 } else {
Mike Lockwood0ef3fd02010-02-19 17:53:27 -05001340 snprintf(to, sizeof to, where, filename);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001341 }
1342 if (p[0] == '\0') {
1343 }
1344
1345 err = stat(filename, &st);
1346 if (err != 0) {
1347 fprintf(stderr, "can't find '%s' to install\n", filename);
1348 return 1;
1349 }
1350 if (!S_ISREG(st.st_mode)) {
1351 fprintf(stderr, "can't install '%s' because it's not a file\n",
1352 filename);
1353 return 1;
1354 }
1355
1356 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1357 /* file in place; tell the Package Manager to install it */
1358 argv[argc - 1] = to; /* destination name, not source location */
1359 pm_command(transport, serial, argc, argv);
1360 delete_file(transport, serial, to);
1361 }
1362
1363 return err;
1364}