Merge "trusty: Add host build for rpmb_dev" into main
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 08619b9..e33cea5 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -86,7 +86,6 @@
#define ARCH_SUFFIX ""
#endif
-constexpr size_t kTagGranuleSize = 16;
constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
#define TIMEOUT(seconds, expr) \
@@ -742,6 +741,8 @@
}
#if defined(__aarch64__)
+constexpr size_t kTagGranuleSize = 16;
+
static uintptr_t CreateTagMapping() {
// 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.
@@ -1772,6 +1773,75 @@
AssertDeath(SIGABRT);
}
+extern "C" void malloc_enable();
+extern "C" void malloc_disable();
+
+TEST_F(CrasherTest, seccomp_tombstone_no_allocation) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdTombstone;
+ StartProcess(
+ []() {
+ std::thread a(foo);
+ std::thread b(bar);
+
+ std::this_thread::sleep_for(100ms);
+
+ // Disable allocations to verify that nothing in the fallback
+ // signal handler does an allocation.
+ malloc_disable();
+ raise_debugger_signal(dump_type);
+ _exit(0);
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(0);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+ ASSERT_BACKTRACE_FRAME(result, "foo");
+ ASSERT_BACKTRACE_FRAME(result, "bar");
+}
+
+TEST_F(CrasherTest, seccomp_backtrace_no_allocation) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdNativeBacktrace;
+ StartProcess(
+ []() {
+ std::thread a(foo);
+ std::thread b(bar);
+
+ std::this_thread::sleep_for(100ms);
+
+ // Disable allocations to verify that nothing in the fallback
+ // signal handler does an allocation.
+ malloc_disable();
+ raise_debugger_signal(dump_type);
+ _exit(0);
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(0);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+ ASSERT_BACKTRACE_FRAME(result, "foo");
+ ASSERT_BACKTRACE_FRAME(result, "bar");
+}
+
TEST_F(CrasherTest, competing_tracer) {
int intercept_result;
unique_fd output_fd;
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 4721391..8ab5f25 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -48,50 +48,69 @@
extern "C" bool __linker_enable_fallback_allocator();
extern "C" void __linker_disable_fallback_allocator();
-// This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
-// uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
-// the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
-//
-// This isn't the default method of dumping because it can fail in cases such as address space
-// exhaustion.
+// This file implements a fallback path for processes that do not allow the
+// normal fork and exec of crash_dump to handle crashes/unwinds.
+// The issue is that all of this happens from within a signal handler, which
+// can cause problems since this code uses the linker allocator which is not
+// thread safe. In order to avoid any problems allocating, the code calls
+// a function to switch to use a fallback allocator in the linker that will
+// only be used for the current thread. All of the libunwindstack code does
+// allocations using C++ stl, but should be fine since the code runs in the
+// linker and should use the fallback handler.
+
+// This method can still fail if the virtual space is exhausted on a 32 bit
+// process or mmap failing due to hitting the maximum number of maps (65535
+// total maps) on a 64 bit process.
+
+// Class to handle automatically turning on and off the fallback allocator.
+class ScopedUseFallbackAllocator {
+ public:
+ ScopedUseFallbackAllocator() { Enable(); }
+
+ ~ScopedUseFallbackAllocator() { Disable(); }
+
+ bool Enable() {
+ if (!enabled_) {
+ enabled_ = __linker_enable_fallback_allocator();
+ if (!enabled_) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "Unable to enable fallback allocator, already in use.");
+ }
+ }
+ return enabled_;
+ }
+
+ void Disable() {
+ if (enabled_) {
+ __linker_disable_fallback_allocator();
+ enabled_ = false;
+ }
+ }
+
+ bool enabled() { return enabled_; }
+
+ private:
+ bool enabled_ = false;
+};
+
static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
- if (!__linker_enable_fallback_allocator()) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
- return;
- }
+ std::unique_ptr<unwindstack::Regs> regs;
- {
- std::unique_ptr<unwindstack::Regs> regs;
+ ThreadInfo thread;
+ thread.pid = getpid();
+ thread.tid = gettid();
+ thread.thread_name = get_thread_name(gettid());
+ thread.registers.reset(
+ unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
- ThreadInfo thread;
- thread.pid = getpid();
- thread.tid = gettid();
- thread.thread_name = get_thread_name(gettid());
- thread.registers.reset(
- unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
-
- // 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 thread is stopped, and there
- // is no chance of data changing between reads.
- auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
- // TODO: Create this once and store it in a global?
- unwindstack::AndroidLocalUnwinder unwinder(process_memory);
- dump_backtrace_thread(output_fd, &unwinder, thread);
- }
- __linker_disable_fallback_allocator();
-}
-
-static void debuggerd_fallback_tombstone(int output_fd, int proto_fd, ucontext_t* ucontext,
- siginfo_t* siginfo, void* abort_message) {
- if (!__linker_enable_fallback_allocator()) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
- return;
- }
-
- engrave_tombstone_ucontext(output_fd, proto_fd, reinterpret_cast<uintptr_t>(abort_message),
- siginfo, ucontext);
- __linker_disable_fallback_allocator();
+ // 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 thread is stopped, and there
+ // is no chance of data changing between reads.
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ // TODO: Create this once and store it in a global?
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
+ dump_backtrace_thread(output_fd, &unwinder, thread);
}
static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
@@ -154,6 +173,11 @@
}
static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
+ ScopedUseFallbackAllocator allocator;
+ if (!allocator.enabled()) {
+ return;
+ }
+
static std::atomic<uint64_t> trace_output(pack_thread_fd(-1, -1));
if (info->si_value.sival_ptr == kDebuggerdFallbackSivalPtrRequestDump) {
@@ -181,6 +205,11 @@
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write to output fd");
}
+ // Stop using the fallback allocator before the close. This will prevent
+ // a race condition where the thread backtracing all of the threads tries
+ // to re-acquire the fallback allocator.
+ allocator.Disable();
+
close(fd);
return;
}
@@ -210,10 +239,15 @@
// Send a signal to all of our siblings, asking them to dump their stack.
pid_t current_tid = gettid();
- if (!iterate_tids(current_tid, [&output_fd, ¤t_tid](pid_t tid) {
+ if (!iterate_tids(current_tid, [&allocator, &output_fd, ¤t_tid](pid_t tid) {
if (current_tid == tid) {
return;
}
+
+ if (!allocator.enabled()) {
+ return;
+ }
+
// Use a pipe, to be able to detect situations where the thread gracefully exits before
// receiving our signal.
unique_fd pipe_read, pipe_write;
@@ -233,22 +267,29 @@
return;
}
+ // Disable our use of the fallback allocator while the target thread
+ // is getting the backtrace.
+ allocator.Disable();
+
siginfo_t siginfo = {};
siginfo.si_code = SI_QUEUE;
siginfo.si_value.sival_ptr = kDebuggerdFallbackSivalPtrRequestDump;
siginfo.si_pid = getpid();
siginfo.si_uid = getuid();
- if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
+ if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) == 0) {
+ if (!forward_output(pipe_read.get(), output_fd.get(), tid)) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "timeout expired while waiting for thread %d to dump", tid);
+ }
+ } else {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
tid, strerror(errno));
- return;
}
- bool success = forward_output(pipe_read.get(), output_fd.get(), tid);
- if (!success) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc",
- "timeout expired while waiting for thread %d to dump", tid);
+ // The thread should be finished now, so try and re-enable the fallback allocator.
+ if (!allocator.Enable()) {
+ return;
}
// Regardless of whether the poll succeeds, check to see if the thread took fd ownership.
@@ -260,14 +301,15 @@
close(fd);
}
}
-
- return;
})) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/%d/task: %s",
current_tid, strerror(errno));
}
- dump_backtrace_footer(output_fd.get());
+ if (allocator.enabled()) {
+ dump_backtrace_footer(output_fd.get());
+ }
+
tombstoned_notify_completion(tombstone_socket.get());
}
@@ -295,7 +337,13 @@
unique_fd tombstone_socket, output_fd, proto_fd;
bool tombstoned_connected = tombstoned_connect(getpid(), &tombstone_socket, &output_fd, &proto_fd,
kDebuggerdTombstoneProto);
- debuggerd_fallback_tombstone(output_fd.get(), proto_fd.get(), ucontext, info, abort_message);
+ {
+ ScopedUseFallbackAllocator allocator;
+ if (allocator.enabled()) {
+ engrave_tombstone_ucontext(output_fd.get(), proto_fd.get(),
+ reinterpret_cast<uintptr_t>(abort_message), info, ucontext);
+ }
+ }
if (tombstoned_connected) {
tombstoned_notify_completion(tombstone_socket.get());
}
diff --git a/debuggerd/libdebuggerd/test/host_signal_fixup.h b/debuggerd/libdebuggerd/test/host_signal_fixup.h
deleted file mode 100644
index 762bae5..0000000
--- a/debuggerd/libdebuggerd/test/host_signal_fixup.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
-#define _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
-
-#include <signal.h>
-
-#if !defined(__BIONIC__)
-
-// In order to compile parts of debuggerd for the host, we need to
-// define these values.
-
-#if !defined(NSIGILL)
-#define NSIGILL ILL_BADSTK
-#endif
-
-#if !defined(BUS_MCEERR_AR)
-#define BUS_MCEERR_AR 4
-#endif
-#if !defined(BUS_MCEERR_AO)
-#define BUS_MCEERR_AO 5
-#endif
-#if !defined(NSIGBUS)
-#define NSIGBUS BUS_MCEERR_AO
-#endif
-
-#if !defined(NSIGFPE)
-#define NSIGFPE FPE_FLTSUB
-#endif
-
-#if !defined(NSIGSEGV)
-#define NSIGSEGV SEGV_ACCERR
-#endif
-
-#if !defined(TRAP_BRANCH)
-#define TRAP_BRANCH 3
-#endif
-#if !defined(TRAP_HWBKPT)
-#define TRAP_HWBKPT 4
-#endif
-#if !defined(NSIGTRAP)
-#define NSIGTRAP TRAP_HWBKPT
-#endif
-
-#if !defined(SI_DETHREAD)
-#define SI_DETHREAD (-7)
-#endif
-
-#endif
-
-#endif // _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 774af28..bfe0768 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -186,6 +186,7 @@
"libprotobuf-cpp-lite",
"libsparse",
"libutils",
+ "libselinux",
],
static_libs: [
diff --git a/fastboot/fuzzy_fastboot/transport_sniffer.cpp b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
index b55ffd3..0aef350 100644
--- a/fastboot/fuzzy_fastboot/transport_sniffer.cpp
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
@@ -90,7 +90,7 @@
// and be printed as a string, or just a raw byte-buffer
const auto msg = [&ret, no_print](const std::vector<char>& buf) {
ret += android::base::StringPrintf("(%lu bytes): ", buf.size());
- std::vector<const char>::iterator iter = buf.end();
+ std::vector<char>::const_iterator iter = buf.end();
const unsigned max_chars = 50;
if (buf.size() > max_chars) {
iter = buf.begin() + max_chars;
diff --git a/fastboot/vendor_boot_img_utils_test.cpp b/fastboot/vendor_boot_img_utils_test.cpp
index 467c6e9..8107270 100644
--- a/fastboot/vendor_boot_img_utils_test.cpp
+++ b/fastboot/vendor_boot_img_utils_test.cpp
@@ -163,7 +163,7 @@
protected:
// |rel_path| is the relative path under test data directory.
TestFileHandle(const std::filesystem::path& rel_path)
- : abs_path_(std::move(std::filesystem::path(GetExecutableDirectory()) / rel_path)) {}
+ : abs_path_(std::filesystem::path(GetExecutableDirectory()) / rel_path) {}
// Given |read_fd|, the readonly fd on the test file, return an fd that's suitable for client
// to use. Implementation is responsible for managing the lifetime of the returned fd.
virtual android::base::Result<borrowed_fd> Transform(const std::filesystem::path& abs_path,
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 76578dd..fbd990b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -38,10 +38,8 @@
#include <array>
#include <chrono>
-#include <functional>
#include <map>
#include <memory>
-#include <numeric>
#include <string>
#include <string_view>
#include <thread>
@@ -66,6 +64,7 @@
#include <fs_mgr/file_wait.h>
#include <fs_mgr_overlayfs.h>
#include <fscrypt/fscrypt.h>
+#include <fstab/fstab.h>
#include <libdm/dm.h>
#include <libdm/loop_control.h>
#include <liblp/metadata_format.h>
@@ -82,7 +81,7 @@
#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
#define TUNE2FS_BIN "/system/bin/tune2fs"
-#define RESIZE2FS_BIN "/system/bin/resize2fs"
+#define RESIZE2FS_BIN "/system/bin/resize2fs"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
@@ -138,8 +137,8 @@
static void log_fs_stat(const std::string& blk_device, int fs_stat) {
std::string msg =
android::base::StringPrintf("\nfs_stat,%s,0x%x\n", blk_device.c_str(), fs_stat);
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(FSCK_LOG_FILE, O_WRONLY | O_CLOEXEC |
- O_APPEND | O_CREAT, 0664)));
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open(FSCK_LOG_FILE, O_WRONLY | O_CLOEXEC | O_APPEND | O_CREAT, 0664)));
if (fd == -1 || !android::base::WriteStringToFd(msg, fd)) {
LWARNING << __FUNCTION__ << "() cannot log " << msg;
}
@@ -593,7 +592,7 @@
// Must give `-T now` to prevent last_fsck_time from growing too large,
// otherwise, tune2fs won't enable metadata_csum.
- const char* tune2fs_args[] = {TUNE2FS_BIN, "-O", "metadata_csum,64bit,extent",
+ const char* tune2fs_args[] = {TUNE2FS_BIN, "-O", "metadata_csum,64bit,extent",
"-T", "now", blk_device.c_str()};
const char* resize2fs_args[] = {RESIZE2FS_BIN, "-b", blk_device.c_str()};
@@ -1430,6 +1429,37 @@
return access(fs_mgr_metadata_encryption_in_progress_file_name(entry).c_str(), R_OK) == 0;
}
+static FstabEntry* LocateFormattableEntry(FstabEntry* const begin, FstabEntry* const end) {
+ if (begin == end) {
+ return nullptr;
+ }
+ const bool dev_option_enabled =
+ android::base::GetBoolProperty("ro.product.build.16k_page.enabled", false);
+ FstabEntry* f2fs_entry = nullptr;
+ for (auto iter = begin; iter != end && iter->blk_device == begin->blk_device; iter++) {
+ if (iter->fs_mgr_flags.formattable) {
+ if (getpagesize() != 4096 && is_f2fs(iter->fs_type) && dev_option_enabled) {
+ f2fs_entry = iter;
+ continue;
+ }
+ if (f2fs_entry) {
+ LOG(INFO) << "Skipping F2FS format for block device " << iter->blk_device << " @ "
+ << iter->mount_point
+ << " in non-4K mode for dev option enabled devices, "
+ "as these devices need to toggle between 4K/16K mode, and F2FS does "
+ "not support page_size != block_size configuration.";
+ }
+ return iter;
+ }
+ }
+ if (f2fs_entry) {
+ LOG(INFO) << "Using F2FS for " << f2fs_entry->blk_device << " @ " << f2fs_entry->mount_point
+ << " even though we are in non-4K mode. Device might require a data wipe after "
+ "going back to 4K mode, as F2FS does not support page_size != block_size";
+ }
+ return f2fs_entry;
+}
+
// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
@@ -1540,8 +1570,8 @@
}
}
- int last_idx_inspected;
- int top_idx = i;
+ int last_idx_inspected = -1;
+ const int top_idx = i;
int attempted_idx = -1;
bool encryption_interrupted = WasMetadataEncryptionInterrupted(current_entry);
@@ -1591,7 +1621,8 @@
// Success! Go get the next one.
continue;
}
-
+ auto formattable_entry =
+ LocateFormattableEntry(fstab->data() + top_idx, fstab->data() + fstab->size());
// Mounting failed, understand why and retry.
wiped = partition_wiped(current_entry.blk_device.c_str());
if (mount_errno != EBUSY && mount_errno != EACCES &&
@@ -1619,12 +1650,12 @@
encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
set_type_property(encryptable);
- if (!call_vdc({"cryptfs", "encryptFstab", current_entry.blk_device,
- current_entry.mount_point, "true" /* shouldFormat */,
- current_entry.fs_type,
- current_entry.fs_mgr_flags.is_zoned ? "true" : "false",
- std::to_string(current_entry.length),
- android::base::Join(current_entry.user_devices, ' ')},
+ if (!call_vdc({"cryptfs", "encryptFstab", formattable_entry->blk_device,
+ formattable_entry->mount_point, "true" /* shouldFormat */,
+ formattable_entry->fs_type,
+ formattable_entry->fs_mgr_flags.is_zoned ? "true" : "false",
+ std::to_string(formattable_entry->length),
+ android::base::Join(formattable_entry->user_devices, ' ')},
nullptr)) {
LERROR << "Encryption failed";
} else {
@@ -1633,7 +1664,7 @@
}
}
- if (fs_mgr_do_format(current_entry) == 0) {
+ if (fs_mgr_do_format(*formattable_entry) == 0) {
// Let's replay the mount actions.
i = top_idx - 1;
continue;
@@ -1749,12 +1780,12 @@
int ret = prepare_fs_for_mount(entry.blk_device, entry, mount_point);
// Wiped case doesn't require to try __mount below.
if (ret & FS_STAT_INVALID_MAGIC) {
- return FS_MGR_DOMNT_FAILED;
+ return FS_MGR_DOMNT_FAILED;
}
ret = __mount(entry.blk_device, mount_point, entry);
if (ret) {
- ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
+ ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
return ret;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7e4d5e5..84e4924 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -80,10 +80,8 @@
using namespace std::chrono_literals;
-bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
bool fs_mgr_is_device_unlocked();
-bool fs_mgr_is_ext4(const std::string& blk_device);
bool fs_mgr_is_f2fs(const std::string& blk_device);
bool fs_mgr_filesystem_available(const std::string& filesystem);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index af5ae2d..9cfa93f 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -104,6 +104,12 @@
// returned. Otherwise, it will use the current slot.
std::string fs_mgr_get_super_partition_name(int slot = -1);
+// Set readonly for the block device
+bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
+
+// Check if the block device has ext4 filesystem
+bool fs_mgr_is_ext4(const std::string& blk_device);
+
enum FsMgrUmountStatus : int {
SUCCESS = 0,
ERROR_UNKNOWN = 1 << 0,
diff --git a/fs_mgr/include/fs_mgr/roots.h b/fs_mgr/include/fs_mgr/roots.h
index 65c59cf..e19f9ad 100644
--- a/fs_mgr/include/fs_mgr/roots.h
+++ b/fs_mgr/include/fs_mgr/roots.h
@@ -29,6 +29,8 @@
// first match or nullptr.
FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path);
+std::vector<FstabEntry*> GetEntriesForPath(Fstab* fstab, const std::string& path);
+
// Make sure that the volume 'path' is on is mounted.
// * If 'mount_point' is nullptr, use mount point in fstab. Caller can call
// fs_mgr_ensure_path_unmounted() with the same 'path' argument to unmount.
diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp
index 21d2e2e..d344b2d 100644
--- a/fs_mgr/libfstab/fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -39,6 +39,10 @@
#include "fstab_priv.h"
#include "logging_macros.h"
+#if !defined(MS_LAZYTIME)
+#define MS_LAZYTIME (1 << 25)
+#endif
+
using android::base::EndsWith;
using android::base::ParseByteCount;
using android::base::ParseInt;
@@ -74,6 +78,7 @@
{"private", MS_PRIVATE},
{"slave", MS_SLAVE},
{"shared", MS_SHARED},
+ {"lazytime", MS_LAZYTIME},
{"defaults", 0},
};
diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h
index 5105da0..73cb175 100644
--- a/fs_mgr/libfstab/fstab_priv.h
+++ b/fs_mgr/libfstab/fstab_priv.h
@@ -39,9 +39,6 @@
void ImportBootconfigFromString(const std::string& bootconfig,
const std::function<void(std::string, std::string)>& fn);
-bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key,
- std::string* out);
-
void ImportKernelCmdlineFromString(const std::string& cmdline,
const std::function<void(std::string, std::string)>& fn);
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 1696daf..21fe017 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -153,5 +153,8 @@
// Return the "other" slot for the given slot suffix.
std::string OtherSlotSuffix(const std::string& suffix);
+bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key,
+ std::string* out);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index f297125..50efb03 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -91,6 +91,7 @@
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
+ "scratch_super.cpp",
],
}
@@ -110,6 +111,9 @@
static_libs: [
"libfs_mgr_binder",
],
+ whole_static_libs: [
+ "libselinux",
+ ],
}
cc_library {
@@ -128,6 +132,9 @@
static_libs: [
"libsnapshot_cow",
],
+ whole_static_libs: [
+ "libselinux",
+ ],
}
cc_library_static {
@@ -142,6 +149,7 @@
],
static_libs: [
"libfs_mgr",
+ "libselinux",
],
}
@@ -159,6 +167,9 @@
static_libs: [
"libfs_mgr",
],
+ whole_static_libs: [
+ "libselinux",
+ ],
}
cc_defaults {
@@ -241,6 +252,7 @@
"libfs_mgr",
"libgmock",
"libgtest",
+ "libselinux",
],
}
@@ -283,7 +295,6 @@
],
auto_gen_config: true,
require_root: true,
- compile_multilib: "first",
}
cc_test {
@@ -296,6 +307,15 @@
"vts",
"general-tests",
],
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
test_options: {
min_shipping_api_level: 30,
},
@@ -313,6 +333,7 @@
test_suites: [
"general-tests",
],
+ compile_multilib: "64",
test_options: {
// Legacy VAB launched in Android R.
min_shipping_api_level: 30,
@@ -351,6 +372,7 @@
],
srcs: [
"snapshotctl.cpp",
+ "scratch_super.cpp",
],
static_libs: [
"libbrotli",
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index e0969f4..19f3e02 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include "device_info.h"
+#include "scratch_super.h"
#include <android-base/logging.h>
#include <fs_mgr.h>
@@ -37,8 +38,24 @@
constexpr bool kIsRecovery = false;
#endif
+DeviceInfo::DeviceInfo() {
+ std::string scratch_device = android::snapshot::GetScratchOtaMetadataPartition();
+ if (!scratch_device.empty()) {
+ std::string scratch_metadata =
+ android::snapshot::MapScratchOtaMetadataPartition(scratch_device);
+ if (!scratch_metadata.empty()) {
+ SetMetadataDir(scratch_metadata);
+ SetTempMetadata();
+ }
+ }
+}
+
std::string DeviceInfo::GetMetadataDir() const {
- return "/metadata/ota"s;
+ return metadata_dir_;
+}
+
+void DeviceInfo::SetMetadataDir(const std::string& value) {
+ metadata_dir_ = value;
}
std::string DeviceInfo::GetSlotSuffix() const {
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index 9153abb..e93ec49 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -29,6 +29,7 @@
using MergeStatus = ::aidl::android::hardware::boot::MergeStatus;
public:
+ DeviceInfo();
std::string GetMetadataDir() const override;
std::string GetSlotSuffix() const override;
std::string GetOtherSlotSuffix() const override;
@@ -42,14 +43,19 @@
std::unique_ptr<IImageManager> OpenImageManager() const override;
bool IsFirstStageInit() const override;
android::dm::IDeviceMapper& GetDeviceMapper() override;
-
+ void SetMetadataDir(const std::string& value);
void set_first_stage_init(bool value) { first_stage_init_ = value; }
+ bool IsTempMetadata() const override { return temp_metadata_; }
+ void SetTempMetadata() { temp_metadata_ = true; }
private:
bool EnsureBootHal();
android::fs_mgr::PartitionOpener opener_;
bool first_stage_init_ = false;
+ // Default value
+ std::string metadata_dir_ = "/metadata/ota";
+ bool temp_metadata_ = false;
#ifdef LIBSNAPSHOT_USE_HAL
std::unique_ptr<::android::hal::BootControlClient> boot_control_;
#endif
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index deb2d6e..7ae55db 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -111,6 +111,7 @@
virtual bool IsFirstStageInit() const = 0;
virtual std::unique_ptr<IImageManager> OpenImageManager() const = 0;
virtual android::dm::IDeviceMapper& GetDeviceMapper() = 0;
+ virtual bool IsTempMetadata() const = 0;
// Helper method for implementing OpenImageManager.
std::unique_ptr<IImageManager> OpenImageManager(const std::string& gsid_dir) const;
@@ -329,6 +330,10 @@
// might be needed to perform first-stage mounts.
static bool IsSnapshotManagerNeeded();
+ // Map the temp OTA metadata partition from super
+ static bool MapTempOtaMetadataPartitionIfNeeded(
+ const std::function<bool(const std::string&)>& init);
+
// Helper function for second stage init to restorecon on the rollback indicator.
static std::string GetGlobalRollbackIndicatorPath();
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 620b03c..1cd6651 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -79,7 +79,7 @@
: TestDeviceInfo(fake_super) {
set_slot_suffix(slot_suffix);
}
- std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
+ std::string GetMetadataDir() const override { return metadata_dir_; }
std::string GetSlotSuffix() const override { return slot_suffix_; }
std::string GetOtherSlotSuffix() const override { return slot_suffix_ == "_a" ? "_b" : "_a"; }
std::string GetSuperDevice([[maybe_unused]] uint32_t slot) const override { return "super"; }
@@ -120,6 +120,7 @@
void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }
MergeStatus merge_status() const { return merge_status_; }
+ bool IsTempMetadata() const override { return temp_metadata_; }
private:
std::string slot_suffix_ = "_a";
@@ -129,6 +130,8 @@
bool first_stage_init_ = false;
std::unordered_set<uint32_t> unbootable_slots_;
android::dm::IDeviceMapper* dm_ = nullptr;
+ std::string metadata_dir_ = "/metadata/ota/test";
+ bool temp_metadata_ = false;
};
class DeviceMapperWrapper : public android::dm::IDeviceMapper {
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
index 871ed27..9e7cf7a2 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
@@ -82,7 +82,7 @@
CowOperationType type);
size_t GetCompressionFactor(const size_t blocks_to_compress, CowOperationType type) const;
- constexpr bool IsBlockAligned(const size_t size) {
+ constexpr bool IsBlockAligned(const uint64_t size) {
// These are the only block size supported. Block size beyond 256k
// may impact random read performance post OTA boot.
const size_t values[] = {4_KiB, 8_KiB, 16_KiB, 32_KiB, 64_KiB, 128_KiB, 256_KiB};
diff --git a/fs_mgr/libsnapshot/scratch_super.cpp b/fs_mgr/libsnapshot/scratch_super.cpp
new file mode 100644
index 0000000..805abf3
--- /dev/null
+++ b/fs_mgr/libsnapshot/scratch_super.cpp
@@ -0,0 +1,417 @@
+// Copyright (C) 2024 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <selinux/selinux.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ext4_utils/ext4_utils.h>
+
+#include <libsnapshot/snapshot.h>
+
+#include <fs_mgr.h>
+#include <fs_mgr_dm_linear.h>
+#include <fstab/fstab.h>
+#include <liblp/builder.h>
+#include <storage_literals/storage_literals.h>
+#include <algorithm>
+#include <filesystem>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "device_info.h"
+#include "scratch_super.h"
+
+using namespace std::literals;
+using namespace android::dm;
+using namespace android::fs_mgr;
+using namespace android::storage_literals;
+
+namespace android {
+namespace snapshot {
+
+static bool UmountScratch() {
+ auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
+ std::error_code ec;
+
+ if (std::filesystem::remove_all(ota_dir, ec) == static_cast<std::uintmax_t>(-1)) {
+ LOG(ERROR) << "Failed to remove OTA directory: " << ec.message();
+ return false;
+ }
+
+ if (umount(kOtaMetadataMount) != 0) {
+ PLOG(ERROR) << "UmountScratch failed";
+ return false;
+ }
+
+ LOG(INFO) << "umount scratch_super success";
+ return true;
+}
+
+bool CleanupScratchOtaMetadataIfPresent(const ISnapshotManager::IDeviceInfo* info) {
+ if (!UmountScratch()) {
+ return false;
+ }
+
+ std::unique_ptr<MetadataBuilder> builder;
+ const auto partition_name = android::base::Basename(kOtaMetadataMount);
+ const std::vector<int> slots = {0, 1};
+
+ if (info == nullptr) {
+ info = new android::snapshot::DeviceInfo();
+ }
+
+ std::string super_device;
+ if (info->IsTestDevice()) {
+ super_device = "super";
+ } else {
+ super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
+ }
+ const auto& opener = info->GetPartitionOpener();
+ std::string slot_suffix = info->GetSlotSuffix();
+ int slot = SlotNumberForSlotSuffix(slot_suffix);
+ // Walk both the slots and clean up metadata related to scratch space from
+ // both the slots.
+ for (auto slot : slots) {
+ std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(opener, super_device, slot);
+ if (!builder) {
+ return false;
+ }
+
+ if (builder->FindPartition(partition_name) != nullptr) {
+ builder->RemovePartition(partition_name);
+ auto metadata = builder->Export();
+ if (!metadata) {
+ return false;
+ }
+ if (!UpdatePartitionTable(info->GetPartitionOpener(), super_device, *metadata.get(),
+ slot)) {
+ LOG(ERROR) << "UpdatePartitionTable failed for slot: " << slot;
+ return false;
+ }
+ if (DestroyLogicalPartition(partition_name)) {
+ LOG(INFO) << "CleanupScratchOtaMetadata success for slot: " << slot;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool SetupOTADirs() {
+ if (setfscreatecon(android::snapshot::kOtaMetadataFileContext)) {
+ PLOG(ERROR) << "setfscreatecon failed: " << android::snapshot::kOtaMetadataFileContext;
+ return false;
+ }
+ const auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
+ if (mkdir(ota_dir.c_str(), 0755) != 0 && errno != EEXIST) {
+ PLOG(ERROR) << "mkdir " << ota_dir;
+ return false;
+ }
+
+ const auto snapshot_dir = ota_dir + "/" + "snapshots";
+ if (mkdir(snapshot_dir.c_str(), 0755) != 0 && errno != EEXIST) {
+ PLOG(ERROR) << "mkdir " << snapshot_dir;
+ return false;
+ }
+ if (setfscreatecon(nullptr)) {
+ PLOG(ERROR) << "setfscreatecon null";
+ return false;
+ }
+ return true;
+}
+
+static bool MountScratch(const std::string& device_path) {
+ if (access(device_path.c_str(), R_OK | W_OK)) {
+ LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
+ return false;
+ }
+
+ std::string filesystem_candidate;
+ if (fs_mgr_is_ext4(device_path)) {
+ filesystem_candidate = "ext4";
+ } else {
+ LOG(ERROR) << "Scratch partition is not ext4";
+ return false;
+ }
+ if (setfscreatecon(android::snapshot::kOtaMetadataFileContext)) {
+ PLOG(ERROR) << "setfscreatecon failed: " << android::snapshot::kOtaMetadataFileContext;
+ return false;
+ }
+ if (mkdir(kOtaMetadataMount, 0755) && (errno != EEXIST)) {
+ PLOG(ERROR) << "create " << kOtaMetadataMount;
+ return false;
+ }
+
+ android::fs_mgr::FstabEntry entry;
+ entry.blk_device = device_path;
+ entry.mount_point = kOtaMetadataMount;
+ entry.flags = MS_NOATIME;
+ entry.flags |= MS_SYNCHRONOUS;
+ entry.fs_options = "nodiscard";
+ fs_mgr_set_blk_ro(device_path, false);
+ entry.fs_mgr_flags.check = true;
+
+ bool mounted = false;
+ entry.fs_type = filesystem_candidate.c_str();
+ if (fs_mgr_do_mount_one(entry) == 0) {
+ mounted = true;
+ }
+
+ if (setfscreatecon(nullptr)) {
+ PLOG(ERROR) << "setfscreatecon null";
+ return false;
+ }
+ if (!mounted) {
+ rmdir(kOtaMetadataMount);
+ return false;
+ }
+
+ return true;
+}
+
+static bool MakeScratchFilesystem(const std::string& scratch_device) {
+ std::string fs_type;
+ std::string command;
+ if (!access(kMkExt4, X_OK)) {
+ fs_type = "ext4";
+ command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M "s + kOtaMetadataMount;
+ } else {
+ LOG(ERROR) << "No supported mkfs command or filesystem driver available, supported "
+ "filesystems "
+ "are: f2fs, ext4";
+ return false;
+ }
+ command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null";
+ fs_mgr_set_blk_ro(scratch_device, false);
+ auto ret = system(command.c_str());
+ if (ret) {
+ LOG(ERROR) << "make " << fs_type << " filesystem on " << scratch_device
+ << " return=" << ret;
+ return false;
+ }
+ return true;
+}
+
+static bool CreateDynamicScratch(const ISnapshotManager::IDeviceInfo* info,
+ std::string* scratch_device) {
+ const auto partition_name = android::base::Basename(kOtaMetadataMount);
+ auto& dm = DeviceMapper::Instance();
+ if (info == nullptr) {
+ info = new android::snapshot::DeviceInfo();
+ }
+
+ std::string super_device;
+ if (info->IsTestDevice()) {
+ super_device = "super";
+ } else {
+ super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
+ }
+
+ bool partition_exists = dm.GetState(partition_name) != DmDeviceState::INVALID;
+ if (partition_exists) {
+ LOG(ERROR) << "Partition already exists: " << partition_name;
+ return false;
+ }
+
+ const auto& opener = info->GetPartitionOpener();
+ std::string slot_suffix = info->GetSlotSuffix();
+ int slot = SlotNumberForSlotSuffix(slot_suffix);
+ std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(opener, super_device, slot);
+
+ if (!builder) {
+ LOG(ERROR) << "open " << super_device << " failed";
+ return false;
+ }
+
+ auto partition = builder->FindPartition(partition_name);
+ partition_exists = partition != nullptr;
+ if (partition_exists) {
+ LOG(ERROR) << "Partition exists in super metadata";
+ return false;
+ }
+
+ partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+ if (!partition) {
+ LOG(ERROR) << "AddPartition failed " << partition_name;
+ return false;
+ }
+
+ auto free_space = builder->AllocatableSpace() - builder->UsedSpace();
+ if (free_space < kOtaMetadataPartitionSize) {
+ LOG(ERROR) << "No space in super partition. Free space: " << free_space
+ << " Requested space: " << kOtaMetadataPartitionSize;
+ return false;
+ }
+
+ LOG(INFO) << "CreateDynamicScratch: free_space: " << free_space
+ << " scratch_size: " << kOtaMetadataPartitionSize << " slot_number: " << slot;
+
+ if (!builder->ResizePartition(partition, kOtaMetadataPartitionSize)) {
+ LOG(ERROR) << "ResizePartition failed: " << partition_name << " free_space: " << free_space
+ << " scratch_size: " << kOtaMetadataPartitionSize;
+ return false;
+ }
+
+ auto metadata = builder->Export();
+ CreateLogicalPartitionParams params;
+
+ if (!metadata ||
+ !UpdatePartitionTable(info->GetPartitionOpener(), super_device, *metadata.get(), slot)) {
+ LOG(ERROR) << "UpdatePartitionTable failed: " << partition_name;
+ return false;
+ }
+ params = {
+ .block_device = super_device,
+ .metadata_slot = slot,
+ .partition_name = partition_name,
+ .force_writable = true,
+ .timeout_ms = 10s,
+ .partition_opener = &info->GetPartitionOpener(),
+ };
+
+ if (!CreateLogicalPartition(params, scratch_device)) {
+ LOG(ERROR) << "CreateLogicalPartition failed";
+ return false;
+ }
+
+ LOG(INFO) << "Scratch device created successfully: " << *scratch_device << " slot: " << slot;
+ return true;
+}
+
+bool IsScratchOtaMetadataOnSuper() {
+ auto partition_name = android::base::Basename(kOtaMetadataMount);
+ auto source_slot = fs_mgr_get_slot_suffix();
+ auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
+
+ const auto super_device =
+ kPhysicalDevice + fs_mgr_get_super_partition_name(!source_slot_number);
+
+ auto metadata = android::fs_mgr::ReadMetadata(super_device, !source_slot_number);
+ if (!metadata) {
+ return false;
+ }
+ auto partition = android::fs_mgr::FindPartition(*metadata.get(), partition_name);
+ if (!partition) {
+ return false;
+ }
+
+ auto& dm = DeviceMapper::Instance();
+ if (dm.GetState(partition_name) == DmDeviceState::ACTIVE) {
+ LOG(INFO) << "Partition: " << partition_name << " is active";
+ return true;
+ }
+
+ CreateLogicalPartitionParams params = {
+ .block_device = super_device,
+ .metadata = metadata.get(),
+ .partition = partition,
+ };
+
+ std::string scratch_path;
+ if (!CreateLogicalPartition(params, &scratch_path)) {
+ LOG(ERROR) << "Could not create logical partition: " << partition_name;
+ return false;
+ }
+ LOG(INFO) << "Scratch device: " << scratch_path << " created successfully";
+
+ return true;
+}
+
+std::string GetScratchOtaMetadataPartition() {
+ std::string device;
+ auto& dm = DeviceMapper::Instance();
+ auto partition_name = android::base::Basename(kOtaMetadataMount);
+
+ bool invalid_partition = (dm.GetState(partition_name) == DmDeviceState::INVALID);
+ if (!invalid_partition && dm.GetDmDevicePathByName(partition_name, &device)) {
+ return device;
+ }
+ return "";
+}
+
+static bool ScratchAlreadyMounted(const std::string& mount_point) {
+ android::fs_mgr::Fstab fstab;
+ if (!ReadFstabFromProcMounts(&fstab)) {
+ return false;
+ }
+ for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) {
+ if (entry->fs_type == "ext4") {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string MapScratchOtaMetadataPartition(const std::string& scratch_device) {
+ if (!ScratchAlreadyMounted(kOtaMetadataMount)) {
+ if (!MountScratch(scratch_device)) {
+ return "";
+ }
+ }
+
+ auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
+ if (access(ota_dir.c_str(), F_OK) != 0) {
+ return "";
+ }
+ return ota_dir;
+}
+
+// Entry point to create a scratch device on super partition
+// This will create a 1MB space in super. The space will be
+// from the current active slot. Ext4 filesystem will be created
+// on this scratch device and all the OTA related directories
+// will be created.
+bool CreateScratchOtaMetadataOnSuper(const ISnapshotManager::IDeviceInfo* info) {
+ std::string scratch_device;
+
+ if (!CreateDynamicScratch(info, &scratch_device)) {
+ LOG(ERROR) << "CreateDynamicScratch failed";
+ return false;
+ }
+ if (!MakeScratchFilesystem(scratch_device)) {
+ LOG(ERROR) << "MakeScratchFilesystem failed";
+ return false;
+ }
+ if (!MountScratch(scratch_device)) {
+ LOG(ERROR) << "MountScratch failed";
+ return false;
+ }
+ if (!SetupOTADirs()) {
+ LOG(ERROR) << "SetupOTADirs failed";
+ return false;
+ }
+ return true;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/scratch_super.h b/fs_mgr/libsnapshot/scratch_super.h
new file mode 100644
index 0000000..3e6fe70
--- /dev/null
+++ b/fs_mgr/libsnapshot/scratch_super.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 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
+
+namespace android {
+namespace snapshot {
+
+constexpr char kMkExt4[] = "/system/bin/mke2fs";
+constexpr char kOtaMetadataFileContext[] = "u:object_r:ota_metadata_file:s0";
+constexpr char kOtaMetadataMount[] = "/mnt/scratch_ota_metadata_super";
+const size_t kOtaMetadataPartitionSize = uint64_t(1 * 1024 * 1024);
+constexpr char kPhysicalDevice[] = "/dev/block/by-name/";
+
+bool IsScratchOtaMetadataOnSuper();
+std::string GetScratchOtaMetadataPartition();
+std::string MapScratchOtaMetadataPartition(const std::string& device);
+bool CreateScratchOtaMetadataOnSuper(const ISnapshotManager::IDeviceInfo* info = nullptr);
+bool CleanupScratchOtaMetadataIfPresent(const ISnapshotManager::IDeviceInfo* info = nullptr);
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 108fd90..6c3bedd 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -48,6 +48,7 @@
#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
#include "partition_cow_creator.h"
+#include "scratch_super.h"
#include "snapshot_metadata_updater.h"
#include "utility.h"
@@ -117,7 +118,11 @@
info = new DeviceInfo();
}
- return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
+ auto sm = std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
+ if (info->IsTempMetadata()) {
+ LOG(INFO) << "Using temp metadata from super";
+ }
+ return sm;
}
std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) {
@@ -1110,6 +1115,13 @@
if (result.state == UpdateState::MergeFailed) {
AcknowledgeMergeFailure(result.failure_code);
}
+
+ if (result.state == UpdateState::MergeCompleted) {
+ if (device_->IsTempMetadata()) {
+ CleanupScratchOtaMetadataIfPresent();
+ }
+ }
+
if (result.state != UpdateState::Merging) {
// Either there is no merge, or the merge was finished, so no need
// to keep waiting.
@@ -2310,7 +2322,27 @@
}
bool SnapshotManager::IsSnapshotManagerNeeded() {
- return access(kBootIndicatorPath, F_OK) == 0;
+ if (access(kBootIndicatorPath, F_OK) == 0) {
+ return true;
+ }
+
+ if (IsScratchOtaMetadataOnSuper()) {
+ return true;
+ }
+
+ return false;
+}
+
+bool SnapshotManager::MapTempOtaMetadataPartitionIfNeeded(
+ const std::function<bool(const std::string&)>& init) {
+ auto device = android::snapshot::GetScratchOtaMetadataPartition();
+ if (!device.empty()) {
+ init(device);
+ if (android::snapshot::MapScratchOtaMetadataPartition(device).empty()) {
+ return false;
+ }
+ }
+ return true;
}
std::string SnapshotManager::GetGlobalRollbackIndicatorPath() {
@@ -2397,6 +2429,12 @@
continue;
}
+ if (GetPartitionName(partition) ==
+ android::base::Basename(android::snapshot::kOtaMetadataMount)) {
+ LOG(INFO) << "Partition: " << GetPartitionName(partition) << " skipping";
+ continue;
+ }
+
CreateLogicalPartitionParams params = {
.block_device = super_device,
.metadata = metadata.get(),
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 16c247f..46c3a35 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -47,6 +47,7 @@
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/test_helpers.h>
#include "partition_cow_creator.h"
+#include "scratch_super.h"
#include "utility.h"
// Mock classes are not used. Header included to ensure mocked class definition aligns with the
@@ -1342,6 +1343,15 @@
DynamicPartitionGroup* group_ = nullptr;
};
+TEST_F(SnapshotUpdateTest, SuperOtaMetadataTest) {
+ auto info = new TestDeviceInfo(fake_super);
+ ASSERT_TRUE(CreateScratchOtaMetadataOnSuper(info));
+ std::string scratch_device = GetScratchOtaMetadataPartition();
+ ASSERT_NE(scratch_device, "");
+ ASSERT_NE(MapScratchOtaMetadataPartition(scratch_device), "");
+ ASSERT_TRUE(CleanupScratchOtaMetadataIfPresent(info));
+}
+
// Test full update flow executed by update_engine. Some partitions uses super empty space,
// some uses images, and some uses both.
// Also test UnmapUpdateSnapshot unmaps everything.
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 0158d4d..97a8cb2 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -16,7 +16,6 @@
#include <sysexits.h>
#include <unistd.h>
-
#include <chrono>
#include <filesystem>
#include <fstream>
@@ -46,6 +45,7 @@
#include <storage_literals/storage_literals.h>
#include "partition_cow_creator.h"
+#include "scratch_super.h"
#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
#include <BootControlClient.h>
@@ -57,6 +57,8 @@
using android::base::LogdLogger;
using android::base::StderrLogger;
using android::base::TeeLogger;
+using namespace android::dm;
+using namespace android::fs_mgr;
using android::fs_mgr::CreateLogicalPartitionParams;
using android::fs_mgr::FindPartition;
using android::fs_mgr::GetPartitionSize;
@@ -97,7 +99,7 @@
#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
class MapSnapshots {
public:
- MapSnapshots(std::string path = "");
+ MapSnapshots(std::string path = "", bool metadata_super = false);
bool CreateSnapshotDevice(std::string& partition_name, std::string& patch);
bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch);
bool FinishSnapshotWrites();
@@ -122,15 +124,12 @@
std::vector<std::string> patchfiles_;
chromeos_update_engine::DeltaArchiveManifest manifest_;
+ bool metadata_super_ = false;
};
-MapSnapshots::MapSnapshots(std::string path) {
- sm_ = SnapshotManager::New();
- if (!sm_) {
- std::cout << "Failed to create snapshotmanager";
- exit(1);
- }
+MapSnapshots::MapSnapshots(std::string path, bool metadata_super) {
snapshot_dir_path_ = path + "/";
+ metadata_super_ = metadata_super;
}
std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
@@ -150,6 +149,12 @@
}
bool MapSnapshots::PrepareUpdate() {
+ if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
+ LOG(ERROR) << "Failed to create OTA metadata on super";
+ return false;
+ }
+ sm_ = SnapshotManager::New();
+
auto source_slot = fs_mgr_get_slot_suffix();
auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
@@ -234,7 +239,17 @@
bool MapSnapshots::GetCowDevicePath(std::string partition_name, std::string* cow_path) {
auto& dm = android::dm::DeviceMapper::Instance();
- std::string cow_device = partition_name + "-cow";
+
+ std::string cow_device = partition_name + "-cow-img";
+ if (metadata_super_) {
+ // If COW device exists on /data, then data wipe cannot be done.
+ if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
+ LOG(ERROR) << "COW device exists on /data: " << *cow_path;
+ return false;
+ }
+ }
+
+ cow_device = partition_name + "-cow";
if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
return true;
}
@@ -321,6 +336,12 @@
}
bool MapSnapshots::BeginUpdate() {
+ if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
+ LOG(ERROR) << "Failed to create OTA metadata on super";
+ return false;
+ }
+ sm_ = SnapshotManager::New();
+
lock_ = sm_->LockExclusive();
std::vector<std::string> snapshots;
sm_->ListSnapshots(lock_.get(), &snapshots);
@@ -470,10 +491,12 @@
}
bool MapSnapshots::UnmapCowImagePath(std::string& name) {
+ sm_ = SnapshotManager::New();
return sm_->UnmapCowImage(name);
}
bool MapSnapshots::DeleteSnapshots() {
+ sm_ = SnapshotManager::New();
lock_ = sm_->LockExclusive();
if (!sm_->RemoveAllUpdateState(lock_.get())) {
LOG(ERROR) << "Remove All Update State failed";
@@ -583,13 +606,19 @@
}
if (argc < 3) {
- std::cerr << " apply-update <directory location where snapshot patches are present>"
+ std::cerr << " apply-update <directory location where snapshot patches are present> {-w}"
" Apply the snapshots to the COW block device\n";
return false;
}
std::string path = std::string(argv[2]);
- MapSnapshots cow(path);
+ bool metadata_on_super = false;
+ if (argc == 4) {
+ if (std::string(argv[3]) == "-w") {
+ metadata_on_super = true;
+ }
+ }
+ MapSnapshots cow(path, metadata_on_super);
if (!cow.ApplyUpdate()) {
return false;
}
@@ -607,7 +636,7 @@
}
if (argc < 3) {
- std::cerr << " map-snapshots <directory location where snapshot patches are present>"
+ std::cerr << " map-snapshots <directory location where snapshot patches are present> {-w}"
" Map all snapshots based on patches present in the directory\n";
return false;
}
@@ -638,7 +667,14 @@
}
}
- MapSnapshots cow(path);
+ bool metadata_on_super = false;
+ if (argc == 4) {
+ if (std::string(argv[3]) == "-w") {
+ metadata_on_super = true;
+ }
+ }
+
+ MapSnapshots cow(path, metadata_on_super);
if (!cow.BeginUpdate()) {
LOG(ERROR) << "BeginUpdate failed";
return false;
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index efbcb5a..298fd9f 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -42,6 +42,7 @@
static_libs: [
"libcutils_sockets",
"libfs_mgr_file_wait",
+ "libdm",
],
shared_libs: [
"libbase",
@@ -169,7 +170,7 @@
recovery_available: true,
}
-// This target will install to /system/bin/snapuserd_ramdisk
+// This target will install to /system/bin/snapuserd_ramdisk
// It will also create a symblink on /system/bin/snapuserd that point to
// /system/bin/snapuserd_ramdisk .
// This way, init can check if generic ramdisk copy exists.
@@ -238,9 +239,19 @@
test_options: {
min_shipping_api_level: 30,
},
+
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
auto_gen_config: true,
require_root: true,
- compile_multilib: "first",
}
cc_test {
@@ -248,7 +259,7 @@
defaults: ["snapuserd_test_defaults"],
host_supported: true,
test_suites: [
- "device-tests",
+ "general-tests",
],
test_options: {
test_runner_options: [
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
index 789c980..ddefb9f 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
@@ -35,6 +35,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr/file_wait.h>
+#include <libdm/dm.h>
#include <snapuserd/snapuserd_client.h>
namespace android {
@@ -333,7 +334,21 @@
}
std::string SnapuserdClient::GetDaemonAliveIndicatorPath() {
- return "/metadata/ota/" + std::string(kDaemonAliveIndicator);
+ std::string metadata_dir;
+ std::string temp_metadata_mnt = "/mnt/scratch_ota_metadata_super";
+
+ auto& dm = ::android::dm::DeviceMapper::Instance();
+ auto partition_name = android::base::Basename(temp_metadata_mnt);
+
+ bool invalid_partition = (dm.GetState(partition_name) == dm::DmDeviceState::INVALID);
+ std::string temp_device;
+ if (!invalid_partition && dm.GetDmDevicePathByName(partition_name, &temp_device)) {
+ metadata_dir = temp_metadata_mnt + "/" + "ota/";
+ } else {
+ metadata_dir = "/metadata/ota/";
+ }
+
+ return metadata_dir + std::string(kDaemonAliveIndicator);
}
bool SnapuserdClient::IsTransitionedDaemonReady() {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
index 04b2736..378d809 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
@@ -57,7 +57,7 @@
bool ReadFromSourceDevice(const CowOperation* cow_op, void* buffer);
bool ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size);
- constexpr bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); }
+ constexpr bool IsBlockAligned(uint64_t size) { return ((size & (BLOCK_SZ - 1)) == 0); }
constexpr sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
constexpr chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index bd3d6b5..6522c02 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -37,6 +37,10 @@
using namespace android::fs_mgr;
using namespace testing;
+#if !defined(MS_LAZYTIME)
+#define MS_LAZYTIME (1 << 25)
+#endif
+
namespace {
const std::string cmdline =
@@ -329,6 +333,7 @@
{"private", MS_PRIVATE},
{"slave", MS_SLAVE},
{"shared", MS_SHARED},
+ {"lazytime", MS_LAZYTIME},
{"defaults", 0},
{0, 0},
};
diff --git a/init/Android.bp b/init/Android.bp
index ed1f148..18a79d6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -38,7 +38,6 @@
"capabilities.cpp",
"epoll.cpp",
"import_parser.cpp",
- "interface_utils.cpp",
"interprocess_fifo.cpp",
"keychords.cpp",
"parser.cpp",
@@ -85,10 +84,6 @@
"ueventd.cpp",
"ueventd_parser.cpp",
]
-init_host_sources = [
- "check_builtins.cpp",
- "host_import_parser.cpp",
-]
soong_config_module_type {
name: "libinit_cc_defaults",
@@ -190,7 +185,6 @@
"libext4_utils",
"libfs_mgr",
"libgsi",
- "libhidl-gen-utils",
"liblog",
"liblogwrap",
"liblp",
@@ -607,8 +601,6 @@
whole_static_libs: ["libcap"],
shared_libs: [
"libcutils",
- "libhidl-gen-utils",
- "libhidlmetadata",
"liblog",
"libprocessgroup",
"libprotobuf-cpp-lite",
@@ -616,9 +608,6 @@
proto: {
type: "lite",
},
- generated_headers: [
- "generated_stub_builtin_function_map",
- ],
target: {
android: {
enabled: false,
@@ -637,17 +626,43 @@
cc_binary {
name: "host_init_verifier",
defaults: ["init_host_defaults"],
- srcs: ["host_init_verifier.cpp"] + init_common_sources + init_host_sources,
+ srcs: [
+ "check_builtins.cpp",
+ "host_import_parser.cpp",
+ "host_init_verifier.cpp",
+ "interface_utils.cpp",
+ ] + init_common_sources,
generated_headers: [
"generated_android_ids",
+ "generated_stub_builtin_function_map",
],
+ shared_libs: [
+ "libhidl-gen-utils",
+ "libhidlmetadata",
+ ],
+}
+
+genrule {
+ name: "noop_builtin_function_map",
+ tool_files: ["host_builtin_map.py"],
+ out: ["noop_builtin_function_map.h"],
+ srcs: [
+ "builtins.cpp",
+ "noop_builtins.cpp",
+ ],
+ cmd: "$(location host_builtin_map.py) --builtins $(location builtins.cpp) --check_builtins $(location noop_builtins.cpp) > $(out)",
}
cc_library_host_static {
name: "libinit_host",
defaults: ["init_host_defaults"],
- srcs: init_common_sources + init_host_sources,
+ srcs: [
+ "noop_builtins.cpp",
+ ] + init_common_sources,
export_include_dirs: ["."],
+ generated_headers: [
+ "noop_builtin_function_map",
+ ],
proto: {
export_proto_headers: true,
},
diff --git a/init/devices.cpp b/init/devices.cpp
index 5560c20..f2bb9d2 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -283,7 +283,7 @@
void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const {
- auto[mode, uid, gid] = GetDevicePermissions(path, links);
+ auto [mode, uid, gid] = GetDevicePermissions(path, links);
mode |= (block ? S_IFBLK : S_IFCHR);
std::string secontext;
@@ -330,11 +330,11 @@
if (gid != s.st_gid) {
new_group = gid;
}
- if (mode != s.st_mode) {
- if (chmod(path.c_str(), mode) != 0) {
- PLOG(ERROR) << "Cannot chmod " << path << " to " << mode;
+ if (mode != s.st_mode) {
+ if (chmod(path.c_str(), mode) != 0) {
+ PLOG(ERROR) << "Cannot chmod " << path << " to " << mode;
+ }
}
- }
} else {
PLOG(ERROR) << "Cannot stat " << path;
}
@@ -531,7 +531,7 @@
if (!ReadFileToString(boot_id_path, &boot_id)) {
PLOG(ERROR) << "Cannot duplicate ashmem device node. Failed to read " << boot_id_path;
return;
- };
+ }
boot_id = Trim(boot_id);
Uevent dup_ashmem_uevent = uevent;
@@ -542,10 +542,10 @@
}
void DeviceHandler::HandleUevent(const Uevent& uevent) {
- if (uevent.action == "add" || uevent.action == "change" ||
- uevent.action == "bind" || uevent.action == "online") {
- FixupSysPermissions(uevent.path, uevent.subsystem);
- }
+ if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" ||
+ uevent.action == "online") {
+ FixupSysPermissions(uevent.path, uevent.subsystem);
+ }
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index bfe636b..e06a645 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -38,6 +38,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android/avf_cc_flags.h>
+#include <fs_mgr.h>
#include <modprobe/modprobe.h>
#include <private/android_filesystem_config.h>
@@ -303,6 +304,22 @@
return BootMode::NORMAL_MODE;
}
+static void MaybeResumeFromHibernation(const std::string& bootconfig) {
+ std::string hibernationResumeDevice;
+ android::fs_mgr::GetBootconfigFromString(bootconfig, "androidboot.hibernation_resume_device",
+ &hibernationResumeDevice);
+ if (!hibernationResumeDevice.empty()) {
+ android::base::unique_fd fd(open("/sys/power/resume", O_RDWR | O_CLOEXEC));
+ if (fd >= 0) {
+ if (!android::base::WriteStringToFd(hibernationResumeDevice, fd)) {
+ PLOG(ERROR) << "Failed to write to /sys/power/resume";
+ }
+ } else {
+ PLOG(ERROR) << "Failed to open /sys/power/resume";
+ }
+ }
+}
+
static std::unique_ptr<FirstStageMount> CreateFirstStageMount(const std::string& cmdline) {
auto ret = FirstStageMount::Create(cmdline);
if (ret.ok()) {
@@ -442,6 +459,8 @@
<< module_elapse_time.count() << " ms";
}
+ MaybeResumeFromHibernation(bootconfig);
+
std::unique_ptr<FirstStageMount> fsm;
bool created_devices = false;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 927b45f..ece430b 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -371,6 +371,14 @@
}
if (SnapshotManager::IsSnapshotManagerNeeded()) {
+ auto init_devices = [this](const std::string& device) -> bool {
+ if (android::base::StartsWith(device, "/dev/block/dm-")) {
+ return block_dev_init_.InitDmDevice(device);
+ }
+ return block_dev_init_.InitDevices({device});
+ };
+
+ SnapshotManager::MapTempOtaMetadataPartitionIfNeeded(init_devices);
auto sm = SnapshotManager::NewForFirstStageMount();
if (!sm) {
return false;
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
index 5823932..8cfd597 100644
--- a/init/fuzzer/Android.bp
+++ b/init/fuzzer/Android.bp
@@ -30,7 +30,6 @@
shared_libs: [
"libbase",
"libfs_mgr",
- "libhidl-gen-utils",
"liblog",
"libprocessgroup",
"libselinux",
@@ -49,7 +48,6 @@
srcs: [
"init_parser_fuzzer.cpp",
],
- shared_libs: ["libhidlmetadata",],
defaults: [
"libinit_fuzzer_defaults",
],
diff --git a/init/fuzzer/init_parser_fuzzer.cpp b/init/fuzzer/init_parser_fuzzer.cpp
index dc76465..21b04f4 100644
--- a/init/fuzzer/init_parser_fuzzer.cpp
+++ b/init/fuzzer/init_parser_fuzzer.cpp
@@ -15,9 +15,7 @@
*/
#include <fuzzer/FuzzedDataProvider.h>
-#include <hidl/metadata.h>
#include <import_parser.h>
-#include <interface_utils.h>
#include <rlimit_parser.h>
using namespace android;
@@ -34,7 +32,6 @@
};
const int32_t kMaxBytes = 256;
-const std::string kValidInterfaces = "android.frameworks.vr.composer@2.0::IVrComposerClient";
class InitParserFuzzer {
public:
@@ -44,9 +41,6 @@
private:
void InvokeParser();
void InvokeLimitParser();
- void InvokeInterfaceUtils();
- InterfaceInheritanceHierarchyMap GenerateHierarchyMap();
- std::vector<HidlInterfaceMetadata> GenerateInterfaceMetadata();
FuzzedDataProvider fdp_;
};
@@ -64,60 +58,6 @@
}
}
-std::vector<HidlInterfaceMetadata> InitParserFuzzer::GenerateInterfaceMetadata() {
- std::vector<HidlInterfaceMetadata> random_interface;
- for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
- HidlInterfaceMetadata metadata;
- metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
- for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral<size_t>(); ++idx1) {
- metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
- }
- random_interface.push_back(metadata);
- }
- return random_interface;
-}
-
-InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
- InterfaceInheritanceHierarchyMap result;
- std::vector<HidlInterfaceMetadata> random_interface;
- if (fdp_.ConsumeBool()) {
- random_interface = GenerateInterfaceMetadata();
- } else {
- random_interface = HidlInterfaceMetadata::all();
- }
-
- for (const HidlInterfaceMetadata& iface : random_interface) {
- std::set<FQName> inherited_interfaces;
- for (const std::string& intf : iface.inherited) {
- FQName fqname;
- (void)fqname.setTo(intf);
- inherited_interfaces.insert(fqname);
- }
- FQName fqname;
- (void)fqname.setTo(iface.name);
- result[fqname] = inherited_interfaces;
- }
- return result;
-}
-
-void InitParserFuzzer::InvokeInterfaceUtils() {
- InterfaceInheritanceHierarchyMap hierarchy_map = GenerateHierarchyMap();
- SetKnownInterfaces(hierarchy_map);
- IsKnownInterface(fdp_.ConsumeRandomLengthString(kMaxBytes));
- std::set<std::string> interface_set;
- for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
- auto set_interface_values = fdp_.PickValueInArray<const std::function<void()>>({
- [&]() {
- interface_set.insert(("aidl/" + fdp_.ConsumeRandomLengthString(kMaxBytes)));
- },
- [&]() { interface_set.insert(fdp_.ConsumeRandomLengthString(kMaxBytes)); },
- [&]() { interface_set.insert(kValidInterfaces); },
- });
- set_interface_values();
- }
- CheckInterfaceInheritanceHierarchy(interface_set, hierarchy_map);
-}
-
void InitParserFuzzer::InvokeParser() {
Parser parser;
std::string name = fdp_.ConsumeBool() ? fdp_.ConsumeRandomLengthString(kMaxBytes) : "import";
@@ -132,7 +72,6 @@
while (fdp_.remaining_bytes()) {
auto invoke_parser_fuzzer = fdp_.PickValueInArray<const std::function<void()>>({
[&]() { InvokeParser(); },
- [&]() { InvokeInterfaceUtils(); },
[&]() { InvokeLimitParser(); },
});
invoke_parser_fuzzer();
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index f746ab9..287857a 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -297,9 +297,7 @@
ActionManager& am = ActionManager::GetInstance();
ServiceList& sl = ServiceList::GetInstance();
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&sl, GetSubcontext(),
- *interface_inheritance_hierarchy_map));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sl, GetSubcontext()));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, GetSubcontext()));
parser.AddSectionParser("import", std::make_unique<HostImportParser>());
@@ -317,11 +315,23 @@
return EXIT_FAILURE;
}
}
+
size_t failures = parser.parse_error_count() + am.CheckAllCommands() + sl.CheckAllCommands();
if (failures > 0) {
LOG(ERROR) << "Failed to parse init scripts with " << failures << " error(s).";
return EXIT_FAILURE;
}
+
+ for (const auto& service : sl) {
+ if (const auto& result = CheckInterfaceInheritanceHierarchy(
+ service->interfaces(), *interface_inheritance_hierarchy_map);
+ !result.ok()) {
+ LOG(ERROR) << service->filename() << ": invalid interface in service '"
+ << service->name() << "': " << result.error();
+ return EXIT_FAILURE;
+ }
+ }
+
return EXIT_SUCCESS;
}
diff --git a/init/init.cpp b/init/init.cpp
index 4878660..6c80899 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -268,8 +268,8 @@
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
- parser.AddSectionParser("service", std::make_unique<ServiceParser>(
- &service_list, GetSubcontext(), std::nullopt));
+ parser.AddSectionParser("service",
+ std::make_unique<ServiceParser>(&service_list, GetSubcontext()));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
@@ -324,9 +324,7 @@
}
}
#endif // RECOVERY
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, subcontext,
- std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontext));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontext));
return parser;
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 5088273..f280de9 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -62,8 +62,7 @@
Action::set_function_map(&test_function_map);
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(service_list, nullptr));
parser.AddSectionParser("on", std::make_unique<ActionParser>(action_manager, nullptr));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
@@ -625,8 +624,7 @@
ServiceList service_list;
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
ASSERT_TRUE(parser.ParseConfig(tf.path));
@@ -657,8 +655,7 @@
ServiceList service_list;
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
ASSERT_TRUE(parser.ParseConfig(tf.path));
ASSERT_EQ(1u, parser.parse_error_count());
diff --git a/init/interface_utils.cpp b/init/interface_utils.cpp
index 1b76bba..84407aa 100644
--- a/init/interface_utils.cpp
+++ b/init/interface_utils.cpp
@@ -39,27 +39,6 @@
return android::base::Join(fqname_strings, " ");
}
-} // namespace
-
-Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
- const InterfaceInheritanceHierarchyMap& hierarchy) {
- std::set<FQName> interface_fqnames;
- for (const std::string& instance : instances) {
- // There is insufficient build-time information on AIDL interfaces to check them here
- // TODO(b/139307527): Rework how services store interfaces to avoid excess string parsing
- if (base::Split(instance, "/")[0] == "aidl") {
- continue;
- }
-
- FqInstance fqinstance;
- if (!fqinstance.setTo(instance)) {
- return Error() << "Unable to parse interface instance '" << instance << "'";
- }
- interface_fqnames.insert(fqinstance.getFqName());
- }
- return CheckInterfaceInheritanceHierarchy(interface_fqnames, hierarchy);
-}
-
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<FQName>& interfaces,
const InterfaceInheritanceHierarchyMap& hierarchy) {
std::ostringstream error_stream;
@@ -90,6 +69,27 @@
return {};
}
+} // namespace
+
+Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
+ const InterfaceInheritanceHierarchyMap& hierarchy) {
+ std::set<FQName> interface_fqnames;
+ for (const std::string& instance : instances) {
+ // There is insufficient build-time information on AIDL interfaces to check them here
+ // TODO(b/139307527): Rework how services store interfaces to avoid excess string parsing
+ if (base::Split(instance, "/")[0] == "aidl") {
+ continue;
+ }
+
+ FqInstance fqinstance;
+ if (!fqinstance.setTo(instance)) {
+ return Error() << "Unable to parse interface instance '" << instance << "'";
+ }
+ interface_fqnames.insert(fqinstance.getFqName());
+ }
+ return CheckInterfaceInheritanceHierarchy(interface_fqnames, hierarchy);
+}
+
std::optional<std::set<FQName>> known_interfaces;
void SetKnownInterfaces(const InterfaceInheritanceHierarchyMap& hierarchy) {
diff --git a/init/interface_utils.h b/init/interface_utils.h
index 4ca377f..214feda 100644
--- a/init/interface_utils.h
+++ b/init/interface_utils.h
@@ -34,8 +34,6 @@
// interface set. Uses the provided hierarchy data.
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
const InterfaceInheritanceHierarchyMap& hierarchy);
-Result<void> CheckInterfaceInheritanceHierarchy(const std::set<android::FQName>& interfaces,
- const InterfaceInheritanceHierarchyMap& hierarchy);
// Saves the set of known interfaces using the provided HIDL interface
// inheritance hierarchy.
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index 5789bf5..2b1d428 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -168,16 +168,16 @@
const std::vector<int> triple1_chord = {KEY_BACKSPACE, KEY_VOLUMEDOWN, KEY_VOLUMEUP};
const std::vector<int> triple2_chord = {KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_BACK};
-const std::vector<const std::vector<int>> empty_chords;
-const std::vector<const std::vector<int>> chords = {
- escape_chord,
- triple1_chord,
- triple2_chord,
+const std::vector<std::vector<int>> empty_chords;
+const std::vector<std::vector<int>> chords = {
+ escape_chord,
+ triple1_chord,
+ triple2_chord,
};
class TestFrame {
public:
- TestFrame(const std::vector<const std::vector<int>>& chords, EventHandler* ev = nullptr);
+ TestFrame(const std::vector<std::vector<int>>& chords, EventHandler* ev = nullptr);
void RelaxForMs(std::chrono::milliseconds wait = 1ms);
@@ -194,16 +194,15 @@
std::string Format() const;
private:
- static std::string Format(const std::vector<const std::vector<int>>& chords);
+ static std::string Format(const std::vector<std::vector<int>>& chords);
Epoll epoll_;
Keychords keychords_;
- std::vector<const std::vector<int>> keycodes_;
+ std::vector<std::vector<int>> keycodes_;
EventHandler* ev_;
};
-TestFrame::TestFrame(const std::vector<const std::vector<int>>& chords, EventHandler* ev)
- : ev_(ev) {
+TestFrame::TestFrame(const std::vector<std::vector<int>>& chords, EventHandler* ev) : ev_(ev) {
if (!epoll_.Open().ok()) return;
for (const auto& keycodes : chords) keychords_.Register(keycodes);
keychords_.Start(&epoll_, [this](const std::vector<int>& keycodes) {
@@ -262,7 +261,7 @@
for (int retry = 1000; retry && !IsChord(chord); --retry) RelaxForMs();
}
-std::string TestFrame::Format(const std::vector<const std::vector<int>>& chords) {
+std::string TestFrame::Format(const std::vector<std::vector<int>>& chords) {
std::string ret("{");
if (!chords.empty()) {
ret += android::base::Join(chords.front(), ' ');
diff --git a/init/noop_builtins.cpp b/init/noop_builtins.cpp
new file mode 100644
index 0000000..c4e140b
--- /dev/null
+++ b/init/noop_builtins.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+// Note that parser will perform arity checks only.
+
+#include <android-base/result.h>
+
+#include "builtin_arguments.h"
+#include "builtins.h"
+
+namespace android::init {
+
+static base::Result<void> check_stub(const BuiltinArguments&) {
+ return {};
+}
+
+#include "noop_builtin_function_map.h"
+
+} // namespace android::init
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 4d3742a..f2606e3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1251,6 +1251,16 @@
update_sys_usb_config();
}
+void PropertyLoadDerivedDefaults() {
+ const char* PAGE_PROP = "ro.boot.hardware.cpu.pagesize";
+ if (GetProperty(PAGE_PROP, "").empty()) {
+ std::string error;
+ if (PropertySetNoSocket(PAGE_PROP, std::to_string(getpagesize()), &error) != PROP_SUCCESS) {
+ LOG(ERROR) << "Could not set '" << PAGE_PROP << "' because: " << error;
+ }
+ }
+}
+
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
@@ -1421,6 +1431,7 @@
ExportKernelBootProps();
PropertyLoadBootDefaults();
+ PropertyLoadDerivedDefaults();
}
static void HandleInitSocket() {
diff --git a/init/reboot_test.cpp b/init/reboot_test.cpp
index b3d038d..b7a1cfd 100644
--- a/init/reboot_test.cpp
+++ b/init/reboot_test.cpp
@@ -103,8 +103,7 @@
"$selabel", GetSecurityContext(), false);
ServiceList& service_list = ServiceList::GetInstance();
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 6781c70..e6f3af6 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -27,7 +27,6 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <system/thread_defs.h>
@@ -201,24 +200,6 @@
Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
const std::string& interface_name = args[1];
const std::string& instance_name = args[2];
-
- // AIDL services don't use fully qualified names and instead just use "interface aidl <name>"
- if (interface_name != "aidl") {
- FQName fq_name;
- if (!FQName::parse(interface_name, &fq_name)) {
- return Error() << "Invalid fully-qualified name for interface '" << interface_name
- << "'";
- }
-
- if (!fq_name.isFullyQualified()) {
- return Error() << "Interface name not fully-qualified '" << interface_name << "'";
- }
-
- if (fq_name.isValidValueName()) {
- return Error() << "Interface name must not be a value name '" << interface_name << "'";
- }
- }
-
const std::string fullname = interface_name + "/" + instance_name;
for (const auto& svc : *service_list_) {
@@ -702,14 +683,6 @@
}
}
- if (interface_inheritance_hierarchy_) {
- if (const auto& check_hierarchy_result = CheckInterfaceInheritanceHierarchy(
- service_->interfaces(), *interface_inheritance_hierarchy_);
- !check_hierarchy_result.ok()) {
- return Error() << check_hierarchy_result.error();
- }
- }
-
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) {
return Error() << "service '" << service_->name()
diff --git a/init/service_parser.h b/init/service_parser.h
index 670a5c6..f06cfc4 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -18,7 +18,6 @@
#include <vector>
-#include "interface_utils.h"
#include "parser.h"
#include "service.h"
#include "service_list.h"
@@ -29,13 +28,8 @@
class ServiceParser : public SectionParser {
public:
- ServiceParser(
- ServiceList* service_list, Subcontext* subcontext,
- const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
- : service_list_(service_list),
- subcontext_(subcontext),
- interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
- service_(nullptr) {}
+ ServiceParser(ServiceList* service_list, Subcontext* subcontext)
+ : service_list_(service_list), subcontext_(subcontext), service_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -88,7 +82,6 @@
ServiceList* service_list_;
Subcontext* subcontext_;
- std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
std::unique_ptr<Service> service_;
std::string filename_;
};
diff --git a/init/service_test.cpp b/init/service_test.cpp
index a3590b5..53b53ed 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -253,8 +253,7 @@
"$selabel", GetSecurityContext(), false);
ServiceList& service_list = ServiceList::GetInstance();
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
TemporaryFile tf;
ASSERT_GE(tf.fd, 0);
diff --git a/init/test_utils/service_utils.cpp b/init/test_utils/service_utils.cpp
index 6426ed9..7002a67 100644
--- a/init/test_utils/service_utils.cpp
+++ b/init/test_utils/service_utils.cpp
@@ -30,8 +30,7 @@
android::base::Result<ServiceInterfacesMap> GetOnDeviceServiceInterfacesMap() {
ServiceList& service_list = ServiceList::GetInstance();
Parser parser;
- parser.AddSectionParser("service",
- std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
for (const auto& location : {
"/init.rc",
"/system/etc/init",
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index ea61cc2..eeb0394 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -142,6 +142,7 @@
#define AID_SECURITY_LOG_WRITER 1091 /* write to security log */
#define AID_PRNG_SEEDER 1092 /* PRNG seeder daemon */
#define AID_UPROBESTATS 1093 /* uid for uprobestats */
+#define AID_CROS_EC 1094 /* uid for accessing ChromeOS EC (cros_ec) */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libsync/Android.bp b/libsync/Android.bp
index b6b4a6e..99c88cf 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -27,9 +27,6 @@
name: "libsync",
symbol_file: "libsync.map.txt",
first_version: "26",
- export_header_libs: [
- "libsync_headers",
- ],
}
cc_defaults {
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 0b96ab0..d8d75ac 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -60,7 +60,7 @@
* We create it "detached", so it cleans up after itself.
*/
-typedef void* (*android_pthread_entry)(void*);
+typedef int (*android_pthread_entry)(void*);
#if defined(__ANDROID__)
struct thread_data_t {
@@ -88,6 +88,20 @@
};
#endif
+// Adapted from bionic's implmenetation of trampoline to make C11 thrd_create
+// work with pthread_create.
+struct libutil_thread_data {
+ android_pthread_entry _Nonnull entry_func;
+ void* _Nullable entry_func_arg;
+};
+
+static void* _Nonnull libutil_thread_trampoline(void* _Nonnull arg) {
+ libutil_thread_data *data_ptr = static_cast<libutil_thread_data*>(arg);
+ int result = data_ptr->entry_func(data_ptr->entry_func_arg);
+ delete data_ptr;
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(result));
+}
+
void androidSetThreadName(const char* name) {
#if defined(__linux__)
// Mac OS doesn't have this, and we build libutil for the host too
@@ -145,8 +159,13 @@
errno = 0;
pthread_t thread;
+
+ libutil_thread_data* pthread_arg = new libutil_thread_data;
+ pthread_arg->entry_func = entryFunction;
+ pthread_arg->entry_func_arg = userData;
+
int result = pthread_create(&thread, &attr,
- (android_pthread_entry)entryFunction, userData);
+ libutil_thread_trampoline, pthread_arg);
pthread_attr_destroy(&attr);
if (result != 0) {
ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index f866e9b..ac9ca85 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -35,7 +35,8 @@
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
ln -sfn /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
- ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
+ ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard; \
+ ln -sf /product/etc/security/adb_keys $(TARGET_ROOT_OUT)/adb_keys
ALL_ROOTDIR_SYMLINKS := \
$(TARGET_ROOT_OUT)/bin \
@@ -150,4 +151,3 @@
init.environ.rc-soong := $(call intermediates-dir-for,ETC,init.environ.rc-soong)/init.environ.rc-soong
$(eval $(call copy-one-file,$(init.environ.rc-soong),$(LOCAL_BUILT_MODULE)))
init.environ.rc-soong :=
-
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7b2b96a..63e3d06 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -103,7 +103,7 @@
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
- copy /system/etc/prop.default /dev/urandom
+ copy /proc/bootconfig /dev/urandom
symlink /proc/self/fd/0 /dev/stdin
symlink /proc/self/fd/1 /dev/stdout
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index d85f6ed..d5893de 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -18,6 +18,7 @@
"awk",
"bc",
"bzip2",
+ "cpu-target-features",
"fsck.exfat",
"ldd",
"logwrapper",
diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp
index 92d9c6f..5cdd381 100644
--- a/trusty/keymint/Android.bp
+++ b/trusty/keymint/Android.bp
@@ -17,12 +17,9 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-rust_binary {
- name: "android.hardware.security.keymint-service.rust.trusty",
+rust_defaults {
+ name: "android.hardware.security.keymint-service.rust.trusty.default",
relative_install_path: "hw",
- vendor: true,
- init_rc: ["android.hardware.security.keymint-service.rust.trusty.rc"],
- vintf_fragments: ["android.hardware.security.keymint-service.rust.trusty.xml"],
srcs: [
"src/keymint_hal_main.rs",
],
@@ -37,7 +34,26 @@
"liblog_rust",
],
prefer_rlib: true,
+}
+
+rust_binary {
+ name: "android.hardware.security.keymint-service.rust.trusty",
+ vendor: true,
+ defaults: ["android.hardware.security.keymint-service.rust.trusty.default"],
+ init_rc: ["android.hardware.security.keymint-service.rust.trusty.rc"],
+ vintf_fragments: ["android.hardware.security.keymint-service.rust.trusty.xml"],
required: [
"android.hardware.hardware_keystore.xml",
],
}
+
+rust_binary {
+ name: "android.hardware.security.keymint-service.rust.trusty.system.nonsecure",
+ system_ext_specific: true,
+ defaults: ["android.hardware.security.keymint-service.rust.trusty.default"],
+ init_rc: ["android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc"],
+ features: ["nonsecure"],
+ rustlibs: [
+ "libkmr_hal_nonsecure",
+ ],
+}
diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc
new file mode 100644
index 0000000..318c13b
--- /dev/null
+++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc
@@ -0,0 +1,17 @@
+service system.keymint.rust-trusty.nonsecure \
+ /system_ext/bin/hw/android.hardware.security.keymint-service.rust.trusty.system.nonsecure \
+ --dev ${ro.hardware.trusty_ipc_dev.keymint:-/dev/trusty-ipc-dev0}
+ disabled
+ user nobody
+ group drmrpc
+ # The keymint service is not allowed to restart.
+ # If it crashes, a device restart is required.
+ oneshot
+
+# Only starts the non-secure KeyMint HALs when the KeyMint VM feature is enabled
+# TODO(b/357821690): Start the KeyMint HALs when the KeyMint VM is ready once the Trusty VM
+# has a mechanism to notify the host.
+on late-fs && property:ro.hardware.security.keymint.trusty.system=1 && \
+ property:ro.hardware.trusty_vm_cid=*
+ setprop ro.hardware.trusty_ipc_dev.keymint VSOCK:${ro.hardware.trusty_vm_cid}:1
+ start system.keymint.rust-trusty.nonsecure
diff --git a/trusty/keymint/src/keymint_hal_main.rs b/trusty/keymint/src/keymint_hal_main.rs
index 3c5627b..a0b1d79 100644
--- a/trusty/keymint/src/keymint_hal_main.rs
+++ b/trusty/keymint/src/keymint_hal_main.rs
@@ -18,7 +18,7 @@
use kmr_hal::{
extract_rsp, keymint, rpc, secureclock, send_hal_info, sharedsecret, SerializedChannel,
};
-use log::{error, info};
+use log::{error, info, warn};
use std::{
ffi::CString,
ops::DerefMut,
@@ -109,7 +109,11 @@
error!("{}", panic_info);
}));
- info!("Trusty KM HAL service is starting.");
+ if cfg!(feature = "nonsecure") {
+ warn!("Non-secure Trusty KM HAL service is starting.");
+ } else {
+ info!("Trusty KM HAL service is starting.");
+ }
info!("Starting thread pool now.");
binder::ProcessState::start_thread_pool();
@@ -126,6 +130,29 @@
)?;
let tipc_channel = Arc::new(Mutex::new(TipcChannel(connection)));
+ #[cfg(feature = "nonsecure")]
+ {
+ // When the non-secure feature is enabled, retrieve root-of-trust information
+ // (with the exception of the verified boot key hash) from Android properties, and
+ // populate the TA with this information. On a real device, the bootloader should
+ // provide this data to the TA directly.
+ let boot_req = kmr_hal_nonsecure::get_boot_info();
+ info!("boot/HAL->TA: boot info is {:?}", boot_req);
+ kmr_hal::send_boot_info(tipc_channel.lock().unwrap().deref_mut(), boot_req)
+ .map_err(|e| HalServiceError(format!("Failed to send boot info: {:?}", e)))?;
+ // When the non-secure feature is enabled, also retrieve device ID information
+ // (except for IMEI/MEID values) from Android properties and populate the TA with
+ // this information. On a real device, a factory provisioning process would populate
+ // this information.
+ let attest_ids = kmr_hal_nonsecure::attestation_id_info();
+ if let Err(e) =
+ kmr_hal::send_attest_ids(tipc_channel.lock().unwrap().deref_mut(), attest_ids)
+ {
+ error!("Failed to send attestation ID info: {:?}", e);
+ }
+ info!("Successfully sent non-secure boot info and attestation IDs to the TA.");
+ }
+
// Register the Keymint service
let km_service = keymint::Device::new_as_binder(tipc_channel.clone());
let km_service_name = format!("{}/{}", KM_SERVICE_NAME, SERVICE_INSTANCE);
diff --git a/trusty/keymint/trusty-keymint.mk b/trusty/keymint/trusty-keymint.mk
new file mode 100644
index 0000000..d5791ea
--- /dev/null
+++ b/trusty/keymint/trusty-keymint.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2024 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.
+#
+
+#
+# This makefile should be included by devices that use Trusty TEE
+# to pull in a set of Trusty KeyMint specific modules.
+#
+# Allow KeyMint HAL service implementation selection at build time. This must be
+# synchronized with the TA implementation included in Trusty. Possible values:
+#
+# - Rust implementation for Trusty VM (requires Trusty VM support):
+# export TRUSTY_KEYMINT_IMPL=rust
+# export TRUSTY_SYSTEM_VM=nonsecure
+# - Rust implementation for Trusty TEE (no Trusty VM support):
+# export TRUSTY_KEYMINT_IMPL=rust
+# - C++ implementation (default): (any other value or unset TRUSTY_KEYMINT_IMPL)
+
+ifeq ($(TRUSTY_KEYMINT_IMPL),rust)
+ ifeq ($(TRUSTY_SYSTEM_VM),nonsecure)
+ LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.rust.trusty.system.nonsecure
+ else
+ LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.rust.trusty
+ endif
+else
+ # Default to the C++ implementation
+ LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.trusty
+endif
+
+PRODUCT_PACKAGES += \
+ $(LOCAL_KEYMINT_PRODUCT_PACKAGE) \
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
index b21eca6..9d810dc 100644
--- a/trusty/trusty-base.mk
+++ b/trusty/trusty-base.mk
@@ -22,18 +22,7 @@
# For gatekeeper, we include the generic -service and -impl to use legacy
# HAL loading of gatekeeper.trusty.
-# Allow the KeyMint HAL service implementation to be selected at build time. This needs to be
-# done in sync with the TA implementation included in Trusty. Possible values are:
-#
-# - Rust implementation: export TRUSTY_KEYMINT_IMPL=rust
-# - C++ implementation: (any other value of TRUSTY_KEYMINT_IMPL)
-
-ifeq ($(TRUSTY_KEYMINT_IMPL),rust)
- LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.rust.trusty
-else
- # Default to the C++ implementation
- LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.trusty
-endif
+$(call inherit-product, system/core/trusty/keymint/trusty-keymint.mk)
ifeq ($(SECRETKEEPER_ENABLED),true)
LOCAL_SECRETKEEPER_PRODUCT_PACKAGE := android.hardware.security.secretkeeper.trusty
@@ -42,7 +31,6 @@
endif
PRODUCT_PACKAGES += \
- $(LOCAL_KEYMINT_PRODUCT_PACKAGE) \
$(LOCAL_SECRETKEEPER_PRODUCT_PACKAGE) \
android.hardware.gatekeeper-service.trusty \
trusty_apploader \