Merge "Revert "Completely migrate init first stage to Soong"" into sc-dev
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 24804d0..abda071 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -58,6 +58,7 @@
#include <scoped_minijail.h>
#include "debuggerd/handler.h"
+#include "libdebuggerd/utility.h"
#include "protocol.h"
#include "tombstoned/tombstoned.h"
#include "util.h"
@@ -526,6 +527,8 @@
std::vector<std::string> log_sources(2);
ConsumeFd(std::move(output_fd), &log_sources[0]);
logcat_collector.Collect(&log_sources[1]);
+ // Tag dump only available in the tombstone, not logcat.
+ ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
for (const auto& result : log_sources) {
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
@@ -597,6 +600,12 @@
ConsumeFd(std::move(output_fd), &log_sources[0]);
logcat_collector.Collect(&log_sources[1]);
+ // Tag dump only in tombstone, not logcat, and tagging is not used for
+ // overflow protection in the scudo secondary (guard pages are used instead).
+ if (GetParam() < 0x10000) {
+ ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
+ }
+
for (const auto& result : log_sources) {
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
@@ -637,6 +646,7 @@
std::to_string(GetParam()) + R"(-byte allocation)");
ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
#00 pc)");
+ ASSERT_MATCH(result, "Memory tags around the fault address");
#else
GTEST_SKIP() << "Requires aarch64";
#endif
@@ -686,6 +696,9 @@
ConsumeFd(std::move(output_fd), &log_sources[0]);
logcat_collector.Collect(&log_sources[1]);
+ // Tag dump only in the tombstone, not logcat.
+ ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
+
for (const auto& result : log_sources) {
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
@@ -706,21 +719,26 @@
#if defined(__aarch64__)
static uintptr_t CreateTagMapping() {
- uintptr_t mapping =
- reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
- if (reinterpret_cast<void*>(mapping) == MAP_FAILED) {
+ // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
+ // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
+ size_t page_size = getpagesize();
+ void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
+ if (mapping == MAP_FAILED) {
return 0;
}
- __asm__ __volatile__(".arch_extension mte; stg %0, [%0]"
- :
- : "r"(mapping + (1ULL << 56))
- : "memory");
- return mapping;
+ mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
+ PROT_READ | PROT_WRITE | PROT_MTE);
+ // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
+ for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
+ uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
+ __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
+ }
+ return mapping_uptr + page_size;
}
#endif
-TEST_F(CrasherTest, mte_tag_dump) {
+TEST_F(CrasherTest, mte_register_tag_dump) {
#if defined(__aarch64__)
if (!mte_supported()) {
GTEST_SKIP() << "Requires MTE";
@@ -753,6 +771,107 @@
#endif
}
+TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
+#if defined(__aarch64__)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([&]() {
+ SetTagCheckingLevelSync();
+ volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
+ p[0] = 0; // Untagged pointer, tagged memory.
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(Memory tags around the fault address.*
+\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
+#else
+ GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
+TEST_F(CrasherTest, mte_fault_tag_dump) {
+#if defined(__aarch64__)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([&]() {
+ SetTagCheckingLevelSync();
+ volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
+ p[320] = 0; // Untagged pointer, tagged memory.
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(Memory tags around the fault address.*
+\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
+\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
+\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
+)");
+#else
+ GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
+TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
+#if defined(__aarch64__)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([&]() {
+ SetTagCheckingLevelSync();
+ size_t page_size = getpagesize();
+ volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
+ p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(Memory tags around the fault address)");
+ ASSERT_MATCH(result,
+ R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
+\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
+
+)"); // Ensure truncation happened and there's a newline after the tag fault.
+#else
+ GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
TEST_F(CrasherTest, LD_PRELOAD) {
int intercept_result;
unique_fd output_fd;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index c490fb1..24ae169 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -96,4 +96,8 @@
// Number of bytes per MTE granule.
constexpr size_t kTagGranuleSize = 16;
+// Number of rows and columns to display in an MTE tag dump.
+constexpr size_t kNumTagColumns = 16;
+constexpr size_t kNumTagRows = 16;
+
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ad903ce..9c01f15 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -593,6 +593,9 @@
};
unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
+ auto process_memory =
+ unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwinder.SetProcessMemory(process_memory);
if (!unwinder.Init()) {
async_safe_fatal("failed to init unwinder object");
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index abd1f12..ff12017 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -362,8 +362,10 @@
dump.set_mapping_name(map_info->name());
}
- char buf[256];
- uint8_t tags[256 / kTagGranuleSize];
+ constexpr size_t kNumBytesAroundRegister = 256;
+ constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize;
+ char buf[kNumBytesAroundRegister];
+ uint8_t tags[kNumTagsAroundRegister];
size_t start_offset = 0;
ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory);
if (bytes == -1) {
@@ -377,7 +379,19 @@
}
dump.set_memory(buf, bytes);
- dump.set_tags(tags, bytes / kTagGranuleSize);
+
+ bool has_tags = false;
+#if defined(__aarch64__)
+ for (size_t i = 0; i < kNumTagsAroundRegister; ++i) {
+ if (tags[i] != 0) {
+ has_tags = true;
+ }
+ }
+#endif // defined(__aarch64__)
+
+ if (has_tags) {
+ dump.mutable_arm_mte_metadata()->set_memory_tags(tags, kNumTagsAroundRegister);
+ }
*thread.add_memory_dump() = std::move(dump);
}
@@ -531,6 +545,50 @@
dump_log_file(tombstone, "main", pid);
}
+static void dump_tags_around_fault_addr(Signal* signal, const Tombstone& tombstone,
+ unwindstack::Unwinder* unwinder, uintptr_t fault_addr) {
+ if (tombstone.arch() != Architecture::ARM64) return;
+
+ fault_addr = untag_address(fault_addr);
+ constexpr size_t kNumGranules = kNumTagRows * kNumTagColumns;
+ constexpr size_t kBytesToRead = kNumGranules * kTagGranuleSize;
+
+ // If the low part of the tag dump would underflow to the high address space, it's probably not
+ // a valid address for us to dump tags from.
+ if (fault_addr < kBytesToRead / 2) return;
+
+ unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
+
+ constexpr uintptr_t kRowStartMask = ~(kNumTagColumns * kTagGranuleSize - 1);
+ size_t start_address = (fault_addr & kRowStartMask) - kBytesToRead / 2;
+ MemoryDump tag_dump;
+ size_t granules_to_read = kNumGranules;
+
+ // Attempt to read the first tag. If reading fails, this likely indicates the
+ // lowest touched page is inaccessible or not marked with PROT_MTE.
+ // Fast-forward over pages until one has tags, or we exhaust the search range.
+ while (memory->ReadTag(start_address) < 0) {
+ size_t page_size = sysconf(_SC_PAGE_SIZE);
+ size_t bytes_to_next_page = page_size - (start_address % page_size);
+ if (bytes_to_next_page >= granules_to_read * kTagGranuleSize) return;
+ start_address += bytes_to_next_page;
+ granules_to_read -= bytes_to_next_page / kTagGranuleSize;
+ }
+ tag_dump.set_begin_address(start_address);
+
+ std::string* mte_tags = tag_dump.mutable_arm_mte_metadata()->mutable_memory_tags();
+
+ for (size_t i = 0; i < granules_to_read; ++i) {
+ long tag = memory->ReadTag(start_address + i * kTagGranuleSize);
+ if (tag < 0) break;
+ mte_tags->push_back(static_cast<uint8_t>(tag));
+ }
+
+ if (!mte_tags->empty()) {
+ *signal->mutable_fault_adjacent_metadata() = tag_dump;
+ }
+}
+
static std::optional<uint64_t> read_uptime_secs() {
std::string uptime;
if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
@@ -594,7 +652,9 @@
if (process_info.has_fault_address) {
sig.set_has_fault_address(true);
- sig.set_fault_address(process_info.maybe_tagged_fault_address);
+ uintptr_t fault_addr = process_info.maybe_tagged_fault_address;
+ sig.set_fault_address(fault_addr);
+ dump_tags_around_fault_addr(&sig, result, unwinder, fault_addr);
}
*result.mutable_signal_info() = sig;
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index a932d48..053299a 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -29,6 +29,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
+#include <bionic/macros.h>
#include "tombstone.pb.h"
@@ -193,8 +194,11 @@
uint64_t addr = mem.begin_address();
for (size_t offset = 0; offset < mem.memory().size(); offset += bytes_per_line) {
uint64_t tagged_addr = addr;
- if (mem.tags().size() > offset / kTagGranuleSize) {
- tagged_addr |= static_cast<uint64_t>(mem.tags()[offset / kTagGranuleSize]) << 56;
+ if (mem.has_arm_mte_metadata() &&
+ mem.arm_mte_metadata().memory_tags().size() > offset / kTagGranuleSize) {
+ tagged_addr |=
+ static_cast<uint64_t>(mem.arm_mte_metadata().memory_tags()[offset / kTagGranuleSize])
+ << 56;
}
std::string line = StringPrintf(" %0*" PRIx64, word_size * 2, tagged_addr + offset);
@@ -232,6 +236,60 @@
print_thread_memory_dump(callback, tombstone, thread);
}
+static void print_tag_dump(CallbackType callback, const Tombstone& tombstone) {
+ if (!tombstone.has_signal_info()) return;
+
+ const Signal& signal = tombstone.signal_info();
+
+ if (!signal.has_fault_address() || !signal.has_fault_adjacent_metadata()) {
+ return;
+ }
+
+ const MemoryDump& memory_dump = signal.fault_adjacent_metadata();
+
+ if (!memory_dump.has_arm_mte_metadata() || memory_dump.arm_mte_metadata().memory_tags().empty()) {
+ return;
+ }
+
+ const std::string& tags = memory_dump.arm_mte_metadata().memory_tags();
+
+ CBS("");
+ CBS("Memory tags around the fault address (0x%" PRIx64 "), one tag per %zu bytes:",
+ signal.fault_address(), kTagGranuleSize);
+ constexpr uintptr_t kRowStartMask = ~(kNumTagColumns * kTagGranuleSize - 1);
+
+ size_t tag_index = 0;
+ size_t num_tags = tags.length();
+ uintptr_t fault_granule = untag_address(signal.fault_address()) & ~(kTagGranuleSize - 1);
+ for (size_t row = 0; tag_index < num_tags; ++row) {
+ uintptr_t row_addr =
+ (memory_dump.begin_address() + row * kNumTagColumns * kTagGranuleSize) & kRowStartMask;
+ std::string row_contents;
+ bool row_has_fault = false;
+
+ for (size_t column = 0; column < kNumTagColumns; ++column) {
+ uintptr_t granule_addr = row_addr + column * kTagGranuleSize;
+ if (granule_addr < memory_dump.begin_address() ||
+ granule_addr >= memory_dump.begin_address() + num_tags * kTagGranuleSize) {
+ row_contents += " . ";
+ } else if (granule_addr == fault_granule) {
+ row_contents += StringPrintf("[%1hhx]", tags[tag_index++]);
+ row_has_fault = true;
+ } else {
+ row_contents += StringPrintf(" %1hhx ", tags[tag_index++]);
+ }
+ }
+
+ if (row_contents.back() == ' ') row_contents.pop_back();
+
+ if (row_has_fault) {
+ CBS(" =>0x%" PRIxPTR ":%s", row_addr, row_contents.c_str());
+ } else {
+ CBS(" 0x%" PRIxPTR ":%s", row_addr, row_contents.c_str());
+ }
+ }
+}
+
static void print_main_thread(CallbackType callback, const Tombstone& tombstone,
const Thread& thread) {
print_thread_header(callback, tombstone, thread, true);
@@ -299,6 +357,8 @@
}
}
+ print_tag_dump(callback, tombstone);
+
print_thread_memory_dump(callback, tombstone, thread);
CBS("");
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index 22fc30e..a701212 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -56,8 +56,11 @@
bool has_fault_address = 8;
uint64 fault_address = 9;
+ // Note, may or may not contain the dump of the actual memory contents. Currently, on arm64, we
+ // only include metadata, and not the contents.
+ MemoryDump fault_adjacent_metadata = 10;
- reserved 10 to 999;
+ reserved 11 to 999;
}
message HeapObject {
@@ -142,14 +145,22 @@
reserved 9 to 999;
}
+message ArmMTEMetadata {
+ // One memory tag per granule (e.g. every 16 bytes) of regular memory.
+ bytes memory_tags = 1;
+ reserved 2 to 999;
+}
+
message MemoryDump {
string register_name = 1;
string mapping_name = 2;
uint64 begin_address = 3;
bytes memory = 4;
- bytes tags = 5;
+ oneof metadata {
+ ArmMTEMetadata arm_mte_metadata = 6;
+ }
- reserved 6 to 999;
+ reserved 5, 7 to 999;
}
message MemoryMapping {
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index e3ef232..75d1e0d 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -91,12 +91,6 @@
if (key == bootconfig_key) {
*out_val = value;
return true;
- } else if (android_key == "hardware" && android_key == key) {
- // bootconfig doesn't allow subkeys and values to coexist, so
- // "androidboot.hardware" cannot be used. It is replaced in
- // bootconfig with "hardware"
- *out_val = value;
- return true;
}
}
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 92aa55c..de8768c 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -158,6 +158,13 @@
ExpectedMergeTarget = 11;
UnmergedSectorsAfterCompletion = 12;
UnexpectedMergeState = 13;
+ GetCowPathConsistencyCheck = 14;
+ OpenCowConsistencyCheck = 15;
+ ParseCowConsistencyCheck = 16;
+ OpenCowDirectConsistencyCheck = 17;
+ MemAlignConsistencyCheck = 18;
+ DirectReadConsistencyCheck = 19;
+ WrongMergeCountConsistencyCheck = 20;
};
// Next: 8
@@ -184,6 +191,9 @@
// Merge failure code, filled if state == MergeFailed.
MergeFailureCode merge_failure_code = 7;
+
+ // Source build fingerprint.
+ string source_build_fingerprint = 8;
}
// Next: 10
@@ -215,4 +225,7 @@
// Merge failure code, filled if state == MergeFailed.
MergeFailureCode merge_failure_code = 9;
+
+ // The source fingerprint at the time the OTA was downloaded.
+ string source_build_fingerprint = 10;
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 9ebcfd9..669e58a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -143,12 +143,11 @@
void InitializeMerge();
+ // 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_; }
void CloseCowFd() { owned_fd_ = {}; }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 94d5055..ec58cca 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -60,6 +60,7 @@
MOCK_METHOD(bool, Dump, (std::ostream & os), (override));
MOCK_METHOD(std::unique_ptr<AutoDevice>, EnsureMetadataMounted, (), (override));
MOCK_METHOD(ISnapshotMergeStats*, GetSnapshotMergeStatsInstance, (), (override));
+ MOCK_METHOD(std::string, ReadSourceBuildFingerprint, (), (override));
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
index 067f99c..3d384cc 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
@@ -35,13 +35,16 @@
MOCK_METHOD(void, set_boot_complete_time_ms, (uint32_t), (override));
MOCK_METHOD(void, set_boot_complete_to_merge_start_time_ms, (uint32_t), (override));
MOCK_METHOD(void, set_merge_failure_code, (MergeFailureCode), (override));
+ MOCK_METHOD(void, set_source_build_fingerprint, (const std::string&), (override));
MOCK_METHOD(uint64_t, cow_file_size, (), (override));
MOCK_METHOD(uint64_t, total_cow_size_bytes, (), (override));
MOCK_METHOD(uint64_t, estimated_cow_size_bytes, (), (override));
MOCK_METHOD(uint32_t, boot_complete_time_ms, (), (override));
MOCK_METHOD(uint32_t, boot_complete_to_merge_start_time_ms, (), (override));
+ MOCK_METHOD(std::string, source_build_fingerprint, (), (override));
MOCK_METHOD(MergeFailureCode, merge_failure_code, (), (override));
MOCK_METHOD(std::unique_ptr<Result>, Finish, (), (override));
+ MOCK_METHOD(bool, WriteState, (), (override));
using ISnapshotMergeStats::Result;
// Return nullptr if any failure.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 603e896..15882b3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -177,6 +177,9 @@
// code. Otherwise, MergeFailureCode::Ok is returned.
virtual MergeFailureCode ReadMergeFailureCode() = 0;
+ // If an update is in progress, return the source build fingerprint.
+ virtual std::string ReadSourceBuildFingerprint() = 0;
+
// Find the status of the current update, if any.
//
// |progress| depends on the returned status:
@@ -369,6 +372,7 @@
ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
bool MapAllSnapshots(const std::chrono::milliseconds& timeout_ms = {}) override;
bool UnmapAllSnapshots() override;
+ std::string ReadSourceBuildFingerprint() override;
// We can't use WaitForFile during first-stage init, because ueventd is not
// running and therefore will not automatically create symlinks. Instead,
@@ -603,6 +607,8 @@
MergeResult CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel);
MergeResult CheckTargetMergeState(LockedFile* lock, const std::string& name,
const SnapshotUpdateStatus& update_status);
+ MergeFailureCode CheckMergeConsistency(LockedFile* lock, const std::string& name,
+ const SnapshotStatus& update_status);
// Interact with status files under /metadata/ota/snapshots.
bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 4ce5077..8c2fec7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -35,12 +35,14 @@
virtual void set_boot_complete_time_ms(uint32_t ms) = 0;
virtual void set_boot_complete_to_merge_start_time_ms(uint32_t ms) = 0;
virtual void set_merge_failure_code(MergeFailureCode code) = 0;
+ virtual void set_source_build_fingerprint(const std::string& fingerprint) = 0;
virtual uint64_t cow_file_size() = 0;
virtual uint64_t total_cow_size_bytes() = 0;
virtual uint64_t estimated_cow_size_bytes() = 0;
virtual uint32_t boot_complete_time_ms() = 0;
virtual uint32_t boot_complete_to_merge_start_time_ms() = 0;
virtual MergeFailureCode merge_failure_code() = 0;
+ virtual std::string source_build_fingerprint() = 0;
// Called when merge ends. Properly clean up permanent storage.
class Result {
@@ -52,6 +54,10 @@
};
// Return nullptr if any failure.
virtual std::unique_ptr<Result> Finish() = 0;
+
+ // Write out the current state. This should be called when data might be lost that
+ // cannot be recovered (eg the COW sizes).
+ virtual bool WriteState() = 0;
};
class SnapshotMergeStats : public ISnapshotMergeStats {
@@ -74,11 +80,13 @@
uint32_t boot_complete_to_merge_start_time_ms() override;
void set_merge_failure_code(MergeFailureCode code) override;
MergeFailureCode merge_failure_code() override;
+ void set_source_build_fingerprint(const std::string& fingerprint) override;
+ std::string source_build_fingerprint() override;
std::unique_ptr<Result> Finish() override;
+ bool WriteState() override;
private:
bool ReadState();
- bool WriteState();
bool DeleteState();
SnapshotMergeStats(const std::string& path);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index a7cd939..74b78c5 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -57,6 +57,7 @@
ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
bool MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) override;
bool UnmapAllSnapshots() override;
+ std::string ReadSourceBuildFingerprint() override;
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e2c03ae..0e36da1 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -716,7 +716,7 @@
}
}
- SnapshotUpdateStatus initial_status;
+ SnapshotUpdateStatus initial_status = ReadSnapshotUpdateStatus(lock.get());
initial_status.set_state(UpdateState::Merging);
initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
initial_status.set_total_sectors(initial_target_values.total_sectors);
@@ -1126,6 +1126,11 @@
return MergeResult(UpdateState::Merging);
}
+ auto code = CheckMergeConsistency(lock, name, snapshot_status);
+ if (code != MergeFailureCode::Ok) {
+ return MergeResult(UpdateState::MergeFailed, code);
+ }
+
// Merging is done. First, update the status file to indicate the merge
// is complete. We do this before calling OnSnapshotMergeComplete, even
// though this means the write is potentially wasted work (since in the
@@ -1144,6 +1149,91 @@
return MergeResult(UpdateState::MergeCompleted, MergeFailureCode::Ok);
}
+// This returns the backing device, not the dm-user layer.
+static std::string GetMappedCowDeviceName(const std::string& snapshot,
+ const SnapshotStatus& status) {
+ // If no partition was created (the COW exists entirely on /data), the
+ // device-mapper layering is different than if we had a partition.
+ if (status.cow_partition_size() == 0) {
+ return GetCowImageDeviceName(snapshot);
+ }
+ return GetCowName(snapshot);
+}
+
+MergeFailureCode SnapshotManager::CheckMergeConsistency(LockedFile* lock, const std::string& name,
+ const SnapshotStatus& status) {
+ CHECK(lock);
+
+ if (!status.compression_enabled()) {
+ // Do not try to verify old-style COWs yet.
+ return MergeFailureCode::Ok;
+ }
+
+ auto& dm = DeviceMapper::Instance();
+
+ std::string cow_image_name = GetMappedCowDeviceName(name, status);
+ std::string cow_image_path;
+ if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_path)) {
+ LOG(ERROR) << "Failed to get path for cow device: " << cow_image_name;
+ return MergeFailureCode::GetCowPathConsistencyCheck;
+ }
+
+ // First pass, count # of ops.
+ size_t num_ops = 0;
+ {
+ unique_fd fd(open(cow_image_path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open " << cow_image_name;
+ return MergeFailureCode::OpenCowConsistencyCheck;
+ }
+
+ CowReader reader;
+ if (!reader.Parse(std::move(fd))) {
+ LOG(ERROR) << "Failed to parse cow " << cow_image_path;
+ return MergeFailureCode::ParseCowConsistencyCheck;
+ }
+
+ for (auto iter = reader.GetOpIter(); !iter->Done(); iter->Next()) {
+ if (!IsMetadataOp(iter->Get())) {
+ num_ops++;
+ }
+ }
+ }
+
+ // Second pass, try as hard as we can to get the actual number of blocks
+ // the system thinks is merged.
+ unique_fd fd(open(cow_image_path.c_str(), O_RDONLY | O_DIRECT | O_SYNC | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open direct " << cow_image_name;
+ return MergeFailureCode::OpenCowDirectConsistencyCheck;
+ }
+
+ void* addr;
+ size_t page_size = getpagesize();
+ if (posix_memalign(&addr, page_size, page_size) < 0) {
+ PLOG(ERROR) << "posix_memalign with page size " << page_size;
+ return MergeFailureCode::MemAlignConsistencyCheck;
+ }
+
+ // COWs are always at least 2MB, this is guaranteed in snapshot creation.
+ std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
+ if (!android::base::ReadFully(fd, buffer.get(), page_size)) {
+ PLOG(ERROR) << "Direct read failed " << cow_image_name;
+ return MergeFailureCode::DirectReadConsistencyCheck;
+ }
+
+ auto header = reinterpret_cast<CowHeader*>(buffer.get());
+ if (header->num_merge_ops != num_ops) {
+ LOG(ERROR) << "COW consistency check failed, expected " << num_ops << " to be merged, "
+ << "but " << header->num_merge_ops << " were actually recorded.";
+ LOG(ERROR) << "Aborting merge progress for snapshot " << name
+ << ", will try again next boot";
+ return MergeFailureCode::WrongMergeCountConsistencyCheck;
+ }
+
+ return MergeFailureCode::Ok;
+}
+
MergeFailureCode SnapshotManager::MergeSecondPhaseSnapshots(LockedFile* lock) {
std::vector<std::string> snapshots;
if (!ListSnapshots(lock, &snapshots)) {
@@ -1429,14 +1519,7 @@
continue;
}
- // If no partition was created (the COW exists entirely on /data), the
- // device-mapper layering is different than if we had a partition.
- std::string cow_image_name;
- if (snapshot_status.cow_partition_size() == 0) {
- cow_image_name = GetCowImageDeviceName(snapshot);
- } else {
- cow_image_name = GetCowName(snapshot);
- }
+ std::string cow_image_name = GetMappedCowDeviceName(snapshot, snapshot_status);
std::string cow_image_device;
if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
@@ -2432,15 +2515,25 @@
SnapshotUpdateStatus status;
status.set_state(state);
- if (state == UpdateState::MergeFailed) {
- status.set_merge_failure_code(failure_code);
+ switch (state) {
+ case UpdateState::MergeFailed:
+ status.set_merge_failure_code(failure_code);
+ break;
+ case UpdateState::Initiated:
+ status.set_source_build_fingerprint(
+ android::base::GetProperty("ro.build.fingerprint", ""));
+ break;
+ default:
+ break;
}
// If we're transitioning between two valid states (eg, we're not beginning
- // or ending an OTA), then make sure to propagate the compression bit.
+ // or ending an OTA), then make sure to propagate the compression bit and
+ // build fingerprint.
if (!(state == UpdateState::Initiated || state == UpdateState::None)) {
SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
status.set_compression_enabled(old_status.compression_enabled());
+ status.set_source_build_fingerprint(old_status.source_build_fingerprint());
}
return WriteSnapshotUpdateStatus(lock, status);
}
@@ -2755,7 +2848,7 @@
}
}
- SnapshotUpdateStatus status = {};
+ SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock.get());
status.set_state(update_state);
status.set_compression_enabled(cow_creator.compression_enabled);
if (!WriteSnapshotUpdateStatus(lock.get(), status)) {
@@ -3181,9 +3274,10 @@
std::stringstream ss;
+ auto update_status = ReadSnapshotUpdateStatus(file.get());
+
ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
- ss << "Compression: " << ReadSnapshotUpdateStatus(file.get()).compression_enabled()
- << std::endl;
+ ss << "Compression: " << update_status.compression_enabled() << std::endl;
ss << "Current slot: " << device_->GetSlotSuffix() << std::endl;
ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl;
ss << "Rollback indicator: "
@@ -3192,6 +3286,7 @@
ss << "Forward merge indicator: "
<< (access(GetForwardMergeIndicatorPath().c_str(), F_OK) == 0 ? "exists" : strerror(errno))
<< std::endl;
+ ss << "Source build fingerprint: " << update_status.source_build_fingerprint() << std::endl;
bool ok = true;
std::vector<std::string> snapshots;
@@ -3709,5 +3804,13 @@
return status.merge_failure_code();
}
+std::string SnapshotManager::ReadSourceBuildFingerprint() {
+ auto lock = LockExclusive();
+ if (!lock) return {};
+
+ SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock.get());
+ return status.source_build_fingerprint();
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 4a93d65..712eafb 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -91,7 +91,6 @@
void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) {
report_.set_cow_file_size(cow_file_size);
- WriteState();
}
uint64_t SnapshotMergeStats::cow_file_size() {
@@ -138,6 +137,14 @@
return report_.merge_failure_code();
}
+void SnapshotMergeStats::set_source_build_fingerprint(const std::string& fingerprint) {
+ report_.set_source_build_fingerprint(fingerprint);
+}
+
+std::string SnapshotMergeStats::source_build_fingerprint() {
+ return report_.source_build_fingerprint();
+}
+
class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
public:
SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 1a9eda5..a8d5b8a 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -136,7 +136,10 @@
void set_boot_complete_to_merge_start_time_ms(uint32_t) override {}
uint32_t boot_complete_to_merge_start_time_ms() override { return 0; }
void set_merge_failure_code(MergeFailureCode) override {}
- MergeFailureCode merge_failure_code() { return MergeFailureCode::Ok; }
+ MergeFailureCode merge_failure_code() override { return MergeFailureCode::Ok; }
+ void set_source_build_fingerprint(const std::string&) override {}
+ std::string source_build_fingerprint() override { return {}; }
+ bool WriteState() override { return false; }
};
ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
@@ -170,4 +173,9 @@
return MergeFailureCode::Ok;
}
+std::string SnapshotManagerStub::ReadSourceBuildFingerprint() {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return {};
+}
+
} // namespace android::snapshot
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index eb2919b..953574b 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -127,7 +127,7 @@
"androidboot.serialno = \"BLAHBLAHBLAH\"\n"
"androidboot.slot_suffix = \"_a\"\n"
"androidboot.hardware.platform = \"sdw813\"\n"
- "hardware = \"foo\"\n"
+ "androidboot.hardware = \"foo\"\n"
"androidboot.revision = \"EVT1.0\"\n"
"androidboot.bootloader = \"burp-0.1-7521\"\n"
"androidboot.hardware.sku = \"mary\"\n"
@@ -159,7 +159,7 @@
{"androidboot.serialno", "BLAHBLAHBLAH"},
{"androidboot.slot_suffix", "_a"},
{"androidboot.hardware.platform", "sdw813"},
- {"hardware", "foo"},
+ {"androidboot.hardware", "foo"},
{"androidboot.revision", "EVT1.0"},
{"androidboot.bootloader", "burp-0.1-7521"},
{"androidboot.hardware.sku", "mary"},
diff --git a/init/property_service.cpp b/init/property_service.cpp
index ff9da42..2d67bf5 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1238,21 +1238,11 @@
});
}
-// bootconfig does not allow to populate `key=value` simultaneously with
-// `key.subkey=value` which does not work with the existing code for
-// `hardware` (e.g. we want both `ro.boot.hardware=value` and
-// `ro.boot.hardware.sku=value`) and for `qemu` (Android Stidio Emulator
-// specific).
-static bool IsAllowedBootconfigKey(const std::string_view key) {
- return (key == "hardware"sv) || (key == "qemu"sv);
-}
static void ProcessBootconfig() {
ImportBootconfig([&](const std::string& key, const std::string& value) {
if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
- } else if (IsAllowedBootconfigKey(key)) {
- InitPropertySet("ro.boot." + key, value);
}
});
}
diff --git a/init/reboot_test.cpp b/init/reboot_test.cpp
index 06702e3..b3d038d 100644
--- a/init/reboot_test.cpp
+++ b/init/reboot_test.cpp
@@ -113,6 +113,11 @@
}
TEST_F(RebootTest, StopServicesSIGTERM) {
+ if (getuid() != 0) {
+ GTEST_SKIP() << "Skipping test, must be run as root.";
+ return;
+ }
+
AddTestService("A");
AddTestService("B");
@@ -148,6 +153,11 @@
}
TEST_F(RebootTest, StopServicesSIGKILL) {
+ if (getuid() != 0) {
+ GTEST_SKIP() << "Skipping test, must be run as root.";
+ return;
+ }
+
AddTestService("A");
AddTestService("B");
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 98f6857..b3fa9fd 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -31,6 +31,7 @@
#include "capabilities.h"
#include "reboot_utils.h"
+#include "util.h"
namespace android {
namespace init {
@@ -38,31 +39,51 @@
static std::string init_fatal_reboot_target = "bootloader";
static bool init_fatal_panic = false;
+// this needs to read the /proc/* files directly because it is called before
+// ro.boot.* properties are initialized
void SetFatalRebootTarget(const std::optional<std::string>& reboot_target) {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
cmdline = android::base::Trim(cmdline);
- const char kInitFatalPanicString[] = "androidboot.init_fatal_panic=true";
- init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos;
+ const std::string kInitFatalPanicParamString = "androidboot.init_fatal_panic";
+ if (cmdline.find(kInitFatalPanicParamString) == std::string::npos) {
+ init_fatal_panic = false;
+ ImportBootconfig(
+ [kInitFatalPanicParamString](const std::string& key, const std::string& value) {
+ if (key == kInitFatalPanicParamString && value == "true") {
+ init_fatal_panic = true;
+ }
+ });
+ } else {
+ const std::string kInitFatalPanicString = kInitFatalPanicParamString + "=true";
+ init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos;
+ }
if (reboot_target) {
init_fatal_reboot_target = *reboot_target;
return;
}
- const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target=";
+ const std::string kRebootTargetString = "androidboot.init_fatal_reboot_target";
auto start_pos = cmdline.find(kRebootTargetString);
if (start_pos == std::string::npos) {
- return; // We already default to bootloader if no setting is provided.
- }
- start_pos += sizeof(kRebootTargetString) - 1;
+ ImportBootconfig([kRebootTargetString](const std::string& key, const std::string& value) {
+ if (key == kRebootTargetString) {
+ init_fatal_reboot_target = value;
+ }
+ });
+ // We already default to bootloader if no setting is provided.
+ } else {
+ const std::string kRebootTargetStringPattern = kRebootTargetString + "=";
+ start_pos += sizeof(kRebootTargetStringPattern) - 1;
- auto end_pos = cmdline.find(' ', start_pos);
- // if end_pos isn't found, then we've run off the end, but this is okay as this is the last
- // entry, and -1 is a valid size for string::substr();
- auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
- init_fatal_reboot_target = cmdline.substr(start_pos, size);
+ auto end_pos = cmdline.find(' ', start_pos);
+ // if end_pos isn't found, then we've run off the end, but this is okay as this is the last
+ // entry, and -1 is a valid size for string::substr();
+ auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
+ init_fatal_reboot_target = cmdline.substr(start_pos, size);
+ }
}
bool IsRebootCapable() {
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 815d2bb..5c7a75d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -146,12 +146,6 @@
std::this_thread::sleep_for(5ms);
}
- // With the exception of boot or shutdown, system uid_ folders are always populated. Spinning
- // here would needlessly delay most pid removals. Additionally, once empty a uid_ cgroup won't
- // have processes hanging on it (we've already spun for all its pid_), so there's no need to
- // spin anyway.
- rmdir(uid_path.c_str());
-
return ret;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 85c107d..376a678 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -191,33 +191,6 @@
chown system system /dev/cpuctl/camera-daemon/tasks
chmod 0664 /dev/cpuctl/camera-daemon/tasks
- # Android only use global RT throttling and doesn't use CONFIG_RT_GROUP_SCHED
- # for RT group throttling. These values here are just to make sure RT threads
- # can be migrated to those groups. These settings can be removed once we migrate
- # to GKI kernel.
- write /dev/cpuctl/cpu.rt_period_us 1000000
- write /dev/cpuctl/cpu.rt_runtime_us 950000
- # Surfaceflinger is in FG group so giving it a bit more
- write /dev/cpuctl/foreground/cpu.rt_runtime_us 450000
- write /dev/cpuctl/foreground/cpu.rt_period_us 1000000
- write /dev/cpuctl/background/cpu.rt_runtime_us 50000
- write /dev/cpuctl/background/cpu.rt_period_us 1000000
- write /dev/cpuctl/top-app/cpu.rt_runtime_us 100000
- write /dev/cpuctl/top-app/cpu.rt_period_us 1000000
- write /dev/cpuctl/rt/cpu.rt_runtime_us 100000
- write /dev/cpuctl/rt/cpu.rt_period_us 1000000
- write /dev/cpuctl/system/cpu.rt_runtime_us 100000
- write /dev/cpuctl/system/cpu.rt_period_us 1000000
- write /dev/cpuctl/system-background/cpu.rt_runtime_us 50000
- write /dev/cpuctl/system-background/cpu.rt_period_us 1000000
- write /dev/cpuctl/nnapi-hal/cpu.rt_runtime_us 50000
- write /dev/cpuctl/nnapi-hal/cpu.rt_period_us 1000000
- write /dev/cpuctl/camera-daemon/cpu.rt_runtime_us 50000
- write /dev/cpuctl/camera-daemon/cpu.rt_period_us 1000000
-
- # Migrate root group to system subgroup
- copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
-
# Create an stune group for camera-specific processes
mkdir /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon
@@ -1278,7 +1251,3 @@
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
-
-# Migrate tasks again in case kernel threads are created during boot
-on property:sys.boot_completed=1
- copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
diff --git a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
index 41a21e9..9440724 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
@@ -34,6 +34,7 @@
using ::keymaster::FinishOperationResponse;
using ::keymaster::TAG_ASSOCIATED_DATA;
using ::keymaster::TAG_AUTH_TOKEN;
+using ::keymaster::TAG_CONFIRMATION_TOKEN;
using ::keymaster::UpdateOperationRequest;
using ::keymaster::UpdateOperationResponse;
using km_utils::authToken2AidlVec;
@@ -106,12 +107,12 @@
return ScopedAStatus::ok();
}
-ScopedAStatus TrustyKeyMintOperation::finish(
- const optional<vector<uint8_t>>& input, //
- const optional<vector<uint8_t>>& signature, //
- const optional<HardwareAuthToken>& authToken,
- const optional<TimeStampToken>& /* timestampToken */,
- const optional<vector<uint8_t>>& /* confirmationToken */, vector<uint8_t>* output) {
+ScopedAStatus TrustyKeyMintOperation::finish(const optional<vector<uint8_t>>& input, //
+ const optional<vector<uint8_t>>& signature, //
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& /* timestampToken */,
+ const optional<vector<uint8_t>>& confirmationToken,
+ vector<uint8_t>* output) {
if (!output) {
return ScopedAStatus(AStatus_fromServiceSpecificError(
static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
@@ -119,6 +120,16 @@
output->clear();
FinishOperationRequest request(impl_->message_version());
+
+ if (authToken) {
+ auto tokenAsVec(authToken2AidlVec(*authToken));
+ request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
+ }
+ if (confirmationToken) {
+ request.additional_params.push_back(TAG_CONFIRMATION_TOKEN, confirmationToken->data(),
+ confirmationToken->size());
+ }
+
request.op_handle = opHandle_;
if (signature) request.signature.Reinitialize(signature->data(), signature->size());
size_t serialized_size = request.SerializedSize();