Merge "Add exfat utilities for mkfs and fsck"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 198e4de..8555b3d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,29 +1,5 @@
package {
- default_applicable_licenses: ["system_core_debuggerd_license"],
-}
-
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-// See: http://go/android-license-faq
-license {
- name: "system_core_debuggerd_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-BSD",
- ],
- // large-scale-change unable to identify any license_text files
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
cc_defaults {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index a152740..5bb1d75 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -32,6 +32,7 @@
#include <set>
#include <vector>
+#include <android-base/errno_restorer.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -67,8 +68,9 @@
#include "protocol.h"
#include "util.h"
-using android::base::unique_fd;
+using android::base::ErrnoRestorer;
using android::base::StringPrintf;
+using android::base::unique_fd;
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
@@ -89,10 +91,11 @@
static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error, int flags = 0) {
if (ptrace(PTRACE_SEIZE, tid, 0, flags) != 0) {
if (errno == EPERM) {
- pid_t tracer = get_tracer(tid);
- if (tracer != -1) {
+ ErrnoRestorer errno_restorer; // In case get_tracer() fails and we fall through.
+ pid_t tracer_pid = get_tracer(tid);
+ if (tracer_pid > 0) {
*error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid,
- tracer, get_process_name(tracer).c_str());
+ tracer_pid, get_process_name(tracer_pid).c_str());
return false;
}
}
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/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index feafa73..baf994f 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -1,29 +1,17 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2017 The Android Open Source Project
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
+ * 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
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * 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 <dirent.h>
@@ -87,6 +75,12 @@
// TODO: Create this once and store it in a global?
unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
+ // Do not use the thread cache here because it will call pthread_key_create
+ // which doesn't work in linker code. See b/189803009.
+ // Use a normal cached object because the process is stopped, and there
+ // is no chance of data changing between reads.
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwinder.SetProcessMemory(process_memory);
dump_backtrace_thread(output_fd, &unwinder, thread);
}
__linker_disable_fallback_allocator();
diff --git a/debuggerd/handler/debuggerd_fallback_nop.cpp b/debuggerd/handler/debuggerd_fallback_nop.cpp
index 331301f..5666d98 100644
--- a/debuggerd/handler/debuggerd_fallback_nop.cpp
+++ b/debuggerd/handler/debuggerd_fallback_nop.cpp
@@ -1,29 +1,17 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2017 The Android Open Source Project
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
+ * 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
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * 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.
*/
extern "C" void debuggerd_fallback_handler(struct siginfo_t*, struct ucontext_t*, void*) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index b607397..375dbed 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -1,29 +1,17 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2008 The Android Open Source Project
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
+ * 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
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * 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 "debuggerd/handler.h"
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/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index c39f4e4..fc43f4e 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -5,4 +5,4 @@
socket tombstoned_crash seqpacket 0666 system system
socket tombstoned_intercept seqpacket 0666 system system
socket tombstoned_java_trace seqpacket 0666 system system
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6a49fdf..c87ce60 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -104,8 +104,6 @@
static bool g_disable_verity = false;
static bool g_disable_verification = false;
-static const std::string convert_fbe_marker_filename("convert_fbe");
-
fastboot::FastBootDriver* fb = nullptr;
enum fb_buffer_type {
@@ -429,7 +427,7 @@
" snapshot-update merge On devices that support snapshot-based updates, finish\n"
" an in-progress update if it is in the \"merging\"\n"
" phase.\n"
- " fetch PARTITION Fetch a partition image from the device."
+ " fetch PARTITION OUT_FILE Fetch a partition image from the device."
"\n"
"boot image:\n"
" boot KERNEL [RAMDISK [SECOND]]\n"
@@ -473,9 +471,6 @@
" --disable-verification Sets disable-verification when flashing vbmeta.\n"
" --fs-options=OPTION[,OPTION]\n"
" Enable filesystem features. OPTION supports casefold, projid, compress\n"
-#if !defined(_WIN32)
- " --wipe-and-use-fbe Enable file-based encryption, wiping userdata.\n"
-#endif
// TODO: remove --unbuffered?
" --unbuffered Don't buffer input or output.\n"
" --verbose, -v Verbose output.\n"
@@ -593,10 +588,6 @@
#define tmpfile win32_tmpfile
-static std::string make_temporary_directory() {
- die("make_temporary_directory not supported under Windows, sorry!");
-}
-
static int make_temporary_fd(const char* /*what*/) {
// TODO: reimplement to avoid leaking a FILE*.
return fileno(tmpfile());
@@ -610,15 +601,6 @@
return std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
}
-static std::string make_temporary_directory() {
- std::string result(make_temporary_template());
- if (mkdtemp(&result[0]) == nullptr) {
- die("unable to create temporary directory with template %s: %s",
- result.c_str(), strerror(errno));
- }
- return result;
-}
-
static int make_temporary_fd(const char* what) {
std::string path_template(make_temporary_template());
int fd = mkstemp(&path_template[0]);
@@ -632,32 +614,6 @@
#endif
-static std::string create_fbemarker_tmpdir() {
- std::string dir = make_temporary_directory();
- std::string marker_file = dir + "/" + convert_fbe_marker_filename;
- int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
- if (fd == -1) {
- die("unable to create FBE marker file %s locally: %s",
- marker_file.c_str(), strerror(errno));
- }
- close(fd);
- return dir;
-}
-
-static void delete_fbemarker_tmpdir(const std::string& dir) {
- std::string marker_file = dir + "/" + convert_fbe_marker_filename;
- if (unlink(marker_file.c_str()) == -1) {
- fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
- marker_file.c_str(), errno, strerror(errno));
- return;
- }
- if (rmdir(dir.c_str()) == -1) {
- fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
- dir.c_str(), errno, strerror(errno));
- return;
- }
-}
-
static unique_fd unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd(entry_name));
@@ -1895,7 +1851,6 @@
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
- bool set_fbe_marker = false;
bool force_flash = false;
unsigned fs_options = 0;
int longindex;
@@ -1933,9 +1888,6 @@
{"unbuffered", no_argument, 0, 0},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 0},
-#if !defined(_WIN32)
- {"wipe-and-use-fbe", no_argument, 0, 0},
-#endif
{0, 0, 0, 0}
};
@@ -1989,11 +1941,6 @@
fprintf(stdout, "fastboot version %s-%s\n", PLATFORM_TOOLS_VERSION, android::build::GetBuildNumber().c_str());
fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
return 0;
-#if !defined(_WIN32)
- } else if (name == "wipe-and-use-fbe") {
- wants_wipe = true;
- set_fbe_marker = true;
-#endif
} else {
die("unknown option %s", longopts[longindex].name);
}
@@ -2305,14 +2252,7 @@
}
if (partition_type.empty()) continue;
fb->Erase(partition);
- if (partition == "userdata" && set_fbe_marker) {
- fprintf(stderr, "setting FBE marker on initial userdata...\n");
- std::string initial_userdata_dir = create_fbemarker_tmpdir();
- fb_perform_format(partition, 1, partition_type, "", initial_userdata_dir, fs_options);
- delete_fbemarker_tmpdir(initial_userdata_dir);
- } else {
- fb_perform_format(partition, 1, partition_type, "", "", fs_options);
- }
+ fb_perform_format(partition, 1, partition_type, "", "", fs_options);
}
}
if (wants_set_active) {
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 5356b00..3d63a44 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -141,6 +141,7 @@
// Do not ever allow this library to be vendor_available as a shared library.
// It does not have a stable interface.
name: "libfs_mgr",
+ ramdisk_available: true,
recovery_available: true,
defaults: [
"libfs_mgr_defaults",
@@ -165,6 +166,7 @@
// It does not have a stable interface.
name: "libfstab",
vendor_available: true,
+ ramdisk_available: true,
recovery_available: true,
host_supported: true,
defaults: ["fs_mgr_defaults"],
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index af71fe6..01c8ad3 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2092,7 +2092,7 @@
}
if (entry.zram_size > 0) {
- if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
+ if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
LERROR << "Failure of zram backing device file for '" << entry.blk_device << "'";
}
// A zram_size was specified, so we need to configure the
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/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index c4874b8..a5eda29 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -170,19 +170,18 @@
return access("/system/bin/recovery", F_OK) == 0;
}
-bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) {
+bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
std::string uuid = GenerateUuid();
- if (!CreateDevice(name, uuid)) {
- return false;
- }
+ return CreateDevice(name, uuid);
+}
+bool DeviceMapper::WaitForDevice(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms, std::string* path) {
// We use the unique path for testing whether the device is ready. After
// that, it's safe to use the dm-N path which is compatible with callers
// that expect it to be formatted as such.
std::string unique_path;
- if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
- !GetDmDevicePathByName(name, path)) {
+ if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
DeleteDevice(name);
return false;
}
@@ -208,6 +207,25 @@
return true;
}
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms) {
+ if (!CreateEmptyDevice(name)) {
+ return false;
+ }
+
+ if (!LoadTableAndActivate(name, table)) {
+ DeleteDevice(name);
+ return false;
+ }
+
+ if (!WaitForDevice(name, timeout_ms, path)) {
+ DeleteDevice(name);
+ return false;
+ }
+
+ return true;
+}
+
bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
struct dm_ioctl io;
InitIo(&io, name);
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index b0639e6..90d91a0 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -109,6 +109,10 @@
optional_args_.emplace_back("ignore_zero_blocks");
}
+void DmTargetVerity::CheckAtMostOnce() {
+ optional_args_.emplace_back("check_at_most_once");
+}
+
std::string DmTargetVerity::GetParameterString() const {
std::string base = android::base::Join(base_args_, " ");
if (optional_args_.empty()) {
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 8006db2..8314ec5 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -29,6 +29,7 @@
#include <thread>
#include <android-base/file.h>
+#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -679,3 +680,17 @@
ASSERT_NE(0, access(path.c_str(), F_OK));
ASSERT_EQ(ENOENT, errno);
}
+
+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); });
+
+ // 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/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 70b14fa..8fcdf74 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -115,6 +115,19 @@
// - ACTIVE: resumes the device.
bool ChangeState(const std::string& name, DmDeviceState state);
+ // Creates empty device.
+ // This supports a use case when a caller doesn't need a device straight away, but instead
+ // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
+ // to create user space paths.
+ // Callers are expected to then activate their device by calling LoadTableAndActivate function.
+ // To avoid race conditions, callers must still synchronize with ueventd by calling
+ // WaitForDevice function.
+ bool CreateEmptyDevice(const std::string& name);
+
+ // Waits for device paths to be created in the user space.
+ bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
+ std::string* path);
+
// Creates a device, loads the given table, and activates it. If the device
// is not able to be activated, it is destroyed, and false is returned.
// After creation, |path| contains the result of calling
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 478a3c6..9543058 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -127,6 +127,7 @@
void UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks, uint32_t start);
void SetVerityMode(const std::string& mode);
void IgnoreZeroBlocks();
+ void CheckAtMostOnce();
std::string name() const override { return "verity"; }
std::string GetParameterString() const override;
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 1c5872e..b62e33f 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -20,6 +20,7 @@
cc_library_headers {
name: "libfiemap_headers",
+ ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["include"],
}
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 6892025..62493eb 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -27,6 +27,7 @@
cc_library_static {
name: "libfs_avb",
defaults: ["fs_mgr_defaults"],
+ ramdisk_available: true,
recovery_available: true,
host_supported: true,
export_include_dirs: ["include"],
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 31494c1..e913d50 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -92,6 +92,10 @@
// Always use ignore_zero_blocks.
target.IgnoreZeroBlocks();
+ if (hashtree_desc.flags & AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE) {
+ target.CheckAtMostOnce();
+ }
+
LINFO << "Built verity table: '" << target.GetParameterString() << "'";
return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 7e528b1..86ca8f3 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -30,6 +30,7 @@
cc_library {
name: "liblp",
host_supported: true,
+ ramdisk_available: true,
recovery_available: true,
defaults: ["fs_mgr_defaults"],
cppflags: [
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 6a764e4..acfaa84 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -118,6 +118,7 @@
native_coverage : true,
defaults: ["libsnapshot_defaults"],
srcs: [":libsnapshot_sources"],
+ ramdisk_available: true,
recovery_available: true,
cflags: [
"-DLIBSNAPSHOT_NO_COW_WRITE",
@@ -310,7 +311,6 @@
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
"libbase",
- "libbinder",
"libext2_uuid",
"libext4_utils",
"libfs_mgr_binder",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 77ed92c..c0649ca 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
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 51c00a9..526fede 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -58,6 +58,12 @@
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*/) {
+ LOG(ERROR) << "AddXorBlocks not yet implemented";
+ return false;
+}
+
bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
uint64_t last_block = new_block_start + num_blocks - 1;
if (!ValidateNewBlock(last_block)) {
@@ -70,6 +76,11 @@
return EmitLabel(label);
}
+bool ICowWriter::AddSequenceData(size_t /*num_ops*/, const uint32_t* /*data*/) {
+ LOG(ERROR) << "AddSequenceData not yet implemented";
+ return false;
+}
+
bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
if (options_.max_blocks && new_block >= options_.max_blocks.value()) {
LOG(ERROR) << "New block " << new_block << " exceeds maximum block count "
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/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index f43ea68..fbe6461 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -55,12 +55,19 @@
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
+ // Add a sequence of xor'd blocks. |size| must be a multiple of the block size.
+ bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
+ uint16_t offset);
+
// Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks);
// Add a label to the op sequence.
bool AddLabel(uint64_t label);
+ // Add sequence data for op merging. Data is a list of the destination block numbers.
+ bool AddSequenceData(size_t num_ops, const uint32_t* data);
+
// Flush all pending writes. This must be called before closing the writer
// to ensure that the correct headers and footers are written.
virtual bool Finalize() = 0;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 603e896..65034f7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -603,6 +603,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/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 4a84fba..1dc61af 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -106,6 +106,8 @@
std::cout << "Header size: " << header.header_size << "\n";
std::cout << "Footer size: " << header.footer_size << "\n";
std::cout << "Block size: " << header.block_size << "\n";
+ std::cout << "Num merge ops: " << header.num_merge_ops << "\n";
+ std::cout << "RA buffer size: " << header.buffer_size << "\n";
std::cout << "\n";
if (has_footer) {
std::cout << "Total Ops size: " << footer.op.ops_size << "\n";
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e2c03ae..be732ec 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -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)) {
diff --git a/fs_mgr/libstorage_literals/Android.bp b/fs_mgr/libstorage_literals/Android.bp
index 5b07168..fd7ea04 100644
--- a/fs_mgr/libstorage_literals/Android.bp
+++ b/fs_mgr/libstorage_literals/Android.bp
@@ -6,6 +6,7 @@
cc_library_headers {
name: "libstorage_literals_headers",
host_supported: true,
+ ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["."],
target: {
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index a1b020a..94e1abb 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/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index 8b126d5..f572b11 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,4 +1,4 @@
service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
class late_start
user system
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/init/Android.bp b/init/Android.bp
index 1381c1d..3e8d4e3 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -253,11 +253,32 @@
visibility: ["//packages/modules/Virtualization/microdroid"],
}
-// This currently is only for the VM usecase.
-// TODO(jiyong): replace init_first_stage in Android.mk with this
+soong_config_module_type {
+ name: "init_first_stage_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["BOARD_BUILD_SYSTEM_ROOT_IMAGE", "BOARD_USES_RECOVERY_AS_BOOT"],
+ properties: ["installable"],
+}
+
+// Do not install init_first_stage even with mma if we're system-as-root.
+// Otherwise, it will overwrite the symlink.
+init_first_stage_cc_defaults {
+ name: "init_first_stage_defaults",
+ soong_config_variables: {
+ BOARD_BUILD_SYSTEM_ROOT_IMAGE: {
+ installable: false,
+ },
+ BOARD_USES_RECOVERY_AS_BOOT: {
+ installable: false,
+ },
+ },
+}
+
cc_binary {
- name: "init_first_stage_soong",
- stem: "init_vendor",
+ name: "init_first_stage",
+ stem: "init",
+ defaults: ["init_first_stage_defaults"],
srcs: [
"block_dev_initializer.cpp",
@@ -313,6 +334,7 @@
],
static_executable: true,
+ system_shared_libs: [],
cflags: [
"-Wall",
@@ -363,8 +385,23 @@
sanitize: {
misc_undefined: ["signed-integer-overflow"],
+
+ // First stage init is weird: it may start without stdout/stderr, and no /proc.
hwaddress: false,
},
+
+ // Install adb_debug.prop into debug ramdisk.
+ // This allows adb root on a user build, when debug ramdisk is used.
+ required: ["adb_debug.prop"],
+
+ ramdisk: true,
+
+ install_in_root: true,
+}
+
+phony {
+ name: "init_system",
+ required: ["init_second_stage"],
}
// Tests
diff --git a/init/Android.mk b/init/Android.mk
index 3c7d95a..c08fe03 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -2,153 +2,6 @@
LOCAL_PATH:= $(call my-dir)
--include system/sepolicy/policy_version.mk
-
-# --
-
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-init_options += \
- -DALLOW_FIRST_STAGE_CONSOLE=1 \
- -DALLOW_LOCAL_PROP_OVERRIDE=1 \
- -DALLOW_PERMISSIVE_SELINUX=1 \
- -DREBOOT_BOOTLOADER_ON_PANIC=1 \
- -DWORLD_WRITABLE_KMSG=1 \
- -DDUMP_ON_UMOUNT_FAILURE=1
-else
-init_options += \
- -DALLOW_FIRST_STAGE_CONSOLE=0 \
- -DALLOW_LOCAL_PROP_OVERRIDE=0 \
- -DALLOW_PERMISSIVE_SELINUX=0 \
- -DREBOOT_BOOTLOADER_ON_PANIC=0 \
- -DWORLD_WRITABLE_KMSG=0 \
- -DDUMP_ON_UMOUNT_FAILURE=0
-endif
-
-ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
-init_options += \
- -DSHUTDOWN_ZERO_TIMEOUT=1
-else
-init_options += \
- -DSHUTDOWN_ZERO_TIMEOUT=0
-endif
-
-init_options += -DLOG_UEVENTS=0 \
- -DSEPOLICY_VERSION=$(POLICYVERS)
-
-init_cflags += \
- $(init_options) \
- -Wall -Wextra \
- -Wno-unused-parameter \
- -Werror \
-
-# --
-
-# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
-ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-include $(CLEAR_VARS)
-LOCAL_CPPFLAGS := $(init_cflags)
-LOCAL_SRC_FILES := \
- block_dev_initializer.cpp \
- devices.cpp \
- first_stage_console.cpp \
- first_stage_init.cpp \
- first_stage_main.cpp \
- first_stage_mount.cpp \
- reboot_utils.cpp \
- selabel.cpp \
- selinux.cpp \
- service_utils.cpp \
- snapuserd_transition.cpp \
- switch_root.cpp \
- uevent_listener.cpp \
- util.cpp \
-
-LOCAL_MODULE := init_first_stage
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_MODULE_STEM := init
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
-
-# Install adb_debug.prop into debug ramdisk.
-# This allows adb root on a user build, when debug ramdisk is used.
-LOCAL_REQUIRED_MODULES := \
- adb_debug.prop \
-
-# Set up the directories that first stage init mounts on.
-
-my_ramdisk_dirs := \
- debug_ramdisk \
- dev \
- metadata \
- mnt \
- proc \
- second_stage_resources \
- sys \
-
-LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_RAMDISK_OUT)/,$(my_ramdisk_dirs))
-ifeq (true,$(BOARD_USES_GENERIC_KERNEL_IMAGE))
- LOCAL_POST_INSTALL_CMD += $(addprefix $(TARGET_RAMDISK_OUT)/first_stage_ramdisk/,$(my_ramdisk_dirs))
-endif
-
-my_ramdisk_dirs :=
-
-LOCAL_STATIC_LIBRARIES := \
- libc++fs \
- libfs_avb \
- libfs_mgr \
- libfec \
- libfec_rs \
- libsquashfs_utils \
- liblogwrap \
- libext4_utils \
- libcrypto_utils \
- libsparse \
- libavb \
- libkeyutils \
- liblp \
- libcutils \
- libbase \
- liblog \
- libcrypto_static \
- libdl \
- libz \
- libselinux \
- libcap \
- libgsi \
- libcom.android.sysprop.apex \
- liblzma \
- libunwindstack_no_dex \
- libbacktrace_no_dex \
- libmodprobe \
- libext2_uuid \
- libprotobuf-cpp-lite \
- libsnapshot_cow \
- libsnapshot_init \
- update_metadata-protos \
- libprocinfo \
-
-LOCAL_SANITIZE := signed-integer-overflow
-# First stage init is weird: it may start without stdout/stderr, and no /proc.
-LOCAL_NOSANITIZE := hwaddress
-include $(BUILD_EXECUTABLE)
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := init_system
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_REQUIRED_MODULES := \
- init_second_stage \
-
-include $(BUILD_PHONY_PACKAGE)
-
include $(CLEAR_VARS)
LOCAL_MODULE := init_vendor
@@ -156,8 +9,10 @@
LOCAL_LICENSE_CONDITIONS := notice
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
+ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
LOCAL_REQUIRED_MODULES := \
init_first_stage \
-endif
+endif # BOARD_USES_RECOVERY_AS_BOOT
+endif # BOARD_BUILD_SYSTEM_ROOT_IMAGE
include $(BUILD_PHONY_PACKAGE)
diff --git a/init/README.md b/init/README.md
index 75dc328..4b04628 100644
--- a/init/README.md
+++ b/init/README.md
@@ -406,6 +406,33 @@
3. Any time that property c transitions to value d, while property a already equals b.
+Trigger Sequence
+----------------
+
+Init uses the following sequence of triggers during early boot. These are the
+built-in triggers defined in init.cpp.
+
+ 1. `early-init` - The first in the sequence, triggered after cgroups has been configured
+ but before ueventd's coldboot is complete.
+ 2. `init` - Triggered after coldboot is complete.
+ 3. `charger` - Triggered if `ro.bootmode == "charger"`.
+ 4. `late-init` - Triggered if `ro.bootmode != "charger"`, or via healthd triggering a boot
+ from charging mode.
+
+Remaining triggers are configured in `init.rc` and are not built-in. The default sequence for
+these is specified under the "on late-init" event in `init.rc`. Actions internal to `init.rc`
+have been omitted.
+
+ 1. `early-fs` - Start vold.
+ 2. `fs` - Vold is up. Mount partitions not marked as first-stage or latemounted.
+ 3. `post-fs` - Configure anything dependent on early mounts.
+ 4. `late-fs` - Mount partitions marked as latemounted.
+ 5. `post-fs-data` - Mount and configure `/data`; set up encryption. `/metadata` is
+ reformatted here if it couldn't mount in first-stage init.
+ 6. `zygote-start` - Start the zygote.
+ 7. `early-boot` - After zygote has started.
+ 8. `boot` - After `early-boot` actions have completed.
+
Commands
--------
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 46f8331..f0d8d45 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -90,12 +90,18 @@
auto mount_prop = entry.mount_point;
if (mount_prop == "/") mount_prop = "/root";
std::replace(mount_prop.begin(), mount_prop.end(), '/', '.');
- mount_prop = "dev.mnt.blk" + mount_prop;
+ auto blk_mount_prop = "dev.mnt.blk" + mount_prop;
+ auto dev_mount_prop = "dev.mnt.dev" + mount_prop;
// Set property even if its value does not change to trigger 'on property:'
// handling, except for clearing non-existent or already clear property.
// Goal is reduction of empty properties and associated triggers.
- if (value.empty() && android::base::GetProperty(mount_prop, "").empty()) return;
- android::base::SetProperty(mount_prop, value);
+ if (value.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return;
+ android::base::SetProperty(blk_mount_prop, value);
+ if (!value.empty()) {
+ android::base::SetProperty(dev_mount_prop, entry.blk_device.substr(strlen(devblock)));
+ } else {
+ android::base::SetProperty(dev_mount_prop, "");
+ }
}
} // namespace
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_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/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index b33d46d..c8a183b 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -21,6 +21,7 @@
cc_library {
name: "libcrypto_utils",
vendor_available: true,
+ ramdisk_available: true,
recovery_available: true,
vndk: {
enabled: true,
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 86f68fb..fbb8049 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -5,16 +5,15 @@
license {
name: "system_core_libkeyutils_license",
visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-BSD",
- ],
- // large-scale-change unable to identify any license_text files
+ license_kinds: ["SPDX-license-identifier-BSD"],
+ license_text: ["NOTICE"],
}
cc_library {
name: "libkeyutils",
cflags: ["-Werror"],
defaults: ["linux_bionic_supported"],
+ ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["include/"],
local_include_dirs: ["include/"],
diff --git a/libkeyutils/NOTICE b/libkeyutils/NOTICE
new file mode 100644
index 0000000..5828550
--- /dev/null
+++ b/libkeyutils/NOTICE
@@ -0,0 +1,25 @@
+Copyright (C) 2017 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/libmodprobe/Android.bp b/libmodprobe/Android.bp
index ba11dc9..525a880 100644
--- a/libmodprobe/Android.bp
+++ b/libmodprobe/Android.bp
@@ -8,6 +8,7 @@
"-Werror",
],
vendor_available: true,
+ ramdisk_available: true,
recovery_available: true,
srcs: [
"libmodprobe.cpp",
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index bd94621..b5fa475 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -476,6 +476,33 @@
},
{
+ "Name": "SFMainPolicy",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "cpuset",
+ "Path": "system-background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "SFRenderEnginePolicy",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "cpuset",
+ "Path": "system-background"
+ }
+ }
+ ]
+ },
+
+ {
"Name": "PerfBoost",
"Actions": [
{
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 4b11b1c..8697e9a 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -16,4 +16,4 @@
capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE SYS_ADMIN
file /dev/kmsg w
file /proc/sysrq-trigger w
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
index b1f96a8..5d701fc 100644
--- a/llkd/llkd.rc
+++ b/llkd/llkd.rc
@@ -42,4 +42,4 @@
capabilities KILL IPC_LOCK
file /dev/kmsg w
file /proc/sysrq-trigger w
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index ae21633..e98733a 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -45,4 +45,11 @@
src: "etc/public.libraries.android.txt",
filename: "public.libraries.txt",
installable: false,
-}
\ No newline at end of file
+}
+
+// adb_debug.prop in debug ramdisk
+prebuilt_root {
+ name: "adb_debug.prop",
+ src: "adb_debug.prop",
+ debug_ramdisk: true,
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 99d8f9a..9b80575 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -210,15 +210,4 @@
$(hide) $(foreach lib,$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES), \
echo $(lib) >> $@;)
-#######################################
-# adb_debug.prop in debug ramdisk
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_debug.prop
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
-include $(BUILD_PREBUILT)
-
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index c58f298..d62c41d 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -11,6 +11,9 @@
"libsigchain.so",
// TODO(b/122876336): Remove libpac.so once it's migrated to Webview
"libpac.so",
+ // TODO(b/184872979): Remove libbinder_rpc_unstable.so once stablized and
+ // added to libbinder_ndk.
+ "libbinder_rpc_unstable.so",
// TODO(b/120786417 or b/134659294): libicuuc.so
// and libicui18n.so are kept for app compat.
"libicui18n.so",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c6b74bc..db61fc5 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
@@ -884,6 +857,8 @@
# Create mirror directory for jit profiles
mkdir /data_mirror/cur_profiles 0700 root root
mount none /data/misc/profiles/cur /data_mirror/cur_profiles bind rec
+ mkdir /data_mirror/ref_profiles 0700 root root
+ mount none /data/misc/profiles/ref /data_mirror/ref_profiles bind rec
mkdir /data/cache 0770 system cache encryption=Require
mkdir /data/cache/recovery 0770 system cache
@@ -1028,11 +1003,11 @@
# to access F2FS sysfs on dm-<num> directly
mkdir /dev/sys/fs/by-name 0755 system system
- symlink /sys/fs/f2fs/${dev.mnt.blk.data} /dev/sys/fs/by-name/userdata
+ symlink /sys/fs/f2fs/${dev.mnt.dev.data} /dev/sys/fs/by-name/userdata
# to access dm-<num> sysfs
mkdir /dev/sys/block/by-name 0755 system system
- symlink /sys/devices/virtual/block/${dev.mnt.blk.data} /dev/sys/block/by-name/userdata
+ symlink /sys/devices/virtual/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata
# F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs,
# to avoid power consumption when system becomes mostly idle. Be careful
@@ -1265,6 +1240,7 @@
umount /data_mirror/data_ce/null
umount /data_mirror/data_de/null
umount /data_mirror/cur_profiles
+ umount /data_mirror/ref_profiles
umount /data_mirror
remount_userdata
start bootanim
@@ -1278,7 +1254,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/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 9469a48..0090841 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -12,5 +12,5 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 98dc088..63772bd 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -12,5 +12,5 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
diff --git a/storaged/Android.bp b/storaged/Android.bp
index ec27a08..9d5cb48 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -30,7 +30,6 @@
"libhidlbase",
"liblog",
"libprotobuf-cpp-lite",
- "libsysutils",
"libutils",
"libz",
],
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index 0614fad..7085743 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -3,6 +3,6 @@
capabilities DAC_READ_SEARCH
priority 10
file /d/mmc0/mmc0:0001/ext_csd r
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
user root
group package_info
diff --git a/trusty/fuzz/counters.cpp b/trusty/fuzz/counters.cpp
index c28fd05..65a3ba6 100644
--- a/trusty/fuzz/counters.cpp
+++ b/trusty/fuzz/counters.cpp
@@ -33,7 +33,7 @@
* We don't know how many counters the coverage record will contain. So, eyeball
* the size of this section.
*/
-static const size_t kMaxNumCounters = 0x8000;
+static const size_t kMaxNumCounters = 0x10000;
__attribute__((section("__libfuzzer_extra_counters"))) volatile uint8_t counters[kMaxNumCounters];
namespace android {
diff --git a/trusty/keymaster/3.0/service.cpp b/trusty/keymaster/3.0/service.cpp
index 0d8436e..b916c37 100644
--- a/trusty/keymaster/3.0/service.cpp
+++ b/trusty/keymaster/3.0/service.cpp
@@ -24,7 +24,7 @@
int main() {
::android::hardware::configureRpcThreadpool(1, true);
auto trustyKeymaster = new keymaster::TrustyKeymaster();
- int err = trustyKeymaster->Initialize();
+ int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMASTER_3);
if (err != 0) {
LOG(FATAL) << "Could not initialize TrustyKeymaster (" << err << ")";
return -1;
diff --git a/trusty/keymaster/4.0/service.cpp b/trusty/keymaster/4.0/service.cpp
index 96eb584..0e5144d 100644
--- a/trusty/keymaster/4.0/service.cpp
+++ b/trusty/keymaster/4.0/service.cpp
@@ -24,7 +24,7 @@
int main() {
::android::hardware::configureRpcThreadpool(1, true);
auto trustyKeymaster = new keymaster::TrustyKeymaster();
- int err = trustyKeymaster->Initialize();
+ int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMASTER_4);
if (err != 0) {
LOG(FATAL) << "Could not initialize TrustyKeymaster (" << err << ")";
return -1;
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6d24e84..58dfa94 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -80,6 +80,49 @@
vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
}
+cc_binary {
+ name: "android.hardware.security.keymint-service.trusty",
+ relative_install_path: "hw",
+ init_rc: ["keymint/android.hardware.security.keymint-service.trusty.rc"],
+ vintf_fragments: [
+ "keymint/android.hardware.security.keymint-service.trusty.xml",
+ ],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ srcs: [
+ "TrustyKeymaster.cpp",
+ "ipc/trusty_keymaster_ipc.cpp",
+ "keymint/TrustyKeyMintDevice.cpp",
+ "keymint/TrustyKeyMintOperation.cpp",
+ "keymint/TrustySecureClock.cpp",
+ "keymint/TrustySharedSecret.cpp",
+ "keymint/service.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.secureclock-V1-ndk_platform",
+ "android.hardware.security.sharedsecret-V1-ndk_platform",
+ "lib_android_keymaster_keymint_utils",
+ "libbase",
+ "libbinder_ndk",
+ "libhardware",
+ "libkeymaster_messages",
+ "libkeymint",
+ "liblog",
+ "libtrusty",
+ ],
+ required: [
+ "RemoteProvisioner",
+ "android.hardware.hardware_keystore.xml",
+ ],
+}
+
prebuilt_etc {
name: "keymaster_soft_attestation_keys.xml",
vendor: true,
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index 23e0433..ef5fc3f 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-#include <cutils/log.h>
+#define LOG_TAG "trusty_keymaster_hal"
+#include <android-base/logging.h>
+
#include <keymaster/android_keymaster_messages.h>
#include <keymaster/keymaster_configuration.h>
#include <trusty_keymaster/TrustyKeymaster.h>
@@ -22,24 +24,28 @@
namespace keymaster {
-int TrustyKeymaster::Initialize() {
+int TrustyKeymaster::Initialize(KmVersion version) {
int err;
+ LOG(INFO) << "Initializing TrustyKeymaster as KmVersion: " << (int)version;
+
err = trusty_keymaster_connect();
if (err) {
- ALOGE("Failed to connect to trusty keymaster %d", err);
+ LOG(ERROR) << "Failed to connect to trusty keymaster (1st try)" << err;
return err;
}
// Try GetVersion2 first.
GetVersion2Request versionReq;
+ versionReq.max_message_version = MessageVersion(version);
GetVersion2Response versionRsp = GetVersion2(versionReq);
if (versionRsp.error != KM_ERROR_OK) {
- ALOGW("TA appears not to support GetVersion2, falling back (err = %d)", versionRsp.error);
+ LOG(WARNING) << "TA appears not to support GetVersion2, falling back (err = "
+ << versionRsp.error << ")";
err = trusty_keymaster_connect();
if (err) {
- ALOGE("Failed to connect to trusty keymaster %d", err);
+ LOG(FATAL) << "Failed to connect to trusty keymaster (2nd try) " << err;
return err;
}
@@ -47,13 +53,13 @@
GetVersionResponse versionRsp;
GetVersion(versionReq, &versionRsp);
if (versionRsp.error != KM_ERROR_OK) {
- ALOGE("Failed to get TA version %d", versionRsp.error);
+ LOG(FATAL) << "Failed to get TA version " << versionRsp.error;
return -1;
} else {
keymaster_error_t error;
message_version_ = NegotiateMessageVersion(versionRsp, &error);
if (error != KM_ERROR_OK) {
- ALOGE("Failed to negotiate message version %d", error);
+ LOG(FATAL) << "Failed to negotiate message version " << error;
return -1;
}
}
@@ -69,7 +75,7 @@
Configure(req, &rsp);
if (rsp.error != KM_ERROR_OK) {
- ALOGE("Failed to configure keymaster %d", rsp.error);
+ LOG(FATAL) << "Failed to configure keymaster " << rsp.error;
return -1;
}
@@ -87,7 +93,7 @@
keymaster_error_t err;
err = trusty_keymaster_send(command, req, rsp);
if (err != KM_ERROR_OK) {
- ALOGE("Failed to send cmd %d err: %d", command, err);
+ LOG(ERROR) << "Cmd " << command << " returned error: " << err;
rsp->error = err;
}
}
@@ -137,14 +143,19 @@
void TrustyKeymaster::GenerateKey(const GenerateKeyRequest& request,
GenerateKeyResponse* response) {
- GenerateKeyRequest datedRequest(request.message_version);
- datedRequest.key_description = request.key_description;
+ if (message_version_ < 4) {
+ // Pre-KeyMint we need to add TAG_CREATION_DATETIME if not provided by the caller.
+ GenerateKeyRequest datedRequest(request.message_version);
+ datedRequest.key_description = request.key_description;
- if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
- datedRequest.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+ if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+ datedRequest.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+ }
+
+ ForwardCommand(KM_GENERATE_KEY, datedRequest, response);
+ } else {
+ ForwardCommand(KM_GENERATE_KEY, request, response);
}
-
- ForwardCommand(KM_GENERATE_KEY, datedRequest, response);
}
void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
@@ -229,4 +240,16 @@
return response;
}
+EarlyBootEndedResponse TrustyKeymaster::EarlyBootEnded() {
+ EarlyBootEndedResponse response(message_version());
+ ForwardCommand(KM_EARLY_BOOT_ENDED, EarlyBootEndedRequest(message_version()), &response);
+ return response;
+}
+
+DeviceLockedResponse TrustyKeymaster::DeviceLocked(const DeviceLockedRequest& request) {
+ DeviceLockedResponse response(message_version());
+ ForwardCommand(KM_DEVICE_LOCKED, request, &response);
+ return response;
+}
+
} // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
new file mode 100644
index 0000000..5fd628f
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h
@@ -0,0 +1,88 @@
+/*
+ * 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/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using ::std::optional;
+using ::std::shared_ptr;
+using ::std::vector;
+
+class TrustyKeyMintDevice : public BnKeyMintDevice {
+ public:
+ explicit TrustyKeyMintDevice(shared_ptr<TrustyKeymaster> impl) : impl_(std::move(impl)) {}
+ virtual ~TrustyKeyMintDevice() = default;
+
+ ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+ ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+ ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus getKeyCharacteristics(const vector<uint8_t>& keyBlob,
+ const vector<uint8_t>& clientId,
+ const vector<uint8_t>& appData,
+ vector<KeyCharacteristics>* characteristics) override;
+
+ ScopedAStatus importKey(const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+ const vector<uint8_t>& keyData,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ const vector<uint8_t>& wrappingKeyBlob,
+ const vector<uint8_t>& maskingKey,
+ const vector<KeyParameter>& unwrappingParams,
+ int64_t passwordSid, int64_t biometricSid,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+ const vector<KeyParameter>& upgradeParams,
+ vector<uint8_t>* keyBlob) override;
+
+ ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+ ScopedAStatus deleteAllKeys() override;
+ ScopedAStatus destroyAttestationIds() override;
+
+ ScopedAStatus begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+ const vector<KeyParameter>& params,
+ const optional<HardwareAuthToken>& authToken, BeginResult* result) override;
+
+ ScopedAStatus deviceLocked(bool passwordOnly,
+ const optional<TimeStampToken>& timestampToken) override;
+ ScopedAStatus earlyBootEnded() override;
+
+ ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+ std::vector<uint8_t>* ephemeralKeyBlob) override;
+
+ protected:
+ std::shared_ptr<TrustyKeymaster> impl_;
+ SecurityLevel securityLevel_;
+};
+
+} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h
new file mode 100644
index 0000000..65fd2f5
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintOperation.h
@@ -0,0 +1,64 @@
+/*
+ * 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/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+class TrustyKeyMintOperation : public BnKeyMintOperation {
+ public:
+ explicit TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,
+ keymaster_operation_handle_t opHandle);
+ virtual ~TrustyKeyMintOperation();
+
+ ScopedAStatus updateAad(const vector<uint8_t>& input,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken) override;
+
+ ScopedAStatus update(const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken,
+ vector<uint8_t>* output) override;
+
+ ScopedAStatus 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) override;
+
+ ScopedAStatus abort() override;
+
+ protected:
+ std::shared_ptr<TrustyKeymaster> impl_;
+ keymaster_operation_handle_t opHandle_;
+};
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index bec2a2a..45ebf7f 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -25,7 +25,7 @@
public:
TrustyKeymaster();
~TrustyKeymaster();
- int Initialize();
+ int Initialize(KmVersion version);
void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
SupportedAlgorithmsResponse* response);
@@ -60,6 +60,8 @@
ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
GetVersion2Response GetVersion2(const GetVersion2Request& request);
+ EarlyBootEndedResponse EarlyBootEnded();
+ DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
uint32_t message_version() const { return message_version_; }
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h b/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h
new file mode 100644
index 0000000..f077b27
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustySecureClock.h
@@ -0,0 +1,38 @@
+/*
+ * 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/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/secureclock/Timestamp.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::secureclock::trusty {
+
+class TrustySecureClock : public BnSecureClock {
+ public:
+ explicit TrustySecureClock(std::shared_ptr<::keymaster::TrustyKeymaster> impl)
+ : impl_(std::move(impl)) {}
+ ~TrustySecureClock() = default;
+ ::ndk::ScopedAStatus generateTimeStamp(int64_t challenge, TimeStampToken* token) override;
+
+ private:
+ std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+
+} // namespace aidl::android::hardware::security::secureclock::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h b/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h
new file mode 100644
index 0000000..946f57e
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustySharedSecret.h
@@ -0,0 +1,39 @@
+/*
+ * 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/sharedsecret/BnSharedSecret.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::sharedsecret::trusty {
+
+class TrustySharedSecret : public BnSharedSecret {
+ public:
+ explicit TrustySharedSecret(std::shared_ptr<::keymaster::TrustyKeymaster> impl)
+ : impl_(std::move(impl)) {}
+ ~TrustySharedSecret() = default;
+
+ ::ndk::ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override;
+ ::ndk::ScopedAStatus computeSharedSecret(const std::vector<SharedSecretParameters>& params,
+ std::vector<uint8_t>* sharingCheck) override;
+
+ private:
+ std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+} // namespace aidl::android::hardware::security::sharedsecret::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 419c96f..a1229a3 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -54,6 +54,8 @@
KM_DESTROY_ATTESTATION_IDS = (24 << KEYMASTER_REQ_SHIFT),
KM_IMPORT_WRAPPED_KEY = (25 << KEYMASTER_REQ_SHIFT),
KM_GET_VERSION_2 = (28 << KEYMASTER_REQ_SHIFT),
+ KM_EARLY_BOOT_ENDED = (29 << KEYMASTER_REQ_SHIFT),
+ KM_DEVICE_LOCKED = (30 << KEYMASTER_REQ_SHIFT),
// Bootloader/provisioning calls.
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
new file mode 100644
index 0000000..5f8524b
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
@@ -0,0 +1,324 @@
+/*
+
+ * 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/TrustyKeyMintDevice.h>
+
+#define TAG TrustyKeyMintDevice
+#include <android-base/logging.h>
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+
+#include <KeyMintUtils.h>
+
+#include <trusty_keymaster/TrustyKeyMintOperation.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using keymaster::KeymasterBlob;
+using keymaster::KeymasterKeyBlob;
+using keymaster::TAG_APPLICATION_DATA;
+using keymaster::TAG_APPLICATION_ID;
+using keymaster::TAG_AUTH_TOKEN;
+using km_utils::authToken2AidlVec;
+using km_utils::kmBlob2vector;
+using km_utils::kmError2ScopedAStatus;
+using km_utils::kmParam2Aidl;
+using km_utils::KmParamSet;
+using km_utils::kmParamSet2Aidl;
+using km_utils::legacy_enum_conversion;
+
+namespace {
+
+auto kSecurityLevel = SecurityLevel::TRUSTED_ENVIRONMENT;
+
+KeyCharacteristics convertAuthSet(SecurityLevel securityLevel,
+ const keymaster::AuthorizationSet& authorizations) {
+ KeyCharacteristics retval{securityLevel, {}};
+ std::transform(authorizations.begin(), authorizations.end(),
+ std::back_inserter(retval.authorizations), kmParam2Aidl);
+ return retval;
+}
+
+vector<KeyCharacteristics> convertKeyCharacteristics(const keymaster::AuthorizationSet& sw_enforced,
+ const keymaster::AuthorizationSet& hw_enforced,
+ bool includeKeystoreEnforced = true) {
+ KeyCharacteristics keyMintEnforced = convertAuthSet(kSecurityLevel, hw_enforced);
+ KeyCharacteristics keystoreEnforced = convertAuthSet(SecurityLevel::KEYSTORE, sw_enforced);
+
+ vector<KeyCharacteristics> retval;
+ retval.reserve(2);
+
+ if (!keyMintEnforced.authorizations.empty()) retval.push_back(std::move(keyMintEnforced));
+ if (includeKeystoreEnforced && !keystoreEnforced.authorizations.empty()) {
+ retval.push_back(std::move(keystoreEnforced));
+ }
+
+ return retval;
+}
+
+Certificate convertCertificate(const keymaster_blob_t& cert) {
+ return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
+}
+
+vector<Certificate> convertCertificateChain(const keymaster::CertificateChain& chain) {
+ vector<Certificate> retval;
+ std::transform(chain.begin(), chain.end(), std::back_inserter(retval), convertCertificate);
+ return retval;
+}
+
+void addClientAndAppData(const vector<uint8_t>& clientId, const vector<uint8_t>& appData,
+ ::keymaster::AuthorizationSet* params) {
+ params->Clear();
+ if (clientId.size()) params->push_back(TAG_APPLICATION_ID, clientId.data(), clientId.size());
+ if (appData.size()) params->push_back(TAG_APPLICATION_DATA, appData.data(), appData.size());
+}
+
+} // namespace
+
+ScopedAStatus TrustyKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+ info->versionNumber = 1;
+ info->securityLevel = kSecurityLevel;
+ info->keyMintName = "TrustyKeyMintDevice";
+ info->keyMintAuthorName = "Google";
+ info->timestampTokenRequired = false;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+ if (data.size() == 0) return ScopedAStatus::ok();
+ if (data.size() > 2048) {
+ LOG(DEBUG) << "Too-large entropy update of " << data.size() << " bytes.";
+ return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+ }
+
+ keymaster::AddEntropyRequest request(impl_->message_version());
+ request.random_data.Reinitialize(data.data(), data.size());
+
+ keymaster::AddEntropyResponse response(impl_->message_version());
+ impl_->AddRngEntropy(request, &response);
+
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) {
+ keymaster::GenerateKeyRequest request(impl_->message_version());
+ request.key_description.Reinitialize(KmParamSet(keyParams));
+ if (attestationKey) {
+ request.attestation_signing_key_blob =
+ KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+ request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+ request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+ attestationKey->issuerSubjectName.size());
+ }
+
+ keymaster::GenerateKeyResponse response(impl_->message_version());
+ impl_->GenerateKey(request, &response);
+
+ if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+ creationResult->keyBlob = kmBlob2vector(response.key_blob);
+ creationResult->keyCharacteristics =
+ convertKeyCharacteristics(response.unenforced, response.enforced);
+ creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::getKeyCharacteristics(
+ const vector<uint8_t>& keyBlob,
+ const vector<uint8_t>& clientId, //
+ const vector<uint8_t>& appData, //
+ vector<KeyCharacteristics>* characteristics) {
+ keymaster::GetKeyCharacteristicsRequest request(impl_->message_version());
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+ addClientAndAppData(clientId, appData, &request.additional_params);
+
+ keymaster::GetKeyCharacteristicsResponse response(impl_->message_version());
+ impl_->GetKeyCharacteristics(request, &response);
+
+ if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+ *characteristics = convertKeyCharacteristics(response.unenforced, response.enforced,
+ false /* includeKeystoreEnforced */);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
+ KeyFormat keyFormat, const vector<uint8_t>& keyData,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) {
+ keymaster::ImportKeyRequest request(impl_->message_version());
+ request.key_description.Reinitialize(KmParamSet(keyParams));
+ request.key_format = legacy_enum_conversion(keyFormat);
+ request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+ if (attestationKey) {
+ request.attestation_signing_key_blob =
+ KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+ request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+ request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+ attestationKey->issuerSubjectName.size());
+ }
+
+ keymaster::ImportKeyResponse response(impl_->message_version());
+ impl_->ImportKey(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ creationResult->keyBlob = kmBlob2vector(response.key_blob);
+ creationResult->keyCharacteristics =
+ convertKeyCharacteristics(response.unenforced, response.enforced);
+ creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ const vector<uint8_t>& wrappingKeyBlob, //
+ const vector<uint8_t>& maskingKey,
+ const vector<KeyParameter>& unwrappingParams,
+ int64_t passwordSid, //
+ int64_t biometricSid,
+ KeyCreationResult* creationResult) {
+ keymaster::ImportWrappedKeyRequest request(impl_->message_version());
+ request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+ request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+ request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+ request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+ request.password_sid = static_cast<uint64_t>(passwordSid);
+ request.biometric_sid = static_cast<uint64_t>(biometricSid);
+
+ keymaster::ImportWrappedKeyResponse response(impl_->message_version());
+ impl_->ImportWrappedKey(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ creationResult->keyBlob = kmBlob2vector(response.key_blob);
+ creationResult->keyCharacteristics =
+ convertKeyCharacteristics(response.unenforced, response.enforced);
+ creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+ const vector<KeyParameter>& upgradeParams,
+ vector<uint8_t>* keyBlob) {
+ keymaster::UpgradeKeyRequest request(impl_->message_version());
+ request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+ request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+ keymaster::UpgradeKeyResponse response(impl_->message_version());
+ impl_->UpgradeKey(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ *keyBlob = kmBlob2vector(response.upgraded_key);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+ keymaster::DeleteKeyRequest request(impl_->message_version());
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+ keymaster::DeleteKeyResponse response(impl_->message_version());
+ impl_->DeleteKey(request, &response);
+
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::deleteAllKeys() {
+ // There's nothing to be done to delete software key blobs.
+ keymaster::DeleteAllKeysRequest request(impl_->message_version());
+ keymaster::DeleteAllKeysResponse response(impl_->message_version());
+ impl_->DeleteAllKeys(request, &response);
+
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::destroyAttestationIds() {
+ return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus TrustyKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+ const vector<KeyParameter>& params,
+ const optional<HardwareAuthToken>& authToken,
+ BeginResult* result) {
+ keymaster::BeginOperationRequest request(impl_->message_version());
+ request.purpose = legacy_enum_conversion(purpose);
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+ request.additional_params.Reinitialize(KmParamSet(params));
+
+ vector<uint8_t> vector_token = authToken2AidlVec(authToken);
+ request.additional_params.push_back(
+ TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()), vector_token.size());
+
+ keymaster::BeginOperationResponse response(impl_->message_version());
+ impl_->BeginOperation(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ result->params = kmParamSet2Aidl(response.output_params);
+ result->challenge = response.op_handle;
+ result->operation = ndk::SharedRefBase::make<TrustyKeyMintOperation>(impl_, response.op_handle);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintDevice::deviceLocked(
+ bool passwordOnly, const std::optional<secureclock::TimeStampToken>& timestampToken) {
+ keymaster::DeviceLockedRequest request(impl_->message_version());
+ request.passwordOnly = passwordOnly;
+ if (timestampToken.has_value()) {
+ request.token.challenge = timestampToken->challenge;
+ request.token.mac = {timestampToken->mac.data(), timestampToken->mac.size()};
+ request.token.timestamp = timestampToken->timestamp.milliSeconds;
+ }
+ keymaster::DeviceLockedResponse response = impl_->DeviceLocked(request);
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::earlyBootEnded() {
+ keymaster::EarlyBootEndedResponse response = impl_->EarlyBootEnded();
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintDevice::convertStorageKeyToEphemeral(
+ const std::vector<uint8_t>& storageKeyBlob, std::vector<uint8_t>* ephemeralKeyBlob) {
+ keymaster::ExportKeyRequest request(impl_->message_version());
+ request.SetKeyMaterial(storageKeyBlob.data(), storageKeyBlob.size());
+ request.key_format = KM_KEY_FORMAT_RAW;
+
+ keymaster::ExportKeyResponse response(impl_->message_version());
+ impl_->ExportKey(request, &response);
+
+ if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+ if (response.key_data) {
+ *ephemeralKeyBlob = {response.key_data, response.key_data + response.key_data_length};
+ }
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
new file mode 100644
index 0000000..41a21e9
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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/TrustyKeyMintOperation.h>
+
+#define TAG TrustyKeyMintOperation
+#include <android-base/logging.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <KeyMintUtils.h>
+#include <keymaster/android_keymaster.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::TAG_ASSOCIATED_DATA;
+using ::keymaster::TAG_AUTH_TOKEN;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using km_utils::authToken2AidlVec;
+using km_utils::kmError2ScopedAStatus;
+using secureclock::TimeStampToken;
+
+TrustyKeyMintOperation::TrustyKeyMintOperation(shared_ptr<TrustyKeymaster> implementation,
+ keymaster_operation_handle_t opHandle)
+ : impl_(std::move(implementation)), opHandle_(opHandle) {}
+
+TrustyKeyMintOperation::~TrustyKeyMintOperation() {
+ if (opHandle_ != 0) {
+ abort();
+ }
+}
+
+ScopedAStatus TrustyKeyMintOperation::updateAad(
+ const vector<uint8_t>& input, const optional<HardwareAuthToken>& /* authToken */,
+ const optional<TimeStampToken>& /* timestampToken */) {
+ UpdateOperationRequest request(impl_->message_version());
+ request.op_handle = opHandle_;
+ request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
+
+ UpdateOperationResponse response(impl_->message_version());
+ impl_->UpdateOperation(request, &response);
+
+ return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus TrustyKeyMintOperation::update(const vector<uint8_t>& input,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& /* timestampToken */,
+ vector<uint8_t>* output) {
+ if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
+
+ UpdateOperationRequest request(impl_->message_version());
+ request.op_handle = opHandle_;
+ if (authToken) {
+ auto tokenAsVec(authToken2AidlVec(*authToken));
+ request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
+ }
+
+ size_t serialized_size = request.SerializedSize();
+ if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+ }
+
+ const uint8_t* input_pos = input.data();
+ const uint8_t* input_end = input.data() + input.size();
+ const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
+ output->clear();
+
+ while (input_pos < input_end) {
+ size_t to_send = std::min(max_chunk_size, static_cast<size_t>(input_end - input_pos));
+ LOG(DEBUG) << "update: Sending " << to_send << " of " << (input_end - input_pos)
+ << " bytes";
+ request.input.Reinitialize(input_pos, to_send);
+
+ UpdateOperationResponse response(impl_->message_version());
+ impl_->UpdateOperation(request, &response);
+ if (response.error != KM_ERROR_OK) {
+ opHandle_ = 0; // Operation has ended, the handle is invalid. This saves an abort().
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ input_pos += response.input_consumed;
+ output->insert(output->end(), response.output.begin(), response.output.end());
+ }
+
+ 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) {
+ if (!output) {
+ return ScopedAStatus(AStatus_fromServiceSpecificError(
+ static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
+ }
+ output->clear();
+
+ FinishOperationRequest request(impl_->message_version());
+ request.op_handle = opHandle_;
+ if (signature) request.signature.Reinitialize(signature->data(), signature->size());
+ size_t serialized_size = request.SerializedSize();
+ if (serialized_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ return kmError2ScopedAStatus(KM_ERROR_INVALID_INPUT_LENGTH);
+ }
+
+ if (input) {
+ const size_t max_chunk_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - serialized_size;
+
+ if (input->size() > max_chunk_size) {
+ LOG(DEBUG) << "Sending an update to process finish() data";
+ // Use update to process all but the last max_chunk_size bytes.
+ auto result = update({input->begin(), input->end() - max_chunk_size}, authToken,
+ std::nullopt /* timestampToken */, output);
+ if (!result.isOk()) return result;
+
+ // Process the last max_chunk_size with finish.
+ request.input.Reinitialize(input->data() + (input->size() - max_chunk_size),
+ max_chunk_size);
+ } else {
+ request.input.Reinitialize(input->data(), input->size());
+ }
+ }
+
+ FinishOperationResponse response(impl_->message_version());
+ impl_->FinishOperation(request, &response);
+ opHandle_ = 0;
+
+ if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+ *output = {response.output.begin(), response.output.end()};
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyKeyMintOperation::abort() {
+ AbortOperationRequest request(impl_->message_version());
+ request.op_handle = opHandle_;
+
+ AbortOperationResponse response(impl_->message_version());
+ impl_->AbortOperation(request, &response);
+ opHandle_ = 0;
+
+ return kmError2ScopedAStatus(response.error);
+}
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/trusty/keymaster/keymint/TrustySecureClock.cpp b/trusty/keymaster/keymint/TrustySecureClock.cpp
new file mode 100644
index 0000000..fed5420
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustySecureClock.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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/TrustySecureClock.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <KeyMintUtils.h>
+
+namespace aidl::android::hardware::security::secureclock::trusty {
+
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+::ndk::ScopedAStatus TrustySecureClock::generateTimeStamp(int64_t challenge,
+ TimeStampToken* token) {
+ keymaster::VerifyAuthorizationRequest request(impl_->message_version());
+ request.challenge = challenge;
+
+ auto response = impl_->VerifyAuthorization(request);
+ if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+ token->challenge = response.token.challenge;
+ token->timestamp.milliSeconds = static_cast<int64_t>(response.token.timestamp);
+ token->mac = kmBlob2vector(response.token.mac);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::security::secureclock::trusty
diff --git a/trusty/keymaster/keymint/TrustySharedSecret.cpp b/trusty/keymaster/keymint/TrustySharedSecret.cpp
new file mode 100644
index 0000000..8109168
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustySharedSecret.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <trusty_keymaster/TrustySharedSecret.h>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/android_keymaster.h>
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::sharedsecret::trusty {
+
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+::ndk::ScopedAStatus TrustySharedSecret::getSharedSecretParameters(SharedSecretParameters* params) {
+ auto response = impl_->GetHmacSharingParameters();
+ params->seed = kmBlob2vector(response.params.seed);
+ params->nonce = {std::begin(response.params.nonce), std::end(response.params.nonce)};
+ return kmError2ScopedAStatus(response.error);
+}
+
+::ndk::ScopedAStatus TrustySharedSecret::computeSharedSecret(
+ const std::vector<SharedSecretParameters>& params, std::vector<uint8_t>* sharingCheck) {
+ keymaster::ComputeSharedHmacRequest request(impl_->message_version());
+ request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
+ request.params_array.num_params = params.size();
+ for (size_t i = 0; i < params.size(); ++i) {
+ request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()};
+ if (sizeof(request.params_array.params_array[i].nonce) != params[i].nonce.size()) {
+ return kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
+ }
+ memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+ params[i].nonce.size());
+ }
+
+ auto response = impl_->ComputeSharedHmac(request);
+ if (response.error == KM_ERROR_OK) *sharingCheck = kmBlob2vector(response.sharing_check);
+ return kmError2ScopedAStatus(response.error);
+}
+
+} // namespace aidl::android::hardware::security::sharedsecret::trusty
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc
new file mode 100644
index 0000000..389af41
--- /dev/null
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.rc
@@ -0,0 +1,4 @@
+service vendor.keymint-trusty /vendor/bin/hw/android.hardware.security.keymint-service.trusty
+ class early_hal
+ user nobody
+ group drmrpc
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
new file mode 100644
index 0000000..0ab3d64
--- /dev/null
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -0,0 +1,14 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IKeyMintDevice/default</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.security.secureclock</name>
+ <fqname>ISecureClock/default</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.security.sharedsecret</name>
+ <fqname>ISharedSecret/default</fqname>
+ </hal>
+</manifest>
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
new file mode 100644
index 0000000..8f5f0f8
--- /dev/null
+++ b/trusty/keymaster/keymint/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-service.trusty"
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <trusty_keymaster/TrustyKeyMintDevice.h>
+#include <trusty_keymaster/TrustySecureClock.h>
+#include <trusty_keymaster/TrustySharedSecret.h>
+
+using aidl::android::hardware::security::keymint::trusty::TrustyKeyMintDevice;
+using aidl::android::hardware::security::secureclock::trusty::TrustySecureClock;
+using aidl::android::hardware::security::sharedsecret::trusty::TrustySharedSecret;
+
+template <typename T, class... Args>
+std::shared_ptr<T> addService(Args&&... args) {
+ std::shared_ptr<T> service = std::make_shared<T>(std::forward<Args>(args)...);
+ auto instanceName = std::string(T::descriptor) + "/default";
+ LOG(ERROR) << "Adding service instance: " << instanceName;
+ auto status = AServiceManager_addService(service->asBinder().get(), instanceName.c_str());
+ CHECK(status == STATUS_OK) << "Failed to add service " << instanceName;
+ return service;
+}
+
+int main() {
+ auto trustyKeymaster = std::make_shared<keymaster::TrustyKeymaster>();
+ int err = trustyKeymaster->Initialize(keymaster::KmVersion::KEYMINT_1);
+ if (err != 0) {
+ LOG(FATAL) << "Could not initialize TrustyKeymaster for KeyMint (" << err << ")";
+ return -1;
+ }
+
+ // Zero threads seems like a useless pool but below we'll join this thread to it, increasing
+ // the pool size to 1.
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto keyMint = addService<TrustyKeyMintDevice>(trustyKeymaster);
+ auto secureClock = addService<TrustySecureClock>(trustyKeymaster);
+ auto sharedSecret = addService<TrustySharedSecret>(trustyKeymaster);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/usbd/Android.bp b/usbd/Android.bp
index 22d171d..27db0fa 100644
--- a/usbd/Android.bp
+++ b/usbd/Android.bp
@@ -13,6 +13,5 @@
"libutils",
"libhardware",
"android.hardware.usb.gadget@1.0",
- "libcutils",
],
}