Merge changes I5b1a1ce0,I483a18f9

* changes:
  fastboot: Add 'get_staged' command
  fastboot: Add 'stage' command
diff --git a/fastboot/README.md b/fastboot/README.md
index 022d34b..ec7dcb4 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -126,6 +126,16 @@
                        space in RAM or "FAIL" if not.  The size of
                        the download is remembered.
 
+    upload             Read data from memory which was staged by the last
+                       command, e.g. an oem command.  The client will reply
+                       with "DATA%08x" if it is ready to send %08x bytes of
+                       data.  If no data was staged in the last command,
+                       the client must reply with "FAIL".  After the client
+                       successfully sends %08x bytes, the client shall send
+                       a single packet starting with "OKAY".  Clients
+                       should not support "upload" unless it supports an
+                       oem command that requires "upload" capabilities.
+
     verify:%08x        Send a digital signature to verify the downloaded
                        data.  Required if the bootloader is "secure"
                        otherwise "flash" and "boot" will be ignored.
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index bf887c9..56ee816 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -45,6 +45,7 @@
 #define OP_DOWNLOAD_SPARSE 5
 #define OP_WAIT_FOR_DISCONNECT 6
 #define OP_DOWNLOAD_FD 7
+#define OP_UPLOAD 8
 
 typedef struct Action Action;
 
@@ -332,6 +333,22 @@
     a->msg = mkmsg("downloading '%s'", name);
 }
 
+void fb_queue_download_fd(const char *name, int fd, uint32_t sz)
+{
+    Action *a;
+    a = queue_action(OP_DOWNLOAD_FD, "");
+    a->fd = fd;
+    a->size = sz;
+    a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
+}
+
+void fb_queue_upload(char *outfile)
+{
+    Action *a = queue_action(OP_UPLOAD, "");
+    a->data = outfile;
+    a->msg = mkmsg("uploading '%s'", outfile);
+}
+
 void fb_queue_notice(const char *notice)
 {
     Action *a = queue_action(OP_NOTICE, "");
@@ -386,6 +403,9 @@
             if (status) break;
         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
             transport->WaitForDisconnect();
+        } else if (a->op == OP_UPLOAD) {
+            status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
         } else {
             die("bogus action");
         }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 332b355..982545c 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -371,6 +371,13 @@
             "  continue                                 Continue with autoboot.\n"
             "  reboot [bootloader|emergency]            Reboot device [into bootloader or emergency mode].\n"
             "  reboot-bootloader                        Reboot device into bootloader.\n"
+            "  oem <parameter1> ... <parameterN>        Executes oem specific command.\n"
+            "  stage <infile>                           Sends contents of <infile> to stage for\n"
+            "                                           the next command. Supported only on\n"
+            "                                           Android Things devices.\n"
+            "  get_staged <outfile>                     Receives data to <outfile> staged by the\n"
+            "                                           last command. Supported only on Android\n"
+            "                                           Things devices.\n"
             "  help                                     Show this help message.\n"
             "\n"
             "options:\n"
@@ -1823,6 +1830,20 @@
             }
             fb_set_active(slot.c_str());
             skip(2);
+        } else if(!strcmp(*argv, "stage")) {
+            require(2);
+            std::string infile(argv[1]);
+            skip(2);
+            struct fastboot_buffer buf;
+            if (!load_buf(transport, infile.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
+                die("cannot load '%s'", infile.c_str());
+            }
+            fb_queue_download_fd(infile.c_str(), buf.fd, buf.sz);
+        } else if(!strcmp(*argv, "get_staged")) {
+            require(2);
+            char *outfile = argv[1];
+            skip(2);
+            fb_queue_upload(outfile);
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
         } else if(!strcmp(*argv, "flashing")) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 3f95270..e30c6de 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -44,6 +44,7 @@
 int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
 int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size);
 int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
