Merge "Revert "Revert "Remove unused String8::setPathName."""
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 3d63a44..abd2483 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -15,7 +15,10 @@
//
package {
- default_applicable_licenses: ["system_core_fs_mgr_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "system_core_fs_mgr_license",
+ ],
}
// Added automatically by a large-scale-change that took the approach of
@@ -36,10 +39,9 @@
name: "system_core_fs_mgr_license",
visibility: [":__subpackages__"],
license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
"SPDX-license-identifier-MIT",
],
- // large-scale-change unable to identify any license_text files
+ license_text: ["NOTICE"],
}
cc_defaults {
diff --git a/fs_mgr/NOTICE b/fs_mgr/NOTICE
new file mode 100644
index 0000000..3972a40
--- /dev/null
+++ b/fs_mgr/NOTICE
@@ -0,0 +1,21 @@
+Copyright (C) 2016 The Android Open Source Project
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 8314ec5..541f254 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -684,13 +684,9 @@
TEST(libdm, CreateEmptyDevice) {
DeviceMapper& dm = DeviceMapper::Instance();
ASSERT_TRUE(dm.CreateEmptyDevice("empty-device"));
- auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); });
+ auto guard =
+ android::base::make_scope_guard([&]() { dm.DeleteDeviceIfExists("empty-device", 5s); });
// Empty device should be in suspended state.
ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
-
- std::string path;
- ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path));
- // Path should exist.
- ASSERT_EQ(0, access(path.c_str(), F_OK));
}
diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp
index 36bb3df..8457066 100644
--- a/fs_mgr/libfiemap/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp
@@ -136,6 +136,7 @@
return FiemapStatus::FromErrno(errno);
}
}
+ fsync(fd.get());
// Unset this bit, so we don't unlink on destruction.
out->creating_ = false;
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index b75b154..7f7e40a 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -981,6 +981,137 @@
ASSERT_EQ(num_clusters, 1);
}
+TEST_F(CowTest, BigSeqOp) {
+ CowOptions options;
+ CowWriter writer(options);
+ const int seq_len = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t) + 1;
+ uint32_t sequence[seq_len];
+ for (int i = 0; i < seq_len; i++) {
+ sequence[i] = i + 1;
+ }
+
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
+ ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len));
+ ASSERT_TRUE(writer.Finalize());
+
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ auto iter = reader.GetRevMergeOpIter();
+
+ for (int i = 0; i < seq_len; i++) {
+ ASSERT_TRUE(!iter->Done());
+ const auto& op = iter->Get();
+
+ ASSERT_EQ(op.new_block, seq_len - i);
+
+ iter->Next();
+ }
+ ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, RevMergeOpItrTest) {
+ CowOptions options;
+ options.cluster_ops = 5;
+ options.num_merge_ops = 1;
+ CowWriter writer(options);
+ uint32_t sequence[] = {2, 10, 6, 7, 3, 5};
+
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer.AddSequenceData(6, sequence));
+ ASSERT_TRUE(writer.AddCopy(6, 3));
+ ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
+ ASSERT_TRUE(writer.AddCopy(3, 5));
+ ASSERT_TRUE(writer.AddCopy(2, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
+ ASSERT_TRUE(writer.AddCopy(5, 6));
+ ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
+ ASSERT_TRUE(writer.AddCopy(10, 2));
+ ASSERT_TRUE(writer.AddCopy(7, 4));
+ ASSERT_TRUE(writer.Finalize());
+
+ // New block in cow order is 6, 12, 8, 11, 3, 2, 4, 9, 5, 1, 10, 7
+ // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
+ // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
+ // new block 2 is "already merged", so will be left out.
+
+ std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
+
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ auto iter = reader.GetRevMergeOpIter();
+ auto expected_new_block = revMergeOpSequence.begin();
+
+ while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
+ const auto& op = iter->Get();
+
+ ASSERT_EQ(op.new_block, *expected_new_block);
+
+ iter->Next();
+ expected_new_block++;
+ }
+ ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
+ ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, LegacyRevMergeOpItrTest) {
+ CowOptions options;
+ options.cluster_ops = 5;
+ options.num_merge_ops = 1;
+ CowWriter writer(options);
+
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer.AddCopy(2, 1));
+ ASSERT_TRUE(writer.AddCopy(10, 2));
+ ASSERT_TRUE(writer.AddCopy(6, 3));
+ ASSERT_TRUE(writer.AddCopy(7, 4));
+ ASSERT_TRUE(writer.AddCopy(3, 5));
+ ASSERT_TRUE(writer.AddCopy(5, 6));
+ ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
+ ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
+
+ ASSERT_TRUE(writer.Finalize());
+
+ // New block in cow order is 2, 10, 6, 7, 3, 5, 12, 8, 11, 4, 9, 1
+ // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
+ // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
+ // new block 2 is "already merged", so will be left out.
+
+ std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
+
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ auto iter = reader.GetRevMergeOpIter();
+ auto expected_new_block = revMergeOpSequence.begin();
+
+ while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
+ const auto& op = iter->Get();
+
+ ASSERT_EQ(op.new_block, *expected_new_block);
+
+ iter->Next();
+ expected_new_block++;
+ }
+ ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
+ ASSERT_TRUE(iter->Done());
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/cow_format.cpp
index 0753c49..3085f80 100644
--- a/fs_mgr/libsnapshot/cow_format.cpp
+++ b/fs_mgr/libsnapshot/cow_format.cpp
@@ -37,6 +37,8 @@
os << "kCowLabelOp, ";
else if (op.type == kCowClusterOp)
os << "kCowClusterOp ";
+ else if (op.type == kCowSequenceOp)
+ os << "kCowSequenceOp ";
else if (op.type == kCowFooterOp)
os << "kCowFooterOp ";
else
@@ -81,6 +83,16 @@
case kCowLabelOp:
case kCowClusterOp:
case kCowFooterOp:
+ case kCowSequenceOp:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsOrderedOp(const CowOperation& op) {
+ switch (op.type) {
+ case kCowCopyOp:
return true;
default:
return false;
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 2349e4a..af49c7d 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -19,6 +19,9 @@
#include <limits>
#include <optional>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include <android-base/file.h>
@@ -127,7 +130,10 @@
return false;
}
- return ParseOps(label);
+ if (!ParseOps(label)) {
+ return false;
+ }
+ return PrepMergeOps();
}
bool CowReader::ParseOps(std::optional<uint64_t> label) {
@@ -201,6 +207,8 @@
current_op_num--;
done = true;
break;
+ } else if (current_op.type == kCowSequenceOp) {
+ has_seq_ops_ = true;
}
}
@@ -251,7 +259,7 @@
LOG(ERROR) << "ops checksum does not match";
return false;
}
- SHA256(ops_buffer.get()->data(), footer_->op.ops_size, csum);
+ SHA256(ops_buffer->data(), footer_->op.ops_size, csum);
if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) {
LOG(ERROR) << "ops checksum does not match";
return false;
@@ -264,138 +272,166 @@
return true;
}
-void CowReader::InitializeMerge() {
- uint64_t num_copy_ops = 0;
+//
+// This sets up the data needed for MergeOpIter. MergeOpIter presents
+// data in the order we intend to merge in.
+//
+// We merge all order sensitive ops up front, and sort the rest to allow for
+// batch merging. Order sensitive ops can either be presented in their proper
+// order in the cow, or be ordered by sequence ops (kCowSequenceOp), in which
+// case we want to merge those ops first, followed by any ops not specified by
+// new_block value by the sequence op, in sorted order.
+// We will re-arrange the vector in such a way that
+// kernel can batch merge. Ex:
+//
+// Existing COW format; All the copy operations
+// are at the beginning.
+// =======================================
+// Copy-op-1 - cow_op->new_block = 1
+// Copy-op-2 - cow_op->new_block = 2
+// Copy-op-3 - cow_op->new_block = 3
+// Replace-op-4 - cow_op->new_block = 6
+// Replace-op-5 - cow_op->new_block = 4
+// Replace-op-6 - cow_op->new_block = 8
+// Replace-op-7 - cow_op->new_block = 9
+// Zero-op-8 - cow_op->new_block = 7
+// Zero-op-9 - cow_op->new_block = 5
+// =======================================
+//
+// First find the operation which isn't a copy-op
+// and then sort all the operations in descending order
+// with the key being cow_op->new_block (source block)
+//
+// The data-structure will look like:
+//
+// =======================================
+// Copy-op-1 - cow_op->new_block = 1
+// Copy-op-2 - cow_op->new_block = 2
+// Copy-op-3 - cow_op->new_block = 3
+// Replace-op-7 - cow_op->new_block = 9
+// Replace-op-6 - cow_op->new_block = 8
+// Zero-op-8 - cow_op->new_block = 7
+// Replace-op-4 - cow_op->new_block = 6
+// Zero-op-9 - cow_op->new_block = 5
+// Replace-op-5 - cow_op->new_block = 4
+// =======================================
+//
+// Daemon will read the above data-structure in reverse-order
+// when reading metadata. Thus, kernel will get the metadata
+// in the following order:
+//
+// ========================================
+// Replace-op-5 - cow_op->new_block = 4
+// Zero-op-9 - cow_op->new_block = 5
+// Replace-op-4 - cow_op->new_block = 6
+// Zero-op-8 - cow_op->new_block = 7
+// Replace-op-6 - cow_op->new_block = 8
+// Replace-op-7 - cow_op->new_block = 9
+// Copy-op-3 - cow_op->new_block = 3
+// Copy-op-2 - cow_op->new_block = 2
+// Copy-op-1 - cow_op->new_block = 1
+// ===========================================
+//
+// When merging begins, kernel will start from the last
+// metadata which was read: In the above format, Copy-op-1
+// will be the first merge operation.
+//
+// Now, batching of the merge operations happens only when
+// 1: origin block numbers in the base device are contiguous
+// (cow_op->new_block) and,
+// 2: cow block numbers which are assigned by daemon in ReadMetadata()
+// are contiguous. These are monotonically increasing numbers.
+//
+// When both (1) and (2) are true, kernel will batch merge the operations.
+// In the above case, we have to ensure that the copy operations
+// are merged first before replace operations are done. Hence,
+// we will not change the order of copy operations. Since,
+// cow_op->new_block numbers are contiguous, we will ensure that the
+// cow block numbers assigned in ReadMetadata() for these respective copy
+// operations are not contiguous forcing kernel to issue merge for each
+// copy operations without batch merging.
+//
+// For all the other operations viz. Replace and Zero op, the cow block
+// numbers assigned by daemon will be contiguous allowing kernel to batch
+// merge.
+//
+// The final format after assiging COW block numbers by the daemon will
+// look something like:
+//
+// =========================================================
+// Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
+// Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
+// Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
+// Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
+// Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
+// Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
+// Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
+// Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
+// Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
+// ==========================================================
+//
+// Merge sequence will look like:
+//
+// Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
+// Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
+// Replace-op-4, Zero-op-9, Replace-op-5 }
+//==============================================================
+bool CowReader::PrepMergeOps() {
+ auto merge_op_blocks = std::make_shared<std::vector<uint32_t>>();
+ std::set<int, std::greater<int>> other_ops;
+ auto seq_ops_set = std::unordered_set<uint32_t>();
+ auto block_map = std::make_shared<std::unordered_map<uint32_t, int>>();
+ size_t num_seqs = 0;
+ size_t read;
- // Remove all the metadata operations
- ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
- [](CowOperation& op) { return IsMetadataOp(op); }),
- ops_.get()->end());
-
- set_total_data_ops(ops_->size());
- // We will re-arrange the vector in such a way that
- // kernel can batch merge. Ex:
- //
- // Existing COW format; All the copy operations
- // are at the beginning.
- // =======================================
- // Copy-op-1 - cow_op->new_block = 1
- // Copy-op-2 - cow_op->new_block = 2
- // Copy-op-3 - cow_op->new_block = 3
- // Replace-op-4 - cow_op->new_block = 6
- // Replace-op-5 - cow_op->new_block = 4
- // Replace-op-6 - cow_op->new_block = 8
- // Replace-op-7 - cow_op->new_block = 9
- // Zero-op-8 - cow_op->new_block = 7
- // Zero-op-9 - cow_op->new_block = 5
- // =======================================
- //
- // First find the operation which isn't a copy-op
- // and then sort all the operations in descending order
- // with the key being cow_op->new_block (source block)
- //
- // The data-structure will look like:
- //
- // =======================================
- // Copy-op-1 - cow_op->new_block = 1
- // Copy-op-2 - cow_op->new_block = 2
- // Copy-op-3 - cow_op->new_block = 3
- // Replace-op-7 - cow_op->new_block = 9
- // Replace-op-6 - cow_op->new_block = 8
- // Zero-op-8 - cow_op->new_block = 7
- // Replace-op-4 - cow_op->new_block = 6
- // Zero-op-9 - cow_op->new_block = 5
- // Replace-op-5 - cow_op->new_block = 4
- // =======================================
- //
- // Daemon will read the above data-structure in reverse-order
- // when reading metadata. Thus, kernel will get the metadata
- // in the following order:
- //
- // ========================================
- // Replace-op-5 - cow_op->new_block = 4
- // Zero-op-9 - cow_op->new_block = 5
- // Replace-op-4 - cow_op->new_block = 6
- // Zero-op-8 - cow_op->new_block = 7
- // Replace-op-6 - cow_op->new_block = 8
- // Replace-op-7 - cow_op->new_block = 9
- // Copy-op-3 - cow_op->new_block = 3
- // Copy-op-2 - cow_op->new_block = 2
- // Copy-op-1 - cow_op->new_block = 1
- // ===========================================
- //
- // When merging begins, kernel will start from the last
- // metadata which was read: In the above format, Copy-op-1
- // will be the first merge operation.
- //
- // Now, batching of the merge operations happens only when
- // 1: origin block numbers in the base device are contiguous
- // (cow_op->new_block) and,
- // 2: cow block numbers which are assigned by daemon in ReadMetadata()
- // are contiguous. These are monotonically increasing numbers.
- //
- // When both (1) and (2) are true, kernel will batch merge the operations.
- // In the above case, we have to ensure that the copy operations
- // are merged first before replace operations are done. Hence,
- // we will not change the order of copy operations. Since,
- // cow_op->new_block numbers are contiguous, we will ensure that the
- // cow block numbers assigned in ReadMetadata() for these respective copy
- // operations are not contiguous forcing kernel to issue merge for each
- // copy operations without batch merging.
- //
- // For all the other operations viz. Replace and Zero op, the cow block
- // numbers assigned by daemon will be contiguous allowing kernel to batch
- // merge.
- //
- // The final format after assiging COW block numbers by the daemon will
- // look something like:
- //
- // =========================================================
- // Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
- // Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
- // Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
- // Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
- // Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
- // Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
- // Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
- // Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
- // Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
- // ==========================================================
- //
- // Merge sequence will look like:
- //
- // Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
- // Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
- // Replace-op-4, Zero-op-9, Replace-op-5 }
- //==============================================================
-
- num_copy_ops = FindNumCopyops();
-
- std::sort(ops_.get()->begin() + num_copy_ops, ops_.get()->end(),
- [](CowOperation& op1, CowOperation& op2) -> bool {
- return op1.new_block > op2.new_block;
- });
-
- if (header_.num_merge_ops > 0) {
- ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
- }
-
- num_copy_ops = FindNumCopyops();
- set_copy_ops(num_copy_ops);
-}
-
-uint64_t CowReader::FindNumCopyops() {
- uint64_t num_copy_ops = 0;
-
- for (uint64_t i = 0; i < ops_->size(); i++) {
+ for (size_t i = 0; i < ops_->size(); i++) {
auto& current_op = ops_->data()[i];
- if (current_op.type != kCowCopyOp) {
- break;
+
+ if (current_op.type == kCowSequenceOp) {
+ size_t seq_len = current_op.data_length / sizeof(uint32_t);
+
+ merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
+ if (!GetRawBytes(current_op.source, &merge_op_blocks->data()[num_seqs],
+ current_op.data_length, &read)) {
+ PLOG(ERROR) << "Failed to read sequence op!";
+ return false;
+ }
+ for (size_t j = num_seqs; j < num_seqs + seq_len; j++) {
+ seq_ops_set.insert(merge_op_blocks->data()[j]);
+ }
+ num_seqs += seq_len;
}
- num_copy_ops += 1;
+
+ if (IsMetadataOp(current_op)) {
+ continue;
+ }
+
+ if (!has_seq_ops_ && IsOrderedOp(current_op)) {
+ merge_op_blocks->emplace_back(current_op.new_block);
+ } else if (seq_ops_set.count(current_op.new_block) == 0) {
+ other_ops.insert(current_op.new_block);
+ }
+ block_map->insert({current_op.new_block, i});
+ }
+ if (merge_op_blocks->size() > header_.num_merge_ops) {
+ num_ordered_ops_to_merge_ = merge_op_blocks->size() - header_.num_merge_ops;
+ } else {
+ num_ordered_ops_to_merge_ = 0;
+ }
+ merge_op_blocks->reserve(merge_op_blocks->size() + other_ops.size());
+ for (auto block : other_ops) {
+ merge_op_blocks->emplace_back(block);
}
- return num_copy_ops;
+ num_total_data_ops_ = merge_op_blocks->size();
+ if (header_.num_merge_ops > 0) {
+ merge_op_blocks->erase(merge_op_blocks->begin(),
+ merge_op_blocks->begin() + header_.num_merge_ops);
+ }
+
+ block_map_ = block_map;
+ merge_op_blocks_ = merge_op_blocks;
+ return true;
}
bool CowReader::GetHeader(CowHeader* header) {
@@ -430,11 +466,11 @@
CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
ops_ = ops;
- op_iter_ = ops_.get()->begin();
+ op_iter_ = ops_->begin();
}
bool CowOpIter::Done() {
- return op_iter_ == ops_.get()->end();
+ return op_iter_ == ops_->end();
}
void CowOpIter::Next() {
@@ -447,9 +483,11 @@
return (*op_iter_);
}
-class CowOpReverseIter final : public ICowOpReverseIter {
+class CowRevMergeOpIter final : public ICowOpIter {
public:
- explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops);
+ explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map);
bool Done() override;
const CowOperation& Get() override;
@@ -457,34 +495,41 @@
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::vector<CowOperation>::reverse_iterator op_riter_;
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
+ std::vector<uint32_t>::reverse_iterator block_riter_;
};
-CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) {
+CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+ std::shared_ptr<std::unordered_map<uint32_t, int>> map) {
ops_ = ops;
- op_riter_ = ops_.get()->rbegin();
+ merge_op_blocks_ = merge_op_blocks;
+ map_ = map;
+
+ block_riter_ = merge_op_blocks->rbegin();
}
-bool CowOpReverseIter::Done() {
- return op_riter_ == ops_.get()->rend();
+bool CowRevMergeOpIter::Done() {
+ return block_riter_ == merge_op_blocks_->rend();
}
-void CowOpReverseIter::Next() {
+void CowRevMergeOpIter::Next() {
CHECK(!Done());
- op_riter_++;
+ block_riter_++;
}
-const CowOperation& CowOpReverseIter::Get() {
+const CowOperation& CowRevMergeOpIter::Get() {
CHECK(!Done());
- return (*op_riter_);
+ return ops_->data()[map_->at(*block_riter_)];
}
std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
return std::make_unique<CowOpIter>(ops_);
}
-std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() {
- return std::make_unique<CowOpReverseIter>(ops_);
+std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter() {
+ return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_);
}
bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 526fede..ef30e32 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -58,8 +58,8 @@
return EmitRawBlocks(new_block_start, data, size);
}
-bool AddXorBlocks(uint32_t /*new_block_start*/, const void* /*data*/, size_t /*size*/,
- uint32_t /*old_block*/, uint16_t /*offset*/) {
+bool ICowWriter::AddXorBlocks(uint32_t /*new_block_start*/, const void* /*data*/, size_t /*size*/,
+ uint32_t /*old_block*/, uint16_t /*offset*/) {
LOG(ERROR) << "AddXorBlocks not yet implemented";
return false;
}
@@ -76,9 +76,8 @@
return EmitLabel(label);
}
-bool ICowWriter::AddSequenceData(size_t /*num_ops*/, const uint32_t* /*data*/) {
- LOG(ERROR) << "AddSequenceData not yet implemented";
- return false;
+bool ICowWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
+ return EmitSequenceData(num_ops, data);
}
bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
@@ -103,7 +102,7 @@
header_.footer_size = sizeof(CowFooter);
header_.op_size = sizeof(CowOperation);
header_.block_size = options_.block_size;
- header_.num_merge_ops = 0;
+ header_.num_merge_ops = options_.num_merge_ops;
header_.cluster_ops = options_.cluster_ops;
header_.buffer_size = 0;
footer_ = {};
@@ -337,6 +336,26 @@
return WriteOperation(op) && Sync();
}
+bool CowWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
+ CHECK(!merge_in_progress_);
+ size_t to_add = 0;
+ size_t max_ops = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t);
+ while (num_ops > 0) {
+ CowOperation op = {};
+ op.type = kCowSequenceOp;
+ op.source = next_data_pos_;
+ to_add = std::min(num_ops, max_ops);
+ op.data_length = static_cast<uint16_t>(to_add * sizeof(uint32_t));
+ if (!WriteOperation(op, data, op.data_length)) {
+ PLOG(ERROR) << "AddSequenceData: write failed";
+ return false;
+ }
+ num_ops -= to_add;
+ data += to_add;
+ }
+ return true;
+}
+
bool CowWriter::EmitCluster() {
CowOperation op = {};
op.type = kCowClusterOp;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 000e5e1..464046b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -148,6 +148,7 @@
static constexpr uint8_t kCowZeroOp = 3;
static constexpr uint8_t kCowLabelOp = 4;
static constexpr uint8_t kCowClusterOp = 5;
+static constexpr uint8_t kCowSequenceOp = 7;
static constexpr uint8_t kCowFooterOp = -1;
static constexpr uint8_t kCowCompressNone = 0;
@@ -184,7 +185,10 @@
int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_size);
int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_size);
+// Ops that are internal to the Cow Format and not OTA data
bool IsMetadataOp(const CowOperation& op);
+// Ops that have dependencies on old blocks, and must take care in their merge order
+bool IsOrderedOp(const CowOperation& op);
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 669e58a..6c3059c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -19,6 +19,7 @@
#include <functional>
#include <memory>
#include <optional>
+#include <unordered_map>
#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>
@@ -27,7 +28,6 @@
namespace snapshot {
class ICowOpIter;
-class ICowOpReverseIter;
// A ByteSink object handles requests for a buffer of a specific size. It
// always owns the underlying buffer. It's designed to minimize potential
@@ -75,8 +75,8 @@
// Return an iterator for retrieving CowOperation entries.
virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
- // Return an reverse iterator for retrieving CowOperation entries.
- virtual std::unique_ptr<ICowOpReverseIter> GetRevOpIter() = 0;
+ // Return an iterator for retrieving CowOperation entries in merge order
+ virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter() = 0;
// Get decoded bytes from the data section, handling any decompression.
// All retrieved data is passed to the sink.
@@ -98,21 +98,6 @@
virtual void Next() = 0;
};
-// Reverse Iterate over a sequence of COW operations.
-class ICowOpReverseIter {
- public:
- virtual ~ICowOpReverseIter() {}
-
- // True if there are more items to read, false otherwise.
- virtual bool Done() = 0;
-
- // Read the current operation.
- virtual const CowOperation& Get() = 0;
-
- // Advance to the next item.
- virtual void Next() = 0;
-};
-
class CowReader : public ICowReader {
public:
CowReader();
@@ -135,25 +120,25 @@
// whose lifetime depends on the CowOpIter object; the return
// value of these will never be null.
std::unique_ptr<ICowOpIter> GetOpIter() override;
- std::unique_ptr<ICowOpReverseIter> GetRevOpIter() override;
+ std::unique_ptr<ICowOpIter> GetRevMergeOpIter() override;
bool ReadData(const CowOperation& op, IByteSink* sink) override;
bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
- void InitializeMerge();
+ // Returns the total number of data ops that should be merged. This is the
+ // count of the merge sequence before removing already-merged operations.
+ // It may be different than the actual data op count, for example, if there
+ // are duplicate ops in the stream.
+ uint64_t get_num_total_data_ops() { return num_total_data_ops_; }
- // Number of copy, replace, and zero ops. Set if InitializeMerge is called.
- void set_total_data_ops(uint64_t size) { total_data_ops_ = size; }
- uint64_t total_data_ops() { return total_data_ops_; }
- // Number of copy ops. Set if InitializeMerge is called.
- void set_copy_ops(uint64_t size) { copy_ops_ = size; }
- uint64_t total_copy_ops() { return copy_ops_; }
+ uint64_t get_num_ordered_ops_to_merge() { return num_ordered_ops_to_merge_; }
void CloseCowFd() { owned_fd_ = {}; }
private:
bool ParseOps(std::optional<uint64_t> label);
+ bool PrepMergeOps();
uint64_t FindNumCopyops();
android::base::unique_fd owned_fd_;
@@ -163,8 +148,11 @@
uint64_t fd_size_;
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
- uint64_t total_data_ops_;
- uint64_t copy_ops_;
+ std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+ std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
+ uint64_t num_total_data_ops_;
+ uint64_t num_ordered_ops_to_merge_;
+ bool has_seq_ops_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index fbe6461..4a807fb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -38,6 +38,9 @@
uint32_t cluster_ops = 200;
bool scratch_space = true;
+
+ // Preset the number of merged ops. Only useful for testing.
+ uint64_t num_merge_ops = 0;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -85,6 +88,7 @@
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
virtual bool EmitLabel(uint64_t label) = 0;
+ virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0;
bool ValidateNewBlock(uint64_t new_block);
@@ -120,6 +124,7 @@
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
virtual bool EmitLabel(uint64_t label) override;
+ virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
bool EmitCluster();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
new file mode 100644
index 0000000..0457986
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2021 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.
+//
+
+#include <gmock/gmock.h>
+#include <libsnapshot/snapshot_writer.h>
+
+namespace android::snapshot {
+
+class MockSnapshotWriter : public ISnapshotWriter {
+ public:
+ using FileDescriptor = ISnapshotWriter::FileDescriptor;
+
+ explicit MockSnapshotWriter(const CowOptions& options) : ISnapshotWriter(options) {}
+ MockSnapshotWriter() : ISnapshotWriter({}) {}
+
+ MOCK_METHOD(bool, Finalize, (), (override));
+
+ // Return number of bytes the cow image occupies on disk.
+ MOCK_METHOD(uint64_t, GetCowSize, (), (override));
+
+ // Returns true if AddCopy() operations are supported.
+ MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
+
+ MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
+ MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
+ MOCK_METHOD(bool, EmitZeroBlocks, (uint64_t, uint64_t), (override));
+ MOCK_METHOD(bool, EmitLabel, (uint64_t), (override));
+ MOCK_METHOD(bool, EmitSequenceData, (size_t, const uint32_t*), (override));
+
+ // Open the writer in write mode (no append).
+ MOCK_METHOD(bool, Initialize, (), (override));
+
+ // Open the writer in append mode, with the last label to resume
+ // from. See CowWriter::InitializeAppend.
+ MOCK_METHOD(bool, InitializeAppend, (uint64_t label), (override));
+
+ MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
+};
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index bf5ce8b..c00dafa 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -76,6 +76,7 @@
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitLabel(uint64_t label) override;
+ bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
android::base::unique_fd cow_device_;
@@ -103,6 +104,7 @@
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
bool EmitLabel(uint64_t label) override;
+ bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
private:
android::base::unique_fd snapshot_fd_;
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 1dc61af..ed86c87 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -40,8 +40,18 @@
LOG(ERROR) << "\t -s Run Silent";
LOG(ERROR) << "\t -d Attempt to decompress";
LOG(ERROR) << "\t -b Show data for failed decompress\n";
+ LOG(ERROR) << "\t -m Show ops in reverse merge order\n";
}
+enum OpIter { Normal, RevMerge };
+
+struct Options {
+ bool silent;
+ bool decompress;
+ bool show_bad;
+ OpIter iter_type;
+};
+
// Sink that always appends to the end of a string.
class StringSink : public IByteSink {
public:
@@ -78,7 +88,7 @@
}
}
-static bool Inspect(const std::string& path, bool silent, bool decompress, bool show_bad) {
+static bool Inspect(const std::string& path, Options opt) {
android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
if (fd < 0) {
PLOG(ERROR) << "open failed: " << path;
@@ -100,7 +110,7 @@
bool has_footer = false;
if (reader.GetFooter(&footer)) has_footer = true;
- if (!silent) {
+ if (!opt.silent) {
std::cout << "Major version: " << header.major_version << "\n";
std::cout << "Minor version: " << header.minor_version << "\n";
std::cout << "Header size: " << header.header_size << "\n";
@@ -116,19 +126,24 @@
}
}
- auto iter = reader.GetOpIter();
+ std::unique_ptr<ICowOpIter> iter;
+ if (opt.iter_type == Normal) {
+ iter = reader.GetOpIter();
+ } else if (opt.iter_type == RevMerge) {
+ iter = reader.GetRevMergeOpIter();
+ }
StringSink sink;
bool success = true;
while (!iter->Done()) {
const CowOperation& op = iter->Get();
- if (!silent) std::cout << op << "\n";
+ if (!opt.silent) std::cout << op << "\n";
- if (decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
+ if (opt.decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
if (!reader.ReadData(op, &sink)) {
std::cerr << "Failed to decompress for :" << op << "\n";
success = false;
- if (show_bad) ShowBad(reader, op);
+ if (opt.show_bad) ShowBad(reader, op);
}
sink.Reset();
}
@@ -144,19 +159,24 @@
int main(int argc, char** argv) {
int ch;
- bool silent = false;
- bool decompress = false;
- bool show_bad = false;
- while ((ch = getopt(argc, argv, "sdb")) != -1) {
+ struct android::snapshot::Options opt;
+ opt.silent = false;
+ opt.decompress = false;
+ opt.show_bad = false;
+ opt.iter_type = android::snapshot::Normal;
+ while ((ch = getopt(argc, argv, "sdbm")) != -1) {
switch (ch) {
case 's':
- silent = true;
+ opt.silent = true;
break;
case 'd':
- decompress = true;
+ opt.decompress = true;
break;
case 'b':
- show_bad = true;
+ opt.show_bad = true;
+ break;
+ case 'm':
+ opt.iter_type = android::snapshot::RevMerge;
break;
default:
android::snapshot::usage();
@@ -169,7 +189,7 @@
return 1;
}
- if (!android::snapshot::Inspect(argv[optind], silent, decompress, show_bad)) {
+ if (!android::snapshot::Inspect(argv[optind], opt)) {
return 1;
}
return 0;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 0e36da1..c3db32e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1193,11 +1193,7 @@
return MergeFailureCode::ParseCowConsistencyCheck;
}
- for (auto iter = reader.GetOpIter(); !iter->Done(); iter->Next()) {
- if (!IsMetadataOp(iter->Get())) {
- num_ops++;
- }
- }
+ num_ops = reader.get_num_total_data_ops();
}
// Second pass, try as hard as we can to get the actual number of blocks
@@ -2534,6 +2530,7 @@
SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
status.set_compression_enabled(old_status.compression_enabled());
status.set_source_build_fingerprint(old_status.source_build_fingerprint());
+ status.set_merge_phase(old_status.merge_phase());
}
return WriteSnapshotUpdateStatus(lock, status);
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 6018643..b2203fe 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1184,6 +1184,53 @@
}
}
+TEST_F(SnapshotUpdateTest, DuplicateOps) {
+ if (!IsCompressionEnabled()) {
+ GTEST_SKIP() << "Compression-only test";
+ }
+
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
+ // Execute the update.
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+ // Write some data to target partitions.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(WriteSnapshotAndHash(name));
+ }
+
+ std::vector<PartitionUpdate*> partitions = {sys_, vnd_, prd_};
+ for (auto* partition : partitions) {
+ AddOperation(partition);
+
+ std::unique_ptr<ISnapshotWriter> writer;
+ auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
+ ASSERT_TRUE(res);
+ ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
+ ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
+ ASSERT_TRUE(writer->Finalize());
+ }
+
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+ // Simulate shutting down the device.
+ ASSERT_TRUE(UnmapAll());
+
+ // After reboot, init does first stage mount.
+ auto init = NewManagerForFirstStageMount("_b");
+ ASSERT_NE(init, nullptr);
+ ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+ // Initiate the merge and wait for it to be completed.
+ ASSERT_TRUE(init->InitiateMerge());
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
+}
+
// Test that shrinking and growing partitions at the same time is handled
// correctly in VABC.
TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 080f3b7..34b3e87 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -114,6 +114,10 @@
return cow_->AddLabel(label);
}
+bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
+ return cow_->AddSequenceData(num_ops, data);
+}
+
bool CompressedSnapshotWriter::Initialize() {
return cow_->Initialize(cow_device_);
}
@@ -183,6 +187,11 @@
return true;
}
+bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) {
+ // Not Needed
+ return true;
+}
+
std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
unique_fd fd(dup(snapshot_fd_.get()));
if (fd < 0) {
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 03c2ef6..a09b111 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -64,7 +64,7 @@
int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
if (ret < 0) {
- PLOG(ERROR) << "msync header failed: " << ret;
+ SNAP_PLOG(ERROR) << "msync header failed: " << ret;
return false;
}
@@ -266,14 +266,15 @@
void Snapuserd::CheckMergeCompletionStatus() {
if (!merge_initiated_) {
- SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: " << reader_->total_data_ops();
+ SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
+ << reader_->get_num_total_data_ops();
return;
}
struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
- << " Total-data-ops: " << reader_->total_data_ops();
+ << " Total-data-ops: " << reader_->get_num_total_data_ops();
}
/*
@@ -352,7 +353,6 @@
return false;
}
- reader_->InitializeMerge();
SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops;
if (!MmapMetadata()) {
@@ -361,7 +361,7 @@
}
// Initialize the iterator for reading metadata
- cowop_riter_ = reader_->GetRevOpIter();
+ std::unique_ptr<ICowOpIter> cowop_rm_iter = reader_->GetRevMergeOpIter();
exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
@@ -379,23 +379,18 @@
// this memset will ensure that metadata read is completed.
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- while (!cowop_riter_->Done()) {
- const CowOperation* cow_op = &cowop_riter_->Get();
+ while (!cowop_rm_iter->Done()) {
+ const CowOperation* cow_op = &cowop_rm_iter->Get();
struct disk_exception* de =
reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
- if (IsMetadataOp(*cow_op)) {
- cowop_riter_->Next();
- continue;
- }
-
metadata_found = true;
// This loop will handle all the replace and zero ops.
// We will handle the copy ops later as it requires special
// handling of assigning chunk-id's. Furthermore, we make
// sure that replace/zero and copy ops are not batch merged; hence,
// the bump in the chunk_id before break of this loop
- if (cow_op->type == kCowCopyOp) {
+ if (IsOrderedOp(*cow_op)) {
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
break;
}
@@ -415,7 +410,7 @@
chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
num_ops += 1;
offset += sizeof(struct disk_exception);
- cowop_riter_->Next();
+ cowop_rm_iter->Next();
SNAP_LOG(DEBUG) << num_ops << ":"
<< " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
@@ -432,7 +427,7 @@
sizeof(struct disk_exception));
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- if (cowop_riter_->Done()) {
+ if (cowop_rm_iter->Done()) {
vec_.push_back(std::move(de_ptr));
}
}
@@ -445,18 +440,15 @@
std::map<uint64_t, const CowOperation*> map;
std::set<uint64_t> dest_blocks;
size_t pending_copy_ops = exceptions_per_area_ - num_ops;
- uint64_t total_copy_ops = reader_->total_copy_ops();
+ uint64_t total_copy_ops = reader_->get_num_ordered_ops_to_merge();
SNAP_LOG(DEBUG) << " Processing copy-ops at Area: " << vec_.size()
<< " Number of replace/zero ops completed in this area: " << num_ops
<< " Pending copy ops for this area: " << pending_copy_ops;
- while (!cowop_riter_->Done()) {
+
+ while (!cowop_rm_iter->Done()) {
do {
- const CowOperation* cow_op = &cowop_riter_->Get();
- if (IsMetadataOp(*cow_op)) {
- cowop_riter_->Next();
- continue;
- }
+ const CowOperation* cow_op = &cowop_rm_iter->Get();
// We have two cases specific cases:
//
@@ -572,8 +564,8 @@
map[cow_op->new_block] = cow_op;
dest_blocks.insert(cow_op->source);
prev_id = cow_op->new_block;
- cowop_riter_->Next();
- } while (!cowop_riter_->Done() && pending_copy_ops);
+ cowop_rm_iter->Next();
+ } while (!cowop_rm_iter->Done() && pending_copy_ops);
data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << map.size()
@@ -611,7 +603,7 @@
sizeof(struct disk_exception));
memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
- if (cowop_riter_->Done()) {
+ if (cowop_rm_iter->Done()) {
vec_.push_back(std::move(de_ptr));
SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size();
}
@@ -661,7 +653,7 @@
<< " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops
<< " Copy-ops: " << copy_ops << " Areas: " << vec_.size()
<< " Num-ops-merged: " << header.num_merge_ops
- << " Total-data-ops: " << reader_->total_data_ops();
+ << " Total-data-ops: " << reader_->get_num_total_data_ops();
// Total number of sectors required for creating dm-user device
num_sectors_ = ChunkToSector(data_chunk_id);
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 212c78e..5d86e4f 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -306,8 +306,6 @@
uint32_t exceptions_per_area_;
uint64_t num_sectors_;
- std::unique_ptr<ICowOpIter> cowop_iter_;
- std::unique_ptr<ICowOpReverseIter> cowop_riter_;
std::unique_ptr<CowReader> reader_;
// Vector of disk exception which is a
diff --git a/init/devices.cpp b/init/devices.cpp
index ce6298a..56c6623 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -264,6 +264,8 @@
setfscreatecon(secontext.c_str());
}
+ gid_t new_group = -1;
+
dev_t dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
@@ -291,10 +293,21 @@
PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
<< "' device";
}
+
+ struct stat s;
+ if (stat(path.c_str(), &s) == 0) {
+ if (gid != s.st_gid) {
+ new_group = gid;
+ }
+ } else {
+ PLOG(ERROR) << "Cannot stat " << path;
+ }
}
out:
- chown(path.c_str(), uid, -1);
+ if (chown(path.c_str(), uid, new_group) < 0) {
+ PLOG(ERROR) << "Cannot chown " << path << " " << uid << " " << new_group;
+ }
if (setegid(AID_ROOT)) {
PLOG(FATAL) << "setegid(AID_ROOT) failed";
}
diff --git a/init/main.cpp b/init/main.cpp
index 23f5530..b01a3ee 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -25,9 +25,11 @@
#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
+#elif __has_feature(hwaddress_sanitizer)
+#include <sanitizer/hwasan_interface.h>
#endif
-#if __has_feature(address_sanitizer)
+#if __has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer)
// Load asan.options if it exists since these are not yet in the environment.
// Always ensure detect_container_overflow=0 as there are false positives with this check.
// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
@@ -51,6 +53,8 @@
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
+#elif __has_feature(hwaddress_sanitizer)
+ __hwasan_set_error_report_callback(AsanReportCallback);
#endif
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 15252a6..2a57808 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -158,7 +158,8 @@
auto on_activate = [&](const std::string& apex_path,
const apex::proto::ApexManifest& apex_manifest) {
apex_infos.emplace_back(apex_manifest.name(), apex_path, apex_path, apex_manifest.version(),
- apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true);
+ apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true,
+ /* lastUpdateMillis= */ 0);
};
for (const auto& dir : kBuiltinDirsForApexes) {
diff --git a/init/util.cpp b/init/util.cpp
index a40d104..9f7bfdb 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -253,8 +253,10 @@
for (const auto& entry : android::base::Split(bootconfig, "\n")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
if (pieces.size() == 2) {
- pieces[1].erase(std::remove(pieces[1].begin(), pieces[1].end(), '"'), pieces[1].end());
- fn(android::base::Trim(pieces[0]), android::base::Trim(pieces[1]));
+ // get rid of the extra space between a list of values and remove the quotes.
+ std::string value = android::base::StringReplace(pieces[1], "\", \"", ",", true);
+ value.erase(std::remove(value.begin(), value.end(), '"'), value.end());
+ fn(android::base::Trim(pieces[0]), android::base::Trim(value));
}
}
}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 5c7a75d..c824376 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -224,7 +224,11 @@
* transferred for the user/group passed as uid/gid before system_server can properly access them.
*/
static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
- if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
+ if (mkdir(path.c_str(), mode) == -1) {
+ if (errno == EEXIST) {
+ // Directory already exists and permissions have been set at the time it was created
+ return true;
+ }
return false;
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index b5fa475..449a505 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -584,7 +584,7 @@
}
}
]
- },
+ }
],
"AggregateProfiles": [
@@ -635,6 +635,10 @@
{
"Name": "CPUSET_SP_RESTRICTED",
"Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
+ },
+ {
+ "Name": "Dex2OatBootComplete",
+ "Profiles": [ "SCHED_SP_BACKGROUND" ]
}
]
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a8bef42..a7322fa 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -750,8 +750,7 @@
mkdir /data/misc/odrefresh 0777 system system
# directory used for on-device signing key blob
mkdir /data/misc/odsign 0700 root root
- # Directory for VirtualizationService temporary image files. Ensure that it is empty.
- exec -- /bin/rm -rf /data/misc/virtualizationservice
+ # Directory for VirtualizationService temporary image files.
mkdir /data/misc/virtualizationservice 0700 virtualizationservice virtualizationservice
mkdir /data/preloads 0775 system system encryption=None
diff --git a/trusty/confirmationui/fuzz/msg_fuzzer.cpp b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
index 8e4443c..ee55f82 100644
--- a/trusty/confirmationui/fuzz/msg_fuzzer.cpp
+++ b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
@@ -37,7 +37,7 @@
#define CONFIRMATIONUI_MODULE_NAME "confirmationui.syms.elf"
/* A request to render to screen may take a while. */
-const size_t kTimeoutSeconds = 30;
+const size_t kTimeoutSeconds = 60;
/* ConfirmationUI TA's UUID is 7dee2364-c036-425b-b086-df0f6c233c1b */
static struct uuid confirmationui_uuid = {
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 58dfa94..ff6460d 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -100,6 +100,7 @@
"ipc/trusty_keymaster_ipc.cpp",
"keymint/TrustyKeyMintDevice.cpp",
"keymint/TrustyKeyMintOperation.cpp",
+ "keymint/TrustyRemotelyProvisionedComponentDevice.cpp",
"keymint/TrustySecureClock.cpp",
"keymint/TrustySharedSecret.cpp",
"keymint/service.cpp",
@@ -118,7 +119,6 @@
"libtrusty",
],
required: [
- "RemoteProvisioner",
"android.hardware.hardware_keystore.xml",
],
}
@@ -129,6 +129,27 @@
src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
}
+cc_library {
+ name: "libtrusty_ipc",
+ vendor: true,
+ srcs: ["ipc/trusty_keymaster_ipc.cpp"],
+ local_include_dirs: ["include"],
+ shared_libs: [
+ "libc",
+ "libcrypto",
+ "liblog",
+ "libtrusty",
+ "libhardware",
+ "libkeymaster_messages",
+ "libxml2",
+ ],
+ export_include_dirs: ["include"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
cc_binary {
name: "trusty_keymaster_set_attestation_key",
vendor: true,
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index ef5fc3f..aee3333 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -158,6 +158,16 @@
}
}
+void TrustyKeymaster::GenerateRkpKey(const GenerateRkpKeyRequest& request,
+ GenerateRkpKeyResponse* response) {
+ ForwardCommand(KM_GENERATE_RKP_KEY, request, response);
+}
+
+void TrustyKeymaster::GenerateCsr(const GenerateCsrRequest& request,
+ GenerateCsrResponse* response) {
+ ForwardCommand(KM_GENERATE_CSR, request, response);
+}
+
void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response) {
ForwardCommand(KM_GET_KEY_CHARACTERISTICS, request, response);
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 45ebf7f..35eda45 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -42,6 +42,8 @@
void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
void Configure(const ConfigureRequest& request, ConfigureResponse* response);
void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+ void GenerateRkpKey(const GenerateRkpKeyRequest& request, GenerateRkpKeyResponse* response);
+ void GenerateCsr(const GenerateCsrRequest& request, GenerateCsrResponse* response);
void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response);
void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
new file mode 100644
index 0000000..d544b51
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021, 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using ::std::shared_ptr;
+
+class TrustyRemotelyProvisionedComponentDevice : public BnRemotelyProvisionedComponent {
+ public:
+ explicit TrustyRemotelyProvisionedComponentDevice(shared_ptr<TrustyKeymaster> impl)
+ : impl_(std::move(impl)) {}
+ virtual ~TrustyRemotelyProvisionedComponentDevice() = default;
+
+ ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
+
+ ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+ std::vector<uint8_t>* privateKeyHandle) override;
+
+ ScopedAStatus generateCertificateRequest(bool testMode,
+ const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& endpointEncCertChain,
+ const std::vector<uint8_t>& challenge,
+ DeviceInfo* deviceInfo, ProtectedData* protectedData,
+ std::vector<uint8_t>* keysToSignMac) override;
+
+ private:
+ std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+
+} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index a1229a3..17fee15 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -56,6 +56,8 @@
KM_GET_VERSION_2 = (28 << KEYMASTER_REQ_SHIFT),
KM_EARLY_BOOT_ENDED = (29 << KEYMASTER_REQ_SHIFT),
KM_DEVICE_LOCKED = (30 << KEYMASTER_REQ_SHIFT),
+ KM_GENERATE_RKP_KEY = (31 << KEYMASTER_REQ_SHIFT),
+ KM_GENERATE_CSR = (32 << KEYMASTER_REQ_SHIFT),
// Bootloader/provisioning calls.
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
@@ -69,6 +71,7 @@
KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
+ KM_SET_ATTESTATION_IDS = (0xc000 << KEYMASTER_REQ_SHIFT)
};
#ifdef __ANDROID__
diff --git a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
new file mode 100644
index 0000000..5664829
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021, 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.
+ */
+
+#include <trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h>
+
+#include <assert.h>
+#include <variant>
+
+#include <KeyMintUtils.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include <trusty_keymaster/TrustyKeyMintDevice.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using keymaster::GenerateCsrRequest;
+using keymaster::GenerateCsrResponse;
+using keymaster::GenerateRkpKeyRequest;
+using keymaster::GenerateRkpKeyResponse;
+using keymaster::KeymasterBlob;
+using ::std::string;
+using ::std::unique_ptr;
+using ::std::vector;
+using bytevec = ::std::vector<uint8_t>;
+
+namespace {
+
+constexpr auto STATUS_FAILED = IRemotelyProvisionedComponent::STATUS_FAILED;
+
+struct AStatusDeleter {
+ void operator()(AStatus* p) { AStatus_delete(p); }
+};
+
+class Status {
+ public:
+ Status() : status_(AStatus_newOk()) {}
+ Status(int32_t errCode, const std::string& errMsg)
+ : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
+ explicit Status(const std::string& errMsg)
+ : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
+ explicit Status(AStatus* status) : status_(status ? status : AStatus_newOk()) {}
+
+ Status(Status&&) = default;
+ Status(const Status&) = delete;
+
+ operator ::ndk::ScopedAStatus() && { // NOLINT(google-explicit-constructor)
+ return ndk::ScopedAStatus(status_.release());
+ }
+
+ bool isOk() const { return AStatus_isOk(status_.get()); }
+
+ const char* getMessage() const { return AStatus_getMessage(status_.get()); }
+
+ private:
+ std::unique_ptr<AStatus, AStatusDeleter> status_;
+};
+
+} // namespace
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
+ info->versionNumber = 1;
+ info->rpcAuthorName = "Google";
+ info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(
+ bool testMode, MacedPublicKey* macedPublicKey, bytevec* privateKeyHandle) {
+ GenerateRkpKeyRequest request(impl_->message_version());
+ request.test_mode = testMode;
+ GenerateRkpKeyResponse response(impl_->message_version());
+ impl_->GenerateRkpKey(request, &response);
+ if (response.error != KM_ERROR_OK) {
+ return Status(-static_cast<int32_t>(response.error), "Failure in key generation.");
+ }
+
+ macedPublicKey->macedKey = km_utils::kmBlob2vector(response.maced_public_key);
+ *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::generateCertificateRequest(
+ bool testMode, const vector<MacedPublicKey>& keysToSign,
+ const bytevec& endpointEncCertChain, const bytevec& challenge, DeviceInfo* deviceInfo,
+ ProtectedData* protectedData, bytevec* keysToSignMac) {
+ GenerateCsrRequest request(impl_->message_version());
+ request.test_mode = testMode;
+ request.num_keys = keysToSign.size();
+ request.keys_to_sign_array = new KeymasterBlob[keysToSign.size()];
+ for (size_t i = 0; i < keysToSign.size(); i++) {
+ request.SetKeyToSign(i, keysToSign[i].macedKey.data(), keysToSign[i].macedKey.size());
+ }
+ request.SetEndpointEncCertChain(endpointEncCertChain.data(), endpointEncCertChain.size());
+ request.SetChallenge(challenge.data(), challenge.size());
+ GenerateCsrResponse response(impl_->message_version());
+ impl_->GenerateCsr(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return Status(-static_cast<int32_t>(response.error), "Failure in CSR Generation.");
+ }
+ deviceInfo->deviceInfo = km_utils::kmBlob2vector(response.device_info_blob);
+ protectedData->protectedData = km_utils::kmBlob2vector(response.protected_data_blob);
+ *keysToSignMac = km_utils::kmBlob2vector(response.keys_to_sign_mac);
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
index 0ab3d64..7ca5050 100644
--- a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -11,4 +11,8 @@
<name>android.hardware.security.sharedsecret</name>
<fqname>ISharedSecret/default</fqname>
</hal>
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IRemotelyProvisionedComponent/default</fqname>
+ </hal>
</manifest>
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
index 8f5f0f8..4060278 100644
--- a/trusty/keymaster/keymint/service.cpp
+++ b/trusty/keymaster/keymint/service.cpp
@@ -20,10 +20,12 @@
#include <android/binder_process.h>
#include <trusty_keymaster/TrustyKeyMintDevice.h>
+#include <trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h>
#include <trusty_keymaster/TrustySecureClock.h>
#include <trusty_keymaster/TrustySharedSecret.h>
using aidl::android::hardware::security::keymint::trusty::TrustyKeyMintDevice;
+using aidl::android::hardware::security::keymint::trusty::TrustyRemotelyProvisionedComponentDevice;
using aidl::android::hardware::security::secureclock::trusty::TrustySecureClock;
using aidl::android::hardware::security::sharedsecret::trusty::TrustySharedSecret;
@@ -52,7 +54,8 @@
auto keyMint = addService<TrustyKeyMintDevice>(trustyKeymaster);
auto secureClock = addService<TrustySecureClock>(trustyKeymaster);
auto sharedSecret = addService<TrustySharedSecret>(trustyKeymaster);
-
+ auto remotelyProvisionedComponent =
+ addService<TrustyRemotelyProvisionedComponentDevice>(trustyKeymaster);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index a471435..d67089f 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -29,7 +29,10 @@
"proxy.c",
],
- shared_libs: ["liblog"],
+ shared_libs: [
+ "liblog",
+ "libhardware_legacy",
+ ],
header_libs: ["libcutils_headers"],
static_libs: [
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index d1ed649..b59fb67 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -29,6 +29,8 @@
#include <linux/major.h>
#include <linux/mmc/ioctl.h>
+#include <hardware_legacy/power.h>
+
#include "ipc.h"
#include "log.h"
#include "rpmb.h"
@@ -100,6 +102,8 @@
static uint8_t read_buf[4096];
static enum dev_type dev_type = UNKNOWN_RPMB;
+static const char* UFS_WAKE_LOCK_NAME = "ufs_seq_wakelock";
+
#ifdef RPMB_DEBUG
static void print_buf(const char* prefix, const uint8_t* buf, size_t size) {
@@ -194,6 +198,7 @@
static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req) {
int rc;
+ int wl_rc;
const uint8_t* write_buf = req->payload;
/*
* Meaning of member values are stated on the definition of struct sec_proto_cdb.
@@ -202,6 +207,12 @@
struct sec_proto_cdb out_cdb = {0xB5, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
unsigned char sense_buffer[32];
+ wl_rc = acquire_wake_lock(PARTIAL_WAKE_LOCK, UFS_WAKE_LOCK_NAME);
+ if (wl_rc < 0) {
+ ALOGE("%s: failed to acquire wakelock: %d, %s\n", __func__, wl_rc, strerror(errno));
+ return wl_rc;
+ }
+
if (req->reliable_write_size) {
/* Prepare SECURITY PROTOCOL OUT command. */
out_cdb.length = __builtin_bswap32(req->reliable_write_size);
@@ -212,6 +223,7 @@
rc = ioctl(sg_fd, SG_IO, &io_hdr);
if (rc < 0) {
ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+ goto err_op;
}
write_buf += req->reliable_write_size;
}
@@ -225,6 +237,7 @@
rc = ioctl(sg_fd, SG_IO, &io_hdr);
if (rc < 0) {
ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+ goto err_op;
}
write_buf += req->write_size;
}
@@ -240,6 +253,13 @@
ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
}
}
+
+err_op:
+ wl_rc = release_wake_lock(UFS_WAKE_LOCK_NAME);
+ if (wl_rc < 0) {
+ ALOGE("%s: failed to release wakelock: %d, %s\n", __func__, wl_rc, strerror(errno));
+ }
+
return rc;
}