From 702967afb1bebc97c0b8a23c075d4932820ef7a3 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 May 2011 15:52:54 -0700 Subject: [PATCH] Add 'adb restore' to parallel 'adb backup' It won't actually do anything until the 'bu' tool and framework are updated to respond properly, but this is the adb side of the necessary infrastructure: we copy the tarfile into the socket pointed at the device, using the existing mechanisms. Change-Id: Ic3b5779ade256bd1ad989a94b0685f7b1a7d59d2 --- adb/Android.mk | 1 - adb/adb.h | 6 +++++- adb/backup_service.c | 43 +++++++++++++++++++++++++++---------------- adb/commandline.c | 33 +++++++++++++++++++++++++++++++++ adb/services.c | 4 +++- 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/adb/Android.mk b/adb/Android.mk index e893ca91e..2ac933536 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -165,7 +165,6 @@ LOCAL_LDLIBS := -lrt -lncurses -lpthread LOCAL_SRC_FILES := \ adb.c \ - backup_service.c \ console.c \ transport.c \ transport_local.c \ diff --git a/adb/adb.h b/adb/adb.h index 318a2d8b2..92dc62efa 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -304,7 +304,11 @@ int create_jdwp_connection_fd(int jdwp_pid); #endif #if !ADB_HOST -int backup_service(char* args); +typedef enum { + BACKUP, + RESTORE +} BackupOperation; +int backup_service(BackupOperation operation, char* args); void framebuffer_service(int fd, void *cookie); void log_service(int fd, void *cookie); void remount_service(int fd, void *cookie); diff --git a/adb/backup_service.c b/adb/backup_service.c index 1e55efc74..2e6e75463 100644 --- a/adb/backup_service.c +++ b/adb/backup_service.c @@ -23,17 +23,28 @@ #include "adb.h" /* returns the data socket passing the backup data here for forwarding */ -int backup_service(char* args) { +int backup_service(BackupOperation op, char* args) { pid_t pid; int s[2]; + char* operation; + int socketnum; - D("backup_service(%s)\n", args); + // Command string and choice of stdin/stdout for the pipe depend on our invocation + if (op == BACKUP) { + operation = "backup"; + socketnum = STDOUT_FILENO; + } else { + operation = "restore"; + socketnum = STDIN_FILENO; + } + + D("backup_service(%s, %s)\n", operation, args); // set up the pipe from the subprocess to here // parent will read s[0]; child will write s[1] if (adb_socketpair(s)) { - D("can't create backup socketpair\n"); - fprintf(stderr, "unable to create backup socketpair\n"); + D("can't create backup/restore socketpair\n"); + fprintf(stderr, "unable to create backup/restore socketpair\n"); return -1; } @@ -41,8 +52,8 @@ int backup_service(char* args) { pid = fork(); if (pid < 0) { // failure - D("can't fork for backup\n"); - fprintf(stderr, "unable to fork for backup\n"); + D("can't fork for %s\n", operation); + fprintf(stderr, "unable to fork for %s\n", operation); adb_close(s[0]); adb_close(s[1]); return -1; @@ -52,37 +63,37 @@ int backup_service(char* args) { if (pid == 0) { char* p; int argc; - char** backup_args; + char** bu_args; // child -- actually run the backup here - argc = 2; // room for the basic 'bu' argv[0] and 'backup' argv[1] + argc = 2; // room for the basic 'bu' argv[0] and '[operation]' argv[1] for (p = (char*)args; p && *p; ) { argc++; while (*p && *p != ':') p++; if (*p == ':') p++; } - backup_args = (char**) alloca(argc*sizeof(char*) + 1); - backup_args[0] = "bu"; - backup_args[1] = "backup"; + bu_args = (char**) alloca(argc*sizeof(char*) + 1); + bu_args[0] = "bu"; + bu_args[1] = operation; argc = 2; // run through again to build the argv array - for (p = (char*)args; *p; ) { - backup_args[argc++] = p; + for (p = (char*)args; p && *p; ) { + bu_args[argc++] = p; while (*p && *p != ':') p++; if (*p == ':') { *p = 0; p++; } } - backup_args[argc] = NULL; + bu_args[argc] = NULL; // Close the half of the socket that we don't care about, route 'bu's console // to the output socket, and off we go adb_close(s[0]); - dup2(s[1], STDOUT_FILENO); + dup2(s[1], socketnum); // off we go - execvp("/system/bin/bu", (char * const *)backup_args); + execvp("/system/bin/bu", (char * const *)bu_args); // oops error - close up shop and go home fprintf(stderr, "Unable to exec 'bu', bailing\n"); exit(-1); diff --git a/adb/commandline.c b/adb/commandline.c index 733cbffee..460120e8a 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -142,6 +142,8 @@ void help() " the -all or -shared flags are passed, then the package\n" " list is optional.)\n" "\n" + " adb restore - restore device contents from the backup tarfile\n" + "\n" " adb help - show this help message\n" " adb version - show version num\n" "\n" @@ -601,6 +603,33 @@ static int backup(int argc, char** argv) { return 0; } +static int restore(int argc, char** argv) { + const char* filename; + int fd, tarFd; + + if (argc != 2) return usage(); + + filename = argv[1]; + tarFd = adb_open(filename, O_RDONLY); + if (tarFd < 0) { + fprintf(stderr, "adb: unable to open file %s\n", filename); + return -1; + } + + fd = adb_connect("restore:"); + if (fd < 0) { + fprintf(stderr, "adb: unable to connect for backup\n"); + adb_close(tarFd); + return -1; + } + + copy_to_file(tarFd, fd); + + adb_close(fd); + adb_close(tarFd); + return 0; +} + #define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make" static int top_works(const char *top) { @@ -1164,6 +1193,10 @@ top: return backup(argc, argv); } + if (!strcmp(argv[0], "restore")) { + return restore(argc, argv); + } + if (!strcmp(argv[0], "jdwp")) { int fd = adb_connect("jdwp"); if (fd >= 0) { diff --git a/adb/services.c b/adb/services.c index ec0b0bad0..6bbd6f882 100644 --- a/adb/services.c +++ b/adb/services.c @@ -482,7 +482,9 @@ int service_to_fd(const char *name) } else if(!strncmp(name, "backup:", 7)) { char* arg = strdup(name+7); if (arg == NULL) return -1; - ret = backup_service(arg); + ret = backup_service(BACKUP, arg); + } else if(!strncmp(name, "restore:", 8)) { + ret = backup_service(RESTORE, NULL); } else if(!strncmp(name, "tcpip:", 6)) { int port; if (sscanf(name + 6, "%d", &port) == 0) {