Home | History | Annotate | Download | only in fastboot
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #define round_down(a, b) \
     30     ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
     31 
     32 #include <fcntl.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <errno.h>
     37 
     38 #include <algorithm>
     39 #include <vector>
     40 
     41 #include <android-base/file.h>
     42 #include <android-base/stringprintf.h>
     43 #include <android-base/unique_fd.h>
     44 #include <sparse/sparse.h>
     45 #include <utils/FileMap.h>
     46 
     47 #include "fastboot.h"
     48 #include "transport.h"
     49 
     50 static std::string g_error;
     51 
     52 using android::base::unique_fd;
     53 using android::base::WriteStringToFile;
     54 
     55 const std::string fb_get_error() {
     56     return g_error;
     57 }
     58 
     59 static int64_t check_response(Transport* transport, uint32_t size, char* response) {
     60     char status[65];
     61 
     62     while (true) {
     63         int r = transport->Read(status, 64);
     64         if (r < 0) {
     65             g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
     66             transport->Close();
     67             return -1;
     68         }
     69         status[r] = 0;
     70 
     71         if (r < 4) {
     72             g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
     73             transport->Close();
     74             return -1;
     75         }
     76 
     77         if (!memcmp(status, "INFO", 4)) {
     78             fprintf(stderr,"(bootloader) %s\n", status + 4);
     79             continue;
     80         }
     81 
     82         if (!memcmp(status, "OKAY", 4)) {
     83             if (response) {
     84                 strcpy(response, (char*) status + 4);
     85             }
     86             return 0;
     87         }
     88 
     89         if (!memcmp(status, "FAIL", 4)) {
     90             if (r > 4) {
     91                 g_error = android::base::StringPrintf("remote: %s", status + 4);
     92             } else {
     93                 g_error = "remote failure";
     94             }
     95             return -1;
     96         }
     97 
     98         if (!memcmp(status, "DATA", 4) && size > 0){
     99             uint32_t dsize = strtol(status + 4, 0, 16);
    100             if (dsize > size) {
    101                 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
    102                 transport->Close();
    103                 return -1;
    104             }
    105             return dsize;
    106         }
    107 
    108         g_error = "unknown status code";
    109         transport->Close();
    110         break;
    111     }
    112 
    113     return -1;
    114 }
    115 
    116 static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
    117                               char* response) {
    118     if (cmd.size() > 64) {
    119         g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
    120         return -1;
    121     }
    122 
    123     if (response) {
    124         response[0] = 0;
    125     }
    126 
    127     if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
    128         g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
    129         transport->Close();
    130         return -1;
    131     }
    132 
    133     return check_response(transport, size, response);
    134 }
    135 
    136 static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
    137     int64_t r = transport->Write(data, size);
    138     if (r < 0) {
    139         g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
    140         transport->Close();
    141         return -1;
    142     }
    143     if (r != static_cast<int64_t>(size)) {
    144         g_error = "data write failure (short transfer)";
    145         transport->Close();
    146         return -1;
    147     }
    148     return r;
    149 }
    150 
    151 static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
    152     int64_t r = transport->Read(data, size);
    153     if (r < 0) {
    154         g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
    155         transport->Close();
    156         return -1;
    157     }
    158     if (r != (static_cast<int64_t>(size))) {
    159         g_error = "data read failure (short transfer)";
    160         transport->Close();
    161         return -1;
    162     }
    163     return r;
    164 }
    165 
    166 static int64_t _command_end(Transport* transport) {
    167     return check_response(transport, 0, 0) < 0 ? -1 : 0;
    168 }
    169 
    170 static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
    171                              uint32_t size, char* response) {
    172     if (size == 0) {
    173         return -1;
    174     }
    175 
    176     int64_t r = _command_start(transport, cmd, size, response);
    177     if (r < 0) {
    178         return -1;
    179     }
    180     r = _command_write_data(transport, data, size);
    181     if (r < 0) {
    182         return -1;
    183     }
    184 
    185     r = _command_end(transport);
    186     if (r < 0) {
    187         return -1;
    188     }
    189 
    190     return size;
    191 }
    192 
    193 static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
    194                                 char* response) {
    195     static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
    196     off64_t offset = 0;
    197     uint32_t remaining = size;
    198 
    199     if (_command_start(transport, cmd, size, response) < 0) {
    200         return -1;
    201     }
    202 
    203     while (remaining) {
    204         android::FileMap filemap;
    205         size_t len = std::min(remaining, MAX_MAP_SIZE);
    206 
    207         if (!filemap.create(NULL, fd, offset, len, true)) {
    208             return -1;
    209         }
    210 
    211         if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
    212             return -1;
    213         }
    214 
    215         remaining -= len;
    216         offset += len;
    217     }
    218 
    219     if (_command_end(transport) < 0) {
    220         return -1;
    221     }
    222 
    223     return size;
    224 }
    225 
    226 static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
    227     return _command_start(transport, cmd, 0, response);
    228 }
    229 
    230 int fb_command(Transport* transport, const std::string& cmd) {
    231     return _command_send_no_data(transport, cmd, 0);
    232 }
    233 
    234 int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
    235     return _command_send_no_data(transport, cmd, response);
    236 }
    237 
    238 int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
    239     std::string cmd(android::base::StringPrintf("download:%08x", size));
    240     return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
    241 }
    242 
    243 int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
    244     std::string cmd(android::base::StringPrintf("download:%08x", size));
    245     return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
    246 }
    247 
    248 int64_t fb_upload_data(Transport* transport, const char* outfile) {
    249     // positive return value is the upload size sent by the device
    250     int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr);
    251     if (r <= 0) {
    252         g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
    253         return r;
    254     }
    255 
    256     std::string data;
    257     data.resize(r);
    258     if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
    259         return r;
    260     }
    261 
    262     if (!WriteStringToFile(data, outfile, true)) {
    263         g_error = android::base::StringPrintf("write to '%s' failed", outfile);
    264         return -1;
    265     }
    266 
    267     return _command_end(transport);
    268 }
    269 
    270 #define TRANSPORT_BUF_SIZE 1024
    271 static char transport_buf[TRANSPORT_BUF_SIZE];
    272 static int transport_buf_len;
    273 
    274 static int fb_download_data_sparse_write(void *priv, const void *data, int len)
    275 {
    276     int r;
    277     Transport* transport = reinterpret_cast<Transport*>(priv);
    278     int to_write;
    279     const char* ptr = reinterpret_cast<const char*>(data);
    280 
    281     if (transport_buf_len) {
    282         to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
    283 
    284         memcpy(transport_buf + transport_buf_len, ptr, to_write);
    285         transport_buf_len += to_write;
    286         ptr += to_write;
    287         len -= to_write;
    288     }
    289 
    290     if (transport_buf_len == TRANSPORT_BUF_SIZE) {
    291         r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
    292         if (r != TRANSPORT_BUF_SIZE) {
    293             return -1;
    294         }
    295         transport_buf_len = 0;
    296     }
    297 
    298     if (len > TRANSPORT_BUF_SIZE) {
    299         if (transport_buf_len > 0) {
    300             g_error = "internal error: transport_buf not empty";
    301             return -1;
    302         }
    303         to_write = round_down(len, TRANSPORT_BUF_SIZE);
    304         r = _command_write_data(transport, ptr, to_write);
    305         if (r != to_write) {
    306             return -1;
    307         }
    308         ptr += to_write;
    309         len -= to_write;
    310     }
    311 
    312     if (len > 0) {
    313         if (len > TRANSPORT_BUF_SIZE) {
    314             g_error = "internal error: too much left for transport_buf";
    315             return -1;
    316         }
    317         memcpy(transport_buf, ptr, len);
    318         transport_buf_len = len;
    319     }
    320 
    321     return 0;
    322 }
    323 
    324 static int fb_download_data_sparse_flush(Transport* transport) {
    325     if (transport_buf_len > 0) {
    326         int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
    327         if (r != static_cast<int64_t>(transport_buf_len)) {
    328             return -1;
    329         }
    330         transport_buf_len = 0;
    331     }
    332     return 0;
    333 }
    334 
    335 int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
    336     int size = sparse_file_len(s, true, false);
    337     if (size <= 0) {
    338         return -1;
    339     }
    340 
    341     std::string cmd(android::base::StringPrintf("download:%08x", size));
    342     int r = _command_start(transport, cmd, size, 0);
    343     if (r < 0) {
    344         return -1;
    345     }
    346 
    347     r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
    348     if (r < 0) {
    349         return -1;
    350     }
    351 
    352     r = fb_download_data_sparse_flush(transport);
    353     if (r < 0) {
    354         return -1;
    355     }
    356 
    357     return _command_end(transport);
    358 }
    359