+int64_t fb_upload_data(Transport* transport, const char* outfile);
 const std::string fb_get_error();
 
 #define FB_COMMAND_SZ 64
@@ -64,6 +65,8 @@
 void fb_queue_reboot(void);
 void fb_queue_command(const char *cmd, const char *msg);
 void fb_queue_download(const char *name, void *data, uint32_t size);
+void fb_queue_download_fd(const char *name, int fd, uint32_t sz);
+void fb_queue_upload(char *outfile);
 void fb_queue_notice(const char *notice);
 void fb_queue_wait_for_disconnect(void);
 int64_t fb_execute_queue(Transport* transport);
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 334f81f..dcdf8f0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -29,14 +29,18 @@
 #define round_down(a, b) \
     ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
 
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
 #include <algorithm>
+#include <vector>
 
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <sparse/sparse.h>
 #include <utils/FileMap.h>
 
@@ -45,6 +49,9 @@
 
 static std::string g_error;
 
+using android::base::unique_fd;
+using android::base::WriteStringToFile;
+
 const std::string fb_get_error() {
     return g_error;
 }
@@ -126,15 +133,30 @@
     return check_response(transport, size, response);
 }
 
-static int64_t _command_data(Transport* transport, const void* data, uint32_t size) {
+static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
     int64_t r = transport->Write(data, size);
     if (r < 0) {
-        g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
+        g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
     if (r != static_cast<int64_t>(size)) {
-        g_error = "data transfer failure (short transfer)";
+        g_error = "data write failure (short transfer)";
+        transport->Close();
+        return -1;
+    }
+    return r;
+}
+
+static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
+    int64_t r = transport->Read(data, size);
+    if (r < 0) {
+        g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
+        transport->Close();
+        return -1;
+    }
+    if (r != (static_cast<int64_t>(size))) {
+        g_error = "data read failure (short transfer)";
         transport->Close();
         return -1;
     }
@@ -155,8 +177,7 @@
     if (r < 0) {
         return -1;
     }
-
-    r = _command_data(transport, data, size);
+    r = _command_write_data(transport, data, size);
     if (r < 0) {
         return -1;
     }
@@ -187,7 +208,7 @@
             return -1;
         }
 
-        if (_command_data(transport, filemap.getDataPtr(), len) < 0) {
+        if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
             return -1;
         }
 
@@ -224,6 +245,28 @@
     return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
 }
 
+int64_t fb_upload_data(Transport* transport, const char* outfile) {
+    // positive return value is the upload size sent by the device
+    int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr);
+    if (r <= 0) {
+        g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
+        return r;
+    }
+
+    std::string data;
+    data.resize(r);
+    if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
+        return r;
+    }
+
+    if (!WriteStringToFile(data, outfile, true)) {
+        g_error = android::base::StringPrintf("write to '%s' failed", outfile);
+        return -1;
+    }
+
+    return _command_end(transport);
+}
+
 #define TRANSPORT_BUF_SIZE 1024
 static char transport_buf[TRANSPORT_BUF_SIZE];
 static int transport_buf_len;
@@ -245,7 +288,7 @@
     }
 
     if (transport_buf_len == TRANSPORT_BUF_SIZE) {
-        r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
+        r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
         if (r != TRANSPORT_BUF_SIZE) {
             return -1;
         }
@@ -258,7 +301,7 @@
             return -1;
         }
         to_write = round_down(len, TRANSPORT_BUF_SIZE);
-        r = _command_data(transport, ptr, to_write);
+        r = _command_write_data(transport, ptr, to_write);
         if (r != to_write) {
             return -1;
         }
@@ -280,7 +323,7 @@
 
 static int fb_download_data_sparse_flush(Transport* transport) {
     if (transport_buf_len > 0) {
-        int64_t r = _command_data(transport, transport_buf, transport_buf_len);
+        int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
         if (r != static_cast<int64_t>(transport_buf_len)) {
             return -1;
         }