blob: 2bec487fe8c2ac193736dde840d8b4a3b6528d74 [file] [log] [blame]
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001/*
2 * Copyright (C) 2014 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 <ctype.h>
18#include <errno.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000019#include <dirent.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070020#include <fcntl.h>
Tao Bao0bbc7642017-03-29 23:57:47 -070021#include <inttypes.h>
Tao Baoba9a42a2015-06-23 23:23:33 -070022#include <linux/fs.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070023#include <pthread.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000028#include <sys/stat.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070029#include <sys/types.h>
30#include <sys/wait.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
Sami Tolvanen0a7b4732015-06-25 10:25:36 +010034#include <fec/io.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070035
Tao Baoec8272f2017-03-15 17:39:01 -070036#include <functional>
Tao Baoe6aa3322015-08-05 15:20:27 -070037#include <memory>
38#include <string>
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070039#include <unordered_map>
Tao Bao0940fe12015-08-27 16:41:21 -070040#include <vector>
Tao Baoe6aa3322015-08-05 15:20:27 -070041
Tao Bao039f2da2016-11-22 16:29:50 -080042#include <android-base/logging.h>
Elliott Hughes4b166f02015-12-04 15:30:20 -080043#include <android-base/parseint.h>
44#include <android-base/strings.h>
Elliott Hughesbcabd092016-03-22 20:19:22 -070045#include <android-base/unique_fd.h>
Tao Bao51412212016-12-28 14:44:05 -080046#include <applypatch/applypatch.h>
Tianjie Xu107a34f2017-06-29 17:04:21 -070047#include <brotli/decode.h>
Tao Bao51412212016-12-28 14:44:05 -080048#include <openssl/sha.h>
Tianjie Xua946b9e2017-03-21 16:24:57 -070049#include <private/android_filesystem_config.h>
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070050#include <ziparchive/zip_archive.h>
Tao Baoe6aa3322015-08-05 15:20:27 -070051
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070052#include "edify/expr.h"
Tianjie Xu16255832016-04-30 11:49:59 -070053#include "error_code.h"
Jed Estep39c1b5e2015-12-15 16:04:53 -080054#include "ota_io.h"
Tao Baoe6aa3322015-08-05 15:20:27 -070055#include "print_sha1.h"
Tao Bao8f237572017-03-26 13:36:49 -070056#include "updater/install.h"
57#include "updater/rangeset.h"
Tao Bao0c7839a2016-10-10 15:48:37 -070058#include "updater/updater.h"
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070059
Sami Tolvanene82fa182015-06-10 15:58:12 +000060// Set this to 0 to interpret 'erase' transfers to mean do a
61// BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret
62// erase to mean fill the region with zeroes.
63#define DEBUG_ERASE 0
64
Tao Bao51412212016-12-28 14:44:05 -080065static constexpr size_t BLOCKSIZE = 4096;
66static constexpr const char* STASH_DIRECTORY_BASE = "/cache/recovery";
67static constexpr mode_t STASH_DIRECTORY_MODE = 0700;
68static constexpr mode_t STASH_FILE_MODE = 0600;
Sami Tolvanen90221202014-12-09 16:39:47 +000069
Tianjie Xu16255832016-04-30 11:49:59 -070070static CauseCode failure_type = kNoCause;
Tianjie Xu7ce287d2016-05-31 09:29:49 -070071static bool is_retry = false;
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070072static std::unordered_map<std::string, RangeSet> stash_map;
Tianjie Xu7eca97e2016-03-22 18:08:12 -070073
Sami Tolvanen90221202014-12-09 16:39:47 +000074static int read_all(int fd, uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070075 size_t so_far = 0;
76 while (so_far < size) {
Jed Estepa7b9a462015-12-15 16:04:53 -080077 ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
Elliott Hughes7bad7c42015-04-28 17:24:24 -070078 if (r == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -070079 failure_type = kFreadFailure;
Tao Bao039f2da2016-11-22 16:29:50 -080080 PLOG(ERROR) << "read failed";
Sami Tolvanen90221202014-12-09 16:39:47 +000081 return -1;
Tianjie Xu71e182b2016-08-31 18:06:33 -070082 } else if (r == 0) {
83 failure_type = kFreadFailure;
Tao Bao039f2da2016-11-22 16:29:50 -080084 LOG(ERROR) << "read reached unexpected EOF.";
Tianjie Xu71e182b2016-08-31 18:06:33 -070085 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070086 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -070087 so_far += r;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070088 }
Sami Tolvanen90221202014-12-09 16:39:47 +000089 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070090}
91
Tao Bao612336d2015-08-27 16:41:21 -070092static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
93 return read_all(fd, buffer.data(), size);
94}
95
Sami Tolvanen90221202014-12-09 16:39:47 +000096static int write_all(int fd, const uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070097 size_t written = 0;
98 while (written < size) {
Jed Estepa7b9a462015-12-15 16:04:53 -080099 ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700100 if (w == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700101 failure_type = kFwriteFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800102 PLOG(ERROR) << "write failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000103 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700104 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700105 written += w;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700106 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000107
Sami Tolvanen90221202014-12-09 16:39:47 +0000108 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700109}
110
Tao Bao612336d2015-08-27 16:41:21 -0700111static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
112 return write_all(fd, buffer.data(), size);
113}
114
Tianjie Xu7ce287d2016-05-31 09:29:49 -0700115static bool discard_blocks(int fd, off64_t offset, uint64_t size) {
Tao Baobf5b77d2017-03-30 16:57:29 -0700116 // Don't discard blocks unless the update is a retry run.
117 if (!is_retry) {
Tianjie Xu7ce287d2016-05-31 09:29:49 -0700118 return true;
Tao Baobf5b77d2017-03-30 16:57:29 -0700119 }
120
121 uint64_t args[2] = { static_cast<uint64_t>(offset), size };
122 if (ioctl(fd, BLKDISCARD, &args) == -1) {
123 PLOG(ERROR) << "BLKDISCARD ioctl failed";
124 return false;
125 }
126 return true;
Tianjie Xu7ce287d2016-05-31 09:29:49 -0700127}
128
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700129static bool check_lseek(int fd, off64_t offset, int whence) {
130 off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
131 if (rc == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700132 failure_type = kLseekFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800133 PLOG(ERROR) << "lseek64 failed";
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700134 return false;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700135 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700136 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700137}
138
Tao Bao612336d2015-08-27 16:41:21 -0700139static void allocate(size_t size, std::vector<uint8_t>& buffer) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700140 // if the buffer's big enough, reuse it.
Tao Bao612336d2015-08-27 16:41:21 -0700141 if (size <= buffer.size()) return;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700142
Tao Bao612336d2015-08-27 16:41:21 -0700143 buffer.resize(size);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700144}
145
Tao Bao60a70af2017-03-26 14:03:52 -0700146/**
147 * RangeSinkWriter reads data from the given FD, and writes them to the destination specified by the
148 * given RangeSet.
149 */
150class RangeSinkWriter {
151 public:
152 RangeSinkWriter(int fd, const RangeSet& tgt)
Tianjie Xu107a34f2017-06-29 17:04:21 -0700153 : fd_(fd),
154 tgt_(tgt),
155 next_range_(0),
156 current_range_left_(0),
157 bytes_written_(0) {
Tao Baobf5b77d2017-03-30 16:57:29 -0700158 CHECK_NE(tgt.size(), static_cast<size_t>(0));
Tao Bao60a70af2017-03-26 14:03:52 -0700159 };
Tao Bao0940fe12015-08-27 16:41:21 -0700160
Tianjie Xu107a34f2017-06-29 17:04:21 -0700161 virtual ~RangeSinkWriter() {};
162
Tao Bao60a70af2017-03-26 14:03:52 -0700163 bool Finished() const {
Tao Baobf5b77d2017-03-30 16:57:29 -0700164 return next_range_ == tgt_.size() && current_range_left_ == 0;
Tao Baof7eb7602017-03-27 15:12:48 -0700165 }
166
Tianjie Xu107a34f2017-06-29 17:04:21 -0700167 // Return number of bytes consumed; and 0 indicates a writing failure.
168 virtual size_t Write(const uint8_t* data, size_t size) {
Tao Bao60a70af2017-03-26 14:03:52 -0700169 if (Finished()) {
170 LOG(ERROR) << "range sink write overrun; can't write " << size << " bytes";
171 return 0;
Tao Baof7eb7602017-03-27 15:12:48 -0700172 }
173
Tianjie Xu107a34f2017-06-29 17:04:21 -0700174 size_t consumed = 0;
Tao Bao60a70af2017-03-26 14:03:52 -0700175 while (size > 0) {
176 // Move to the next range as needed.
Tianjie Xu107a34f2017-06-29 17:04:21 -0700177 if (!SeekToOutputRange()) {
178 break;
Tao Bao60a70af2017-03-26 14:03:52 -0700179 }
Tao Baof7eb7602017-03-27 15:12:48 -0700180
Tao Bao60a70af2017-03-26 14:03:52 -0700181 size_t write_now = size;
182 if (current_range_left_ < write_now) {
183 write_now = current_range_left_;
184 }
Tao Baof7eb7602017-03-27 15:12:48 -0700185
Tao Bao60a70af2017-03-26 14:03:52 -0700186 if (write_all(fd_, data, write_now) == -1) {
Tao Baof7eb7602017-03-27 15:12:48 -0700187 break;
188 }
Tao Bao60a70af2017-03-26 14:03:52 -0700189
190 data += write_now;
191 size -= write_now;
192
193 current_range_left_ -= write_now;
Tianjie Xu107a34f2017-06-29 17:04:21 -0700194 consumed += write_now;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700195 }
Tao Bao60a70af2017-03-26 14:03:52 -0700196
Tianjie Xu107a34f2017-06-29 17:04:21 -0700197 bytes_written_ += consumed;
198 return consumed;
Tao Baof7eb7602017-03-27 15:12:48 -0700199 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700200
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700201 size_t BytesWritten() const {
202 return bytes_written_;
203 }
204
Tianjie Xu107a34f2017-06-29 17:04:21 -0700205 protected:
206 // Set up the output cursor, move to next range if needed.
207 bool SeekToOutputRange() {
208 // We haven't finished the current range yet.
209 if (current_range_left_ != 0) {
210 return true;
211 }
212 // We can't write any more; let the write function return how many bytes have been written
213 // so far.
214 if (next_range_ >= tgt_.size()) {
215 return false;
216 }
217
218 const Range& range = tgt_[next_range_];
219 off64_t offset = static_cast<off64_t>(range.first) * BLOCKSIZE;
220 current_range_left_ = (range.second - range.first) * BLOCKSIZE;
221 next_range_++;
222
223 if (!discard_blocks(fd_, offset, current_range_left_)) {
224 return false;
225 }
226 if (!check_lseek(fd_, offset, SEEK_SET)) {
227 return false;
228 }
229 return true;
230 }
231
232 // The output file descriptor.
Tao Bao60a70af2017-03-26 14:03:52 -0700233 int fd_;
Tianjie Xu107a34f2017-06-29 17:04:21 -0700234 // The destination ranges for the data.
Tao Bao60a70af2017-03-26 14:03:52 -0700235 const RangeSet& tgt_;
236 // The next range that we should write to.
237 size_t next_range_;
238 // The number of bytes to write before moving to the next range.
239 size_t current_range_left_;
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700240 // Total bytes written by the writer.
241 size_t bytes_written_;
Tao Bao60a70af2017-03-26 14:03:52 -0700242};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700243
Tianjie Xu107a34f2017-06-29 17:04:21 -0700244class BrotliNewDataWriter : public RangeSinkWriter {
245 public:
246 BrotliNewDataWriter(int fd, const RangeSet& tgt, BrotliDecoderState* state)
247 : RangeSinkWriter(fd, tgt), state_(state) {}
248
249 size_t Write(const uint8_t* data, size_t size) override {
250 if (Finished()) {
251 LOG(ERROR) << "Brotli new data write overrun; can't write " << size << " bytes";
252 return 0;
253 }
254 CHECK(state_ != nullptr);
255
256 size_t consumed = 0;
257 while (true) {
258 // Move to the next range as needed.
259 if (!SeekToOutputRange()) {
260 break;
261 }
262
263 size_t available_in = size;
264 size_t write_now = std::min<size_t>(32768, current_range_left_);
265 uint8_t buffer[write_now];
266
267 size_t available_out = write_now;
268 uint8_t* next_out = buffer;
269
270 // The brotli decoder will update |data|, |available_in|, |next_out| and |available_out|.
271 BrotliDecoderResult result = BrotliDecoderDecompressStream(
272 state_, &available_in, &data, &available_out, &next_out, nullptr);
273
274 // We don't have a way to recover from the decode error; report the failure.
275 if (result == BROTLI_DECODER_RESULT_ERROR) {
276 LOG(ERROR) << "Decompression failed with "
277 << BrotliDecoderErrorString(BrotliDecoderGetErrorCode(state_));
278 return 0;
279 }
280
281 if (write_all(fd_, buffer, write_now - available_out) == -1) {
282 return 0;
283 }
284
285 LOG(DEBUG) << "bytes written: " << write_now - available_out << ", bytes consumed "
286 << size - available_in << ", decoder status " << result;
287
288 // Update the total bytes written to output by the current writer; this is different from the
289 // consumed input bytes.
290 bytes_written_ += write_now - available_out;
291 current_range_left_ -= (write_now - available_out);
292 consumed += (size - available_in);
293
294 // Update the remaining size. The input data ptr is already updated by brotli decoder
295 // function.
296 size = available_in;
297
298 // Continue if we have more output to write, or more input to consume.
299 if (result == BROTLI_DECODER_RESULT_SUCCESS ||
300 (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT && size == 0)) {
301 break;
302 }
303 }
304
305 return consumed;
306 }
307
308 private:
309 // Pointer to the decoder state. (initialized by PerformBlockImageUpdate)
310 BrotliDecoderState* state_;
311};
312
Tao Bao60a70af2017-03-26 14:03:52 -0700313/**
314 * All of the data for all the 'new' transfers is contained in one file in the update package,
315 * concatenated together in the order in which transfers.list will need it. We want to stream it out
316 * of the archive (it's compressed) without writing it to a temp file, but we can't write each
317 * section until it's that transfer's turn to go.
318 *
319 * To achieve this, we expand the new data from the archive in a background thread, and block that
320 * threads 'receive uncompressed data' function until the main thread has reached a point where we
321 * want some new data to be written. We signal the background thread with the destination for the
322 * data and block the main thread, waiting for the background thread to complete writing that
323 * section. Then it signals the main thread to wake up and goes back to blocking waiting for a
324 * transfer.
325 *
326 * NewThreadInfo is the struct used to pass information back and forth between the two threads. When
327 * the main thread wants some data written, it sets writer to the destination location and signals
328 * the condition. When the background thread is done writing, it clears writer and signals the
329 * condition again.
330 */
Tao Bao0940fe12015-08-27 16:41:21 -0700331struct NewThreadInfo {
Tao Bao60a70af2017-03-26 14:03:52 -0700332 ZipArchiveHandle za;
333 ZipEntry entry;
Tianjie Xu107a34f2017-06-29 17:04:21 -0700334 bool brotli_compressed;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700335
Tianjie Xu107a34f2017-06-29 17:04:21 -0700336 std::unique_ptr<RangeSinkWriter> writer;
337 BrotliDecoderState* brotli_decoder_state;
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700338 bool receiver_available;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700339
Tao Bao60a70af2017-03-26 14:03:52 -0700340 pthread_mutex_t mu;
341 pthread_cond_t cv;
Tao Bao0940fe12015-08-27 16:41:21 -0700342};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700343
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -0700344static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
Tao Bao60a70af2017-03-26 14:03:52 -0700345 NewThreadInfo* nti = static_cast<NewThreadInfo*>(cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700346
Tao Bao60a70af2017-03-26 14:03:52 -0700347 while (size > 0) {
348 // Wait for nti->writer to be non-null, indicating some of this data is wanted.
349 pthread_mutex_lock(&nti->mu);
350 while (nti->writer == nullptr) {
351 pthread_cond_wait(&nti->cv, &nti->mu);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700352 }
Tao Bao60a70af2017-03-26 14:03:52 -0700353 pthread_mutex_unlock(&nti->mu);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700354
Tao Bao60a70af2017-03-26 14:03:52 -0700355 // At this point nti->writer is set, and we own it. The main thread is waiting for it to
356 // disappear from nti.
Tianjie Xu107a34f2017-06-29 17:04:21 -0700357 size_t consumed = nti->writer->Write(data, size);
358
359 // We encounter a fatal error if we fail to consume any input bytes. If this happens, abort the
360 // extraction.
361 if (consumed == 0) {
362 LOG(ERROR) << "Failed to process " << size << " input bytes.";
363 return false;
364 }
365 data += consumed;
366 size -= consumed;
Tao Bao60a70af2017-03-26 14:03:52 -0700367
368 if (nti->writer->Finished()) {
369 // We have written all the bytes desired by this writer.
370
371 pthread_mutex_lock(&nti->mu);
372 nti->writer = nullptr;
373 pthread_cond_broadcast(&nti->cv);
374 pthread_mutex_unlock(&nti->mu);
375 }
376 }
377
378 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700379}
380
381static void* unzip_new_data(void* cookie) {
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700382 NewThreadInfo* nti = static_cast<NewThreadInfo*>(cookie);
383 ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti);
384
385 pthread_mutex_lock(&nti->mu);
386 nti->receiver_available = false;
387 if (nti->writer != nullptr) {
388 pthread_cond_broadcast(&nti->cv);
389 }
390 pthread_mutex_unlock(&nti->mu);
391 return nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700392}
393
Tao Bao612336d2015-08-27 16:41:21 -0700394static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) {
Tao Baobf5b77d2017-03-30 16:57:29 -0700395 size_t p = 0;
396 for (const auto& range : src) {
397 if (!check_lseek(fd, static_cast<off64_t>(range.first) * BLOCKSIZE, SEEK_SET)) {
398 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000399 }
400
Tao Baobf5b77d2017-03-30 16:57:29 -0700401 size_t size = (range.second - range.first) * BLOCKSIZE;
402 if (read_all(fd, buffer.data() + p, size) == -1) {
403 return -1;
404 }
405
406 p += size;
407 }
408
409 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000410}
411
Tao Bao612336d2015-08-27 16:41:21 -0700412static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) {
Tao Bao60a70af2017-03-26 14:03:52 -0700413 size_t written = 0;
Tao Baobf5b77d2017-03-30 16:57:29 -0700414 for (const auto& range : tgt) {
415 off64_t offset = static_cast<off64_t>(range.first) * BLOCKSIZE;
416 size_t size = (range.second - range.first) * BLOCKSIZE;
Tao Bao60a70af2017-03-26 14:03:52 -0700417 if (!discard_blocks(fd, offset, size)) {
418 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000419 }
420
Tao Bao60a70af2017-03-26 14:03:52 -0700421 if (!check_lseek(fd, offset, SEEK_SET)) {
422 return -1;
423 }
424
425 if (write_all(fd, buffer.data() + written, size) == -1) {
426 return -1;
427 }
428
429 written += size;
430 }
431
432 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000433}
434
Tao Baobaad2d42015-12-06 16:56:27 -0800435// Parameters for transfer list command functions
436struct CommandParameters {
437 std::vector<std::string> tokens;
438 size_t cpos;
439 const char* cmdname;
440 const char* cmdline;
441 std::string freestash;
442 std::string stashbase;
443 bool canwrite;
444 int createdstash;
Elliott Hughesbcabd092016-03-22 20:19:22 -0700445 android::base::unique_fd fd;
Tao Baobaad2d42015-12-06 16:56:27 -0800446 bool foundwrites;
447 bool isunresumable;
448 int version;
449 size_t written;
Tianjie Xudd874b12016-05-13 12:13:15 -0700450 size_t stashed;
Tao Baobaad2d42015-12-06 16:56:27 -0800451 NewThreadInfo nti;
452 pthread_t thread;
453 std::vector<uint8_t> buffer;
454 uint8_t* patch_start;
455};
456
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000457// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is
458// handled separately).
459static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params,
460 const std::vector<uint8_t>& buffer) {
461 LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline;
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000462 CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" ||
463 params.tokens[0] == "imgdiff");
464
465 size_t pos = 0;
466 // Command example:
467 // move <onehash> <tgt_range> <src_blk_count> <src_range> [<loc_range> <stashed_blocks>]
468 // bsdiff <offset> <len> <src_hash> <tgt_hash> <tgt_range> <src_blk_count> <src_range>
469 // [<loc_range> <stashed_blocks>]
470 if (params.tokens[0] == "move") {
471 // src_range for move starts at the 4th position.
472 if (params.tokens.size() < 5) {
473 LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
474 return;
475 }
476 pos = 4;
477 } else {
478 // src_range for diff starts at the 7th position.
479 if (params.tokens.size() < 8) {
480 LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
481 return;
482 }
483 pos = 7;
484 }
485
486 // Source blocks in stash only, no work to do.
487 if (params.tokens[pos] == "-") {
488 return;
489 }
490
Tao Bao8f237572017-03-26 13:36:49 -0700491 RangeSet src = RangeSet::Parse(params.tokens[pos++]);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000492
493 RangeSet locs;
494 // If there's no stashed blocks, content in the buffer is consecutive and has the same
495 // order as the source blocks.
496 if (pos == params.tokens.size()) {
Tao Baobf5b77d2017-03-30 16:57:29 -0700497 locs = RangeSet(std::vector<Range>{ Range{ 0, src.blocks() } });
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000498 } else {
499 // Otherwise, the next token is the offset of the source blocks in the target range.
500 // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> <stashed_blocks>;
501 // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38];
502 // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978.
Tao Bao8f237572017-03-26 13:36:49 -0700503 locs = RangeSet::Parse(params.tokens[pos++]);
Tao Baobf5b77d2017-03-30 16:57:29 -0700504 CHECK_EQ(src.blocks(), locs.blocks());
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000505 }
506
Tao Baobf5b77d2017-03-30 16:57:29 -0700507 LOG(INFO) << "printing hash in hex for " << src.blocks() << " source blocks";
508 for (size_t i = 0; i < src.blocks(); i++) {
Tao Bao8f237572017-03-26 13:36:49 -0700509 size_t block_num = src.GetBlockNumber(i);
510 size_t buffer_index = locs.GetBlockNumber(i);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000511 CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size());
512
513 uint8_t digest[SHA_DIGEST_LENGTH];
514 SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest);
515 std::string hexdigest = print_sha1(digest);
516 LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
517 }
518}
519
520// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1
521// in hex for each block.
522static void PrintHashForCorruptedStashedBlocks(const std::string& id,
523 const std::vector<uint8_t>& buffer,
524 const RangeSet& src) {
525 LOG(INFO) << "printing hash in hex for stash_id: " << id;
Tao Baobf5b77d2017-03-30 16:57:29 -0700526 CHECK_EQ(src.blocks() * BLOCKSIZE, buffer.size());
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000527
Tao Baobf5b77d2017-03-30 16:57:29 -0700528 for (size_t i = 0; i < src.blocks(); i++) {
Tao Bao8f237572017-03-26 13:36:49 -0700529 size_t block_num = src.GetBlockNumber(i);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000530
531 uint8_t digest[SHA_DIGEST_LENGTH];
532 SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest);
533 std::string hexdigest = print_sha1(digest);
534 LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
535 }
536}
537
538// If the stash file doesn't exist, read the source blocks this stash contains and print the
539// SHA-1 for these blocks.
540static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) {
541 if (stash_map.find(id) == stash_map.end()) {
542 LOG(ERROR) << "No stash saved for id: " << id;
543 return;
544 }
545
546 LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id;
547 const RangeSet& src = stash_map[id];
Tao Baobf5b77d2017-03-30 16:57:29 -0700548 std::vector<uint8_t> buffer(src.blocks() * BLOCKSIZE);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000549 if (ReadBlocks(src, buffer, fd) == -1) {
550 LOG(ERROR) << "failed to read source blocks for stash: " << id;
551 return;
552 }
553 PrintHashForCorruptedStashedBlocks(id, buffer, src);
554}
555
Tao Bao612336d2015-08-27 16:41:21 -0700556static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
Tao Bao0940fe12015-08-27 16:41:21 -0700557 const size_t blocks, bool printerror) {
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800558 uint8_t digest[SHA_DIGEST_LENGTH];
Tao Bao612336d2015-08-27 16:41:21 -0700559 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000560
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800561 SHA1(data, blocks * BLOCKSIZE, digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000562
Tao Baoe6aa3322015-08-05 15:20:27 -0700563 std::string hexdigest = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000564
Tao Bao0940fe12015-08-27 16:41:21 -0700565 if (hexdigest != expected) {
566 if (printerror) {
Tao Bao039f2da2016-11-22 16:29:50 -0800567 LOG(ERROR) << "failed to verify blocks (expected " << expected << ", read "
568 << hexdigest << ")";
Tao Bao0940fe12015-08-27 16:41:21 -0700569 }
570 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000571 }
572
Tao Bao0940fe12015-08-27 16:41:21 -0700573 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000574}
575
Tao Bao0940fe12015-08-27 16:41:21 -0700576static std::string GetStashFileName(const std::string& base, const std::string& id,
577 const std::string& postfix) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700578 if (base.empty()) {
579 return "";
Sami Tolvanen90221202014-12-09 16:39:47 +0000580 }
581
Tao Baoe6aa3322015-08-05 15:20:27 -0700582 std::string fn(STASH_DIRECTORY_BASE);
583 fn += "/" + base + "/" + id + postfix;
Sami Tolvanen90221202014-12-09 16:39:47 +0000584
585 return fn;
586}
587
Tao Baoec8272f2017-03-15 17:39:01 -0700588// Does a best effort enumeration of stash files. Ignores possible non-file items in the stash
589// directory and continues despite of errors. Calls the 'callback' function for each file.
590static void EnumerateStash(const std::string& dirname,
591 const std::function<void(const std::string&)>& callback) {
592 if (dirname.empty()) return;
Sami Tolvanen90221202014-12-09 16:39:47 +0000593
Tao Baoec8272f2017-03-15 17:39:01 -0700594 std::unique_ptr<DIR, decltype(&closedir)> directory(opendir(dirname.c_str()), closedir);
Sami Tolvanen90221202014-12-09 16:39:47 +0000595
Tao Baoec8272f2017-03-15 17:39:01 -0700596 if (directory == nullptr) {
597 if (errno != ENOENT) {
598 PLOG(ERROR) << "opendir \"" << dirname << "\" failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000599 }
Tao Bao51412212016-12-28 14:44:05 -0800600 return;
601 }
Tao Baoe6aa3322015-08-05 15:20:27 -0700602
Tao Baoec8272f2017-03-15 17:39:01 -0700603 dirent* item;
604 while ((item = readdir(directory.get())) != nullptr) {
605 if (item->d_type != DT_REG) continue;
606 callback(dirname + "/" + item->d_name);
Tao Bao51412212016-12-28 14:44:05 -0800607 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000608}
609
610// Deletes the stash directory and all files in it. Assumes that it only
611// contains files. There is nothing we can do about unlikely, but possible
612// errors, so they are merely logged.
Tao Baoec8272f2017-03-15 17:39:01 -0700613static void DeleteFile(const std::string& fn) {
614 if (fn.empty()) return;
Sami Tolvanen90221202014-12-09 16:39:47 +0000615
Tao Baoec8272f2017-03-15 17:39:01 -0700616 LOG(INFO) << "deleting " << fn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000617
Tao Baoec8272f2017-03-15 17:39:01 -0700618 if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
619 PLOG(ERROR) << "unlink \"" << fn << "\" failed";
620 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000621}
622
Tao Baoe6aa3322015-08-05 15:20:27 -0700623static void DeleteStash(const std::string& base) {
Tao Baoec8272f2017-03-15 17:39:01 -0700624 if (base.empty()) return;
625
626 LOG(INFO) << "deleting stash " << base;
627
628 std::string dirname = GetStashFileName(base, "", "");
629 EnumerateStash(dirname, DeleteFile);
630
631 if (rmdir(dirname.c_str()) == -1) {
632 if (errno != ENOENT && errno != ENOTDIR) {
633 PLOG(ERROR) << "rmdir \"" << dirname << "\" failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000634 }
Tao Baoec8272f2017-03-15 17:39:01 -0700635 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000636}
637
Tao Baobcf46492017-03-23 15:28:20 -0700638static int LoadStash(CommandParameters& params, const std::string& id, bool verify, size_t* blocks,
639 std::vector<uint8_t>& buffer, bool printnoent) {
Tao Baobf5b77d2017-03-30 16:57:29 -0700640 // In verify mode, if source range_set was saved for the given hash, check contents in the source
641 // blocks first. If the check fails, search for the stashed files on /cache as usual.
642 if (!params.canwrite) {
643 if (stash_map.find(id) != stash_map.end()) {
644 const RangeSet& src = stash_map[id];
645 allocate(src.blocks() * BLOCKSIZE, buffer);
Tianjie Xu7eca97e2016-03-22 18:08:12 -0700646
Tao Baobf5b77d2017-03-30 16:57:29 -0700647 if (ReadBlocks(src, buffer, params.fd) == -1) {
648 LOG(ERROR) << "failed to read source blocks in stash map.";
Tao Bao0940fe12015-08-27 16:41:21 -0700649 return -1;
Tao Baobf5b77d2017-03-30 16:57:29 -0700650 }
651 if (VerifyBlocks(id, buffer, src.blocks(), true) != 0) {
652 LOG(ERROR) << "failed to verify loaded source blocks in stash map.";
653 PrintHashForCorruptedStashedBlocks(id, buffer, src);
Tao Bao0940fe12015-08-27 16:41:21 -0700654 return -1;
Tao Baobf5b77d2017-03-30 16:57:29 -0700655 }
656 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000657 }
Tao Baobf5b77d2017-03-30 16:57:29 -0700658 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000659
Tao Baobf5b77d2017-03-30 16:57:29 -0700660 size_t blockcount = 0;
661 if (!blocks) {
662 blocks = &blockcount;
663 }
664
665 std::string fn = GetStashFileName(params.stashbase, id, "");
666
667 struct stat sb;
668 if (stat(fn.c_str(), &sb) == -1) {
669 if (errno != ENOENT || printnoent) {
670 PLOG(ERROR) << "stat \"" << fn << "\" failed";
671 PrintHashForMissingStashedBlocks(id, params.fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000672 }
Tao Baobf5b77d2017-03-30 16:57:29 -0700673 return -1;
674 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000675
Tao Baobf5b77d2017-03-30 16:57:29 -0700676 LOG(INFO) << " loading " << fn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000677
Tao Baobf5b77d2017-03-30 16:57:29 -0700678 if ((sb.st_size % BLOCKSIZE) != 0) {
679 LOG(ERROR) << fn << " size " << sb.st_size << " not multiple of block size " << BLOCKSIZE;
680 return -1;
681 }
682
683 android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY)));
684 if (fd == -1) {
685 PLOG(ERROR) << "open \"" << fn << "\" failed";
686 return -1;
687 }
688
689 allocate(sb.st_size, buffer);
690
691 if (read_all(fd, buffer, sb.st_size) == -1) {
692 return -1;
693 }
694
695 *blocks = sb.st_size / BLOCKSIZE;
696
697 if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
698 LOG(ERROR) << "unexpected contents in " << fn;
699 if (stash_map.find(id) == stash_map.end()) {
700 LOG(ERROR) << "failed to find source blocks number for stash " << id
701 << " when executing command: " << params.cmdname;
702 } else {
703 const RangeSet& src = stash_map[id];
704 PrintHashForCorruptedStashedBlocks(id, buffer, src);
Sami Tolvanen90221202014-12-09 16:39:47 +0000705 }
Tao Baobf5b77d2017-03-30 16:57:29 -0700706 DeleteFile(fn);
707 return -1;
708 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000709
Tao Baobf5b77d2017-03-30 16:57:29 -0700710 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000711}
712
Tao Bao612336d2015-08-27 16:41:21 -0700713static int WriteStash(const std::string& base, const std::string& id, int blocks,
Tao Baod2aecd42017-03-23 14:43:44 -0700714 std::vector<uint8_t>& buffer, bool checkspace, bool* exists) {
Tao Bao612336d2015-08-27 16:41:21 -0700715 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700716 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000717 }
718
719 if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) {
Tao Bao039f2da2016-11-22 16:29:50 -0800720 LOG(ERROR) << "not enough space to write stash";
Tao Bao0940fe12015-08-27 16:41:21 -0700721 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000722 }
723
Tao Bao0940fe12015-08-27 16:41:21 -0700724 std::string fn = GetStashFileName(base, id, ".partial");
725 std::string cn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000726
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100727 if (exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700728 struct stat sb;
729 int res = stat(cn.c_str(), &sb);
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100730
731 if (res == 0) {
732 // The file already exists and since the name is the hash of the contents,
733 // it's safe to assume the contents are identical (accidental hash collisions
734 // are unlikely)
Tao Bao039f2da2016-11-22 16:29:50 -0800735 LOG(INFO) << " skipping " << blocks << " existing blocks in " << cn;
Tao Bao0940fe12015-08-27 16:41:21 -0700736 *exists = true;
737 return 0;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100738 }
739
Tao Bao0940fe12015-08-27 16:41:21 -0700740 *exists = false;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100741 }
742
Tao Bao039f2da2016-11-22 16:29:50 -0800743 LOG(INFO) << " writing " << blocks << " blocks to " << cn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000744
Tao Bao039f2da2016-11-22 16:29:50 -0800745 android::base::unique_fd fd(
746 TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)));
Sami Tolvanen90221202014-12-09 16:39:47 +0000747 if (fd == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800748 PLOG(ERROR) << "failed to create \"" << fn << "\"";
Tao Bao0940fe12015-08-27 16:41:21 -0700749 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000750 }
751
Tianjie Xua946b9e2017-03-21 16:24:57 -0700752 if (fchown(fd, AID_SYSTEM, AID_SYSTEM) != 0) { // system user
753 PLOG(ERROR) << "failed to chown \"" << fn << "\"";
754 return -1;
755 }
756
Sami Tolvanen90221202014-12-09 16:39:47 +0000757 if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700758 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000759 }
760
Jed Estepa7b9a462015-12-15 16:04:53 -0800761 if (ota_fsync(fd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700762 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800763 PLOG(ERROR) << "fsync \"" << fn << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700764 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000765 }
766
Tao Baoe6aa3322015-08-05 15:20:27 -0700767 if (rename(fn.c_str(), cn.c_str()) == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800768 PLOG(ERROR) << "rename(\"" << fn << "\", \"" << cn << "\") failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700769 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000770 }
771
Tao Bao0940fe12015-08-27 16:41:21 -0700772 std::string dname = GetStashFileName(base, "", "");
Elliott Hughesbcabd092016-03-22 20:19:22 -0700773 android::base::unique_fd dfd(TEMP_FAILURE_RETRY(ota_open(dname.c_str(),
774 O_RDONLY | O_DIRECTORY)));
Tao Baodc392262015-07-31 15:56:44 -0700775 if (dfd == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700776 failure_type = kFileOpenFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800777 PLOG(ERROR) << "failed to open \"" << dname << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700778 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700779 }
780
Jed Estepa7b9a462015-12-15 16:04:53 -0800781 if (ota_fsync(dfd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700782 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800783 PLOG(ERROR) << "fsync \"" << dname << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700784 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700785 }
786
Tao Bao0940fe12015-08-27 16:41:21 -0700787 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000788}
789
790// Creates a directory for storing stash files and checks if the /cache partition
791// hash enough space for the expected amount of blocks we need to store. Returns
792// >0 if we created the directory, zero if it existed already, and <0 of failure.
793
Tao Bao51412212016-12-28 14:44:05 -0800794static int CreateStash(State* state, size_t maxblocks, const std::string& blockdev,
795 std::string& base) {
796 if (blockdev.empty()) {
797 return -1;
798 }
799
800 // Stash directory should be different for each partition to avoid conflicts
801 // when updating multiple partitions at the same time, so we use the hash of
802 // the block device name as the base directory
803 uint8_t digest[SHA_DIGEST_LENGTH];
804 SHA1(reinterpret_cast<const uint8_t*>(blockdev.data()), blockdev.size(), digest);
805 base = print_sha1(digest);
806
807 std::string dirname = GetStashFileName(base, "", "");
808 struct stat sb;
809 int res = stat(dirname.c_str(), &sb);
810 size_t max_stash_size = maxblocks * BLOCKSIZE;
811
812 if (res == -1 && errno != ENOENT) {
813 ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n", dirname.c_str(),
814 strerror(errno));
815 return -1;
816 } else if (res != 0) {
817 LOG(INFO) << "creating stash " << dirname;
818 res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
819
820 if (res != 0) {
821 ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n", dirname.c_str(),
822 strerror(errno));
823 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000824 }
825
Tianjie Xua946b9e2017-03-21 16:24:57 -0700826 if (chown(dirname.c_str(), AID_SYSTEM, AID_SYSTEM) != 0) { // system user
827 ErrorAbort(state, kStashCreationFailure, "chown \"%s\" failed: %s\n", dirname.c_str(),
828 strerror(errno));
829 return -1;
830 }
831
Tao Bao51412212016-12-28 14:44:05 -0800832 if (CacheSizeCheck(max_stash_size) != 0) {
833 ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu needed)\n",
834 max_stash_size);
835 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000836 }
837
Tao Bao51412212016-12-28 14:44:05 -0800838 return 1; // Created directory
839 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000840
Tao Bao51412212016-12-28 14:44:05 -0800841 LOG(INFO) << "using existing stash " << dirname;
Sami Tolvanen90221202014-12-09 16:39:47 +0000842
Tao Baoec8272f2017-03-15 17:39:01 -0700843 // If the directory already exists, calculate the space already allocated to stash files and check
844 // if there's enough for all required blocks. Delete any partially completed stash files first.
845 EnumerateStash(dirname, [](const std::string& fn) {
846 if (android::base::EndsWith(fn, ".partial")) {
847 DeleteFile(fn);
848 }
849 });
Sami Tolvanen90221202014-12-09 16:39:47 +0000850
Tao Bao51412212016-12-28 14:44:05 -0800851 size_t existing = 0;
Tao Baoec8272f2017-03-15 17:39:01 -0700852 EnumerateStash(dirname, [&existing](const std::string& fn) {
853 if (fn.empty()) return;
854 struct stat sb;
855 if (stat(fn.c_str(), &sb) == -1) {
856 PLOG(ERROR) << "stat \"" << fn << "\" failed";
857 return;
858 }
859 existing += static_cast<size_t>(sb.st_size);
860 });
Sami Tolvanen90221202014-12-09 16:39:47 +0000861
Tao Bao51412212016-12-28 14:44:05 -0800862 if (max_stash_size > existing) {
863 size_t needed = max_stash_size - existing;
864 if (CacheSizeCheck(needed) != 0) {
865 ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu more needed)\n",
866 needed);
867 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000868 }
Tao Bao51412212016-12-28 14:44:05 -0800869 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000870
Tao Bao51412212016-12-28 14:44:05 -0800871 return 0; // Using existing directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000872}
873
Tao Baobaad2d42015-12-06 16:56:27 -0800874static int FreeStash(const std::string& base, const std::string& id) {
Tao Baoec8272f2017-03-15 17:39:01 -0700875 if (base.empty() || id.empty()) {
876 return -1;
877 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000878
Tao Baoec8272f2017-03-15 17:39:01 -0700879 DeleteFile(GetStashFileName(base, id, ""));
Sami Tolvanen90221202014-12-09 16:39:47 +0000880
Tao Baoec8272f2017-03-15 17:39:01 -0700881 return 0;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700882}
883
Tao Baobf5b77d2017-03-30 16:57:29 -0700884// Source contains packed data, which we want to move to the locations given in locs in the dest
885// buffer. source and dest may be the same buffer.
Tao Bao612336d2015-08-27 16:41:21 -0700886static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
Tao Baobf5b77d2017-03-30 16:57:29 -0700887 const std::vector<uint8_t>& source) {
888 const uint8_t* from = source.data();
889 uint8_t* to = dest.data();
890 size_t start = locs.blocks();
891 // Must do the movement backward.
892 for (auto it = locs.crbegin(); it != locs.crend(); it++) {
893 size_t blocks = it->second - it->first;
894 start -= blocks;
895 memmove(to + (it->first * BLOCKSIZE), from + (start * BLOCKSIZE), blocks * BLOCKSIZE);
896 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700897}
898
Tao Baod2aecd42017-03-23 14:43:44 -0700899/**
900 * We expect to parse the remainder of the parameter tokens as one of:
901 *
902 * <src_block_count> <src_range>
903 * (loads data from source image only)
904 *
905 * <src_block_count> - <[stash_id:stash_range] ...>
906 * (loads data from stashes only)
907 *
908 * <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
909 * (loads data from both source image and stashes)
910 *
911 * On return, params.buffer is filled with the loaded source data (rearranged and combined with
912 * stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
913 * tgt is the target RangeSet for detecting overlaps. Any stashes required are loaded using
914 * LoadStash.
915 */
916static int LoadSourceBlocks(CommandParameters& params, const RangeSet& tgt, size_t* src_blocks,
917 bool* overlap) {
918 CHECK(src_blocks != nullptr);
919 CHECK(overlap != nullptr);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700920
Tao Baod2aecd42017-03-23 14:43:44 -0700921 // <src_block_count>
922 const std::string& token = params.tokens[params.cpos++];
923 if (!android::base::ParseUint(token, src_blocks)) {
924 LOG(ERROR) << "invalid src_block_count \"" << token << "\"";
925 return -1;
926 }
Tao Baobaad2d42015-12-06 16:56:27 -0800927
Tao Baod2aecd42017-03-23 14:43:44 -0700928 allocate(*src_blocks * BLOCKSIZE, params.buffer);
929
930 // "-" or <src_range> [<src_loc>]
931 if (params.tokens[params.cpos] == "-") {
932 // no source ranges, only stashes
933 params.cpos++;
934 } else {
Tao Bao8f237572017-03-26 13:36:49 -0700935 RangeSet src = RangeSet::Parse(params.tokens[params.cpos++]);
936 *overlap = src.Overlaps(tgt);
Tao Baod2aecd42017-03-23 14:43:44 -0700937
938 if (ReadBlocks(src, params.buffer, params.fd) == -1) {
939 return -1;
Tao Baobaad2d42015-12-06 16:56:27 -0800940 }
941
Tao Baod2aecd42017-03-23 14:43:44 -0700942 if (params.cpos >= params.tokens.size()) {
943 // no stashes, only source range
944 return 0;
Tao Baobaad2d42015-12-06 16:56:27 -0800945 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700946
Tao Bao8f237572017-03-26 13:36:49 -0700947 RangeSet locs = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baod2aecd42017-03-23 14:43:44 -0700948 MoveRange(params.buffer, locs, params.buffer);
949 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700950
Tao Baod2aecd42017-03-23 14:43:44 -0700951 // <[stash_id:stash_range]>
952 while (params.cpos < params.tokens.size()) {
953 // Each word is a an index into the stash table, a colon, and then a RangeSet describing where
954 // in the source block that stashed data should go.
955 std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
956 if (tokens.size() != 2) {
957 LOG(ERROR) << "invalid parameter";
958 return -1;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700959 }
960
Tao Baod2aecd42017-03-23 14:43:44 -0700961 std::vector<uint8_t> stash;
962 if (LoadStash(params, tokens[0], false, nullptr, stash, true) == -1) {
963 // These source blocks will fail verification if used later, but we
964 // will let the caller decide if this is a fatal failure
965 LOG(ERROR) << "failed to load stash " << tokens[0];
966 continue;
Sami Tolvanen90221202014-12-09 16:39:47 +0000967 }
968
Tao Bao8f237572017-03-26 13:36:49 -0700969 RangeSet locs = RangeSet::Parse(tokens[1]);
Tao Baod2aecd42017-03-23 14:43:44 -0700970 MoveRange(params.buffer, locs, stash);
971 }
972
973 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000974}
975
Tao Bao33567772017-03-13 14:57:34 -0700976/**
977 * Do a source/target load for move/bsdiff/imgdiff in version 3.
978 *
979 * We expect to parse the remainder of the parameter tokens as one of:
980 *
981 * <tgt_range> <src_block_count> <src_range>
982 * (loads data from source image only)
983 *
984 * <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
985 * (loads data from stashes only)
986 *
987 * <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
988 * (loads data from both source image and stashes)
989 *
Tao Baod2aecd42017-03-23 14:43:44 -0700990 * 'onehash' tells whether to expect separate source and targe block hashes, or if they are both the
991 * same and only one hash should be expected. params.isunresumable will be set to true if block
Tao Bao33567772017-03-13 14:57:34 -0700992 * verification fails in a way that the update cannot be resumed anymore.
993 *
994 * If the function is unable to load the necessary blocks or their contents don't match the hashes,
995 * the return value is -1 and the command should be aborted.
996 *
997 * If the return value is 1, the command has already been completed according to the contents of the
998 * target blocks, and should not be performed again.
999 *
1000 * If the return value is 0, source blocks have expected content and the command can be performed.
1001 */
Tao Baod2aecd42017-03-23 14:43:44 -07001002static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t* src_blocks,
1003 bool onehash, bool* overlap) {
1004 CHECK(src_blocks != nullptr);
1005 CHECK(overlap != nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001006
Tao Baod2aecd42017-03-23 14:43:44 -07001007 if (params.cpos >= params.tokens.size()) {
1008 LOG(ERROR) << "missing source hash";
Tao Bao0940fe12015-08-27 16:41:21 -07001009 return -1;
Tao Baod2aecd42017-03-23 14:43:44 -07001010 }
1011
1012 std::string srchash = params.tokens[params.cpos++];
1013 std::string tgthash;
1014
1015 if (onehash) {
1016 tgthash = srchash;
1017 } else {
1018 if (params.cpos >= params.tokens.size()) {
1019 LOG(ERROR) << "missing target hash";
1020 return -1;
1021 }
1022 tgthash = params.tokens[params.cpos++];
1023 }
1024
1025 // At least it needs to provide three parameters: <tgt_range>, <src_block_count> and
1026 // "-"/<src_range>.
1027 if (params.cpos + 2 >= params.tokens.size()) {
1028 LOG(ERROR) << "invalid parameters";
1029 return -1;
1030 }
1031
1032 // <tgt_range>
Tao Bao8f237572017-03-26 13:36:49 -07001033 tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baod2aecd42017-03-23 14:43:44 -07001034
Tao Baobf5b77d2017-03-30 16:57:29 -07001035 std::vector<uint8_t> tgtbuffer(tgt.blocks() * BLOCKSIZE);
Tao Baod2aecd42017-03-23 14:43:44 -07001036 if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
1037 return -1;
1038 }
1039
1040 // Return now if target blocks already have expected content.
Tao Baobf5b77d2017-03-30 16:57:29 -07001041 if (VerifyBlocks(tgthash, tgtbuffer, tgt.blocks(), false) == 0) {
Tao Baod2aecd42017-03-23 14:43:44 -07001042 return 1;
1043 }
1044
1045 // Load source blocks.
1046 if (LoadSourceBlocks(params, tgt, src_blocks, overlap) == -1) {
1047 return -1;
1048 }
1049
1050 if (VerifyBlocks(srchash, params.buffer, *src_blocks, true) == 0) {
1051 // If source and target blocks overlap, stash the source blocks so we can
1052 // resume from possible write errors. In verify mode, we can skip stashing
1053 // because the source blocks won't be overwritten.
1054 if (*overlap && params.canwrite) {
1055 LOG(INFO) << "stashing " << *src_blocks << " overlapping blocks to " << srchash;
1056
1057 bool stash_exists = false;
1058 if (WriteStash(params.stashbase, srchash, *src_blocks, params.buffer, true,
1059 &stash_exists) != 0) {
1060 LOG(ERROR) << "failed to stash overlapping source blocks";
1061 return -1;
1062 }
1063
1064 params.stashed += *src_blocks;
1065 // Can be deleted when the write has completed.
1066 if (!stash_exists) {
1067 params.freestash = srchash;
1068 }
1069 }
1070
1071 // Source blocks have expected content, command can proceed.
1072 return 0;
1073 }
1074
1075 if (*overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
1076 // Overlapping source blocks were previously stashed, command can proceed. We are recovering
1077 // from an interrupted command, so we don't know if the stash can safely be deleted after this
1078 // command.
1079 return 0;
1080 }
1081
1082 // Valid source data not available, update cannot be resumed.
1083 LOG(ERROR) << "partition has unexpected contents";
1084 PrintHashForCorruptedSourceBlocks(params, params.buffer);
1085
1086 params.isunresumable = true;
1087
1088 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001089}
1090
Tao Bao0940fe12015-08-27 16:41:21 -07001091static int PerformCommandMove(CommandParameters& params) {
Tao Bao33567772017-03-13 14:57:34 -07001092 size_t blocks = 0;
1093 bool overlap = false;
1094 RangeSet tgt;
Tao Baod2aecd42017-03-23 14:43:44 -07001095 int status = LoadSrcTgtVersion3(params, tgt, &blocks, true, &overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +00001096
Tao Bao33567772017-03-13 14:57:34 -07001097 if (status == -1) {
1098 LOG(ERROR) << "failed to read blocks for move";
1099 return -1;
1100 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001101
Tao Bao33567772017-03-13 14:57:34 -07001102 if (status == 0) {
1103 params.foundwrites = true;
1104 } else if (params.foundwrites) {
1105 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1106 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001107
Tao Bao33567772017-03-13 14:57:34 -07001108 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001109 if (status == 0) {
Tao Bao33567772017-03-13 14:57:34 -07001110 LOG(INFO) << " moving " << blocks << " blocks";
1111
1112 if (WriteBlocks(tgt, params.buffer, params.fd) == -1) {
1113 return -1;
1114 }
1115 } else {
1116 LOG(INFO) << "skipping " << blocks << " already moved blocks";
Sami Tolvanen90221202014-12-09 16:39:47 +00001117 }
Tao Bao33567772017-03-13 14:57:34 -07001118 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001119
Tao Bao33567772017-03-13 14:57:34 -07001120 if (!params.freestash.empty()) {
1121 FreeStash(params.stashbase, params.freestash);
1122 params.freestash.clear();
1123 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001124
Tao Baobf5b77d2017-03-30 16:57:29 -07001125 params.written += tgt.blocks();
Sami Tolvanen90221202014-12-09 16:39:47 +00001126
Tao Bao33567772017-03-13 14:57:34 -07001127 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001128}
1129
Tao Bao0940fe12015-08-27 16:41:21 -07001130static int PerformCommandStash(CommandParameters& params) {
Tao Baobcf46492017-03-23 15:28:20 -07001131 // <stash_id> <src_range>
1132 if (params.cpos + 1 >= params.tokens.size()) {
1133 LOG(ERROR) << "missing id and/or src range fields in stash command";
1134 return -1;
1135 }
1136
1137 const std::string& id = params.tokens[params.cpos++];
1138 size_t blocks = 0;
1139 if (LoadStash(params, id, true, &blocks, params.buffer, false) == 0) {
1140 // Stash file already exists and has expected contents. Do not read from source again, as the
1141 // source may have been already overwritten during a previous attempt.
1142 return 0;
1143 }
1144
Tao Bao8f237572017-03-26 13:36:49 -07001145 RangeSet src = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baobcf46492017-03-23 15:28:20 -07001146
Tao Baobf5b77d2017-03-30 16:57:29 -07001147 allocate(src.blocks() * BLOCKSIZE, params.buffer);
Tao Baobcf46492017-03-23 15:28:20 -07001148 if (ReadBlocks(src, params.buffer, params.fd) == -1) {
1149 return -1;
1150 }
Tao Baobf5b77d2017-03-30 16:57:29 -07001151 blocks = src.blocks();
Tao Baobcf46492017-03-23 15:28:20 -07001152 stash_map[id] = src;
1153
1154 if (VerifyBlocks(id, params.buffer, blocks, true) != 0) {
1155 // Source blocks have unexpected contents. If we actually need this data later, this is an
1156 // unrecoverable error. However, the command that uses the data may have already completed
1157 // previously, so the possible failure will occur during source block verification.
1158 LOG(ERROR) << "failed to load source blocks for stash " << id;
1159 return 0;
1160 }
1161
1162 // In verify mode, we don't need to stash any blocks.
1163 if (!params.canwrite) {
1164 return 0;
1165 }
1166
1167 LOG(INFO) << "stashing " << blocks << " blocks to " << id;
1168 params.stashed += blocks;
1169 return WriteStash(params.stashbase, id, blocks, params.buffer, false, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001170}
1171
Tao Bao0940fe12015-08-27 16:41:21 -07001172static int PerformCommandFree(CommandParameters& params) {
Tao Baobcf46492017-03-23 15:28:20 -07001173 // <stash_id>
1174 if (params.cpos >= params.tokens.size()) {
1175 LOG(ERROR) << "missing stash id in free command";
1176 return -1;
1177 }
Tao Baobaad2d42015-12-06 16:56:27 -08001178
Tao Baobcf46492017-03-23 15:28:20 -07001179 const std::string& id = params.tokens[params.cpos++];
1180 stash_map.erase(id);
Tianjie Xu7eca97e2016-03-22 18:08:12 -07001181
Tao Baobcf46492017-03-23 15:28:20 -07001182 if (params.createdstash || params.canwrite) {
1183 return FreeStash(params.stashbase, id);
1184 }
Tianjie Xu7eca97e2016-03-22 18:08:12 -07001185
Tao Baobcf46492017-03-23 15:28:20 -07001186 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001187}
1188
Tao Bao0940fe12015-08-27 16:41:21 -07001189static int PerformCommandZero(CommandParameters& params) {
Tao Baobf5b77d2017-03-30 16:57:29 -07001190 if (params.cpos >= params.tokens.size()) {
1191 LOG(ERROR) << "missing target blocks for zero";
1192 return -1;
1193 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001194
Tao Baobf5b77d2017-03-30 16:57:29 -07001195 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
1196
1197 LOG(INFO) << " zeroing " << tgt.blocks() << " blocks";
1198
1199 allocate(BLOCKSIZE, params.buffer);
1200 memset(params.buffer.data(), 0, BLOCKSIZE);
1201
1202 if (params.canwrite) {
1203 for (const auto& range : tgt) {
1204 off64_t offset = static_cast<off64_t>(range.first) * BLOCKSIZE;
1205 size_t size = (range.second - range.first) * BLOCKSIZE;
1206 if (!discard_blocks(params.fd, offset, size)) {
Tao Bao0940fe12015-08-27 16:41:21 -07001207 return -1;
Tao Baobf5b77d2017-03-30 16:57:29 -07001208 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001209
Tao Baobf5b77d2017-03-30 16:57:29 -07001210 if (!check_lseek(params.fd, offset, SEEK_SET)) {
1211 return -1;
1212 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001213
Tao Baobf5b77d2017-03-30 16:57:29 -07001214 for (size_t j = range.first; j < range.second; ++j) {
1215 if (write_all(params.fd, params.buffer, BLOCKSIZE) == -1) {
1216 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001217 }
Tao Baobf5b77d2017-03-30 16:57:29 -07001218 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001219 }
Tao Baobf5b77d2017-03-30 16:57:29 -07001220 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001221
Tao Baobf5b77d2017-03-30 16:57:29 -07001222 if (params.cmdname[0] == 'z') {
1223 // Update only for the zero command, as the erase command will call
1224 // this if DEBUG_ERASE is defined.
1225 params.written += tgt.blocks();
1226 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001227
Tao Baobf5b77d2017-03-30 16:57:29 -07001228 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001229}
1230
Tao Bao0940fe12015-08-27 16:41:21 -07001231static int PerformCommandNew(CommandParameters& params) {
Tao Bao60a70af2017-03-26 14:03:52 -07001232 if (params.cpos >= params.tokens.size()) {
1233 LOG(ERROR) << "missing target blocks for new";
1234 return -1;
1235 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001236
Tao Bao8f237572017-03-26 13:36:49 -07001237 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Bao60a70af2017-03-26 14:03:52 -07001238
1239 if (params.canwrite) {
Tao Baobf5b77d2017-03-30 16:57:29 -07001240 LOG(INFO) << " writing " << tgt.blocks() << " blocks of new data";
Tao Bao60a70af2017-03-26 14:03:52 -07001241
Tao Bao60a70af2017-03-26 14:03:52 -07001242 pthread_mutex_lock(&params.nti.mu);
Tianjie Xu107a34f2017-06-29 17:04:21 -07001243 if (params.nti.brotli_compressed) {
1244 params.nti.writer =
1245 std::make_unique<BrotliNewDataWriter>(params.fd, tgt, params.nti.brotli_decoder_state);
1246 } else {
1247 params.nti.writer = std::make_unique<RangeSinkWriter>(params.fd, tgt);
1248 }
Tao Bao60a70af2017-03-26 14:03:52 -07001249 pthread_cond_broadcast(&params.nti.cv);
1250
1251 while (params.nti.writer != nullptr) {
Tianjie Xu3a8d98d2017-04-03 20:01:17 -07001252 if (!params.nti.receiver_available) {
1253 LOG(ERROR) << "missing " << (tgt.blocks() * BLOCKSIZE - params.nti.writer->BytesWritten())
1254 << " bytes of new data";
1255 pthread_mutex_unlock(&params.nti.mu);
1256 return -1;
1257 }
Tao Bao60a70af2017-03-26 14:03:52 -07001258 pthread_cond_wait(&params.nti.cv, &params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001259 }
1260
Tao Bao60a70af2017-03-26 14:03:52 -07001261 pthread_mutex_unlock(&params.nti.mu);
1262 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001263
Tao Baobf5b77d2017-03-30 16:57:29 -07001264 params.written += tgt.blocks();
Sami Tolvanen90221202014-12-09 16:39:47 +00001265
Tao Bao60a70af2017-03-26 14:03:52 -07001266 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001267}
1268
Tao Bao0940fe12015-08-27 16:41:21 -07001269static int PerformCommandDiff(CommandParameters& params) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001270 // <offset> <length>
1271 if (params.cpos + 1 >= params.tokens.size()) {
1272 LOG(ERROR) << "missing patch offset or length for " << params.cmdname;
1273 return -1;
1274 }
Tao Bao0940fe12015-08-27 16:41:21 -07001275
Tao Baoc0e1c462017-02-01 10:20:10 -08001276 size_t offset;
1277 if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) {
1278 LOG(ERROR) << "invalid patch offset";
1279 return -1;
1280 }
Tao Bao0940fe12015-08-27 16:41:21 -07001281
Tao Baoc0e1c462017-02-01 10:20:10 -08001282 size_t len;
1283 if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) {
1284 LOG(ERROR) << "invalid patch len";
1285 return -1;
1286 }
Tao Bao0940fe12015-08-27 16:41:21 -07001287
Tao Baoc0e1c462017-02-01 10:20:10 -08001288 RangeSet tgt;
1289 size_t blocks = 0;
1290 bool overlap = false;
1291 int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap);
Tao Bao0940fe12015-08-27 16:41:21 -07001292
Tao Baoc0e1c462017-02-01 10:20:10 -08001293 if (status == -1) {
1294 LOG(ERROR) << "failed to read blocks for diff";
1295 return -1;
1296 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001297
Tao Baoc0e1c462017-02-01 10:20:10 -08001298 if (status == 0) {
1299 params.foundwrites = true;
1300 } else if (params.foundwrites) {
1301 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1302 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001303
Tao Baoc0e1c462017-02-01 10:20:10 -08001304 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001305 if (status == 0) {
Tao Baobf5b77d2017-03-30 16:57:29 -07001306 LOG(INFO) << "patching " << blocks << " blocks to " << tgt.blocks();
Tao Baoc0e1c462017-02-01 10:20:10 -08001307 Value patch_value(
1308 VAL_BLOB, std::string(reinterpret_cast<const char*>(params.patch_start + offset), len));
Sami Tolvanen90221202014-12-09 16:39:47 +00001309
Tao Bao60a70af2017-03-26 14:03:52 -07001310 RangeSinkWriter writer(params.fd, tgt);
Tao Baoc0e1c462017-02-01 10:20:10 -08001311 if (params.cmdname[0] == 'i') { // imgdiff
Tao Bao60a70af2017-03-26 14:03:52 -07001312 if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
1313 std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1,
1314 std::placeholders::_2),
1315 nullptr, nullptr) != 0) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001316 LOG(ERROR) << "Failed to apply image patch.";
Tianjie Xu69575552017-05-16 15:51:46 -07001317 failure_type = kPatchApplicationFailure;
Tao Baoc0e1c462017-02-01 10:20:10 -08001318 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001319 }
Tao Baoc0e1c462017-02-01 10:20:10 -08001320 } else {
Tao Bao60a70af2017-03-26 14:03:52 -07001321 if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0,
1322 std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1,
1323 std::placeholders::_2),
1324 nullptr) != 0) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001325 LOG(ERROR) << "Failed to apply bsdiff patch.";
Tianjie Xu69575552017-05-16 15:51:46 -07001326 failure_type = kPatchApplicationFailure;
Tao Baoc0e1c462017-02-01 10:20:10 -08001327 return -1;
1328 }
1329 }
1330
1331 // We expect the output of the patcher to fill the tgt ranges exactly.
Tao Bao60a70af2017-03-26 14:03:52 -07001332 if (!writer.Finished()) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001333 LOG(ERROR) << "range sink underrun?";
1334 }
1335 } else {
Tao Baobf5b77d2017-03-30 16:57:29 -07001336 LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.blocks() << " ["
Tao Baoc0e1c462017-02-01 10:20:10 -08001337 << params.cmdline << "]";
Sami Tolvanen90221202014-12-09 16:39:47 +00001338 }
Tao Baoc0e1c462017-02-01 10:20:10 -08001339 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001340
Tao Baoc0e1c462017-02-01 10:20:10 -08001341 if (!params.freestash.empty()) {
1342 FreeStash(params.stashbase, params.freestash);
1343 params.freestash.clear();
1344 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001345
Tao Baobf5b77d2017-03-30 16:57:29 -07001346 params.written += tgt.blocks();
Sami Tolvanen90221202014-12-09 16:39:47 +00001347
Tao Baoc0e1c462017-02-01 10:20:10 -08001348 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001349}
1350
Tao Bao0940fe12015-08-27 16:41:21 -07001351static int PerformCommandErase(CommandParameters& params) {
Tao Baobf5b77d2017-03-30 16:57:29 -07001352 if (DEBUG_ERASE) {
1353 return PerformCommandZero(params);
1354 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001355
Tao Baobf5b77d2017-03-30 16:57:29 -07001356 struct stat sb;
1357 if (fstat(params.fd, &sb) == -1) {
1358 PLOG(ERROR) << "failed to fstat device to erase";
1359 return -1;
1360 }
1361
1362 if (!S_ISBLK(sb.st_mode)) {
1363 LOG(ERROR) << "not a block device; skipping erase";
1364 return -1;
1365 }
1366
1367 if (params.cpos >= params.tokens.size()) {
1368 LOG(ERROR) << "missing target blocks for erase";
1369 return -1;
1370 }
1371
1372 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
1373
1374 if (params.canwrite) {
1375 LOG(INFO) << " erasing " << tgt.blocks() << " blocks";
1376
1377 for (const auto& range : tgt) {
1378 uint64_t blocks[2];
1379 // offset in bytes
1380 blocks[0] = range.first * static_cast<uint64_t>(BLOCKSIZE);
1381 // length in bytes
1382 blocks[1] = (range.second - range.first) * static_cast<uint64_t>(BLOCKSIZE);
1383
1384 if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
1385 PLOG(ERROR) << "BLKDISCARD ioctl failed";
Tao Bao0940fe12015-08-27 16:41:21 -07001386 return -1;
Tao Baobf5b77d2017-03-30 16:57:29 -07001387 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001388 }
Tao Baobf5b77d2017-03-30 16:57:29 -07001389 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001390
Tao Baobf5b77d2017-03-30 16:57:29 -07001391 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001392}
1393
1394// Definitions for transfer list command functions
Tao Bao0940fe12015-08-27 16:41:21 -07001395typedef int (*CommandFunction)(CommandParameters&);
Sami Tolvanen90221202014-12-09 16:39:47 +00001396
Tao Bao612336d2015-08-27 16:41:21 -07001397struct Command {
Sami Tolvanen90221202014-12-09 16:39:47 +00001398 const char* name;
1399 CommandFunction f;
Tao Bao612336d2015-08-27 16:41:21 -07001400};
Sami Tolvanen90221202014-12-09 16:39:47 +00001401
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001402// args:
1403// - block device (or file) to modify in-place
1404// - transfer list (blob)
1405// - new data stream (filename within package.zip)
1406// - patch stream (filename within package.zip, must be uncompressed)
1407
Tianjie Xuc4447322017-03-06 14:44:59 -08001408static Value* PerformBlockImageUpdate(const char* name, State* state,
1409 const std::vector<std::unique_ptr<Expr>>& argv,
1410 const Command* commands, size_t cmdcount, bool dryrun) {
Tao Bao33567772017-03-13 14:57:34 -07001411 CommandParameters params = {};
1412 params.canwrite = !dryrun;
Sami Tolvanen90221202014-12-09 16:39:47 +00001413
Tao Bao33567772017-03-13 14:57:34 -07001414 LOG(INFO) << "performing " << (dryrun ? "verification" : "update");
1415 if (state->is_retry) {
1416 is_retry = true;
1417 LOG(INFO) << "This update is a retry.";
1418 }
1419 if (argv.size() != 4) {
1420 ErrorAbort(state, kArgsParsingFailure, "block_image_update expects 4 arguments, got %zu",
1421 argv.size());
1422 return StringValue("");
1423 }
1424
1425 std::vector<std::unique_ptr<Value>> args;
1426 if (!ReadValueArgs(state, argv, &args)) {
1427 return nullptr;
1428 }
1429
Tao Baoc97edcb2017-03-31 01:18:13 -07001430 const std::unique_ptr<Value>& blockdev_filename = args[0];
1431 const std::unique_ptr<Value>& transfer_list_value = args[1];
1432 const std::unique_ptr<Value>& new_data_fn = args[2];
1433 const std::unique_ptr<Value>& patch_data_fn = args[3];
Tao Bao33567772017-03-13 14:57:34 -07001434
1435 if (blockdev_filename->type != VAL_STRING) {
1436 ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name);
1437 return StringValue("");
1438 }
1439 if (transfer_list_value->type != VAL_BLOB) {
1440 ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
1441 return StringValue("");
1442 }
1443 if (new_data_fn->type != VAL_STRING) {
1444 ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
1445 return StringValue("");
1446 }
1447 if (patch_data_fn->type != VAL_STRING) {
1448 ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", name);
1449 return StringValue("");
1450 }
1451
1452 UpdaterInfo* ui = static_cast<UpdaterInfo*>(state->cookie);
1453 if (ui == nullptr) {
1454 return StringValue("");
1455 }
1456
1457 FILE* cmd_pipe = ui->cmd_pipe;
1458 ZipArchiveHandle za = ui->package_zip;
1459
1460 if (cmd_pipe == nullptr || za == nullptr) {
1461 return StringValue("");
1462 }
1463
1464 ZipString path_data(patch_data_fn->data.c_str());
1465 ZipEntry patch_entry;
1466 if (FindEntry(za, path_data, &patch_entry) != 0) {
1467 LOG(ERROR) << name << "(): no file \"" << patch_data_fn->data << "\" in package";
1468 return StringValue("");
1469 }
1470
1471 params.patch_start = ui->package_zip_addr + patch_entry.offset;
1472 ZipString new_data(new_data_fn->data.c_str());
1473 ZipEntry new_entry;
1474 if (FindEntry(za, new_data, &new_entry) != 0) {
1475 LOG(ERROR) << name << "(): no file \"" << new_data_fn->data << "\" in package";
1476 return StringValue("");
1477 }
1478
1479 params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR)));
1480 if (params.fd == -1) {
1481 PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed";
1482 return StringValue("");
1483 }
1484
1485 if (params.canwrite) {
1486 params.nti.za = za;
1487 params.nti.entry = new_entry;
Tianjie Xu107a34f2017-06-29 17:04:21 -07001488 // The entry is compressed by brotli if has a 'br' extension.
1489 params.nti.brotli_compressed = android::base::EndsWith(new_data_fn->data, ".br");
1490 if (params.nti.brotli_compressed) {
1491 // Initialize brotli decoder state.
1492 params.nti.brotli_decoder_state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
1493 }
Tianjie Xu3a8d98d2017-04-03 20:01:17 -07001494 params.nti.receiver_available = true;
Tao Bao33567772017-03-13 14:57:34 -07001495
1496 pthread_mutex_init(&params.nti.mu, nullptr);
1497 pthread_cond_init(&params.nti.cv, nullptr);
1498 pthread_attr_t attr;
1499 pthread_attr_init(&attr);
1500 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1501
1502 int error = pthread_create(&params.thread, &attr, unzip_new_data, &params.nti);
1503 if (error != 0) {
1504 PLOG(ERROR) << "pthread_create failed";
1505 return StringValue("");
Tianjie Xu7ce287d2016-05-31 09:29:49 -07001506 }
Tao Bao33567772017-03-13 14:57:34 -07001507 }
1508
1509 std::vector<std::string> lines = android::base::Split(transfer_list_value->data, "\n");
1510 if (lines.size() < 2) {
1511 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
1512 lines.size());
1513 return StringValue("");
1514 }
1515
1516 // First line in transfer list is the version number.
1517 if (!android::base::ParseInt(lines[0], &params.version, 3, 4)) {
1518 LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]";
1519 return StringValue("");
1520 }
1521
1522 LOG(INFO) << "blockimg version is " << params.version;
1523
1524 // Second line in transfer list is the total number of blocks we expect to write.
1525 size_t total_blocks;
1526 if (!android::base::ParseUint(lines[1], &total_blocks)) {
1527 ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
1528 return StringValue("");
1529 }
1530
1531 if (total_blocks == 0) {
1532 return StringValue("t");
1533 }
1534
1535 size_t start = 2;
1536 if (lines.size() < 4) {
1537 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
1538 lines.size());
1539 return StringValue("");
1540 }
1541
1542 // Third line is how many stash entries are needed simultaneously.
1543 LOG(INFO) << "maximum stash entries " << lines[2];
1544
1545 // Fourth line is the maximum number of blocks that will be stashed simultaneously
1546 size_t stash_max_blocks;
1547 if (!android::base::ParseUint(lines[3], &stash_max_blocks)) {
1548 ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
1549 lines[3].c_str());
1550 return StringValue("");
1551 }
1552
1553 int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase);
1554 if (res == -1) {
1555 return StringValue("");
1556 }
1557
1558 params.createdstash = res;
1559
1560 start += 2;
1561
1562 // Build a map of the available commands
1563 std::unordered_map<std::string, const Command*> cmd_map;
1564 for (size_t i = 0; i < cmdcount; ++i) {
1565 if (cmd_map.find(commands[i].name) != cmd_map.end()) {
1566 LOG(ERROR) << "Error: command [" << commands[i].name << "] already exists in the cmd map.";
1567 return StringValue(strdup(""));
1568 }
1569 cmd_map[commands[i].name] = &commands[i];
1570 }
1571
1572 int rc = -1;
1573
1574 // Subsequent lines are all individual transfer commands
1575 for (auto it = lines.cbegin() + start; it != lines.cend(); it++) {
1576 const std::string& line(*it);
1577 if (line.empty()) continue;
1578
1579 params.tokens = android::base::Split(line, " ");
1580 params.cpos = 0;
1581 params.cmdname = params.tokens[params.cpos++].c_str();
1582 params.cmdline = line.c_str();
1583
1584 if (cmd_map.find(params.cmdname) == cmd_map.end()) {
1585 LOG(ERROR) << "unexpected command [" << params.cmdname << "]";
1586 goto pbiudone;
Tianjie Xuc4447322017-03-06 14:44:59 -08001587 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001588
Tao Bao33567772017-03-13 14:57:34 -07001589 const Command* cmd = cmd_map[params.cmdname];
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001590
Tao Bao33567772017-03-13 14:57:34 -07001591 if (cmd->f != nullptr && cmd->f(params) == -1) {
1592 LOG(ERROR) << "failed to execute command [" << line << "]";
1593 goto pbiudone;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001594 }
1595
Sami Tolvanen90221202014-12-09 16:39:47 +00001596 if (params.canwrite) {
Tao Bao33567772017-03-13 14:57:34 -07001597 if (ota_fsync(params.fd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -07001598 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -08001599 PLOG(ERROR) << "fsync failed";
Tao Bao33567772017-03-13 14:57:34 -07001600 goto pbiudone;
1601 }
1602 fprintf(cmd_pipe, "set_progress %.4f\n", static_cast<double>(params.written) / total_blocks);
1603 fflush(cmd_pipe);
Sami Tolvanen90221202014-12-09 16:39:47 +00001604 }
Tao Bao33567772017-03-13 14:57:34 -07001605 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001606
Tao Bao33567772017-03-13 14:57:34 -07001607 if (params.canwrite) {
1608 pthread_join(params.thread, nullptr);
1609
1610 LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks;
1611 LOG(INFO) << "stashed " << params.stashed << " blocks";
1612 LOG(INFO) << "max alloc needed was " << params.buffer.size();
1613
1614 const char* partition = strrchr(blockdev_filename->data.c_str(), '/');
1615 if (partition != nullptr && *(partition + 1) != 0) {
1616 fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE);
1617 fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, params.stashed * BLOCKSIZE);
1618 fflush(cmd_pipe);
Sami Tolvanen90221202014-12-09 16:39:47 +00001619 }
Tao Bao33567772017-03-13 14:57:34 -07001620 // Delete stash only after successfully completing the update, as it may contain blocks needed
1621 // to complete the update later.
1622 DeleteStash(params.stashbase);
1623 } else {
1624 LOG(INFO) << "verified partition contents; update may be resumed";
1625 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001626
Tao Bao33567772017-03-13 14:57:34 -07001627 rc = 0;
Tianjie Xu16255832016-04-30 11:49:59 -07001628
Tao Bao33567772017-03-13 14:57:34 -07001629pbiudone:
1630 if (ota_fsync(params.fd) == -1) {
1631 failure_type = kFsyncFailure;
1632 PLOG(ERROR) << "fsync failed";
1633 }
1634 // params.fd will be automatically closed because it's a unique_fd.
1635
Tianjie Xu107a34f2017-06-29 17:04:21 -07001636 if (params.nti.brotli_decoder_state != nullptr) {
1637 BrotliDecoderDestroyInstance(params.nti.brotli_decoder_state);
1638 }
1639
Tao Bao33567772017-03-13 14:57:34 -07001640 // Only delete the stash if the update cannot be resumed, or it's a verification run and we
1641 // created the stash.
1642 if (params.isunresumable || (!params.canwrite && params.createdstash)) {
1643 DeleteStash(params.stashbase);
1644 }
1645
1646 if (failure_type != kNoCause && state->cause_code == kNoCause) {
1647 state->cause_code = failure_type;
1648 }
1649
1650 return StringValue(rc == 0 ? "t" : "");
Sami Tolvanen90221202014-12-09 16:39:47 +00001651}
1652
Tao Bao33567772017-03-13 14:57:34 -07001653/**
1654 * The transfer list is a text file containing commands to transfer data from one place to another
1655 * on the target partition. We parse it and execute the commands in order:
1656 *
1657 * zero [rangeset]
1658 * - Fill the indicated blocks with zeros.
1659 *
1660 * new [rangeset]
1661 * - Fill the blocks with data read from the new_data file.
1662 *
1663 * erase [rangeset]
1664 * - Mark the given blocks as empty.
1665 *
1666 * move <...>
1667 * bsdiff <patchstart> <patchlen> <...>
1668 * imgdiff <patchstart> <patchlen> <...>
1669 * - Read the source blocks, apply a patch (or not in the case of move), write result to target
1670 * blocks. bsdiff or imgdiff specifies the type of patch; move means no patch at all.
1671 *
1672 * See the comments in LoadSrcTgtVersion3() for a description of the <...> format.
1673 *
1674 * stash <stash_id> <src_range>
1675 * - Load the given source range and stash the data in the given slot of the stash table.
1676 *
1677 * free <stash_id>
1678 * - Free the given stash data.
1679 *
1680 * The creator of the transfer list will guarantee that no block is read (ie, used as the source for
1681 * a patch or move) after it has been written.
1682 *
1683 * The creator will guarantee that a given stash is loaded (with a stash command) before it's used
1684 * in a move/bsdiff/imgdiff command.
1685 *
1686 * Within one command the source and target ranges may overlap so in general we need to read the
1687 * entire source into memory before writing anything to the target blocks.
1688 *
1689 * All the patch data is concatenated into one patch_data file in the update package. It must be
1690 * stored uncompressed because we memory-map it in directly from the archive. (Since patches are
1691 * already compressed, we lose very little by not compressing their concatenation.)
1692 *
1693 * Commands that read data from the partition (i.e. move/bsdiff/imgdiff/stash) have one or more
1694 * additional hashes before the range parameters, which are used to check if the command has already
1695 * been completed and verify the integrity of the source data.
1696 */
Tianjie Xuc4447322017-03-06 14:44:59 -08001697Value* BlockImageVerifyFn(const char* name, State* state,
1698 const std::vector<std::unique_ptr<Expr>>& argv) {
Tao Bao0940fe12015-08-27 16:41:21 -07001699 // Commands which are not tested are set to nullptr to skip them completely
Sami Tolvanen90221202014-12-09 16:39:47 +00001700 const Command commands[] = {
1701 { "bsdiff", PerformCommandDiff },
Tao Bao0940fe12015-08-27 16:41:21 -07001702 { "erase", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001703 { "free", PerformCommandFree },
1704 { "imgdiff", PerformCommandDiff },
1705 { "move", PerformCommandMove },
Tao Bao0940fe12015-08-27 16:41:21 -07001706 { "new", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001707 { "stash", PerformCommandStash },
Tao Bao0940fe12015-08-27 16:41:21 -07001708 { "zero", nullptr }
Sami Tolvanen90221202014-12-09 16:39:47 +00001709 };
1710
1711 // Perform a dry run without writing to test if an update can proceed
Tianjie Xuc4447322017-03-06 14:44:59 -08001712 return PerformBlockImageUpdate(name, state, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001713 sizeof(commands) / sizeof(commands[0]), true);
Sami Tolvanen90221202014-12-09 16:39:47 +00001714}
1715
Tianjie Xuc4447322017-03-06 14:44:59 -08001716Value* BlockImageUpdateFn(const char* name, State* state,
1717 const std::vector<std::unique_ptr<Expr>>& argv) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001718 const Command commands[] = {
1719 { "bsdiff", PerformCommandDiff },
1720 { "erase", PerformCommandErase },
1721 { "free", PerformCommandFree },
1722 { "imgdiff", PerformCommandDiff },
1723 { "move", PerformCommandMove },
1724 { "new", PerformCommandNew },
1725 { "stash", PerformCommandStash },
1726 { "zero", PerformCommandZero }
1727 };
1728
Tianjie Xuc4447322017-03-06 14:44:59 -08001729 return PerformBlockImageUpdate(name, state, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001730 sizeof(commands) / sizeof(commands[0]), false);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001731}
1732
Tianjie Xuc4447322017-03-06 14:44:59 -08001733Value* RangeSha1Fn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001734 if (argv.size() != 2) {
1735 ErrorAbort(state, kArgsParsingFailure, "range_sha1 expects 2 arguments, got %zu", argv.size());
1736 return StringValue("");
1737 }
1738
1739 std::vector<std::unique_ptr<Value>> args;
1740 if (!ReadValueArgs(state, argv, &args)) {
1741 return nullptr;
1742 }
1743
1744 const std::unique_ptr<Value>& blockdev_filename = args[0];
1745 const std::unique_ptr<Value>& ranges = args[1];
1746
1747 if (blockdev_filename->type != VAL_STRING) {
1748 ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name);
1749 return StringValue("");
1750 }
1751 if (ranges->type != VAL_STRING) {
1752 ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
1753 return StringValue("");
1754 }
1755
1756 android::base::unique_fd fd(ota_open(blockdev_filename->data.c_str(), O_RDWR));
1757 if (fd == -1) {
1758 ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data.c_str(),
1759 strerror(errno));
1760 return StringValue("");
1761 }
1762
1763 RangeSet rs = RangeSet::Parse(ranges->data);
1764
1765 SHA_CTX ctx;
1766 SHA1_Init(&ctx);
1767
1768 std::vector<uint8_t> buffer(BLOCKSIZE);
Tao Baobf5b77d2017-03-30 16:57:29 -07001769 for (const auto& range : rs) {
1770 if (!check_lseek(fd, static_cast<off64_t>(range.first) * BLOCKSIZE, SEEK_SET)) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001771 ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data.c_str(),
1772 strerror(errno));
1773 return StringValue("");
1774 }
1775
Tao Baobf5b77d2017-03-30 16:57:29 -07001776 for (size_t j = range.first; j < range.second; ++j) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001777 if (read_all(fd, buffer, BLOCKSIZE) == -1) {
1778 ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data.c_str(),
1779 strerror(errno));
Tianjie Xuc4447322017-03-06 14:44:59 -08001780 return StringValue("");
Tao Baoc97edcb2017-03-31 01:18:13 -07001781 }
1782
1783 SHA1_Update(&ctx, buffer.data(), BLOCKSIZE);
Tianjie Xuc4447322017-03-06 14:44:59 -08001784 }
Tao Baoc97edcb2017-03-31 01:18:13 -07001785 }
1786 uint8_t digest[SHA_DIGEST_LENGTH];
1787 SHA1_Final(digest, &ctx);
Tianjie Xuc4447322017-03-06 14:44:59 -08001788
Tao Baoc97edcb2017-03-31 01:18:13 -07001789 return StringValue(print_sha1(digest));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001790}
1791
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001792// This function checks if a device has been remounted R/W prior to an incremental
1793// OTA update. This is an common cause of update abortion. The function reads the
1794// 1st block of each partition and check for mounting time/count. It return string "t"
1795// if executes successfully and an empty string otherwise.
1796
Tianjie Xuc4447322017-03-06 14:44:59 -08001797Value* CheckFirstBlockFn(const char* name, State* state,
1798 const std::vector<std::unique_ptr<Expr>>& argv) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001799 if (argv.size() != 1) {
1800 ErrorAbort(state, kArgsParsingFailure, "check_first_block expects 1 argument, got %zu",
1801 argv.size());
1802 return StringValue("");
1803 }
Tianjie Xuc4447322017-03-06 14:44:59 -08001804
Tao Baoc97edcb2017-03-31 01:18:13 -07001805 std::vector<std::unique_ptr<Value>> args;
1806 if (!ReadValueArgs(state, argv, &args)) {
1807 return nullptr;
1808 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001809
Tao Baoc97edcb2017-03-31 01:18:13 -07001810 const std::unique_ptr<Value>& arg_filename = args[0];
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001811
Tao Baoc97edcb2017-03-31 01:18:13 -07001812 if (arg_filename->type != VAL_STRING) {
1813 ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
1814 return StringValue("");
1815 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001816
Tao Baoc97edcb2017-03-31 01:18:13 -07001817 android::base::unique_fd fd(ota_open(arg_filename->data.c_str(), O_RDONLY));
1818 if (fd == -1) {
1819 ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data.c_str(),
1820 strerror(errno));
1821 return StringValue("");
1822 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001823
Tao Baobf5b77d2017-03-30 16:57:29 -07001824 RangeSet blk0(std::vector<Range>{ Range{ 0, 1 } });
Tao Baoc97edcb2017-03-31 01:18:13 -07001825 std::vector<uint8_t> block0_buffer(BLOCKSIZE);
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001826
Tao Baoc97edcb2017-03-31 01:18:13 -07001827 if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
1828 ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data.c_str(),
1829 strerror(errno));
1830 return StringValue("");
1831 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001832
Tao Baoc97edcb2017-03-31 01:18:13 -07001833 // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
1834 // Super block starts from block 0, offset 0x400
1835 // 0x2C: len32 Mount time
1836 // 0x30: len32 Write time
1837 // 0x34: len16 Number of mounts since the last fsck
1838 // 0x38: len16 Magic signature 0xEF53
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001839
Tao Baoc97edcb2017-03-31 01:18:13 -07001840 time_t mount_time = *reinterpret_cast<uint32_t*>(&block0_buffer[0x400 + 0x2C]);
1841 uint16_t mount_count = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400 + 0x34]);
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001842
Tao Baoc97edcb2017-03-31 01:18:13 -07001843 if (mount_count > 0) {
1844 uiPrintf(state, "Device was remounted R/W %" PRIu16 " times", mount_count);
1845 uiPrintf(state, "Last remount happened on %s", ctime(&mount_time));
1846 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001847
Tao Baoc97edcb2017-03-31 01:18:13 -07001848 return StringValue("t");
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001849}
1850
Tianjie Xuc4447322017-03-06 14:44:59 -08001851Value* BlockImageRecoverFn(const char* name, State* state,
1852 const std::vector<std::unique_ptr<Expr>>& argv) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001853 if (argv.size() != 2) {
1854 ErrorAbort(state, kArgsParsingFailure, "block_image_recover expects 2 arguments, got %zu",
1855 argv.size());
1856 return StringValue("");
1857 }
1858
1859 std::vector<std::unique_ptr<Value>> args;
1860 if (!ReadValueArgs(state, argv, &args)) {
1861 return nullptr;
1862 }
1863
1864 const std::unique_ptr<Value>& filename = args[0];
1865 const std::unique_ptr<Value>& ranges = args[1];
1866
1867 if (filename->type != VAL_STRING) {
1868 ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
1869 return StringValue("");
1870 }
1871 if (ranges->type != VAL_STRING) {
1872 ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
1873 return StringValue("");
1874 }
1875
1876 // Output notice to log when recover is attempted
1877 LOG(INFO) << filename->data << " image corrupted, attempting to recover...";
1878
1879 // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
1880 fec::io fh(filename->data, O_RDWR);
1881
1882 if (!fh) {
1883 ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(),
1884 strerror(errno));
1885 return StringValue("");
1886 }
1887
1888 if (!fh.has_ecc() || !fh.has_verity()) {
1889 ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors");
1890 return StringValue("");
1891 }
1892
1893 fec_status status;
Tao Baoc97edcb2017-03-31 01:18:13 -07001894 if (!fh.get_status(status)) {
1895 ErrorAbort(state, kLibfecFailure, "failed to read FEC status");
1896 return StringValue("");
1897 }
1898
Tao Baoc97edcb2017-03-31 01:18:13 -07001899 uint8_t buffer[BLOCKSIZE];
Tao Baobf5b77d2017-03-30 16:57:29 -07001900 for (const auto& range : RangeSet::Parse(ranges->data)) {
1901 for (size_t j = range.first; j < range.second; ++j) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001902 // Stay within the data area, libfec validates and corrects metadata
Tao Baobf5b77d2017-03-30 16:57:29 -07001903 if (status.data_size <= static_cast<uint64_t>(j) * BLOCKSIZE) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001904 continue;
1905 }
1906
Tao Baobf5b77d2017-03-30 16:57:29 -07001907 if (fh.pread(buffer, BLOCKSIZE, static_cast<off64_t>(j) * BLOCKSIZE) != BLOCKSIZE) {
Tao Baoc97edcb2017-03-31 01:18:13 -07001908 ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
1909 filename->data.c_str(), j, strerror(errno));
Tianjie Xuc4447322017-03-06 14:44:59 -08001910 return StringValue("");
Tao Baoc97edcb2017-03-31 01:18:13 -07001911 }
1912
1913 // If we want to be able to recover from a situation where rewriting a corrected
1914 // block doesn't guarantee the same data will be returned when re-read later, we
1915 // can save a copy of corrected blocks to /cache. Note:
1916 //
1917 // 1. Maximum space required from /cache is the same as the maximum number of
1918 // corrupted blocks we can correct. For RS(255, 253) and a 2 GiB partition,
1919 // this would be ~16 MiB, for example.
1920 //
1921 // 2. To find out if this block was corrupted, call fec_get_status after each
1922 // read and check if the errors field value has increased.
Tianjie Xuc4447322017-03-06 14:44:59 -08001923 }
Tao Baoc97edcb2017-03-31 01:18:13 -07001924 }
1925 LOG(INFO) << "..." << filename->data << " image recovered successfully.";
1926 return StringValue("t");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001927}
1928
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001929void RegisterBlockImageFunctions() {
Tao Baoc97edcb2017-03-31 01:18:13 -07001930 RegisterFunction("block_image_verify", BlockImageVerifyFn);
1931 RegisterFunction("block_image_update", BlockImageUpdateFn);
1932 RegisterFunction("block_image_recover", BlockImageRecoverFn);
1933 RegisterFunction("check_first_block", CheckFirstBlockFn);
1934 RegisterFunction("range_sha1", RangeSha1Fn);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001935}