• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fb_get_error()55 const std::string fb_get_error() {
56     return g_error;
57 }
58 
check_response(Transport * transport,uint32_t size,char * response)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 
_command_start(Transport * transport,const std::string & cmd,uint32_t size,char * response)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 
_command_write_data(Transport * transport,const void * data,uint32_t size)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 
_command_read_data(Transport * transport,void * data,uint32_t size)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 
_command_end(Transport * transport)166 static int64_t _command_end(Transport* transport) {
167     return check_response(transport, 0, 0) < 0 ? -1 : 0;
168 }
169 
_command_send(Transport * transport,const std::string & cmd,const void * data,uint32_t size,char * response)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 
_command_send_fd(Transport * transport,const std::string & cmd,int fd,uint32_t size,char * response)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 
_command_send_no_data(Transport * transport,const std::string & cmd,char * response)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 
fb_command(Transport * transport,const std::string & cmd)230 int fb_command(Transport* transport, const std::string& cmd) {
231     return _command_send_no_data(transport, cmd, 0);
232 }
233 
fb_command_response(Transport * transport,const std::string & cmd,char * response)234 int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
235     return _command_send_no_data(transport, cmd, response);
236 }
237 
fb_download_data(Transport * transport,const void * data,uint32_t size)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 
fb_download_data_fd(Transport * transport,int fd,uint32_t size)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 
fb_upload_data(Transport * transport,const char * outfile)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 
fb_download_data_sparse_write(void * priv,const void * data,int len)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 
fb_download_data_sparse_flush(Transport * transport)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 
fb_download_data_sparse(Transport * transport,struct sparse_file * s)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