Merge "BatteryMonitor: report current_now in uA" into rvc-dev
diff --git a/adb/apex/Android.bp b/adb/apex/Android.bp
index 4346f67..ddb17da 100644
--- a/adb/apex/Android.bp
+++ b/adb/apex/Android.bp
@@ -1,6 +1,7 @@
apex_defaults {
name: "com.android.adbd-defaults",
updatable: true,
+ min_sdk_version: "R",
binaries: ["adbd"],
compile_multilib: "both",
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index b56df44..f56ef9a 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -16,13 +16,13 @@
#include "incremental.h"
-#include <android-base/endian.h>
+#include "incremental_utils.h"
+
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <openssl/base64.h>
#include "adb_client.h"
-#include "adb_io.h"
#include "adb_utils.h"
#include "commandline.h"
#include "sysdeps.h"
@@ -31,65 +31,8 @@
namespace incremental {
-namespace {
-
-static constexpr auto IDSIG = ".idsig"sv;
-
using android::base::StringPrintf;
-using Size = int64_t;
-
-static inline int32_t read_int32(borrowed_fd fd) {
- int32_t result;
- return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1;
-}
-
-static inline void append_int(borrowed_fd fd, std::vector<char>* bytes) {
- int32_t le_val = read_int32(fd);
- auto old_size = bytes->size();
- bytes->resize(old_size + sizeof(le_val));
- memcpy(bytes->data() + old_size, &le_val, sizeof(le_val));
-}
-
-static inline void append_bytes_with_size(borrowed_fd fd, std::vector<char>* bytes) {
- int32_t le_size = read_int32(fd);
- if (le_size < 0) {
- return;
- }
- int32_t size = int32_t(le32toh(le_size));
- auto old_size = bytes->size();
- bytes->resize(old_size + sizeof(le_size) + size);
- memcpy(bytes->data() + old_size, &le_size, sizeof(le_size));
- ReadFdExactly(fd, bytes->data() + old_size + sizeof(le_size), size);
-}
-
-static inline std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
- std::vector<char> result;
- append_int(fd, &result); // version
- append_bytes_with_size(fd, &result); // hashingInfo
- append_bytes_with_size(fd, &result); // signingInfo
- auto le_tree_size = read_int32(fd);
- auto tree_size = int32_t(le32toh(le_tree_size)); // size of the verity tree
- return {std::move(result), tree_size};
-}
-
-static inline Size verity_tree_size_for_file(Size fileSize) {
- constexpr int INCFS_DATA_FILE_BLOCK_SIZE = 4096;
- constexpr int SHA256_DIGEST_SIZE = 32;
- constexpr int digest_size = SHA256_DIGEST_SIZE;
- constexpr int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
-
- Size total_tree_block_count = 0;
-
- auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
- auto hash_block_count = block_count;
- for (auto i = 0; hash_block_count > 1; i++) {
- hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
- total_tree_block_count += hash_block_count;
- }
- return total_tree_block_count * INCFS_DATA_FILE_BLOCK_SIZE;
-}
-
// Read, verify and return the signature bytes. Keeping fd at the position of start of verity tree.
static std::pair<unique_fd, std::vector<char>> read_signature(Size file_size,
std::string signature_file,
@@ -104,7 +47,7 @@
return {};
}
- unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY | O_CLOEXEC));
+ unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY));
if (fd < 0) {
if (!silent) {
fprintf(stderr, "Failed to open signature file: %s. Abort.\n", signature_file.c_str());
@@ -172,9 +115,8 @@
return {};
}
- auto file_desc =
- StringPrintf("%s:%lld:%s:%s", android::base::Basename(file).c_str(),
- (long long)st.st_size, std::to_string(i).c_str(), signature.c_str());
+ auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
+ (long long)st.st_size, i, signature.c_str());
command_args.push_back(std::move(file_desc));
signature_fds.push_back(std::move(signature_fd));
@@ -190,21 +132,9 @@
return {};
}
- // Pushing verity trees for all installation files.
- for (auto&& local_fd : signature_fds) {
- if (!copy_to_file(local_fd.get(), connection_fd.get())) {
- if (!silent) {
- fprintf(stderr, "Failed to stream tree bytes: %s. Abort.\n", strerror(errno));
- }
- return {};
- }
- }
-
return connection_fd;
}
-} // namespace
-
bool can_install(const Files& files) {
for (const auto& file : files) {
struct stat st;
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
index 4a131ce..bfe18c0 100644
--- a/adb/client/incremental_server.cpp
+++ b/adb/client/incremental_server.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,9 +44,10 @@
namespace incremental {
-static constexpr int kBlockSize = 4096;
+static constexpr int kHashesPerBlock = kBlockSize / kDigestSize;
static constexpr int kCompressedSizeMax = kBlockSize * 0.95;
static constexpr int8_t kTypeData = 0;
+static constexpr int8_t kTypeHash = 1;
static constexpr int8_t kCompressionNone = 0;
static constexpr int8_t kCompressionLZ4 = 1;
static constexpr int kCompressBound = std::max(kBlockSize, LZ4_COMPRESSBOUND(kBlockSize));
@@ -132,41 +133,64 @@
CompressionType compression_type; // 1 byte
BlockIdx block_idx; // 4 bytes
BlockSize block_size; // 2 bytes
+
+ static constexpr size_t responseSizeFor(size_t dataSize) {
+ return dataSize + sizeof(ResponseHeader);
+ }
+} __attribute__((packed));
+
+template <size_t Size = kBlockSize>
+struct BlockBuffer {
+ ResponseHeader header;
+ char data[Size];
} __attribute__((packed));
// Holds streaming state for a file
class File {
public:
// Plain file
- File(const char* filepath, FileId id, int64_t size, unique_fd fd) : File(filepath, id, size) {
+ File(const char* filepath, FileId id, int64_t size, unique_fd fd, int64_t tree_offset,
+ unique_fd tree_fd)
+ : File(filepath, id, size, tree_offset) {
this->fd_ = std::move(fd);
+ this->tree_fd_ = std::move(tree_fd);
priority_blocks_ = PriorityBlocksForFile(filepath, fd_.get(), size);
}
- int64_t ReadBlock(BlockIdx block_idx, void* buf, bool* is_zip_compressed,
- std::string* error) const {
- char* buf_ptr = static_cast<char*>(buf);
+ int64_t ReadDataBlock(BlockIdx block_idx, void* buf, bool* is_zip_compressed) const {
int64_t bytes_read = -1;
const off64_t offsetStart = blockIndexToOffset(block_idx);
- bytes_read = adb_pread(fd_, &buf_ptr[sizeof(ResponseHeader)], kBlockSize, offsetStart);
+ bytes_read = adb_pread(fd_, buf, kBlockSize, offsetStart);
+ return bytes_read;
+ }
+ int64_t ReadTreeBlock(BlockIdx block_idx, void* buf) const {
+ int64_t bytes_read = -1;
+ const off64_t offsetStart = tree_offset_ + blockIndexToOffset(block_idx);
+ bytes_read = adb_pread(tree_fd_, buf, kBlockSize, offsetStart);
return bytes_read;
}
- const unique_fd& RawFd() const { return fd_; }
const std::vector<BlockIdx>& PriorityBlocks() const { return priority_blocks_; }
std::vector<bool> sentBlocks;
NumBlocks sentBlocksCount = 0;
+ std::vector<bool> sentTreeBlocks;
+
const char* const filepath;
const FileId id;
const int64_t size;
private:
- File(const char* filepath, FileId id, int64_t size) : filepath(filepath), id(id), size(size) {
+ File(const char* filepath, FileId id, int64_t size, int64_t tree_offset)
+ : filepath(filepath), id(id), size(size), tree_offset_(tree_offset) {
sentBlocks.resize(numBytesToNumBlocks(size));
+ sentTreeBlocks.resize(verity_tree_blocks_for_file(size));
}
unique_fd fd_;
std::vector<BlockIdx> priority_blocks_;
+
+ unique_fd tree_fd_;
+ const int64_t tree_offset_;
};
class IncrementalServer {
@@ -174,6 +198,8 @@
IncrementalServer(unique_fd adb_fd, unique_fd output_fd, std::vector<File> files)
: adb_fd_(std::move(adb_fd)), output_fd_(std::move(output_fd)), files_(std::move(files)) {
buffer_.reserve(kReadBufferSize);
+ pendingBlocksBuffer_.resize(kChunkFlushSize + 2 * kBlockSize);
+ pendingBlocks_ = pendingBlocksBuffer_.data() + sizeof(ChunkHeader);
}
bool Serve();
@@ -208,7 +234,11 @@
void erase_buffer_head(int count) { buffer_.erase(buffer_.begin(), buffer_.begin() + count); }
enum class SendResult { Sent, Skipped, Error };
- SendResult SendBlock(FileId fileId, BlockIdx blockIdx, bool flush = false);
+ SendResult SendDataBlock(FileId fileId, BlockIdx blockIdx, bool flush = false);
+
+ bool SendTreeBlock(FileId fileId, int32_t fileBlockIdx, BlockIdx blockIdx);
+ bool SendTreeBlocksForDataBlock(FileId fileId, BlockIdx blockIdx);
+
bool SendDone();
void RunPrefetching();
@@ -228,7 +258,10 @@
int compressed_ = 0, uncompressed_ = 0;
long long sentSize_ = 0;
- std::vector<char> pendingBlocks_;
+ static constexpr auto kChunkFlushSize = 31 * kBlockSize;
+
+ std::vector<char> pendingBlocksBuffer_;
+ char* pendingBlocks_ = nullptr;
// True when client notifies that all the data has been received
bool servingComplete_ = false;
@@ -250,7 +283,7 @@
if (bcur > 0) {
// output the rest.
- WriteFdExactly(output_fd_, buffer_.data(), bcur);
+ (void)WriteFdExactly(output_fd_, buffer_.data(), bcur);
erase_buffer_head(bcur);
}
@@ -265,9 +298,10 @@
auto res = adb_poll(&pfd, 1, blocking ? kPollTimeoutMillis : 0);
if (res != 1) {
- WriteFdExactly(output_fd_, buffer_.data(), buffer_.size());
+ auto err = errno;
+ (void)WriteFdExactly(output_fd_, buffer_.data(), buffer_.size());
if (res < 0) {
- D("Failed to poll: %s\n", strerror(errno));
+ D("Failed to poll: %s", strerror(err));
return false;
}
if (blocking) {
@@ -289,7 +323,7 @@
continue;
}
- D("Failed to read from fd %d: %d. Exit\n", adb_fd_.get(), errno);
+ D("Failed to read from fd %d: %d. Exit", adb_fd_.get(), errno);
break;
}
// socket is closed. print remaining messages
@@ -313,56 +347,113 @@
return request;
}
-auto IncrementalServer::SendBlock(FileId fileId, BlockIdx blockIdx, bool flush) -> SendResult {
+bool IncrementalServer::SendTreeBlocksForDataBlock(const FileId fileId, const BlockIdx blockIdx) {
+ auto& file = files_[fileId];
+ const int32_t data_block_count = numBytesToNumBlocks(file.size);
+
+ const int32_t total_nodes_count(file.sentTreeBlocks.size());
+ const int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock;
+
+ const int32_t leaf_nodes_offset = total_nodes_count - leaf_nodes_count;
+
+ // Leaf level, sending only 1 block.
+ const int32_t leaf_idx = leaf_nodes_offset + blockIdx / kHashesPerBlock;
+ if (file.sentTreeBlocks[leaf_idx]) {
+ return true;
+ }
+ if (!SendTreeBlock(fileId, blockIdx, leaf_idx)) {
+ return false;
+ }
+ file.sentTreeBlocks[leaf_idx] = true;
+
+ // Non-leaf, sending EVERYTHING. This should be done only once.
+ if (leaf_nodes_offset == 0 || file.sentTreeBlocks[0]) {
+ return true;
+ }
+
+ for (int32_t i = 0; i < leaf_nodes_offset; ++i) {
+ if (!SendTreeBlock(fileId, blockIdx, i)) {
+ return false;
+ }
+ file.sentTreeBlocks[i] = true;
+ }
+ return true;
+}
+
+bool IncrementalServer::SendTreeBlock(FileId fileId, int32_t fileBlockIdx, BlockIdx blockIdx) {
+ const auto& file = files_[fileId];
+
+ BlockBuffer buffer;
+ const int64_t bytesRead = file.ReadTreeBlock(blockIdx, buffer.data);
+ if (bytesRead <= 0) {
+ fprintf(stderr, "Failed to get data for %s.idsig at blockIdx=%d.\n", file.filepath,
+ blockIdx);
+ return false;
+ }
+
+ buffer.header.compression_type = kCompressionNone;
+ buffer.header.block_type = kTypeHash;
+ buffer.header.file_id = toBigEndian(fileId);
+ buffer.header.block_size = toBigEndian(int16_t(bytesRead));
+ buffer.header.block_idx = toBigEndian(blockIdx);
+
+ Send(&buffer, ResponseHeader::responseSizeFor(bytesRead), /*flush=*/false);
+
+ return true;
+}
+
+auto IncrementalServer::SendDataBlock(FileId fileId, BlockIdx blockIdx, bool flush) -> SendResult {
auto& file = files_[fileId];
if (blockIdx >= static_cast<long>(file.sentBlocks.size())) {
- fprintf(stderr, "Failed to read file %s at block %" PRId32 " (past end).\n", file.filepath,
- blockIdx);
- return SendResult::Error;
+ // may happen as we schedule some extra blocks for reported page misses
+ D("Skipped reading file %s at block %" PRId32 " (past end).", file.filepath, blockIdx);
+ return SendResult::Skipped;
}
if (file.sentBlocks[blockIdx]) {
return SendResult::Skipped;
}
- std::string error;
- char raw[sizeof(ResponseHeader) + kBlockSize];
- bool isZipCompressed = false;
- const int64_t bytesRead = file.ReadBlock(blockIdx, &raw, &isZipCompressed, &error);
- if (bytesRead < 0) {
- fprintf(stderr, "Failed to get data for %s at blockIdx=%d (%s).\n", file.filepath, blockIdx,
- error.c_str());
+
+ if (!SendTreeBlocksForDataBlock(fileId, blockIdx)) {
return SendResult::Error;
}
- ResponseHeader* header = nullptr;
- char data[sizeof(ResponseHeader) + kCompressBound];
- char* compressed = data + sizeof(*header);
+ BlockBuffer raw;
+ bool isZipCompressed = false;
+ const int64_t bytesRead = file.ReadDataBlock(blockIdx, raw.data, &isZipCompressed);
+ if (bytesRead < 0) {
+ fprintf(stderr, "Failed to get data for %s at blockIdx=%d (%d).\n", file.filepath, blockIdx,
+ errno);
+ return SendResult::Error;
+ }
+
+ BlockBuffer<kCompressBound> compressed;
int16_t compressedSize = 0;
if (!isZipCompressed) {
- compressedSize =
- LZ4_compress_default(raw + sizeof(*header), compressed, bytesRead, kCompressBound);
+ compressedSize = LZ4_compress_default(raw.data, compressed.data, bytesRead, kCompressBound);
}
int16_t blockSize;
+ ResponseHeader* header;
if (compressedSize > 0 && compressedSize < kCompressedSizeMax) {
++compressed_;
blockSize = compressedSize;
- header = reinterpret_cast<ResponseHeader*>(data);
+ header = &compressed.header;
header->compression_type = kCompressionLZ4;
} else {
++uncompressed_;
blockSize = bytesRead;
- header = reinterpret_cast<ResponseHeader*>(raw);
+ header = &raw.header;
header->compression_type = kCompressionNone;
}
header->block_type = kTypeData;
-
header->file_id = toBigEndian(fileId);
header->block_size = toBigEndian(blockSize);
header->block_idx = toBigEndian(blockIdx);
file.sentBlocks[blockIdx] = true;
file.sentBlocksCount += 1;
- Send(header, sizeof(*header) + blockSize, flush);
+ Send(header, ResponseHeader::responseSizeFor(blockSize), flush);
+
return SendResult::Sent;
}
@@ -388,7 +479,8 @@
if (!priority_blocks.empty()) {
for (auto& i = prefetch.priorityIndex;
blocksToSend > 0 && i < (BlockIdx)priority_blocks.size(); ++i) {
- if (auto res = SendBlock(file.id, priority_blocks[i]); res == SendResult::Sent) {
+ if (auto res = SendDataBlock(file.id, priority_blocks[i]);
+ res == SendResult::Sent) {
--blocksToSend;
} else if (res == SendResult::Error) {
fprintf(stderr, "Failed to send priority block %" PRId32 "\n", i);
@@ -396,7 +488,7 @@
}
}
for (auto& i = prefetch.overallIndex; blocksToSend > 0 && i < prefetch.overallEnd; ++i) {
- if (auto res = SendBlock(file.id, i); res == SendResult::Sent) {
+ if (auto res = SendDataBlock(file.id, i); res == SendResult::Sent) {
--blocksToSend;
} else if (res == SendResult::Error) {
fprintf(stderr, "Failed to send block %" PRId32 "\n", i);
@@ -409,30 +501,25 @@
}
void IncrementalServer::Send(const void* data, size_t size, bool flush) {
- constexpr auto kChunkFlushSize = 31 * kBlockSize;
-
- if (pendingBlocks_.empty()) {
- pendingBlocks_.resize(sizeof(ChunkHeader));
- }
- pendingBlocks_.insert(pendingBlocks_.end(), static_cast<const char*>(data),
- static_cast<const char*>(data) + size);
- if (flush || pendingBlocks_.size() > kChunkFlushSize) {
+ pendingBlocks_ = std::copy_n(static_cast<const char*>(data), size, pendingBlocks_);
+ if (flush || pendingBlocks_ - pendingBlocksBuffer_.data() > kChunkFlushSize) {
Flush();
}
}
void IncrementalServer::Flush() {
- if (pendingBlocks_.empty()) {
+ auto dataBytes = pendingBlocks_ - (pendingBlocksBuffer_.data() + sizeof(ChunkHeader));
+ if (dataBytes == 0) {
return;
}
- *(ChunkHeader*)pendingBlocks_.data() =
- toBigEndian<int32_t>(pendingBlocks_.size() - sizeof(ChunkHeader));
- if (!WriteFdExactly(adb_fd_, pendingBlocks_.data(), pendingBlocks_.size())) {
- fprintf(stderr, "Failed to write %d bytes\n", int(pendingBlocks_.size()));
+ *(ChunkHeader*)pendingBlocksBuffer_.data() = toBigEndian<int32_t>(dataBytes);
+ auto totalBytes = sizeof(ChunkHeader) + dataBytes;
+ if (!WriteFdExactly(adb_fd_, pendingBlocksBuffer_.data(), totalBytes)) {
+ fprintf(stderr, "Failed to write %d bytes\n", int(totalBytes));
}
- sentSize_ += pendingBlocks_.size();
- pendingBlocks_.clear();
+ sentSize_ += totalBytes;
+ pendingBlocks_ = pendingBlocksBuffer_.data() + sizeof(ChunkHeader);
}
bool IncrementalServer::ServingComplete(std::optional<TimePoint> startTime, int missesCount,
@@ -443,7 +530,7 @@
D("Streaming completed.\n"
"Misses: %d, of those unique: %d; sent compressed: %d, uncompressed: "
"%d, mb: %.3f\n"
- "Total time taken: %.3fms\n",
+ "Total time taken: %.3fms",
missesCount, missesSent, compressed_, uncompressed_, sentSize_ / 1024.0 / 1024.0,
duration_cast<microseconds>(endTime - (startTime ? *startTime : endTime)).count() / 1000.0);
return true;
@@ -510,9 +597,21 @@
fileId, blockIdx);
break;
}
- // fprintf(stderr, "\treading file %d block %04d\n", (int)fileId,
- // (int)blockIdx);
- if (auto res = SendBlock(fileId, blockIdx, true); res == SendResult::Error) {
+
+ if (VLOG_IS_ON(INCREMENTAL)) {
+ auto& file = files_[fileId];
+ auto posP = std::find(file.PriorityBlocks().begin(),
+ file.PriorityBlocks().end(), blockIdx);
+ D("\tMISSING BLOCK: reading file %d block %04d (in priority: %d of %d)",
+ (int)fileId, (int)blockIdx,
+ posP == file.PriorityBlocks().end()
+ ? -1
+ : int(posP - file.PriorityBlocks().begin()),
+ int(file.PriorityBlocks().size()));
+ }
+
+ if (auto res = SendDataBlock(fileId, blockIdx, true);
+ res == SendResult::Error) {
fprintf(stderr, "Failed to send block %" PRId32 ".\n", blockIdx);
} else if (res == SendResult::Sent) {
++missesSent;
@@ -536,7 +635,7 @@
fileId);
break;
}
- D("Received prefetch request for file_id %" PRId16 ".\n", fileId);
+ D("Received prefetch request for file_id %" PRId16 ".", fileId);
prefetches_.emplace_back(files_[fileId]);
break;
}
@@ -551,6 +650,43 @@
}
}
+static std::pair<unique_fd, int64_t> open_fd(const char* filepath) {
+ struct stat st;
+ if (stat(filepath, &st)) {
+ error_exit("inc-server: failed to stat input file '%s'.", filepath);
+ }
+
+ unique_fd fd(adb_open(filepath, O_RDONLY));
+ if (fd < 0) {
+ error_exit("inc-server: failed to open file '%s'.", filepath);
+ }
+
+ return {std::move(fd), st.st_size};
+}
+
+static std::pair<unique_fd, int64_t> open_signature(int64_t file_size, const char* filepath) {
+ std::string signature_file(filepath);
+ signature_file += IDSIG;
+
+ unique_fd fd(adb_open(signature_file.c_str(), O_RDONLY));
+ if (fd < 0) {
+ error_exit("inc-server: failed to open file '%s'.", signature_file.c_str());
+ }
+
+ auto [tree_offset, tree_size] = skip_id_sig_headers(fd);
+ if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) {
+ error_exit("Verity tree size mismatch in signature file: %s [was %lld, expected %lld].\n",
+ signature_file.c_str(), (long long)tree_size, (long long)expected);
+ }
+
+ int32_t data_block_count = numBytesToNumBlocks(file_size);
+ int32_t leaf_nodes_count = (data_block_count + kHashesPerBlock - 1) / kHashesPerBlock;
+ D("Verity tree loaded: %s, tree size: %d (%d blocks, %d leafs)", signature_file.c_str(),
+ int(tree_size), int(numBytesToNumBlocks(tree_size)), int(leaf_nodes_count));
+
+ return {std::move(fd), tree_offset};
+}
+
bool serve(int connection_fd, int output_fd, int argc, const char** argv) {
auto connection_ufd = unique_fd(connection_fd);
auto output_ufd = unique_fd(output_fd);
@@ -563,17 +699,11 @@
for (int i = 0; i < argc; ++i) {
auto filepath = argv[i];
- struct stat st;
- if (stat(filepath, &st)) {
- fprintf(stderr, "Failed to stat input file %s. Abort.\n", filepath);
- return {};
- }
+ auto [file_fd, file_size] = open_fd(filepath);
+ auto [sign_fd, sign_offset] = open_signature(file_size, filepath);
- unique_fd fd(adb_open(filepath, O_RDONLY));
- if (fd < 0) {
- error_exit("inc-server: failed to open file '%s'.", filepath);
- }
- files.emplace_back(filepath, i, st.st_size, std::move(fd));
+ files.emplace_back(filepath, i, file_size, std::move(file_fd), sign_offset,
+ std::move(sign_fd));
}
IncrementalServer server(std::move(connection_ufd), std::move(output_ufd), std::move(files));
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index caadb26..076b766 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -18,6 +18,7 @@
#include "incremental_utils.h"
+#include <android-base/endian.h>
#include <android-base/mapped_file.h>
#include <android-base/strings.h>
#include <ziparchive/zip_archive.h>
@@ -27,17 +28,96 @@
#include <numeric>
#include <unordered_set>
+#include "adb_io.h"
#include "adb_trace.h"
#include "sysdeps.h"
-static constexpr int kBlockSize = 4096;
+namespace incremental {
static constexpr inline int32_t offsetToBlockIndex(int64_t offset) {
return (offset & ~(kBlockSize - 1)) >> 12;
}
+Size verity_tree_blocks_for_file(Size fileSize) {
+ if (fileSize == 0) {
+ return 0;
+ }
+
+ constexpr int hash_per_block = kBlockSize / kDigestSize;
+
+ Size total_tree_block_count = 0;
+
+ auto block_count = 1 + (fileSize - 1) / kBlockSize;
+ auto hash_block_count = block_count;
+ for (auto i = 0; hash_block_count > 1; i++) {
+ hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block;
+ total_tree_block_count += hash_block_count;
+ }
+ return total_tree_block_count;
+}
+
+Size verity_tree_size_for_file(Size fileSize) {
+ return verity_tree_blocks_for_file(fileSize) * kBlockSize;
+}
+
+static inline int32_t read_int32(borrowed_fd fd) {
+ int32_t result;
+ return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1;
+}
+
+static inline int32_t skip_int(borrowed_fd fd) {
+ return adb_lseek(fd, 4, SEEK_CUR);
+}
+
+static inline void append_int(borrowed_fd fd, std::vector<char>* bytes) {
+ int32_t le_val = read_int32(fd);
+ auto old_size = bytes->size();
+ bytes->resize(old_size + sizeof(le_val));
+ memcpy(bytes->data() + old_size, &le_val, sizeof(le_val));
+}
+
+static inline void append_bytes_with_size(borrowed_fd fd, std::vector<char>* bytes) {
+ int32_t le_size = read_int32(fd);
+ if (le_size < 0) {
+ return;
+ }
+ int32_t size = int32_t(le32toh(le_size));
+ auto old_size = bytes->size();
+ bytes->resize(old_size + sizeof(le_size) + size);
+ memcpy(bytes->data() + old_size, &le_size, sizeof(le_size));
+ ReadFdExactly(fd, bytes->data() + old_size + sizeof(le_size), size);
+}
+
+static inline int32_t skip_bytes_with_size(borrowed_fd fd) {
+ int32_t le_size = read_int32(fd);
+ if (le_size < 0) {
+ return -1;
+ }
+ int32_t size = int32_t(le32toh(le_size));
+ return (int32_t)adb_lseek(fd, size, SEEK_CUR);
+}
+
+std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
+ std::vector<char> result;
+ append_int(fd, &result); // version
+ append_bytes_with_size(fd, &result); // hashingInfo
+ append_bytes_with_size(fd, &result); // signingInfo
+ auto le_tree_size = read_int32(fd);
+ auto tree_size = int32_t(le32toh(le_tree_size)); // size of the verity tree
+ return {std::move(result), tree_size};
+}
+
+std::pair<off64_t, ssize_t> skip_id_sig_headers(borrowed_fd fd) {
+ skip_int(fd); // version
+ skip_bytes_with_size(fd); // hashingInfo
+ auto offset = skip_bytes_with_size(fd); // signingInfo
+ auto le_tree_size = read_int32(fd);
+ auto tree_size = int32_t(le32toh(le_tree_size)); // size of the verity tree
+ return {offset + sizeof(le_tree_size), tree_size};
+}
+
template <class T>
-T valueAt(int fd, off64_t offset) {
+static T valueAt(borrowed_fd fd, off64_t offset) {
T t;
memset(&t, 0, sizeof(T));
if (adb_pread(fd, &t, sizeof(T), offset) != sizeof(T)) {
@@ -65,7 +145,7 @@
v.end());
}
-static off64_t CentralDirOffset(int fd, int64_t fileSize) {
+static off64_t CentralDirOffset(borrowed_fd fd, Size fileSize) {
static constexpr int kZipEocdRecMinSize = 22;
static constexpr int32_t kZipEocdRecSig = 0x06054b50;
static constexpr int kZipEocdCentralDirSizeFieldOffset = 12;
@@ -100,7 +180,7 @@
}
// Does not support APKs larger than 4GB
-static off64_t SignerBlockOffset(int fd, int64_t fileSize) {
+static off64_t SignerBlockOffset(borrowed_fd fd, Size fileSize) {
static constexpr int kApkSigBlockMinSize = 32;
static constexpr int kApkSigBlockFooterSize = 24;
static constexpr int64_t APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42l;
@@ -129,7 +209,7 @@
return signerBlockOffset;
}
-static std::vector<int32_t> ZipPriorityBlocks(off64_t signerBlockOffset, int64_t fileSize) {
+static std::vector<int32_t> ZipPriorityBlocks(off64_t signerBlockOffset, Size fileSize) {
int32_t signerBlockIndex = offsetToBlockIndex(signerBlockOffset);
int32_t lastBlockIndex = offsetToBlockIndex(fileSize);
const auto numPriorityBlocks = lastBlockIndex - signerBlockIndex + 1;
@@ -157,7 +237,7 @@
return zipPriorityBlocks;
}
-[[maybe_unused]] static ZipArchiveHandle openZipArchiveFd(int fd) {
+[[maybe_unused]] static ZipArchiveHandle openZipArchiveFd(borrowed_fd fd) {
bool transferFdOwnership = false;
#ifdef _WIN32
//
@@ -176,20 +256,22 @@
D("%s failed at DuplicateHandle: %d", __func__, (int)::GetLastError());
return {};
}
- fd = _open_osfhandle((intptr_t)dupedHandle, _O_RDONLY | _O_BINARY);
- if (fd < 0) {
+ int osfd = _open_osfhandle((intptr_t)dupedHandle, _O_RDONLY | _O_BINARY);
+ if (osfd < 0) {
D("%s failed at _open_osfhandle: %d", __func__, errno);
::CloseHandle(handle);
return {};
}
transferFdOwnership = true;
+#else
+ int osfd = fd.get();
#endif
ZipArchiveHandle zip;
- if (OpenArchiveFd(fd, "apk_fd", &zip, transferFdOwnership) != 0) {
+ if (OpenArchiveFd(osfd, "apk_fd", &zip, transferFdOwnership) != 0) {
D("%s failed at OpenArchiveFd: %d", __func__, errno);
#ifdef _WIN32
// "_close()" is a secret WinCRT name for the regular close() function.
- _close(fd);
+ _close(osfd);
#endif
return {};
}
@@ -197,7 +279,7 @@
}
static std::pair<ZipArchiveHandle, std::unique_ptr<android::base::MappedFile>> openZipArchive(
- int fd, int64_t fileSize) {
+ borrowed_fd fd, Size fileSize) {
#ifndef __LP64__
if (fileSize >= INT_MAX) {
return {openZipArchiveFd(fd), nullptr};
@@ -219,7 +301,7 @@
// TODO(b/151676293): avoid using libziparchive as it reads local file headers
// which causes additional performance cost. Instead, only read from central directory.
-static std::vector<int32_t> InstallationPriorityBlocks(int fd, int64_t fileSize) {
+static std::vector<int32_t> InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) {
auto [zip, _] = openZipArchive(fd, fileSize);
if (!zip) {
return {};
@@ -252,7 +334,8 @@
} else if (entryName == "classes.dex") {
// Only the head is needed for installation
int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
- appendBlocks(startBlockIndex, 1, &installationPriorityBlocks);
+ appendBlocks(startBlockIndex, 2, &installationPriorityBlocks);
+ D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
}
}
@@ -261,8 +344,8 @@
return installationPriorityBlocks;
}
-namespace incremental {
-std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, int fd, int64_t fileSize) {
+std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd,
+ Size fileSize) {
if (!android::base::EndsWithIgnoreCase(filepath, ".apk")) {
return {};
}
@@ -279,4 +362,5 @@
unduplicate(priorityBlocks);
return priorityBlocks;
}
+
} // namespace incremental
diff --git a/adb/client/incremental_utils.h b/adb/client/incremental_utils.h
index 8bcf6c0..d969d94 100644
--- a/adb/client/incremental_utils.h
+++ b/adb/client/incremental_utils.h
@@ -16,11 +16,31 @@
#pragma once
-#include <stdint.h>
+#include "adb_unique_fd.h"
#include <string>
+#include <string_view>
+#include <utility>
#include <vector>
+#include <stdint.h>
+
namespace incremental {
-std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, int fd, int64_t fileSize);
-} // namespace incremental
\ No newline at end of file
+
+using Size = int64_t;
+constexpr int kBlockSize = 4096;
+constexpr int kSha256DigestSize = 32;
+constexpr int kDigestSize = kSha256DigestSize;
+
+constexpr std::string_view IDSIG = ".idsig";
+
+std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd,
+ Size fileSize);
+
+Size verity_tree_blocks_for_file(Size fileSize);
+Size verity_tree_size_for_file(Size fileSize);
+
+std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd);
+std::pair<off64_t, ssize_t> skip_id_sig_headers(borrowed_fd fd);
+
+} // namespace incremental
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index 7bd611b..e538ca8 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -300,7 +300,6 @@
}
// Signal only when writing the descriptors to ffs
android::base::SetProperty("sys.usb.ffs.ready", "1");
- *out_control = std::move(control);
}
bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
@@ -315,6 +314,7 @@
return false;
}
+ *out_control = std::move(control);
*out_bulk_in = std::move(bulk_in);
*out_bulk_out = std::move(bulk_out);
return true;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3e781b8..6ce5098 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -42,6 +42,12 @@
#include "sysdeps/network.h"
#include "sysdeps/stat.h"
+#if defined(__APPLE__)
+static void* mempcpy(void* dst, const void* src, size_t n) {
+ return static_cast<char*>(memcpy(dst, src, n)) + n;
+}
+#endif
+
#ifdef _WIN32
// Clang-only nullability specifiers
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a9c1676..5d6cee4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -1238,16 +1238,26 @@
// Shift last_reboot_reason_property to last_last_reboot_reason_property
std::string last_boot_reason;
if (!android::base::ReadFileToString(last_reboot_reason_file, &last_boot_reason)) {
+ PLOG(ERROR) << "Failed to read " << last_reboot_reason_file;
last_boot_reason = android::base::GetProperty(last_reboot_reason_property, "");
+ LOG(INFO) << "Value of " << last_reboot_reason_property << " : " << last_boot_reason;
+ } else {
+ LOG(INFO) << "Last reboot reason read from " << last_reboot_reason_file << " : "
+ << last_boot_reason << ". Last reboot reason read from "
+ << last_reboot_reason_property << " : "
+ << android::base::GetProperty(last_reboot_reason_property, "");
}
if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
last_boot_reason = system_boot_reason;
} else {
transformReason(last_boot_reason);
}
+ LOG(INFO) << "Normalized last reboot reason : " << last_boot_reason;
android::base::SetProperty(last_last_reboot_reason_property, last_boot_reason);
android::base::SetProperty(last_reboot_reason_property, "");
- unlink(last_reboot_reason_file);
+ if (unlink(last_reboot_reason_file) != 0) {
+ PLOG(ERROR) << "Failed to unlink " << last_reboot_reason_file;
+ }
}
// Gets the boot time offset. This is useful when Android is running in a
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index bb54fd9..aa449b2 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -49,6 +49,6 @@
auto_gen_config: false,
test_suites: [
"general-tests",
- "vts-core",
+ "vts",
],
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 12aa1f0..47cf843 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -97,7 +97,6 @@
using android::base::Basename;
using android::base::GetBoolProperty;
using android::base::GetUintProperty;
-using android::base::Readlink;
using android::base::Realpath;
using android::base::SetProperty;
using android::base::StartsWith;
@@ -1573,8 +1572,8 @@
return std::chrono::milliseconds(std::move(value));
}
-static bool fs_mgr_unmount_all_data_mounts(const std::string& block_device) {
- LINFO << __FUNCTION__ << "(): about to umount everything on top of " << block_device;
+static bool fs_mgr_unmount_all_data_mounts(const std::string& data_block_device) {
+ LINFO << __FUNCTION__ << "(): about to umount everything on top of " << data_block_device;
Timer t;
auto timeout = GetMillisProperty("init.userspace_reboot.userdata_remount.timeoutmillis", 5s);
while (true) {
@@ -1586,7 +1585,13 @@
}
// Now proceed with other bind mounts on top of /data.
for (const auto& entry : proc_mounts) {
- if (entry.blk_device == block_device) {
+ std::string block_device;
+ if (StartsWith(entry.blk_device, "/dev/block") &&
+ !Realpath(entry.blk_device, &block_device)) {
+ PWARNING << __FUNCTION__ << "(): failed to realpath " << entry.blk_device;
+ block_device = entry.blk_device;
+ }
+ if (data_block_device == block_device) {
if (umount2(entry.mount_point.c_str(), 0) != 0) {
PERROR << __FUNCTION__ << "(): Failed to umount " << entry.mount_point;
umount_done = false;
@@ -1598,7 +1603,8 @@
return true;
}
if (t.duration() > timeout) {
- LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on " << block_device;
+ LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on "
+ << data_block_device;
Fstab remaining_mounts;
if (!ReadFstabFromFile("/proc/mounts", &remaining_mounts)) {
LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
@@ -1637,14 +1643,11 @@
return true;
}
-FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab, const FstabEntry& mounted_entry) {
- if (mounted_entry.mount_point != "/data") {
- LERROR << mounted_entry.mount_point << " is not /data";
- return nullptr;
- }
+FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab,
+ const std::string& data_block_device) {
std::vector<std::string> dm_stack;
- if (!UnwindDmDeviceStack(mounted_entry.blk_device, &dm_stack)) {
- LERROR << "Failed to unwind dm-device stack for " << mounted_entry.blk_device;
+ if (!UnwindDmDeviceStack(data_block_device, &dm_stack)) {
+ LERROR << "Failed to unwind dm-device stack for " << data_block_device;
return nullptr;
}
for (auto& entry : *fstab) {
@@ -1658,15 +1661,15 @@
continue;
}
block_device = entry.blk_device;
- } else if (!Readlink(entry.blk_device, &block_device)) {
- PWARNING << "Failed to read link " << entry.blk_device;
+ } else if (!Realpath(entry.blk_device, &block_device)) {
+ PWARNING << "Failed to realpath " << entry.blk_device;
block_device = entry.blk_device;
}
if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
return &entry;
}
}
- LERROR << "Didn't find entry that was used to mount /data onto " << mounted_entry.blk_device;
+ LERROR << "Didn't find entry that was used to mount /data onto " << data_block_device;
return nullptr;
}
@@ -1677,14 +1680,17 @@
LERROR << "Can't read /proc/mounts";
return -1;
}
- std::string block_device;
auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
if (mounted_entry == nullptr) {
LERROR << "/data is not mounted";
return -1;
}
- block_device = mounted_entry->blk_device;
- auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, *mounted_entry);
+ std::string block_device;
+ if (!Realpath(mounted_entry->blk_device, &block_device)) {
+ PERROR << "Failed to realpath " << mounted_entry->blk_device;
+ return -1;
+ }
+ auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, block_device);
if (fstab_entry == nullptr) {
LERROR << "Can't find /data in fstab";
return -1;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3d556c9..86090c1 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -107,10 +107,9 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
-// Finds a entry in |fstab| that was used to mount a /data |mounted_entry| from
-// /proc/mounts.
+// Finds a entry in |fstab| that was used to mount a /data on |data_block_device|.
android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
- android::fs_mgr::Fstab* fstab, const android::fs_mgr::FstabEntry& mounted_entry);
+ android::fs_mgr::Fstab* fstab, const std::string& data_block_device);
int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
// Finds the dm_bow device on which this block device is stacked, or returns
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 910c4fc..d5b59cc 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -79,7 +79,7 @@
cc_test {
name: "vts_libdm_test",
defaults: ["libdm_test_defaults"],
- test_suites: ["vts-core"],
+ test_suites: ["vts"],
test_min_api_level: 29,
}
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 29b1032..a594198 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -243,20 +243,8 @@
return android::base::Join(argv, " ");
}
-bool DmTargetDefaultKey::IsLegacy(bool* result) {
- DeviceMapper& dm = DeviceMapper::Instance();
- DmTargetTypeInfo info;
- if (!dm.GetTargetByName(kName, &info)) return false;
- // dm-default-key was modified to be like dm-crypt with version 2
- *result = !info.IsAtLeast(2, 0, 0);
- return true;
-}
-
bool DmTargetDefaultKey::Valid() const {
- bool real_is_legacy;
- if (!DmTargetDefaultKey::IsLegacy(&real_is_legacy)) return false;
- if (real_is_legacy != is_legacy_) return false;
- if (!is_legacy_ && !set_dun_) return false;
+ if (!use_legacy_options_format_ && !set_dun_) return false;
return true;
}
@@ -264,13 +252,13 @@
std::vector<std::string> argv;
argv.emplace_back(cipher_);
argv.emplace_back(key_);
- if (!is_legacy_) {
+ if (!use_legacy_options_format_) {
argv.emplace_back("0"); // iv_offset
}
argv.emplace_back(blockdev_);
argv.push_back(std::to_string(start_sector_));
std::vector<std::string> extra_argv;
- if (is_legacy_) {
+ if (use_legacy_options_format_) {
if (set_dun_) { // v2 always sets the DUN.
extra_argv.emplace_back("set_dun");
}
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 67af59a..41d3145 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -516,32 +516,22 @@
}
TEST(libdm, DefaultKeyArgs) {
- DmTargetTypeInfo info;
-
- DeviceMapper& dm = DeviceMapper::Instance();
- if (!dm.GetTargetByName("default-key", &info)) {
- cout << "default-key module not enabled; skipping test" << std::endl;
- return;
- }
- bool is_legacy;
- ASSERT_TRUE(DmTargetDefaultKey::IsLegacy(&is_legacy));
- // set_dun only in the non-is_legacy case
- DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
- if (is_legacy) {
- target.SetIsLegacy();
- } else {
- target.SetSetDun();
- }
+ DmTargetDefaultKey target(0, 4096, "aes-xts-plain64", "abcdef0123456789", "/dev/loop0", 0);
+ target.SetSetDun();
ASSERT_EQ(target.name(), "default-key");
ASSERT_TRUE(target.Valid());
- if (is_legacy) {
- ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
- } else {
- // TODO: Add case for wrapped key enabled
- ASSERT_EQ(target.GetParameterString(),
- "AES-256-XTS abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
- "iv_large_sectors");
- }
+ // TODO: Add case for wrapped key enabled
+ ASSERT_EQ(target.GetParameterString(),
+ "aes-xts-plain64 abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
+ "iv_large_sectors");
+}
+
+TEST(libdm, DefaultKeyLegacyArgs) {
+ DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
+ target.SetUseLegacyOptionsFormat();
+ ASSERT_EQ(target.name(), "default-key");
+ ASSERT_TRUE(target.Valid());
+ ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
}
TEST(libdm, DeleteDeviceWithTimeout) {
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 050d0b6..57096ce 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -290,8 +290,7 @@
std::string name() const override { return kName; }
bool Valid() const override;
std::string GetParameterString() const override;
- static bool IsLegacy(bool* result);
- void SetIsLegacy() { is_legacy_ = true; }
+ void SetUseLegacyOptionsFormat() { use_legacy_options_format_ = true; }
void SetSetDun() { set_dun_ = true; }
void SetWrappedKeyV0() { is_hw_wrapped_ = true; }
@@ -302,7 +301,7 @@
std::string key_;
std::string blockdev_;
uint64_t start_sector_;
- bool is_legacy_ = false;
+ bool use_legacy_options_format_ = false;
bool set_dun_ = false;
bool is_hw_wrapped_ = false;
};
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 2fd463c..f6c2b5a 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -80,7 +80,7 @@
"fiemap_writer_test.cpp",
],
- test_suites: ["vts-core", "device-tests"],
+ test_suites: ["vts", "device-tests"],
auto_gen_config: true,
test_min_api_level: 29,
require_root: true,
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index ea0fca8..20349dc 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -97,7 +97,7 @@
cc_test {
name: "vts_core_liblp_test",
defaults: ["liblp_test_defaults"],
- test_suites: ["vts-core"],
+ test_suites: ["vts"],
auto_gen_config: true,
test_min_api_level: 29,
require_root: true,
diff --git a/fs_mgr/liblp/liblp_test.xml b/fs_mgr/liblp/liblp_test.xml
index d9ee12e..98414b1 100644
--- a/fs_mgr/liblp/liblp_test.xml
+++ b/fs_mgr/liblp/liblp_test.xml
@@ -19,7 +19,6 @@
<option name="cleanup" value="true" />
<option name="push" value="liblp_test->/data/local/tmp/liblp_test" />
</target_preparer>
- <option name="test-suite-tag" value="vts-core" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="liblp_test" />
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index d670ca0..a209ea6 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -182,7 +182,7 @@
"libstorage_literals_headers",
],
test_suites: [
- "vts-core",
+ "vts",
"device-tests"
],
test_min_api_level: 29,
@@ -195,6 +195,12 @@
defaults: ["libsnapshot_test_defaults"],
}
+// For VTS 10
+vts_config {
+ name: "VtsLibsnapshotTest",
+ test_config: "VtsLibsnapshotTest.xml"
+}
+
cc_binary {
name: "snapshotctl",
srcs: [
diff --git a/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml b/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml
new file mode 100644
index 0000000..b53b51e
--- /dev/null
+++ b/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for VTS VtsLibsnapshotTest">
+ <option name="config-descriptor:metadata" key="plan" value="vts-kernel"/>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsLibsnapshotTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_libsnapshot_test/vts_libsnapshot_test"/>
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_libsnapshot_test/vts_libsnapshot_test"/>
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="5m"/>
+ </test>
+</configuration>
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 4f6ec5a..f68ab87 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -17,7 +17,7 @@
test_suites: [
"cts",
"device-tests",
- "vts",
+ "vts10",
],
compile_multilib: "both",
multilib: {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index cf324fe..82c4262 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -732,6 +732,7 @@
grep -v \
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
-e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
+ -e " functionfs " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
-e "^rootfs / rootfs rw," \
-e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 16e38f1..46f1c59 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1006,6 +1006,8 @@
ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
- ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, *mounted_entry))
+ std::string block_device;
+ ASSERT_TRUE(android::base::Realpath(mounted_entry->blk_device, &block_device));
+ ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
diff --git a/init/Android.bp b/init/Android.bp
index 9053c39..1b3aa18 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -258,7 +258,7 @@
test_suites: [
"cts",
"device-tests",
- "vts",
+ "vts10",
],
}
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index bd71cb5..ad546bf 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -107,7 +107,7 @@
return;
}
int fd = -1;
- int tries = 10;
+ int tries = 50; // should timeout after 5s
// The device driver for console may not be ready yet so retry for a while in case of failure.
while (tries--) {
fd = open("/dev/console", O_RDWR);
@@ -234,7 +234,16 @@
old_root_dir.reset();
}
- Modprobe m({"/lib/modules"});
+ std::string module_load_file = "modules.load";
+ if (IsRecoveryMode() && !ForceNormalBoot(cmdline)) {
+ struct stat fileStat;
+ std::string recovery_load_path = "/lib/modules/modules.load.recovery";
+ if (!stat(recovery_load_path.c_str(), &fileStat)) {
+ module_load_file = "modules.load.recovery";
+ }
+ }
+
+ Modprobe m({"/lib/modules"}, module_load_file);
auto want_console = ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline);
if (!m.LoadListedModules(!want_console)) {
if (want_console) {
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index fc06c1d..c9eebfe 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -327,7 +327,7 @@
cc_test {
name: "KernelLibcutilsTest",
- test_suites: ["general-tests", "vts-core"],
+ test_suites: ["general-tests", "vts"],
defaults: ["libcutils_test_static_defaults"],
test_config: "KernelLibcutilsTest.xml",
}
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 18c1c33..f9c1d69 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -48,8 +48,6 @@
* access to raw information, or parsing is an issue.
*/
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wzero-length-array"
struct logger_entry {
uint16_t len; /* length of the payload */
uint16_t hdr_size; /* sizeof(struct logger_entry) */
@@ -59,9 +57,7 @@
uint32_t nsec; /* nanoseconds */
uint32_t lid; /* log id of the payload, bottom 4 bits currently */
uint32_t uid; /* generating process's uid */
- char msg[0]; /* the entry's payload */
};
-#pragma clang diagnostic pop
/*
* The maximum size of the log entry payload that can be
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index e32878a..5c69bf8 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -509,12 +509,12 @@
* format: <priority:1><tag:N>\0<message:N>\0
*
* tag str
- * starts at buf->msg+1
+ * starts at buf + buf->hdr_size + 1
* msg
- * starts at buf->msg+1+len(tag)+1
+ * starts at buf + buf->hdr_size + 1 + len(tag) + 1
*
- * The message may have been truncated by the kernel log driver.
- * When that happens, we must null-terminate the message ourselves.
+ * The message may have been truncated. When that happens, we must null-terminate the message
+ * ourselves.
*/
if (buf->len < 3) {
/*
@@ -529,11 +529,11 @@
int msgEnd = -1;
int i;
- char* msg = buf->msg;
- if (buf->hdr_size != sizeof(struct logger_entry)) {
- fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+ if (buf->hdr_size < sizeof(logger_entry)) {
+ fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
return -1;
}
+ char* msg = reinterpret_cast<char*>(buf) + buf->hdr_size;
entry->uid = buf->uid;
for (i = 1; i < buf->len; i++) {
@@ -985,11 +985,11 @@
entry->pid = buf->pid;
entry->tid = buf->tid;
- eventData = (const unsigned char*)buf->msg;
- if (buf->hdr_size != sizeof(struct logger_entry)) {
- fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+ if (buf->hdr_size < sizeof(logger_entry)) {
+ fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
return -1;
}
+ eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
if (buf->lid == LOG_ID_SECURITY) {
entry->priority = ANDROID_LOG_WARN;
}
@@ -1048,7 +1048,7 @@
}
if ((result == 1) && fmtStr) {
/* We overflowed :-(, let's repaint the line w/o format dressings */
- eventData = (const unsigned char*)buf->msg;
+ eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
eventData += 4;
outBuf = messageBuf;
outRemaining = messageBufLen - 1;
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 64a92b7..d006ba4 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -96,7 +96,7 @@
((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
(logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
(!logger_list->pid || (logger_list->pid == buf.p.pid))) {
- char* msg = log_msg->entry.msg;
+ char* msg = reinterpret_cast<char*>(&log_msg->entry) + log_msg->entry.hdr_size;
*msg = buf.prio;
fd = atomic_load(&logger_list->fd);
if (fd <= 0) {
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index b4bb77f..385b079 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -96,7 +96,7 @@
cflags: ["-DNO_PSTORE"],
test_suites: [
"cts",
- "vts",
+ "vts10",
],
}
diff --git a/liblog/tests/logprint_test.cpp b/liblog/tests/logprint_test.cpp
index 7ca02ac..72e53f9 100644
--- a/liblog/tests/logprint_test.cpp
+++ b/liblog/tests/logprint_test.cpp
@@ -14,8 +14,14 @@
* limitations under the License.
*/
+#include <log/logprint.h>
+
+#include <string>
+
#include <gtest/gtest.h>
+#include <log/log_read.h>
+
size_t convertPrintable(char* p, const char* message, size_t messageLen);
TEST(liblog, convertPrintable_ascii) {
@@ -85,3 +91,63 @@
EXPECT_EQ(output_size, strlen(expected_output));
EXPECT_STREQ(expected_output, output);
}
+
+TEST(liblog, log_print_different_header_size) {
+ constexpr int32_t kPid = 123;
+ constexpr uint32_t kTid = 456;
+ constexpr uint32_t kSec = 1000;
+ constexpr uint32_t kNsec = 999;
+ constexpr uint32_t kLid = LOG_ID_MAIN;
+ constexpr uint32_t kUid = 987;
+ constexpr char kPriority = ANDROID_LOG_ERROR;
+
+ auto create_buf = [](char* buf, size_t len, uint16_t hdr_size) {
+ memset(buf, 0, len);
+ logger_entry* header = reinterpret_cast<logger_entry*>(buf);
+ header->hdr_size = hdr_size;
+ header->pid = kPid;
+ header->tid = kTid;
+ header->sec = kSec;
+ header->nsec = kNsec;
+ header->lid = kLid;
+ header->uid = kUid;
+ char* message = buf + header->hdr_size;
+ uint16_t message_len = 0;
+ message[message_len++] = kPriority;
+ message[message_len++] = 'T';
+ message[message_len++] = 'a';
+ message[message_len++] = 'g';
+ message[message_len++] = '\0';
+ message[message_len++] = 'm';
+ message[message_len++] = 's';
+ message[message_len++] = 'g';
+ message[message_len++] = '!';
+ message[message_len++] = '\0';
+ header->len = message_len;
+ };
+
+ auto check_entry = [&](const AndroidLogEntry& entry) {
+ EXPECT_EQ(kSec, static_cast<uint32_t>(entry.tv_sec));
+ EXPECT_EQ(kNsec, static_cast<uint32_t>(entry.tv_nsec));
+ EXPECT_EQ(kPriority, entry.priority);
+ EXPECT_EQ(kUid, static_cast<uint32_t>(entry.uid));
+ EXPECT_EQ(kPid, entry.pid);
+ EXPECT_EQ(kTid, static_cast<uint32_t>(entry.tid));
+ EXPECT_STREQ("Tag", entry.tag);
+ EXPECT_EQ(4U, entry.tagLen); // Apparently taglen includes the nullptr?
+ EXPECT_EQ(4U, entry.messageLen);
+ EXPECT_STREQ("msg!", entry.message);
+ };
+ alignas(logger_entry) char buf[LOGGER_ENTRY_MAX_LEN];
+ create_buf(buf, sizeof(buf), sizeof(logger_entry));
+
+ AndroidLogEntry entry_normal_size;
+ ASSERT_EQ(0,
+ android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_normal_size));
+ check_entry(entry_normal_size);
+
+ create_buf(buf, sizeof(buf), sizeof(logger_entry) + 3);
+ AndroidLogEntry entry_odd_size;
+ ASSERT_EQ(0, android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_odd_size));
+ check_entry(entry_odd_size);
+}
\ No newline at end of file
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index ee6ae7a..297036e 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -24,7 +24,7 @@
class Modprobe {
public:
- Modprobe(const std::vector<std::string>&);
+ Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load");
bool LoadListedModules(bool strict = true);
bool LoadWithAliases(const std::string& module_name, bool strict,
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index f22bbf1..d193796 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -312,7 +312,7 @@
}
}
-Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
+Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file) {
using namespace std::placeholders;
for (const auto& base_path : base_paths) {
@@ -326,7 +326,7 @@
ParseCfg(base_path + "/modules.softdep", softdep_callback);
auto load_callback = std::bind(&Modprobe::ParseLoadCallback, this, _1);
- ParseCfg(base_path + "/modules.load", load_callback);
+ ParseCfg(base_path + "/" + load_file, load_callback);
auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
ParseCfg(base_path + "/modules.options", options_callback);
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index a7b5d91..ef1c5c5 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -30,11 +30,11 @@
shared_libs: [
"libbinder_ndk",
"liblog",
- "statsd-aidl-ndk_platform",
"libstatssocket",
],
static_libs: [
"libutils",
+ "statsd-aidl-ndk_platform",
],
}
cc_library_shared {
@@ -53,6 +53,9 @@
"com.android.os.statsd",
"test_com.android.os.statsd",
],
+
+ stl: "libc++_static",
+
// TODO(b/151102177): Enable it when the build error is fixed.
header_abi_checker: {
enabled: false,
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index b02ab42..c86d650 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -54,6 +54,7 @@
},
},
},
+ stl: "libc++_static",
// enumerate stable entry points for APEX use
stubs: {
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 958c34b..fb2a1d2 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -60,7 +60,7 @@
// Used to turn on crc checks - verify that the content CRC matches the values
// specified in the local file header and the central directory.
-static const bool kCrcChecksEnabled = false;
+static constexpr bool kCrcChecksEnabled = false;
// The maximum number of bytes to scan backwards for the EOCD start.
static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
@@ -1076,11 +1076,15 @@
if (!writer->Append(&buf[0], block_size)) {
return kIoError;
}
- crc = crc32(crc, &buf[0], block_size);
+ if (crc_out) {
+ crc = crc32(crc, &buf[0], block_size);
+ }
count += block_size;
}
- *crc_out = crc;
+ if (crc_out) {
+ *crc_out = crc;
+ }
return 0;
}
@@ -1092,9 +1096,11 @@
int32_t return_value = -1;
uint64_t crc = 0;
if (method == kCompressStored) {
- return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
+ return_value =
+ CopyEntryToWriter(archive->mapped_zip, entry, writer, kCrcChecksEnabled ? &crc : nullptr);
} else if (method == kCompressDeflated) {
- return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
+ return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer,
+ kCrcChecksEnabled ? &crc : nullptr);
}
if (!return_value && entry->has_data_descriptor) {
diff --git a/libziparchive/zip_archive_benchmark.cpp b/libziparchive/zip_archive_benchmark.cpp
index 09d3b8a..cfa5912 100644
--- a/libziparchive/zip_archive_benchmark.cpp
+++ b/libziparchive/zip_archive_benchmark.cpp
@@ -17,7 +17,6 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <iostream>
#include <string>
#include <tuple>
#include <vector>
@@ -28,17 +27,20 @@
#include <ziparchive/zip_archive_stream_entry.h>
#include <ziparchive/zip_writer.h>
-static TemporaryFile* CreateZip() {
- TemporaryFile* result = new TemporaryFile;
+static std::unique_ptr<TemporaryFile> CreateZip(int size = 4, int count = 1000) {
+ auto result = std::make_unique<TemporaryFile>();
FILE* fp = fdopen(result->fd, "w");
ZipWriter writer(fp);
std::string lastName = "file";
- for (size_t i = 0; i < 1000; i++) {
+ for (size_t i = 0; i < count; i++) {
// Make file names longer and longer.
lastName = lastName + std::to_string(i);
writer.StartEntry(lastName.c_str(), ZipWriter::kCompress);
- writer.WriteBytes("helo", 4);
+ while (size > 0) {
+ writer.WriteBytes("helo", 4);
+ size -= 4;
+ }
writer.FinishEntry();
}
writer.Finish();
@@ -106,5 +108,28 @@
}
BENCHMARK(StartAlignedEntry)->Arg(2)->Arg(16)->Arg(1024)->Arg(4096);
+static void ExtractEntry(benchmark::State& state) {
+ std::unique_ptr<TemporaryFile> temp_file(CreateZip(1024 * 1024, 1));
+
+ ZipArchiveHandle handle;
+ ZipEntry data;
+ if (OpenArchive(temp_file->path, &handle)) {
+ state.SkipWithError("Failed to open archive");
+ }
+ if (FindEntry(handle, "file0", &data)) {
+ state.SkipWithError("Failed to find archive entry");
+ }
+
+ std::vector<uint8_t> buffer(1024 * 1024);
+ for (auto _ : state) {
+ if (ExtractToMemory(handle, &data, buffer.data(), uint32_t(buffer.size()))) {
+ state.SkipWithError("Failed to extract archive entry");
+ break;
+ }
+ }
+ CloseArchive(handle);
+}
+
+BENCHMARK(ExtractEntry)->Arg(2)->Arg(16)->Arg(1024);
BENCHMARK_MAIN();
diff --git a/logd/tests/Android.bp b/logd/tests/Android.bp
index d39da8a..9a5defa 100644
--- a/logd/tests/Android.bp
+++ b/logd/tests/Android.bp
@@ -63,6 +63,6 @@
},
test_suites: [
"cts",
- "vts",
+ "vts10",
],
}
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index f47bee1..d0945f3 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -246,7 +246,7 @@
std::cerr << std::flush;
fflush(stdout);
fflush(stderr);
- EXPECT_EQ(sizeof(logger_entry), msg->entry.hdr_size);
+ EXPECT_GE(msg->entry.hdr_size, sizeof(logger_entry));
fprintf(stderr, "%s: [%u] ", prefix, msg->len());
fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 53d9f8f..a70e6c7 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1062,6 +1062,12 @@
start vold
exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
exec - system system -- /system/bin/vdc checkpoint markBootAttempt
+ # Unmount /data_mirror mounts in the reverse order of corresponding mounts.
+ umount /data_mirror/data_ce/null/0
+ umount /data_mirror/data_ce/null
+ umount /data_mirror/data_de/null
+ umount /data_mirror/cur_profiles
+ umount /data_mirror
remount_userdata
start bootanim