Merge "Move native coverage output directory." into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 235fdfd..2529516 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -373,7 +373,6 @@
sanitize: {
memtag_heap: true,
- memtag_stack: true,
},
shared_libs: [
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 526e2ca..7c52e6e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -610,7 +610,7 @@
setjmp(jump_buf);
}
-TEST_F(CrasherTest, mte_illegal_setjmp) {
+TEST_F(CrasherTest, DISABLED_mte_illegal_setjmp) {
// This setjmp is illegal because it jumps back into a function that already returned.
// Quoting man 3 setjmp:
// If the function which called setjmp() returns before longjmp() is
@@ -1874,8 +1874,8 @@
StartProcess([&recoverable]() {
const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
"GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
- if (recoverable) {
- env[3] = "GWP_ASAN_RECOVERABLE=true";
+ if (!recoverable) {
+ env[3] = "GWP_ASAN_RECOVERABLE=false";
}
std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 25031bf..e26746b 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -108,7 +108,7 @@
"persist.device_config.memory_safety_native.permissive.process.%s",
getprogname());
// DO NOT REPLACE this with GetBoolProperty. That uses std::string which allocates, so it is
- // not async-safe (and this functiong gets used in a signal handler).
+ // not async-safe, and this function gets used in a signal handler.
return property_parse_bool("persist.sys.mte.permissive") ||
property_parse_bool("persist.device_config.memory_safety_native.permissive.default") ||
property_parse_bool(process_sysprop_name) ||
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 74f9a8c..4cde986 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -203,7 +203,7 @@
}
static void dump_probable_cause(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
- const ProcessInfo& process_info, const ThreadInfo& main_thread) {
+ const ProcessInfo& process_info, const ThreadInfo& target_thread) {
#if defined(USE_SCUDO)
ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
if (scudo_crash_data.CrashIsMine()) {
@@ -213,13 +213,13 @@
#endif
GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
- main_thread);
+ target_thread);
if (gwp_asan_crash_data.CrashIsMine()) {
gwp_asan_crash_data.AddCauseProtos(tombstone, unwinder);
return;
}
- const siginfo *si = main_thread.siginfo;
+ const siginfo *si = target_thread.siginfo;
auto fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
unwindstack::Maps* maps = unwinder->GetMaps();
@@ -238,14 +238,14 @@
} else if (fault_addr == 0xffff0f60) {
cause = "call to kuser_cmpxchg64";
} else {
- cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps);
+ cause = get_stack_overflow_cause(fault_addr, target_thread.registers->sp(), maps);
}
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
auto map_info = maps->Find(fault_addr);
if (map_info != nullptr && map_info->flags() == PROT_EXEC) {
cause = "execute-only (no-read) memory access error; likely due to data in .text.";
} else {
- cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps);
+ cause = get_stack_overflow_cause(fault_addr, target_thread.registers->sp(), maps);
}
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -685,7 +685,7 @@
}
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
- const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
+ const std::map<pid_t, ThreadInfo>& threads, pid_t target_tid,
const ProcessInfo& process_info, const OpenFilesList* open_files) {
Tombstone result;
@@ -694,19 +694,19 @@
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
result.set_timestamp(get_timestamp());
- const ThreadInfo& main_thread = threads.at(target_thread);
- result.set_pid(main_thread.pid);
- result.set_tid(main_thread.tid);
- result.set_uid(main_thread.uid);
- result.set_selinux_label(main_thread.selinux_label);
+ const ThreadInfo& target_thread = threads.at(target_tid);
+ result.set_pid(target_thread.pid);
+ result.set_tid(target_thread.tid);
+ result.set_uid(target_thread.uid);
+ result.set_selinux_label(target_thread.selinux_label);
// The main thread must have a valid siginfo.
- CHECK(main_thread.siginfo != nullptr);
+ CHECK(target_thread.siginfo != nullptr);
struct sysinfo si;
sysinfo(&si);
android::procinfo::ProcessInfo proc_info;
std::string error;
- if (android::procinfo::GetProcessInfo(main_thread.pid, &proc_info, &error)) {
+ if (android::procinfo::GetProcessInfo(target_thread.pid, &proc_info, &error)) {
uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK);
result.set_process_uptime(si.uptime - starttime);
} else {
@@ -715,24 +715,24 @@
}
auto cmd_line = result.mutable_command_line();
- for (const auto& arg : main_thread.command_line) {
+ for (const auto& arg : target_thread.command_line) {
*cmd_line->Add() = arg;
}
- if (!main_thread.siginfo) {
+ if (!target_thread.siginfo) {
async_safe_fatal("siginfo missing");
}
Signal sig;
- sig.set_number(main_thread.signo);
- sig.set_name(get_signame(main_thread.siginfo));
- sig.set_code(main_thread.siginfo->si_code);
- sig.set_code_name(get_sigcode(main_thread.siginfo));
+ sig.set_number(target_thread.signo);
+ sig.set_name(get_signame(target_thread.siginfo));
+ sig.set_code(target_thread.siginfo->si_code);
+ sig.set_code_name(get_sigcode(target_thread.siginfo));
- if (signal_has_sender(main_thread.siginfo, main_thread.pid)) {
+ if (signal_has_sender(target_thread.siginfo, target_thread.pid)) {
sig.set_has_sender(true);
- sig.set_sender_uid(main_thread.siginfo->si_uid);
- sig.set_sender_pid(main_thread.siginfo->si_pid);
+ sig.set_sender_uid(target_thread.siginfo->si_uid);
+ sig.set_sender_pid(target_thread.siginfo->si_pid);
}
if (process_info.has_fault_address) {
@@ -746,28 +746,28 @@
dump_abort_message(&result, unwinder->GetProcessMemory(), process_info);
dump_crash_details(&result, unwinder->GetProcessMemory(), process_info);
- // Dump the main thread, but save the memory around the registers.
- dump_thread(&result, unwinder, main_thread, /* memory_dump */ true);
+ // Dump the target thread, but save the memory around the registers.
+ dump_thread(&result, unwinder, target_thread, /* memory_dump */ true);
for (const auto& [tid, thread_info] : threads) {
- if (tid != target_thread) {
+ if (tid != target_tid) {
dump_thread(&result, unwinder, thread_info);
}
}
- dump_probable_cause(&result, unwinder, process_info, main_thread);
+ dump_probable_cause(&result, unwinder, process_info, target_thread);
dump_mappings(&result, unwinder->GetMaps(), unwinder->GetProcessMemory());
// Only dump logs on debuggable devices.
if (android::base::GetBoolProperty("ro.debuggable", false)) {
// Get the thread that corresponds to the main pid of the process.
- const ThreadInfo& thread = threads.at(main_thread.pid);
+ const ThreadInfo& thread = threads.at(target_thread.pid);
// Do not attempt to dump logs of the logd process because the gathering
// of logs can hang until a timeout occurs.
if (thread.thread_name != "logd") {
- dump_logcat(&result, main_thread.pid);
+ dump_logcat(&result, target_thread.pid);
}
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 12a1ddc..6b9e493 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1547,9 +1547,14 @@
void reboot_to_userspace_fastboot() {
fb->RebootTo("fastboot");
+ if (fb->WaitForDisconnect() != fastboot::SUCCESS) {
+ die("Error waiting for USB disconnect.");
+ }
fb->set_transport(nullptr);
- // Give the current connection time to close.
+ // Not all platforms support WaitForDisconnect. There also isn't a great way to tell whether
+ // or not WaitForDisconnect is supported. So, just wait a bit extra for everyone, in order to
+ // make sure that the device has had time to initiate its reboot and disconnect itself.
std::this_thread::sleep_for(std::chrono::seconds(1));
fb->set_transport(open_device());
diff --git a/fastboot/fuzzer/Android.bp b/fastboot/fuzzer/Android.bp
index a898070..59533fa 100644
--- a/fastboot/fuzzer/Android.bp
+++ b/fastboot/fuzzer/Android.bp
@@ -55,7 +55,10 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "dvander@google.com",
+ "elsk@google.com",
+ "enh@google.com",
+ "zhangkelvin@google.com",
],
componentid: 533764,
hotlists: [
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 5cc0346..c3ca758 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -71,6 +71,9 @@
"libbase",
"liblog",
],
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
srcs: [":libdm_test_srcs"],
auto_gen_config: true,
require_root: true,
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index fee67fdf..a963322 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -769,5 +769,25 @@
return true;
}
+bool DeviceMapper::SendMessage(const std::string& name, uint64_t sector,
+ const std::string& message) {
+ std::string ioctl_buffer(sizeof(struct dm_ioctl) + sizeof(struct dm_target_msg), 0);
+ ioctl_buffer += message;
+ ioctl_buffer.push_back('\0');
+
+ struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
+ InitIo(io, name);
+ io->data_size = ioctl_buffer.size();
+ io->data_start = sizeof(struct dm_ioctl);
+ struct dm_target_msg* msg =
+ reinterpret_cast<struct dm_target_msg*>(&ioctl_buffer[sizeof(struct dm_ioctl)]);
+ msg->sector = sector;
+ if (ioctl(fd_, DM_TARGET_MSG, io)) {
+ PLOG(ERROR) << "DM_TARGET_MSG failed";
+ return false;
+ }
+ return true;
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 1f6bd1a..b5cc9aa 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -298,5 +298,43 @@
return android::base::Join(argv, " ");
}
+DmTargetThinPool::DmTargetThinPool(uint64_t start, uint64_t length, const std::string& metadata_dev,
+ const std::string& data_dev, uint64_t data_block_size,
+ uint64_t low_water_mark)
+ : DmTarget(start, length),
+ metadata_dev_(metadata_dev),
+ data_dev_(data_dev),
+ data_block_size_(data_block_size),
+ low_water_mark_(low_water_mark) {}
+
+std::string DmTargetThinPool::GetParameterString() const {
+ std::vector<std::string> args{
+ metadata_dev_,
+ data_dev_,
+ std::to_string(data_block_size_),
+ std::to_string(low_water_mark_),
+ };
+ return android::base::Join(args, " ");
+}
+
+bool DmTargetThinPool::Valid() const {
+ // data_block_size: must be between 128 (64KB) and 2097152 (1GB) and a multiple of 128 (64KB)
+ if (data_block_size_ < 128 || data_block_size_ > 2097152) return false;
+ if (data_block_size_ % 128) return false;
+ return true;
+}
+
+DmTargetThin::DmTargetThin(uint64_t start, uint64_t length, const std::string& pool_dev,
+ uint64_t dev_id)
+ : DmTarget(start, length), pool_dev_(pool_dev), dev_id_(dev_id) {}
+
+std::string DmTargetThin::GetParameterString() const {
+ std::vector<std::string> args{
+ pool_dev_,
+ std::to_string(dev_id_),
+ };
+ return android::base::Join(args, " ");
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index d043be6..b890f47 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -37,12 +37,14 @@
#include <gtest/gtest.h>
#include <libdm/dm.h>
#include <libdm/loop_control.h>
+#include <storage_literals/storage_literals.h>
#include "test_util.h"
#include "utility.h"
using namespace std;
using namespace std::chrono_literals;
using namespace android::dm;
+using namespace android::storage_literals;
using android::base::make_scope_guard;
using android::base::unique_fd;
@@ -773,3 +775,42 @@
ASSERT_EQ(name, test_name_);
ASSERT_FALSE(uuid.empty());
}
+
+TEST_F(DmTest, ThinProvisioning) {
+ if (!DeviceMapper::Instance().GetTargetByName("thin-pool", nullptr)) GTEST_SKIP();
+
+ constexpr uint64_t MetaSize = 2_MiB;
+ constexpr uint64_t DataSize = 64_MiB;
+ constexpr uint64_t ThinSize = 1_TiB;
+
+ // Prepare two loop devices for meta and data devices.
+ TemporaryFile meta;
+ ASSERT_GE(meta.fd, 0);
+ ASSERT_EQ(0, ftruncate64(meta.fd, MetaSize));
+ TemporaryFile data;
+ ASSERT_GE(data.fd, 0);
+ ASSERT_EQ(0, ftruncate64(data.fd, DataSize));
+
+ LoopDevice loop_meta(meta.fd, 10s);
+ ASSERT_TRUE(loop_meta.valid());
+ LoopDevice loop_data(data.fd, 10s);
+ ASSERT_TRUE(loop_data.valid());
+
+ // Create a thin-pool
+ DmTable poolTable;
+ poolTable.Emplace<DmTargetThinPool>(0, DataSize / kSectorSize, loop_meta.device(),
+ loop_data.device(), 128, 0);
+ TempDevice pool("pool", poolTable);
+ ASSERT_TRUE(pool.valid());
+
+ // Create a thin volume
+ uint64_t thin_volume_id = 0;
+ ASSERT_TRUE(DeviceMapper::Instance().SendMessage(
+ "pool", 0, "create_thin " + std::to_string(thin_volume_id)));
+
+ // Use a thin volume to create a 1T device
+ DmTable thinTable;
+ thinTable.Emplace<DmTargetThin>(0, ThinSize / kSectorSize, pool.path(), thin_volume_id);
+ TempDevice thin("thin", thinTable);
+ ASSERT_TRUE(thin.valid());
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index fa97653..43d84f9 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -307,6 +307,9 @@
bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid);
+ // Send |message| to target, pointed by |name| and |sector|. Use 0 if |sector| is not needed.
+ bool SendMessage(const std::string& name, uint64_t sector, const std::string& message);
+
private:
// Maximum possible device mapper targets registered in the kernel.
// This is only used to read the list of targets from kernel so we allocate
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 97f3c13..c49fc5e 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -349,6 +349,35 @@
std::string GetParameterString() const override { return ""; }
};
+class DmTargetThinPool final : public DmTarget {
+ public:
+ DmTargetThinPool(uint64_t start, uint64_t length, const std::string& metadata_dev,
+ const std::string& data_dev, uint64_t data_block_size,
+ uint64_t low_water_mark);
+
+ std::string name() const override { return "thin-pool"; }
+ std::string GetParameterString() const override;
+ bool Valid() const override;
+
+ private:
+ std::string metadata_dev_;
+ std::string data_dev_;
+ uint64_t data_block_size_;
+ uint64_t low_water_mark_;
+};
+
+class DmTargetThin final : public DmTarget {
+ public:
+ DmTargetThin(uint64_t start, uint64_t length, const std::string& pool_dev, uint64_t dev_id);
+
+ std::string name() const override { return "thin"; }
+ std::string GetParameterString() const override;
+
+ private:
+ std::string pool_dev_;
+ uint64_t dev_id_;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp
index 6fa22fe..6273ee2 100644
--- a/fs_mgr/libfstab/fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -849,6 +849,14 @@
[&path](const FstabEntry& entry) { return entry.mount_point == path; });
}
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string_view path,
+ const std::string_view fstype) {
+ auto&& vec = GetEntriesByPred(fstab, [&path, fstype](const FstabEntry& entry) {
+ return entry.mount_point == path && entry.fs_type == fstype;
+ });
+ return vec.empty() ? nullptr : vec.front();
+}
+
std::vector<const FstabEntry*> GetEntriesForMountPoint(const Fstab* fstab,
const std::string& path) {
return GetEntriesByPred(fstab,
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 5e4019c..dea7238 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -108,6 +108,9 @@
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& path);
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string_view path,
+ const std::string_view fstype);
+
// This method builds DSU fstab entries and transfer the fstab.
//
// fstab points to the unmodified fstab.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
index ac04245..21dc666 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
@@ -17,7 +17,6 @@
#pragma once
#include <memory>
-#include <vector>
#include "libsnapshot/cow_format.h"
namespace android {
@@ -25,27 +24,30 @@
class ICompressor {
public:
- explicit ICompressor(uint32_t compression_level, uint32_t block_size)
+ explicit ICompressor(const int32_t compression_level, const uint32_t block_size)
: compression_level_(compression_level), block_size_(block_size) {}
virtual ~ICompressor() {}
// Factory methods for compression methods.
- static std::unique_ptr<ICompressor> Gz(uint32_t compression_level, const int32_t block_size);
- static std::unique_ptr<ICompressor> Brotli(uint32_t compression_level,
- const int32_t block_size);
- static std::unique_ptr<ICompressor> Lz4(uint32_t compression_level, const int32_t block_size);
- static std::unique_ptr<ICompressor> Zstd(uint32_t compression_level, const int32_t block_size);
+ static std::unique_ptr<ICompressor> Gz(const int32_t compression_level,
+ const uint32_t block_size);
+ static std::unique_ptr<ICompressor> Brotli(const int32_t compression_level,
+ const uint32_t block_size);
+ static std::unique_ptr<ICompressor> Lz4(const int32_t compression_level,
+ const uint32_t block_size);
+ static std::unique_ptr<ICompressor> Zstd(const int32_t compression_level,
+ const uint32_t block_size);
static std::unique_ptr<ICompressor> Create(CowCompression compression,
- const int32_t block_size);
+ const uint32_t block_size);
- uint32_t GetCompressionLevel() const { return compression_level_; }
+ int32_t GetCompressionLevel() const { return compression_level_; }
uint32_t GetBlockSize() const { return block_size_; }
[[nodiscard]] virtual std::vector<uint8_t> Compress(const void* data, size_t length) const = 0;
private:
- uint32_t compression_level_;
- uint32_t block_size_;
+ const int32_t compression_level_;
+ const uint32_t block_size_;
};
} // namespace snapshot
} // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 6865b19..991e17c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -31,15 +31,9 @@
static constexpr uint32_t kCowVersionMajor = 2;
static constexpr uint32_t kCowVersionMinor = 0;
-static constexpr uint32_t kCowVersionManifest = 2;
-
static constexpr uint32_t kMinCowVersion = 1;
static constexpr uint32_t kMaxCowVersion = 3;
-// Normally, this should be kMaxCowVersion. When a new version is under testing
-// it may be the previous value of kMaxCowVersion.
-static constexpr uint32_t kDefaultCowVersion = 2;
-
// This header appears as the first sequence of bytes in the COW. All fields
// in the layout are little-endian encoded. The on-disk layout is:
//
@@ -293,7 +287,7 @@
};
struct CowCompression {
CowCompressionAlgorithm algorithm = kCowCompressNone;
- uint32_t compression_level = 0;
+ int32_t compression_level = 0;
};
static constexpr uint8_t kCowReadAheadNotStarted = 0;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
index 0205f50..bff5257 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -17,6 +17,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <cstdint>
#include <limits>
#include <memory>
#include <queue>
@@ -57,7 +58,7 @@
}
std::unique_ptr<ICompressor> ICompressor::Create(CowCompression compression,
- const int32_t block_size) {
+ const uint32_t block_size) {
switch (compression.algorithm) {
case kCowCompressLz4:
return ICompressor::Lz4(compression.compression_level, block_size);
@@ -101,7 +102,7 @@
class GzCompressor final : public ICompressor {
public:
- GzCompressor(uint32_t compression_level, const uint32_t block_size)
+ GzCompressor(int32_t compression_level, const uint32_t block_size)
: ICompressor(compression_level, block_size){};
std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -122,7 +123,7 @@
class Lz4Compressor final : public ICompressor {
public:
- Lz4Compressor(uint32_t compression_level, const uint32_t block_size)
+ Lz4Compressor(int32_t compression_level, const uint32_t block_size)
: ICompressor(compression_level, block_size){};
std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -154,7 +155,7 @@
class BrotliCompressor final : public ICompressor {
public:
- BrotliCompressor(uint32_t compression_level, const uint32_t block_size)
+ BrotliCompressor(int32_t compression_level, const uint32_t block_size)
: ICompressor(compression_level, block_size){};
std::vector<uint8_t> Compress(const void* data, size_t length) const override {
@@ -180,7 +181,7 @@
class ZstdCompressor final : public ICompressor {
public:
- ZstdCompressor(uint32_t compression_level, const uint32_t block_size)
+ ZstdCompressor(int32_t compression_level, const uint32_t block_size)
: ICompressor(compression_level, block_size),
zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) {
ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level);
@@ -318,22 +319,23 @@
}
}
-std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level,
- const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Brotli(const int32_t compression_level,
+ const uint32_t block_size) {
return std::make_unique<BrotliCompressor>(compression_level, block_size);
}
-std::unique_ptr<ICompressor> ICompressor::Gz(uint32_t compression_level, const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Gz(const int32_t compression_level,
+ const uint32_t block_size) {
return std::make_unique<GzCompressor>(compression_level, block_size);
}
-std::unique_ptr<ICompressor> ICompressor::Lz4(uint32_t compression_level,
- const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Lz4(const int32_t compression_level,
+ const uint32_t block_size) {
return std::make_unique<Lz4Compressor>(compression_level, block_size);
}
-std::unique_ptr<ICompressor> ICompressor::Zstd(uint32_t compression_level,
- const int32_t block_size) {
+std::unique_ptr<ICompressor> ICompressor::Zstd(const int32_t compression_level,
+ const uint32_t block_size) {
return std::make_unique<ZstdCompressor>(compression_level, block_size);
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
index 10cb06d..f00f236 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
@@ -184,7 +184,7 @@
unique_fd cow_fd(dup(cow_->fd));
ASSERT_GE(cow_fd, 0);
- auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd));
+ auto writer = CreateCowWriter(2, options, std::move(cow_fd));
ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get()));
ASSERT_NO_FATAL_FAILURE(TestReads(writer.get()));
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index d0864e0..0993dba 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -134,7 +134,7 @@
return false;
}
if (parts.size() > 1) {
- if (!android::base::ParseUint(parts[1], &compression_.compression_level)) {
+ if (!android::base::ParseInt(parts[1], &compression_.compression_level)) {
LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1];
return false;
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index 73deafb..95398e4 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -149,7 +149,7 @@
}
if (parts.size() > 1) {
- if (!android::base::ParseUint(parts[1], &compression_.compression_level)) {
+ if (!android::base::ParseInt(parts[1], &compression_.compression_level)) {
LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1];
return false;
}
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index de91bd2..7ca53ad 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -24,7 +24,6 @@
#include <filesystem>
#include <optional>
#include <thread>
-#include <unordered_set>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -46,7 +45,6 @@
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
-#include "libsnapshot_cow/parser_v2.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
#include "utility.h"
@@ -3309,7 +3307,7 @@
compression_algorithm = "gz";
}
LOG(INFO) << "using compression algorithm: " << compression_algorithm
- << ", max compressible block size: " << compression_factor;
+ << ", max compressible block size: " << compression_factor;
}
PartitionCowCreator cow_creator{
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 5d3f96c..0158d4d 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -47,7 +47,9 @@
#include "partition_cow_creator.h"
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
#include <BootControlClient.h>
+#endif
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -92,6 +94,7 @@
namespace android {
namespace snapshot {
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
class MapSnapshots {
public:
MapSnapshots(std::string path = "");
@@ -107,6 +110,7 @@
private:
std::optional<std::string> GetCowImagePath(std::string& name);
bool PrepareUpdate();
+ bool GetCowDevicePath(std::string partition_name, std::string* cow_path);
bool WriteSnapshotPatch(std::string cow_device, std::string patch);
std::string GetGroupName(const android::fs_mgr::LpMetadata& pt,
const std::string& partiton_name);
@@ -228,6 +232,23 @@
return true;
}
+bool MapSnapshots::GetCowDevicePath(std::string partition_name, std::string* cow_path) {
+ auto& dm = android::dm::DeviceMapper::Instance();
+ std::string cow_device = partition_name + "-cow";
+ if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
+ return true;
+ }
+
+ LOG(INFO) << "Failed to find cow path: " << cow_device << " Checking the device for -img path";
+ // If the COW device exists only on /data
+ cow_device = partition_name + "-cow-img";
+ if (!dm.GetDmDevicePathByName(cow_device, cow_path)) {
+ LOG(ERROR) << "Failed to cow path: " << cow_device;
+ return false;
+ }
+ return true;
+}
+
bool MapSnapshots::ApplyUpdate() {
if (!PrepareUpdate()) {
LOG(ERROR) << "PrepareUpdate failed";
@@ -250,15 +271,13 @@
LOG(INFO) << "MapAllSnapshots success";
- auto& dm = android::dm::DeviceMapper::Instance();
auto target_slot = fs_mgr_get_other_slot_suffix();
for (auto& patchfile : patchfiles_) {
auto npos = patchfile.rfind(".patch");
auto partition_name = patchfile.substr(0, npos) + target_slot;
- auto cow_device = partition_name + "-cow";
std::string cow_path;
- if (!dm.GetDmDevicePathByName(cow_device, &cow_path)) {
- LOG(ERROR) << "Failed to cow path";
+ if (!GetCowDevicePath(partition_name, &cow_path)) {
+ LOG(ERROR) << "Failed to find cow path";
return false;
}
threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch,
@@ -462,6 +481,7 @@
}
return true;
}
+#endif
bool DumpCmdHandler(int /*argc*/, char** argv) {
android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
@@ -485,6 +505,7 @@
return false;
}
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
bool GetVerityPartitions(std::vector<std::string>& partitions) {
auto& dm = android::dm::DeviceMapper::Instance();
auto dm_block_devices = dm.FindDmPartitions();
@@ -637,7 +658,6 @@
return cow.FinishSnapshotWrites();
}
-#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
bool CreateTestUpdate(SnapshotManager* sm) {
chromeos_update_engine::DeltaArchiveManifest manifest;
@@ -761,13 +781,13 @@
{"map", MapCmdHandler},
#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
{"test-blank-ota", TestOtaHandler},
-#endif
- {"unmap", UnmapCmdHandler},
{"apply-update", ApplyUpdate},
{"map-snapshots", MapPrecreatedSnapshots},
{"unmap-snapshots", UnMapPrecreatedSnapshots},
{"delete-snapshots", DeletePrecreatedSnapshots},
{"revert-snapshots", RemovePrecreatedSnapshots},
+#endif
+ {"unmap", UnmapCmdHandler},
// clang-format on
};
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index d05df82..56f7b59 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -135,7 +135,7 @@
unique_fd fd(cow_system_->fd);
cow_system_->fd = -1;
- return CreateCowWriter(kDefaultCowVersion, options, std::move(fd));
+ return CreateCowWriter(2, options, std::move(fd));
}
std::unique_ptr<ICowWriter> SnapuserdTestBase::CreateV3Cow() {
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 9503072..f55cadb 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -74,6 +74,7 @@
ASSERT_EQ(access("/sys/fs/erofs", F_OK), 0);
}
+// @VsrTest = 3.7.10
TEST(fs, PartitionTypes) {
// Requirements only apply to Android 13+, 5.10+ devices.
int vsr_level = GetVsrLevel();
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index f843821..00f8038 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -50,6 +50,7 @@
std::cerr << " create <dm-name> [-ro] <targets...>" << std::endl;
std::cerr << " delete <dm-name>" << std::endl;
std::cerr << " list <devices | targets> [-v]" << std::endl;
+ std::cerr << " message <dm-name> <sector> <message>" << std::endl;
std::cerr << " getpath <dm-name>" << std::endl;
std::cerr << " getuuid <dm-name>" << std::endl;
std::cerr << " ima <dm-name>" << std::endl;
@@ -203,6 +204,46 @@
return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
} else if (target_type == "error") {
return std::make_unique<DmTargetError>(start_sector, num_sectors);
+ } else if (target_type == "thin-pool") {
+ if (!HasArgs(4)) {
+ std::cerr << "Expected \"thin-pool\" <metadata dev> <data dev> <data block size> "
+ "<low water mark> <feature args>"
+ << std::endl;
+ return nullptr;
+ }
+
+ std::string metadata_dev = NextArg();
+ std::string data_dev = NextArg();
+ std::string data_block_size_str = NextArg();
+ std::string low_water_mark_str = NextArg();
+
+ uint64_t data_block_size;
+ if (!android::base::ParseUint(data_block_size_str, &data_block_size)) {
+ std::cerr << "Data block size must be an unsigned integer.\n";
+ return nullptr;
+ }
+ uint64_t low_water_mark;
+ if (!android::base::ParseUint(low_water_mark_str, &low_water_mark)) {
+ std::cerr << "Low water mark must be an unsigned integer.\n";
+ return nullptr;
+ }
+ return std::make_unique<DmTargetThinPool>(start_sector, num_sectors, metadata_dev,
+ data_dev, data_block_size, low_water_mark);
+ } else if (target_type == "thin") {
+ if (!HasArgs(2)) {
+ std::cerr << "Expected \"thin\" <pool dev> <dev id>" << std::endl;
+ return nullptr;
+ }
+
+ std::string pool_dev = NextArg();
+ std::string dev_id_str = NextArg();
+
+ uint64_t dev_id;
+ if (!android::base::ParseUint(dev_id_str, &dev_id)) {
+ std::cerr << "Dev id must be an unsigned integer.\n";
+ return nullptr;
+ }
+ return std::make_unique<DmTargetThin>(start_sector, num_sectors, pool_dev, dev_id);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
@@ -417,6 +458,24 @@
return -EINVAL;
}
+static int DmMessageCmdHandler(int argc, char** argv) {
+ if (argc != 3) {
+ std::cerr << "Usage: dmctl message <name> <sector> <message>" << std::endl;
+ return -EINVAL;
+ }
+ uint64_t sector;
+ if (!android::base::ParseUint(argv[1], §or)) {
+ std::cerr << "Invalid argument for sector: " << argv[1] << std::endl;
+ return -EINVAL;
+ }
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.SendMessage(argv[0], sector, argv[2])) {
+ std::cerr << "Could not send message to " << argv[0] << std::endl;
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int HelpCmdHandler(int /* argc */, char** /* argv */) {
Usage();
return 0;
@@ -576,6 +635,7 @@
{"delete", DmDeleteCmdHandler},
{"replace", DmReplaceCmdHandler},
{"list", DmListCmdHandler},
+ {"message", DmMessageCmdHandler},
{"help", HelpCmdHandler},
{"getpath", GetPathCmdHandler},
{"getuuid", GetUuidCmdHandler},
diff --git a/init/Android.bp b/init/Android.bp
index d4b7fab..4322f62 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -96,6 +96,7 @@
config_namespace: "ANDROID",
bool_variables: [
"PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
+ "release_write_appcompat_override_system_properties",
],
properties: [
"cflags",
@@ -159,6 +160,9 @@
"-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=1",
],
},
+ release_write_appcompat_override_system_properties: {
+ cflags: ["-DWRITE_APPCOMPAT_OVERRIDE_SYSTEM_PROPERTIES"],
+ }
},
static_libs: [
"libavb",
@@ -255,7 +259,11 @@
cc_library_static {
name: "libinit.microdroid",
- defaults: ["libinit_defaults"],
+ defaults: [
+ "avf_build_flags_cc",
+ "libinit_defaults",
+ ],
+ recovery_available: false,
cflags: ["-DMICRODROID=1"],
}
@@ -273,6 +281,13 @@
defaults: ["init_defaults"],
srcs: ["main.cpp"],
symlinks: ["ueventd"],
+}
+
+cc_binary {
+ name: "init_second_stage",
+ defaults: ["init_second_stage_defaults"],
+ static_libs: ["libinit"],
+ visibility: ["//visibility:any_system_partition"],
target: {
platform: {
required: [
@@ -307,15 +322,12 @@
}
cc_binary {
- name: "init_second_stage",
- defaults: ["init_second_stage_defaults"],
- static_libs: ["libinit"],
- visibility: ["//visibility:any_system_partition"],
-}
-
-cc_binary {
name: "init_second_stage.microdroid",
- defaults: ["init_second_stage_defaults"],
+ defaults: [
+ "avf_build_flags_cc",
+ "init_second_stage_defaults",
+ ],
+ recovery_available: false,
static_libs: ["libinit.microdroid"],
cflags: ["-DMICRODROID=1"],
installable: false,
@@ -444,6 +456,7 @@
// First stage init is weird: it may start without stdout/stderr, and no /proc.
hwaddress: false,
+ memtag_stack: false,
},
// Install adb_debug.prop into debug ramdisk.
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 3c7107a..7d00195 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -59,9 +59,10 @@
`subsystem_name` is used to match uevent `SUBSYSTEM` value
-`devname` takes one of two options
+`devname` takes one of three options
1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME`
- 2. `uevent_devpath` specified that the name of the node will be basename uevent `DEVPATH`
+ 2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH`
+ 3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name`
`dirname` is an optional parameter that specifies a directory within `/dev` where the node will be
created.
diff --git a/init/devices.h b/init/devices.h
index f9f4d79..44ce2a9 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -82,6 +82,7 @@
enum DevnameSource {
DEVNAME_UEVENT_DEVNAME,
DEVNAME_UEVENT_DEVPATH,
+ DEVNAME_SYS_NAME,
};
Subsystem() {}
@@ -92,10 +93,18 @@
// Returns the full path for a uevent of a device that is a member of this subsystem,
// according to the rules parsed from ueventd.rc
std::string ParseDevPath(const Uevent& uevent) const {
- std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME
- ? uevent.device_name
- : android::base::Basename(uevent.path);
-
+ std::string devname;
+ if (devname_source_ == DEVNAME_UEVENT_DEVNAME) {
+ devname = uevent.device_name;
+ } else if (devname_source_ == DEVNAME_UEVENT_DEVPATH) {
+ devname = android::base::Basename(uevent.path);
+ } else if (devname_source_ == DEVNAME_SYS_NAME) {
+ if (android::base::ReadFileToString("/sys/" + uevent.path + "/name", &devname)) {
+ devname.pop_back(); // Remove terminating newline
+ } else {
+ devname = uevent.device_name;
+ }
+ }
return dir_name_ + "/" + devname;
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index ae216c6..5d3a273 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -556,11 +556,11 @@
return true;
}
// clang-format off
- const std::array<const char*, 7> args = {
+ const std::array<const char*, 8> args = {
"/system/bin/derive_microdroid_vendor_dice_node",
"--dice-driver", "/dev/open-dice0",
"--microdroid-vendor-disk-image", microdroid_vendor_block_dev->data(),
- "--output", "/microdroid_resources/dice_chain.raw",
+ "--output", "/microdroid_resources/dice_chain.raw", nullptr,
};
// clang-format-on
// ForkExecveAndWaitForCompletion calls waitpid to wait for the fork-ed process to finish.
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 59e57b9..1d17e3c 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -236,6 +236,9 @@
persistent_properties->mutable_properties()->end(),
[&name](const auto& record) { return record.name() == name; });
if (it != persistent_properties->mutable_properties()->end()) {
+ if (it->value() == value) {
+ return;
+ }
it->set_name(name);
it->set_value(value);
} else {
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 5763050..97865d7 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -17,6 +17,9 @@
#include "persistent_properties.h"
#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <vector>
@@ -155,6 +158,31 @@
EXPECT_FALSE(it == read_back_properties.properties().end());
}
+TEST(persistent_properties, NopUpdateDoesntWriteFile) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ persistent_property_filename = tf.path;
+
+ auto last_modified = [&tf]() -> time_t {
+ struct stat buf;
+ EXPECT_EQ(fstat(tf.fd, &buf), 0);
+ return buf.st_mtime;
+ };
+
+ std::vector<std::pair<std::string, std::string>> persistent_properties = {
+ {"persist.sys.locale", "en-US"},
+ {"persist.sys.timezone", "America/Los_Angeles"},
+ };
+ ASSERT_RESULT_OK(
+ WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
+
+ time_t t = last_modified();
+ sleep(2);
+ WritePersistentProperty("persist.sys.locale", "en-US");
+ // Ensure that the file was not modified
+ ASSERT_EQ(last_modified(), t);
+}
+
TEST(persistent_properties, RejectNonPersistProperty) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 58a0a7f..5a1b63b 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1308,12 +1308,14 @@
}
selinux_android_restorecon(PROP_TREE_FILE, 0);
+#ifdef WRITE_APPCOMPAT_OVERRIDE_SYSTEM_PROPERTIES
mkdir(APPCOMPAT_OVERRIDE_PROP_FOLDERNAME, S_IRWXU | S_IXGRP | S_IXOTH);
if (!WriteStringToFile(serialized_contexts, APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0444, 0, 0,
false)) {
PLOG(ERROR) << "Unable to write appcompat override property infos to file";
}
selinux_android_restorecon(APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0);
+#endif
}
static void ExportKernelBootProps() {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index e191b60..c2d9b8d 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -66,6 +66,7 @@
#include <android-base/result.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <android/avf_cc_flags.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
#include <libgsi/libgsi.h>
@@ -702,6 +703,15 @@
SelinuxSetEnforcement();
+ if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
+ // We run restorecon of /microdroid_resources while we are still in kernel context to avoid
+ // granting init `tmpfs:file relabelfrom` capability.
+ const int flags = SELINUX_ANDROID_RESTORECON_RECURSE;
+ if (selinux_android_restorecon("/microdroid_resources", flags) == -1) {
+ PLOG(FATAL) << "restorecon of /microdroid_resources failed";
+ }
+ }
+
// We're in the kernel domain and want to transition to the init domain. File systems that
// store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
// but other file systems do. In particular, this is needed for ramdisks such as the
diff --git a/init/service.cpp b/init/service.cpp
index eb24dd5..31308a0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -355,20 +355,35 @@
// If we crash > 4 times in 'fatal_crash_window_' minutes or before boot_completed,
// reboot into bootloader or set crashing property
boot_clock::time_point now = boot_clock::now();
+ constexpr const char native_watchdog_reboot_time[] = "persist.init.svc.last_fatal_reboot_epoch";
+ uint64_t throttle_window =
+ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(24)).count();
if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART) &&
!was_last_exit_ok_) {
bool boot_completed = GetBoolProperty("sys.boot_completed", false);
if (now < time_crashed_ + fatal_crash_window_ || !boot_completed) {
if (++crash_count_ > 4) {
- auto exit_reason = boot_completed ?
- "in " + std::to_string(fatal_crash_window_.count()) + " minutes" :
- "before boot completed";
+ auto exit_reason =
+ boot_completed
+ ? "in " + std::to_string(fatal_crash_window_.count()) + " minutes"
+ : "before boot completed";
if (flags_ & SVC_CRITICAL) {
if (!GetBoolProperty("init.svc_debug.no_fatal." + name_, false)) {
- // Aborts into `fatal_reboot_target_'.
- SetFatalRebootTarget(fatal_reboot_target_);
- LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
- << exit_reason;
+ uint64_t epoch_time =
+ std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ // Do not reboot again If it was already initiated in the last 24hrs
+ if (epoch_time - GetIntProperty(native_watchdog_reboot_time, 0) >
+ throttle_window) {
+ SetProperty(native_watchdog_reboot_time, std::to_string(epoch_time));
+ // Aborts into `fatal_reboot_target_'.
+ SetFatalRebootTarget(fatal_reboot_target_);
+ LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
+ << exit_reason;
+ } else {
+ LOG(INFO) << "Reboot already performed in last 24hrs because of crash.";
+ }
}
} else {
LOG(ERROR) << "process with updatable components '" << name_
diff --git a/init/test_kill_services/Android.bp b/init/test_kill_services/Android.bp
index 37361a8..ada87d8 100644
--- a/init/test_kill_services/Android.bp
+++ b/init/test_kill_services/Android.bp
@@ -10,7 +10,10 @@
cc_test {
name: "init_kill_services_test",
srcs: ["init_kill_services_test.cpp"],
- shared_libs: ["libbase"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ ],
test_suites: ["general-tests"],
// TODO(b/153565474): switch back to auto-generation
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
index 510ad8a..3af92bb 100644
--- a/init/test_kill_services/init_kill_services_test.cpp
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -18,15 +18,20 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <hidl/ServiceManagement.h>
#include <iostream>
using ::android::base::GetProperty;
using ::android::base::SetProperty;
using ::android::base::WaitForProperty;
+using ::android::hardware::isHidlSupported;
using std::literals::chrono_literals::operator""s;
void ExpectKillingServiceRecovers(const std::string& service_name) {
+ if (!isHidlSupported() && service_name == "hwservicemanager") {
+ GTEST_SKIP() << "No HIDL support on device so hwservicemanager will not be running";
+ }
LOG(INFO) << "before we say hi to " << service_name << ", I can't have apexd around!";
// b/280514080 - servicemanager will restart apexd, and apexd will restart the
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index d34672e..4395d88 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -218,6 +218,10 @@
subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH;
return {};
}
+ if (args[1] == "sys_name") {
+ subsystem_.devname_source_ = Subsystem::DEVNAME_SYS_NAME;
+ return {};
+ }
return Error() << "invalid devname '" << args[1] << "'";
}
diff --git a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
index 333e61c..67c7514 100644
--- a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
+++ b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
@@ -290,6 +290,9 @@
"name" : "fs_write_atomic_int"
},
{
+ "name" : "get_fs_config"
+ },
+ {
"name" : "hashmapCreate"
},
{
@@ -1274,6 +1277,27 @@
"source_file" : "system/core/libcutils/include/cutils/fs.h"
},
{
+ "function_name" : "get_fs_config",
+ "linker_set_key" : "get_fs_config",
+ "parameters" :
+ [
+ {
+ "referenced_type" : "_ZTIPKc"
+ },
+ {
+ "referenced_type" : "_ZTIb"
+ },
+ {
+ "referenced_type" : "_ZTIPKc"
+ },
+ {
+ "referenced_type" : "_ZTIP9fs_config"
+ }
+ ],
+ "return_type" : "_ZTIb",
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
+ },
+ {
"function_name" : "hashmapCreate",
"linker_set_key" : "hashmapCreate",
"parameters" :
@@ -2392,6 +2416,15 @@
},
{
"alignment" : 8,
+ "linker_set_key" : "_ZTIP9fs_config",
+ "name" : "fs_config *",
+ "referenced_type" : "_ZTI9fs_config",
+ "self_type" : "_ZTIP9fs_config",
+ "size" : 8,
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
+ },
+ {
+ "alignment" : 8,
"linker_set_key" : "_ZTIP9str_parms",
"name" : "str_parms *",
"referenced_type" : "_ZTI9str_parms",
@@ -2684,6 +2717,37 @@
"self_type" : "_ZTI5cnode",
"size" : 40,
"source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+ },
+ {
+ "alignment" : 8,
+ "fields" :
+ [
+ {
+ "field_name" : "uid",
+ "referenced_type" : "_ZTIj"
+ },
+ {
+ "field_name" : "gid",
+ "field_offset" : 32,
+ "referenced_type" : "_ZTIj"
+ },
+ {
+ "field_name" : "mode",
+ "field_offset" : 64,
+ "referenced_type" : "_ZTIj"
+ },
+ {
+ "field_name" : "capabilities",
+ "field_offset" : 128,
+ "referenced_type" : "_ZTIm"
+ }
+ ],
+ "linker_set_key" : "_ZTI9fs_config",
+ "name" : "fs_config",
+ "referenced_type" : "_ZTI9fs_config",
+ "self_type" : "_ZTI9fs_config",
+ "size" : 24,
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
}
],
"rvalue_reference_types" : []
diff --git a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
index f612fb9..f75240c 100644
--- a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
+++ b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
@@ -300,6 +300,9 @@
"name" : "fs_write_atomic_int"
},
{
+ "name" : "get_fs_config"
+ },
+ {
"name" : "hashmapCreate"
},
{
@@ -1284,6 +1287,27 @@
"source_file" : "system/core/libcutils/include/cutils/fs.h"
},
{
+ "function_name" : "get_fs_config",
+ "linker_set_key" : "get_fs_config",
+ "parameters" :
+ [
+ {
+ "referenced_type" : "_ZTIPKc"
+ },
+ {
+ "referenced_type" : "_ZTIb"
+ },
+ {
+ "referenced_type" : "_ZTIPKc"
+ },
+ {
+ "referenced_type" : "_ZTIP9fs_config"
+ }
+ ],
+ "return_type" : "_ZTIb",
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
+ },
+ {
"function_name" : "hashmapCreate",
"linker_set_key" : "hashmapCreate",
"parameters" :
@@ -2402,6 +2426,15 @@
},
{
"alignment" : 4,
+ "linker_set_key" : "_ZTIP9fs_config",
+ "name" : "fs_config *",
+ "referenced_type" : "_ZTI9fs_config",
+ "self_type" : "_ZTIP9fs_config",
+ "size" : 4,
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
+ },
+ {
+ "alignment" : 4,
"linker_set_key" : "_ZTIP9str_parms",
"name" : "str_parms *",
"referenced_type" : "_ZTI9str_parms",
@@ -2694,6 +2727,37 @@
"self_type" : "_ZTI5cnode",
"size" : 20,
"source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+ },
+ {
+ "alignment" : 8,
+ "fields" :
+ [
+ {
+ "field_name" : "uid",
+ "referenced_type" : "_ZTIj"
+ },
+ {
+ "field_name" : "gid",
+ "field_offset" : 32,
+ "referenced_type" : "_ZTIj"
+ },
+ {
+ "field_name" : "mode",
+ "field_offset" : 64,
+ "referenced_type" : "_ZTIt"
+ },
+ {
+ "field_name" : "capabilities",
+ "field_offset" : 128,
+ "referenced_type" : "_ZTIy"
+ }
+ ],
+ "linker_set_key" : "_ZTI9fs_config",
+ "name" : "fs_config",
+ "referenced_type" : "_ZTI9fs_config",
+ "self_type" : "_ZTI9fs_config",
+ "size" : 24,
+ "source_file" : "system/core/libcutils/include/private/fs_config.h"
}
],
"rvalue_reference_types" : []
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 919be2f..5efe209 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -91,7 +91,7 @@
{ 00751, AID_ROOT, AID_SHELL, 0, "vendor/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "vendor/apex/*/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
- { 00755, AID_ROOT, AID_ROOT, 0, 0 },
+ {},
// clang-format on
};
#ifndef __ANDROID_VNDK__
@@ -218,17 +218,32 @@
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "odm/bin/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "odm/framework/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "odm/app/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "odm/priv-app/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "product/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "product/apex/*bin/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "product/framework/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "product/app/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "product/priv-app/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system/framework/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system/app/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system/priv-app/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system_ext/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system_ext/apex/*/bin/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system_ext/framework/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system_ext/app/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "system_ext/priv-app/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/apex/*bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
- { 00644, AID_ROOT, AID_ROOT, 0, 0 },
+ { 00644, AID_ROOT, AID_ROOT, 0, "vendor/framework/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "vendor/app/*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "vendor/priv-app/*" },
+ {},
// clang-format on
};
#ifndef __ANDROID_VNDK__
@@ -318,8 +333,8 @@
auto __for_testing_only__fs_config_cmp = fs_config_cmp;
#endif
-void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
- unsigned* mode, uint64_t* capabilities) {
+bool get_fs_config(const char* path, bool dir, const char* target_out_path,
+ struct fs_config* fs_conf) {
const struct fs_path_config* pc;
size_t which, plen;
@@ -362,11 +377,11 @@
if (fs_config_cmp(dir, prefix, len, path, plen)) {
free(prefix);
close(fd);
- *uid = header.uid;
- *gid = header.gid;
- *mode = (*mode & (~07777)) | header.mode;
- *capabilities = header.capabilities;
- return;
+ fs_conf->uid = header.uid;
+ fs_conf->gid = header.gid;
+ fs_conf->mode = header.mode;
+ fs_conf->capabilities = header.capabilities;
+ return true;
}
free(prefix);
}
@@ -375,11 +390,28 @@
for (pc = dir ? android_dirs : android_files; pc->prefix; pc++) {
if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) {
- break;
+ fs_conf->uid = pc->uid;
+ fs_conf->gid = pc->gid;
+ fs_conf->mode = pc->mode;
+ fs_conf->capabilities = pc->capabilities;
+ return true;
}
}
- *uid = pc->uid;
- *gid = pc->gid;
- *mode = (*mode & (~07777)) | pc->mode;
- *capabilities = pc->capabilities;
+ return false;
+}
+
+void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
+ unsigned* mode, uint64_t* capabilities) {
+ struct fs_config conf;
+ if (get_fs_config(path, dir, target_out_path, &conf)) {
+ *uid = conf.uid;
+ *gid = conf.gid;
+ *mode = (*mode & S_IFMT) | conf.mode;
+ *capabilities = conf.capabilities;
+ } else {
+ *uid = AID_ROOT;
+ *gid = AID_ROOT;
+ *mode = (*mode & S_IFMT) | (dir ? 0755 : 0644);
+ *capabilities = 0;
+ }
}
diff --git a/libcutils/include/private/fs_config.h b/libcutils/include/private/fs_config.h
index 45f46e5..9a727bc 100644
--- a/libcutils/include/private/fs_config.h
+++ b/libcutils/include/private/fs_config.h
@@ -21,8 +21,11 @@
#pragma once
+#include <fcntl.h>
+#include <stdbool.h>
#include <stdint.h>
#include <sys/cdefs.h>
+#include <unistd.h>
#include <linux/capability.h>
@@ -30,17 +33,27 @@
__BEGIN_DECLS
-/*
- * Used in:
- * build/tools/fs_config/fs_config.c
- * build/tools/fs_get_stats/fs_get_stats.c
- * system/extras/ext4_utils/make_ext4fs_main.c
- * external/squashfs-tools/squashfs-tools/android.c
- * system/core/cpio/mkbootfs.c
- * system/core/adb/file_sync_service.cpp
- * system/extras/ext4_utils/canned_fs_config.c
- */
+/* This API is deprecated. New users should call get_fs_config. */
void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
unsigned* mode, uint64_t* capabilities);
+struct fs_config {
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ uint64_t capabilities;
+};
+
+/*
+ * If a file system configuration was found for the specified path, store it to *conf.
+ * Returns whether a file system configuration was found.
+ *
+ * dir: Whether path refers to a directory.
+ * target_out_path: Path to the base directory to read the file system configuration from, or a null
+ * pointer to use the root directory as the base. Host code should pass $ANDROID_PRODUCT_OUT or
+ * equivalent, and device code should pass a null pointer.
+ */
+bool get_fs_config(const char* path, bool dir, const char* target_out_path,
+ struct fs_config* conf);
+
__END_DECLS
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 5023c79..1a40da1 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -484,7 +484,11 @@
return false;
}
- if (module_options_[cnd_last].find("load_sequential=1") != std::string::npos) {
+ std::string str = "load_sequential=1";
+ auto it = module_options_[cnd_last].find(str);
+ if (it != std::string::npos) {
+ module_options_[cnd_last].erase(it, it + str.size());
+
if (!LoadWithAliases(cnd_last, true)) {
return false;
}
diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
index e89cb54..9bd212a 100644
--- a/libpackagelistparser/include/packagelistparser/packagelistparser.h
+++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h
@@ -33,7 +33,10 @@
/** Package name like "com.android.blah". */
char* name;
- /** Package uid like 10014. */
+ /**
+ * Package uid like 10014.
+ * Note that apexes and SDK libraries may have a bogus 0xffffffff value.
+ */
uid_t uid;
/** Package's AndroidManifest.xml debuggable flag. */
diff --git a/libpackagelistparser/packagelistparser.cpp b/libpackagelistparser/packagelistparser.cpp
index 59c3a74..638cc43 100644
--- a/libpackagelistparser/packagelistparser.cpp
+++ b/libpackagelistparser/packagelistparser.cpp
@@ -63,14 +63,13 @@
}
static bool parse_line(const char* path, size_t line_number, const char* line, pkg_info* info) {
- unsigned long uid;
int debuggable;
char* gid_list;
int profileable_from_shell = 0;
-
int fields =
- sscanf(line, "%ms %lu %d %ms %ms %ms %d %ld", &info->name, &uid, &debuggable, &info->data_dir,
- &info->seinfo, &gid_list, &profileable_from_shell, &info->version_code);
+ sscanf(line, "%ms %u %d %ms %ms %ms %d %ld", &info->name, &info->uid,
+ &debuggable, &info->data_dir, &info->seinfo, &gid_list,
+ &profileable_from_shell, &info->version_code);
// Handle the more complicated gids field and free the temporary string.
bool gids_okay = parse_gids(path, line_number, gid_list, info);
@@ -84,14 +83,7 @@
return false;
}
- // Extra validation.
- if (uid > UID_MAX) {
- ALOGE("%s:%zu: uid %lu > UID_MAX", path, line_number, uid);
- return false;
- }
- info->uid = uid;
-
- // Integer to bool conversions.
+ // Convert integers to bools.
info->debuggable = debuggable;
info->profileable_from_shell = profileable_from_shell;
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c6a0737..bb855d5 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,15 +2,34 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_defaults {
- name: "libprocessgroup_defaults",
- cpp_std: "gnu++20",
- cflags: [
- "-Wall",
- "-Werror",
- "-Wexit-time-destructors",
- "-Wno-unused-parameter",
+soong_config_module_type {
+ name: "libprocessgroup_flag_aware_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "memcg_v2_force_enabled",
+ "cgroup_v2_sys_app_isolation",
],
+ properties: [
+ "cflags",
+ ],
+}
+
+libprocessgroup_flag_aware_cc_defaults {
+ name: "libprocessgroup_build_flags_cc",
+ cpp_std: "gnu++20",
+ soong_config_variables: {
+ memcg_v2_force_enabled: {
+ cflags: [
+ "-DMEMCG_V2_FORCE_ENABLED=true",
+ ],
+ },
+ cgroup_v2_sys_app_isolation: {
+ cflags: [
+ "-DCGROUP_V2_SYS_APP_ISOLATION=true",
+ ],
+ },
+ },
}
cc_library_headers {
@@ -73,7 +92,7 @@
export_header_lib_headers: [
"libprocessgroup_headers",
],
- defaults: ["libprocessgroup_defaults"],
+ defaults: ["libprocessgroup_build_flags_cc"],
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -84,7 +103,7 @@
cc_test {
name: "task_profiles_test",
host_supported: true,
- defaults: ["libprocessgroup_defaults"],
+ defaults: ["libprocessgroup_build_flags_cc"],
srcs: [
"task_profiles_test.cpp",
],
diff --git a/libprocessgroup/build_flags.h b/libprocessgroup/build_flags.h
new file mode 100644
index 0000000..bc3e7df
--- /dev/null
+++ b/libprocessgroup/build_flags.h
@@ -0,0 +1,37 @@
+/*
+ * 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
+
+#ifndef MEMCG_V2_FORCE_ENABLED
+#define MEMCG_V2_FORCE_ENABLED false
+#endif
+
+#ifndef CGROUP_V2_SYS_APP_ISOLATION
+#define CGROUP_V2_SYS_APP_ISOLATION false
+#endif
+
+namespace android::libprocessgroup_flags {
+
+inline consteval bool force_memcg_v2() {
+ return MEMCG_V2_FORCE_ENABLED;
+}
+
+inline consteval bool cgroup_v2_sys_app_isolation() {
+ return CGROUP_V2_SYS_APP_ISOLATION;
+}
+
+} // namespace android::libprocessgroup_flags
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 94d9502..387c104 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -78,14 +78,6 @@
return true;
}
-static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
- return StringPrintf("%s/uid_%u", cgroup, uid);
-}
-
-static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, pid_t pid) {
- return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid);
-}
-
static bool CgroupKillAvailable() {
static std::once_flag f;
static bool cgroup_kill_available = false;
@@ -528,8 +520,14 @@
static int KillProcessGroup(
uid_t uid, pid_t initialPid, int signal, bool once = false,
std::chrono::steady_clock::time_point until = std::chrono::steady_clock::now() + 2200ms) {
- CHECK_GE(uid, 0);
- CHECK_GT(initialPid, 0);
+ if (uid < 0) {
+ LOG(ERROR) << __func__ << ": invalid UID " << uid;
+ return -1;
+ }
+ if (initialPid <= 0) {
+ LOG(ERROR) << __func__ << ": invalid PID " << initialPid;
+ return -1;
+ }
// Always attempt to send a kill signal to at least the initialPid, at least once, regardless of
// whether its cgroup exists or not. This should only be necessary if a bug results in the
@@ -689,8 +687,14 @@
}
int createProcessGroup(uid_t uid, pid_t initialPid, bool memControl) {
- CHECK_GE(uid, 0);
- CHECK_GT(initialPid, 0);
+ if (uid < 0) {
+ LOG(ERROR) << __func__ << ": invalid UID " << uid;
+ return -1;
+ }
+ if (initialPid <= 0) {
+ LOG(ERROR) << __func__ << ": invalid PID " << initialPid;
+ return -1;
+ }
if (memControl && !UsePerAppMemcg()) {
LOG(ERROR) << "service memory controls are used without per-process memory cgroup support";
diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp
index ea6c247..1e0783a 100644
--- a/libprocessgroup/setup/Android.bp
+++ b/libprocessgroup/setup/Android.bp
@@ -41,8 +41,5 @@
export_header_lib_headers: [
"libprocessgroup_headers",
],
- cflags: [
- "-Wall",
- "-Werror",
- ],
+ defaults: ["libprocessgroup_build_flags_cc"],
}
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 4e44c91..1b26fbc 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -29,7 +29,7 @@
#include <time.h>
#include <unistd.h>
-#include <regex>
+#include <optional>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -43,6 +43,7 @@
#include <processgroup/processgroup.h>
#include <processgroup/setup.h>
+#include "../build_flags.h"
#include "cgroup_descriptor.h"
using android::base::GetUintProperty;
@@ -57,6 +58,8 @@
static constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json";
+static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup";
+
static bool ChangeDirModeAndOwner(const std::string& path, mode_t mode, const std::string& uid,
const std::string& gid, bool permissive_mode = false) {
uid_t pw_uid = -1;
@@ -182,6 +185,8 @@
}
}
+static const bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2();
+
static bool ReadDescriptorsFromFile(const std::string& file_name,
std::map<std::string, CgroupDescriptor>* descriptors) {
std::vector<CgroupDescriptor> result;
@@ -205,22 +210,41 @@
const Json::Value& cgroups = root["Cgroups"];
for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
std::string name = cgroups[i]["Controller"].asString();
+
+ if (force_memcg_v2 && name == "memory") continue;
+
MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1);
}
}
+ bool memcgv2_present = false;
+ std::string root_path;
if (root.isMember("Cgroups2")) {
const Json::Value& cgroups2 = root["Cgroups2"];
- std::string root_path = cgroups2["Path"].asString();
+ root_path = cgroups2["Path"].asString();
MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME, "", 2);
const Json::Value& childGroups = cgroups2["Controllers"];
for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) {
std::string name = childGroups[i]["Controller"].asString();
+
+ if (force_memcg_v2 && name == "memory") memcgv2_present = true;
+
MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2);
}
}
+ if (force_memcg_v2 && !memcgv2_present) {
+ LOG(INFO) << "Forcing memcg to v2 hierarchy";
+ Json::Value memcgv2;
+ memcgv2["Controller"] = "memory";
+ memcgv2["NeedsActivation"] = true;
+ memcgv2["Path"] = ".";
+ memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot
+ MergeCgroupToDescriptors(descriptors, memcgv2, "memory",
+ root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2);
+ }
+
return true;
}
@@ -308,7 +332,8 @@
if (!base::WriteStringToFile(str, path)) {
if (IsOptionalController(controller)) {
- PLOG(INFO) << "Failed to activate optional controller " << controller->name();
+ PLOG(INFO) << "Failed to activate optional controller " << controller->name()
+ << " at " << path;
return true;
}
PLOG(ERROR) << "Failed to activate controller " << controller->name();
@@ -424,6 +449,76 @@
} // namespace cgrouprc
} // namespace android
+static std::optional<bool> MGLRUDisabled() {
+ const std::string file_name = "/sys/kernel/mm/lru_gen/enabled";
+ std::string content;
+ if (!android::base::ReadFileToString(file_name, &content)) {
+ PLOG(ERROR) << "Failed to read MGLRU state from " << file_name;
+ return {};
+ }
+
+ return content == "0x0000";
+}
+
+static std::optional<bool> MEMCGDisabled(
+ const std::map<std::string, android::cgrouprc::CgroupDescriptor>& descriptors) {
+ std::string cgroup_v2_root = android::cgrouprc::CGROUP_V2_ROOT_DEFAULT;
+ const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+ if (it == descriptors.end()) {
+ LOG(WARNING) << "No Cgroups2 path found in cgroups.json. Vendor has modified Android, and "
+ << "kernel memory use will be higher than intended.";
+ } else if (it->second.controller()->path() != cgroup_v2_root) {
+ cgroup_v2_root = it->second.controller()->path();
+ }
+
+ const std::string file_name = cgroup_v2_root + "/cgroup.controllers";
+ std::string content;
+ if (!android::base::ReadFileToString(file_name, &content)) {
+ PLOG(ERROR) << "Failed to read cgroup controllers from " << file_name;
+ return {};
+ }
+
+ // If we've forced memcg to v2 and it's not available, then it could only have been disabled
+ // on the kernel command line (GKI sets CONFIG_MEMCG).
+ return content.find("memory") == std::string::npos;
+}
+
+static bool CreateV2SubHierarchy(
+ const std::string& path,
+ const std::map<std::string, android::cgrouprc::CgroupDescriptor>& descriptors) {
+ using namespace android::cgrouprc;
+
+ const auto cgv2_iter = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+ if (cgv2_iter == descriptors.end()) return false;
+ const android::cgrouprc::CgroupDescriptor cgv2_descriptor = cgv2_iter->second;
+
+ if (!Mkdir(path, cgv2_descriptor.mode(), cgv2_descriptor.uid(), cgv2_descriptor.gid())) {
+ PLOG(ERROR) << "Failed to create directory for " << path;
+ return false;
+ }
+
+ // Activate all v2 controllers in path so they can be activated in
+ // children as they are created.
+ for (const auto& [name, descriptor] : descriptors) {
+ const format::CgroupController* controller = descriptor.controller();
+ std::uint32_t flags = controller->flags();
+ if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME &&
+ flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+ std::string str("+");
+ str += controller->name();
+ if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) {
+ if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) {
+ PLOG(WARNING) << "Activation of cgroup controller " << str << " failed in path "
+ << path;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
bool CgroupSetup() {
using namespace android::cgrouprc;
@@ -457,6 +552,32 @@
}
}
+ if (force_memcg_v2) {
+ if (MGLRUDisabled().value_or(false)) {
+ LOG(WARNING) << "Memcg forced to v2 hierarchy with MGLRU disabled! "
+ << "Global reclaim performance will suffer.";
+ }
+ if (MEMCGDisabled(descriptors).value_or(false)) {
+ LOG(WARNING) << "Memcg forced to v2 hierarchy while memcg is disabled by kernel "
+ << "command line!";
+ }
+ }
+
+ // System / app isolation.
+ // This really belongs in early-init in init.rc, but we cannot use the flag there.
+ if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation()) {
+ const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME);
+ const std::string cgroup_v2_root = (it == descriptors.end())
+ ? CGROUP_V2_ROOT_DEFAULT
+ : it->second.controller()->path();
+
+ LOG(INFO) << "Using system/app isolation under: " << cgroup_v2_root;
+ if (!CreateV2SubHierarchy(cgroup_v2_root + "/apps", descriptors) ||
+ !CreateV2SubHierarchy(cgroup_v2_root + "/system", descriptors)) {
+ return false;
+ }
+ }
+
// mkdir <CGROUPS_RC_DIR> 0711 system system
if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) {
LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file";
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 2353cf1..0c2252b 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -33,6 +33,8 @@
#include <json/reader.h>
#include <json/value.h>
+#include <build_flags.h>
+
// To avoid issues in sdk_mac build
#if defined(__ANDROID__)
#include <sys/prctl.h>
@@ -126,11 +128,29 @@
file_v2_name_ = file_v2_name;
}
+static bool isSystemApp(uid_t uid) {
+ return uid < AID_APP_START;
+}
+
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid) {
+ if (android::libprocessgroup_flags::cgroup_v2_sys_app_isolation()) {
+ if (isSystemApp(uid))
+ return StringPrintf("%s/system/uid_%u", root_cgroup_path, uid);
+ else
+ return StringPrintf("%s/apps/uid_%u", root_cgroup_path, uid);
+ }
+ return StringPrintf("%s/uid_%u", root_cgroup_path, uid);
+}
+
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid) {
+ const std::string uid_path = ConvertUidToPath(root_cgroup_path, uid);
+ return StringPrintf("%s/pid_%d", uid_path.c_str(), pid);
+}
+
bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const {
if (controller()->version() == 2) {
- // all cgroup v2 attributes use the same process group hierarchy
- *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid,
- file_name().c_str());
+ const std::string cgroup_path = ConvertUidPidToPath(controller()->path(), uid, pid);
+ *path = cgroup_path + "/" + file_name();
return true;
}
return GetPathForTask(pid, path);
@@ -155,12 +175,14 @@
return true;
}
+// NOTE: This function is for cgroup v2 only
bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const {
if (path == nullptr) {
return true;
}
- *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str());
+ const std::string cgroup_path = ConvertUidToPath(controller()->path(), uid);
+ *path = cgroup_path + "/" + file_name();
return true;
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 2fa1931..7e3c50d 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -82,8 +82,8 @@
virtual void EnableResourceCaching(ResourceCacheType) {}
virtual void DropResourceCaching(ResourceCacheType) {}
- virtual bool IsValidForProcess(uid_t uid, pid_t pid) const { return false; }
- virtual bool IsValidForTask(pid_t tid) const { return false; }
+ virtual bool IsValidForProcess(uid_t, pid_t) const { return false; }
+ virtual bool IsValidForTask(pid_t) const { return false; }
protected:
enum CacheUseResult { SUCCESS, FAIL, UNUSED };
@@ -109,8 +109,8 @@
const char* Name() const override { return "SetTimerSlack"; }
bool ExecuteForTask(pid_t tid) const override;
- bool IsValidForProcess(uid_t uid, pid_t pid) const override { return true; }
- bool IsValidForTask(pid_t tid) const override { return true; }
+ bool IsValidForProcess(uid_t, pid_t) const override { return true; }
+ bool IsValidForTask(pid_t) const override { return true; }
private:
unsigned long slack_;
@@ -252,3 +252,6 @@
std::map<std::string, std::shared_ptr<TaskProfile>, std::less<>> profiles_;
std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
};
+
+std::string ConvertUidToPath(const char* root_cgroup_path, uid_t uid);
+std::string ConvertUidPidToPath(const char* root_cgroup_path, uid_t uid, pid_t pid);
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index b17e695..d19da2b 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -102,8 +102,7 @@
public:
ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
~ProfileAttributeMock() override = default;
- void Reset(const CgroupController& controller, const std::string& file_name,
- const std::string& file_v2_name) override {
+ void Reset(const CgroupController&, const std::string&, const std::string&) override {
CHECK(false);
}
const CgroupController* controller() const override {
@@ -111,10 +110,10 @@
return {};
}
const std::string& file_name() const override { return file_name_; }
- bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override {
+ bool GetPathForProcess(uid_t, pid_t pid, std::string* path) const override {
return GetPathForTask(pid, path);
}
- bool GetPathForTask(int tid, std::string* path) const override {
+ bool GetPathForTask(int, std::string* path) const override {
#ifdef __ANDROID__
CHECK(CgroupGetControllerPath(CGROUPV2_HIERARCHY_NAME, path));
CHECK_GT(path->length(), 0);
diff --git a/libsysutils/include/sysutils/SocketListener.h b/libsysutils/include/sysutils/SocketListener.h
index 67a691a..a7fd09e 100644
--- a/libsysutils/include/sysutils/SocketListener.h
+++ b/libsysutils/include/sysutils/SocketListener.h
@@ -19,6 +19,7 @@
#include <pthread.h>
#include <unordered_map>
+#include <vector>
#include <sysutils/SocketClient.h>
#include "SocketClientCommand.h"
diff --git a/libutils/Android.bp b/libutils/Android.bp
index ad5b752..1741187 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -109,7 +109,7 @@
},
},
fuzz_config: {
- cc: ["smoreland@google.com"],
+ cc: ["smoreland@google.com"],
},
}
@@ -273,6 +273,17 @@
"libbase",
"liblog",
],
+ fuzz_config: {
+ cc: [
+ "smoreland@google.com",
+ ],
+ componentid: 128577,
+ description: "The fuzzer targets the APIs of libutils",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
+ },
}
cc_fuzz {
diff --git a/libutils/binder/include/utils/TypeHelpers.h b/libutils/binder/include/utils/TypeHelpers.h
index 1554f52..21d9b3d 100644
--- a/libutils/binder/include/utils/TypeHelpers.h
+++ b/libutils/binder/include/utils/TypeHelpers.h
@@ -109,6 +109,11 @@
ANDROID_BASIC_TYPES_TRAITS( float )
ANDROID_BASIC_TYPES_TRAITS( double )
+template<typename T> struct trait_trivial_ctor<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_dtor<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_copy<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_move<T*> { enum { value = true }; };
+
// ---------------------------------------------------------------------------
diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp
index e87959e..a22737c 100644
--- a/libvendorsupport/Android.bp
+++ b/libvendorsupport/Android.bp
@@ -23,7 +23,7 @@
llndk: {
symbol_file: "libvendorsupport.map.txt",
},
- srcs: ["version_props.c"],
+ srcs: ["version_props.cpp"],
cflags: [
"-Wall",
"-Werror",
@@ -32,6 +32,7 @@
export_include_dirs: ["include"],
shared_libs: [
"liblog",
+ "libbase",
],
}
diff --git a/libvendorsupport/include/vendorsupport/api_level.h b/libvendorsupport/include/vendorsupport/api_level.h
index d365075..3427bc6 100644
--- a/libvendorsupport/include/vendorsupport/api_level.h
+++ b/libvendorsupport/include/vendorsupport/api_level.h
@@ -44,4 +44,22 @@
*/
int AVendorSupport_getSdkApiLevelOf(int vendorApiLevel);
+#if !defined(__ANDROID_VENDOR__)
+/**
+ * @brief Provide vendor API level to system modules.
+ *
+ * @details
+ * Before deprecating VNDK, system modules read ro.vndk.version to find the
+ * API level that vendor image had implemented. With the VNDK deprecation, this
+ * must be replaced with ro.board.api_level. However, there still are devices
+ * keeping old vendor partitions with the new system upgraded. In this case, the
+ * VNDK version can be used as before.
+ * This API is for platform only.
+ *
+ * @return ro.vndk.version if exist. Otherwise fallback to ro.board.api_level.
+ * 0 if none of these properties are found. This is unexpected, though.
+ */
+int AVendorSupport_getVendorApiLevel();
+#endif // __ANDROID_VENDOR__
+
__END_DECLS
diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h
index 58cd18d..cf82fb7 100644
--- a/libvendorsupport/include_llndk/android/llndk-versioning.h
+++ b/libvendorsupport/include_llndk/android/llndk-versioning.h
@@ -14,22 +14,18 @@
#pragma once
-/* As a vendor default header included in all vendor modules, this header MUST NOT include other
- * header files or any declarations. Only macros are allowed.
- */
-#if defined(__ANDROID_VENDOR__)
-
// LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to
// NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are
-// enabled when the vendor api level is equal to or newer than the ro.board.api_level.
-#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
- _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
- __attribute__((enable_if( \
- __ANDROID_VENDOR_API__ >= vendor_api_level, \
- "available in vendor API level " #vendor_api_level " that " \
- "is newer than the current vendor API level. Guard the API " \
- "call with '#if (__ANDROID_VENDOR_API__ >= " #vendor_api_level ")'."))) \
- _Pragma("clang diagnostic pop")
+// enabled when the vendor api level is equal to or newer than the ro.board.api_level. These symbols
+// must be annotated in map.txt files with the `# llndk=YYYYMM` annotation. They also must be marked
+// with `__INTRODUCED_IN_LLNDK(YYYYMM)` in the header files. It leaves a no-op annotation for ABI
+// analysis.
+#if !defined(__INTRODUCED_IN_LLNDK)
+#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
+ __attribute__((annotate("introduced_in_llndk=" #vendor_api_level)))
+#endif
+
+#if defined(__ANDROID_VENDOR__)
// Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK.
// This returns true for the vendor modules if the vendor_api_level is less than or equal to the
@@ -39,13 +35,6 @@
#else // __ANDROID_VENDOR__
-// __INTRODUCED_IN_LLNDK is for LLNDK only but not for NDK. Ignore this for non-vendor modules.
-// It leaves a no-op annotation for ABI analysis.
-#if !defined(__INTRODUCED_IN_LLNDK)
-#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
- __attribute__((annotate("introduced_in_llndk=" #vendor_api_level)))
-#endif
-
// For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to
// guard the API for __INTRODUCED_IN.
#if !defined(API_LEVEL_AT_LEAST)
diff --git a/libvendorsupport/version_props.c b/libvendorsupport/version_props.cpp
similarity index 79%
rename from libvendorsupport/version_props.c
rename to libvendorsupport/version_props.cpp
index 835828c..ecba899 100644
--- a/libvendorsupport/version_props.c
+++ b/libvendorsupport/version_props.cpp
@@ -16,6 +16,10 @@
#include <log/log.h>
+#if !defined(__ANDROID_VENDOR__)
+#include <android-base/properties.h>
+#endif
+
int AVendorSupport_getVendorApiLevelOf(int sdkApiLevel) {
if (sdkApiLevel < __ANDROID_API_V__) {
return sdkApiLevel;
@@ -39,3 +43,13 @@
ALOGE("Unexpected vendor api level: %d", vendorApiLevel);
return __INVALID_API_LEVEL;
}
+
+#if !defined(__ANDROID_VENDOR__)
+int AVendorSupport_getVendorApiLevel() {
+ int vendorApiLevel = android::base::GetIntProperty("ro.vndk.version", 0);
+ if (vendorApiLevel) {
+ return vendorApiLevel;
+ }
+ return android::base::GetIntProperty("ro.board.api_level", 0);
+}
+#endif // __ANDROID_VENDOR__
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 6a3484e..06227c3 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -101,3 +101,15 @@
src: "init.usb.configfs.rc",
sub_dir: "init/hw",
}
+
+prebuilt_etc {
+ name: "etc_hosts",
+ src: "etc/hosts",
+ filename: "hosts",
+}
+
+prebuilt_etc {
+ name: "init-debug.rc",
+ src: "init-debug.rc",
+ sub_dir: "init",
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 0d5abbf..2394b14 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -3,19 +3,6 @@
$(eval $(call declare-1p-copy-files,system/core/rootdir,))
#######################################
-# init-debug.rc
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := init-debug.rc
-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_OUT_ETC)/init
-
-include $(BUILD_PREBUILT)
-
-#######################################
# asan.options
ifneq ($(filter address,$(SANITIZE_TARGET)),)
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index d72ac66..8b3542f 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -9,8 +9,6 @@
"libnativehelper.so",
"libnativeloader.so",
"libsigchain.so",
- // TODO(b/122876336): Remove libpac.so once it's migrated to Webview
- "libpac.so",
// TODO(b/120786417 or b/134659294): libicuuc.so
// and libicui18n.so are kept for app compat.
"libicui18n.so",
@@ -32,6 +30,8 @@
],
"provideLibs": [
"libaptX_encoder.so",
- "libaptXHD_encoder.so"
+ "libaptXHD_encoder.so",
+ "libEGL.so",
+ "libGLESv2.so"
]
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d4cd4b8..f7f0cc3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -425,16 +425,6 @@
chown system system /proc/pressure/memory
chmod 0664 /proc/pressure/memory
- # qtaguid will limit access to specific data based on group memberships.
- # net_bw_acct grants impersonation of socket owners.
- # net_bw_stats grants access to other apps' detailed tagged-socket stats.
- chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
- chown root net_bw_stats /proc/net/xt_qtaguid/stats
-
- # Allow everybody to read the xt_qtaguid resource tracking misc dev.
- # This is needed by any process that uses socket tagging.
- chmod 0644 /dev/xt_qtaguid
-
mount bpf bpf /sys/fs/bpf nodev noexec nosuid
# pstore/ramoops previous console log
@@ -648,6 +638,8 @@
mkdir /metadata/aconfig 0775 root system
mkdir /metadata/aconfig/flags 0770 root system
mkdir /metadata/aconfig/boot 0775 root system
+
+ mkdir /metadata/aconfig_test_missions 0775 root system
exec_start aconfigd-init
start aconfigd
@@ -664,10 +656,6 @@
exec -- /system/bin/fsverity_init --load-verified-keys
# Only enable the bootreceiver tracing instance for kernels 5.10 and above.
-on late-fs && property:ro.kernel.version=4.9
- setprop bootreceiver.enable 0
-on late-fs && property:ro.kernel.version=4.14
- setprop bootreceiver.enable 0
on late-fs && property:ro.kernel.version=4.19
setprop bootreceiver.enable 0
on late-fs && property:ro.kernel.version=5.4
@@ -882,6 +870,9 @@
mkdir /data/app-lib 0771 system system encryption=Require
mkdir /data/app 0771 system system encryption=Require
+ # Create directory for app metadata files
+ mkdir /data/app-metadata 0700 system system encryption=Require
+
# create directory for updated font files.
mkdir /data/fonts/ 0771 root root encryption=Require
mkdir /data/fonts/files 0771 system system
@@ -970,6 +961,10 @@
mkdir /data/vendor_ce 0551 root root encryption=None
mkdir /data/vendor_de 0551 root root encryption=None
+ # Similar to the top-level CE and DE directories, /data/storage_area must
+ # itself be unencrypted, since it contains encrypted directories.
+ mkdir /data/storage_area 0551 root root encryption=None
+
# Set the casefold flag on /data/media. For upgrades, a restorecon can be
# needed first to relabel the directory from media_rw_data_file.
restorecon /data/media
@@ -983,8 +978,12 @@
mkdir /data_mirror/data_de 0700 root root
mkdir /data_mirror/misc_ce 0700 root root
mkdir /data_mirror/misc_de 0700 root root
+ mkdir /data_mirror/storage_area 0700 root root
# Create CE and DE data directory for default volume
+ # Not needed for storage_area directory, since this is
+ # not supported for non-default volumes and the path
+ # does not include the volume ID
mkdir /data_mirror/data_ce/null 0700 root root
mkdir /data_mirror/data_de/null 0700 root root
mkdir /data_mirror/misc_ce/null 0700 root root
@@ -999,6 +998,9 @@
mount none /data/misc_ce /data_mirror/misc_ce/null bind rec
mount none /data/misc_de /data_mirror/misc_de/null bind rec
+ # Also bind mount for the storage area directory (minus the volume ID)
+ mount none /data/storage_area /data_mirror/storage_area bind rec
+
# 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
@@ -1031,7 +1033,7 @@
perform_apex_config
# Create directories for boot animation.
- mkdir /data/misc/bootanim 0755 system system encryption=DeleteIfNecessary
+ mkdir /data/misc/bootanim 0755 system system
exec_start derive_sdk
@@ -1339,6 +1341,8 @@
umount /data_mirror/data_ce/null/0
umount /data_mirror/data_ce/null
umount /data_mirror/data_de/null
+ umount /data_mirror/storage_area/0
+ umount /data_mirror/storage_area
umount /data_mirror/cur_profiles
umount /data_mirror/ref_profiles
umount /data_mirror
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 9a733bb..c7c622e 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -37,7 +37,46 @@
full list for a release by running `toybox` directly.
-## Android 14 ("U")
+## Android 15 (API level 35, "Vanilla Ice Cream")
+
+BSD: fsck\_msdos newfs\_msdos
+
+bzip2: bzcat bzip2 bunzip2
+
+gavinhoward/bc: bc
+
+one-true-awk: awk
+
+toolbox: getevent getprop setprop start stop
+
+toybox ([0.8.11](https://landley.net/toybox/news.html#08-04-2024)-ish):
+[ acpi base64 basename blkdiscard blkid blockdev brctl cal cat chattr
+chcon chgrp chmod chown chroot chrt cksum clear cmp comm cp cpio cut
+date dd devmem df diff dirname dmesg dos2unix du echo egrep env expand
+expr fallocate false fgrep file find flock fmt free freeramdisk fsfreeze
+fsync getconf getenforce **getfattr** getopt **gpiodetect** **gpiofind**
+**gpioget** **gpioinfo** **gpioset** grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset **i2ctransfer** iconv id ifconfig
+inotifyd insmod install ionice iorenice iotop kill killall ln load\_policy
+log logger logname losetup ls lsattr lsmod lsof lspci lsusb makedevs
+md5sum **memeater** microcom mkdir mkfifo mknod mkswap mktemp modinfo modprobe
+more mount mountpoint mv nbd-client nc netcat netstat nice nl nohup
+nproc nsenter od partprobe paste patch pgrep pidof ping ping6 pivot\_root
+pkill pmap printenv printf prlimit ps pwd pwdx readelf readlink realpath
+renice restorecon rev rfkill rm rmdir rmmod rtcwake runcon sed sendevent
+seq setenforce **setfattr** setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split stat strings stty swapoff swapon sync sysctl
+tac tail tar taskset tee test time timeout top touch tr traceroute
+traceroute6 true truncate tty tunctl uclampset ulimit umount uname
+uniq unix2dos unlink unshare uptime usleep uudecode uuencode uuidgen
+vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
+
+Note: technically getfattr and setfattr were available in earlier versions,
+but the symlinks were missing until this release, so they were only available
+as `toybox getfattr` and `toybox setfattr` rather than directly.
+
+
+## Android 14 (API level 34, "Upside Down Cake")
BSD: fsck\_msdos newfs\_msdos
@@ -71,7 +110,7 @@
vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
-## Android 13 ("T")
+## Android 13 (33, "Tiramisu")
BSD: fsck\_msdos newfs\_msdos
@@ -105,7 +144,7 @@
vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
-## Android 12 ("S")
+## Android 12 (31, "Snow Cone")
BSD: fsck\_msdos newfs\_msdos
@@ -139,7 +178,7 @@
vmstat watch wc which whoami xargs xxd yes zcat
-## Android 11 ("R")
+## Android 11 (API level 30, "Red Velvet Cake")
BSD: fsck\_msdos newfs\_msdos
@@ -173,7 +212,7 @@
whoami xargs xxd yes zcat
-## Android 10 ("Q")
+## Android 10 (API level 29, "Quince Tart")
BSD: grep fsck\_msdos newfs\_msdos
@@ -205,7 +244,7 @@
wc which whoami xargs xxd yes zcat
-## Android 9.0 (Pie)
+## Android 9.0 (API level 28, "Pie")
BSD: dd grep
@@ -232,7 +271,7 @@
which whoami xargs xxd yes zcat
-## Android 8.0 (Oreo)
+## Android 8.0 (API level 26, "Oreo")
BSD: dd grep
@@ -257,7 +296,7 @@
vmstat wc which whoami xargs xxd yes **zcat**
-## Android 7.0 (Nougat)
+## Android 7.0 (API level 24, "Nougat")
BSD: dd grep
@@ -279,7 +318,7 @@
**uptime** usleep vmstat wc which whoami xargs **xxd** yes
-## Android 6.0 (Marshmallow)
+## Android 6.0 (API level 23, "Marshmallow")
BSD: dd du grep
@@ -300,7 +339,7 @@
vmstat wc which whoami xargs yes
-## Android 5.0 (Lollipop)
+## Android 5.0 (API level 21, "Lollipop")
BSD: cat chown cp dd du grep kill ln mv printenv rm rmdir sleep sync
@@ -312,7 +351,7 @@
top touch umount uptime vmstat watchprops wipe
-## Android 4.4 (KitKat)
+## Android 4.4 (API level 19, "KitKat")
BSD: cat cp dd du grep newfs\_msdos
@@ -324,7 +363,7 @@
stop swapoff swapon sync top touch umount uptime vmstat watchprops wipe
-## Android 4.1-4.3 (JellyBean)
+## Android 4.1-4.3 (API level 16, "Jelly Bean")
BSD: cat cp dd du grep newfs\_msdos
@@ -336,7 +375,7 @@
sync top touch umount uptime vmstat watchprops wipe
-## Android 4.0 (IceCreamSandwich)
+## Android 4.0 (API level 14, "Ice Cream Sandwich")
BSD: cat dd newfs\_msdos
@@ -347,7 +386,7 @@
touch umount uptime vmstat watchprops wipe
-## Android 2.3 (Gingerbread)
+## Android 2.3 (API level 9, "Gingerbread")
BSD: cat dd newfs\_msdos
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
index 5e2c581..898ddce 100644
--- a/toolbox/OWNERS
+++ b/toolbox/OWNERS
@@ -1,2 +1,3 @@
include platform/system/core:/janitors/OWNERS
per-file modprobe.c=willmcvicker@google.com,dvander@google.com
+per-file getevent.c=file:platform/frameworks/base:/INPUT_OWNERS
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index f65bb20..7b896e9 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -441,7 +441,7 @@
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
return 0;
- fprintf(stderr, "could not get event, %s\n", strerror(errno));
+ fprintf(stderr, "could not get inotify events, %s\n", strerror(errno));
return 1;
}
//printf("got %d bytes of event information\n", res);
@@ -664,7 +664,7 @@
if(ufds[i].revents & POLLIN) {
res = read(ufds[i].fd, &event, sizeof(event));
if(res < (int)sizeof(event)) {
- fprintf(stderr, "could not get event\n");
+ fprintf(stderr, "could not get evdev event, %s\n", strerror(errno));
return 1;
}
if(get_time) {
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 45dd9b8..b0e76ea 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
@@ -27,6 +28,7 @@
#include <modprobe/modprobe.h>
#include <sys/utsname.h>
+#include <unistd.h>
namespace {
@@ -105,6 +107,11 @@
return 0;
}
+std::string GetPageSizeSuffix() {
+ static const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ return android::base::StringPrintf("_%zuk", page_size / 1024);
+}
+
} // anonymous namespace
extern "C" int modprobe_main(int argc, char** argv) {
@@ -233,6 +240,19 @@
// Allow modules to be directly inside /lib/modules
mod_dirs.emplace_back(LIB_MODULES_PREFIX);
}
+ if (getpagesize() != 4096) {
+ struct utsname uts {};
+ if (uname(&uts)) {
+ PLOG(FATAL) << "Failed to get kernel version";
+ }
+ const auto module_dir = android::base::StringPrintf("/lib/modules/%s%s", uts.release,
+ GetPageSizeSuffix().c_str());
+ struct stat st {};
+ if (stat(module_dir.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
+ mod_dirs.clear();
+ mod_dirs.emplace_back(module_dir);
+ }
+ }
LOG(DEBUG) << "mode is " << mode;
LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " ");
diff --git a/toolbox/setprop.cpp b/toolbox/setprop.cpp
index acf8c3e..91edf45 100644
--- a/toolbox/setprop.cpp
+++ b/toolbox/setprop.cpp
@@ -58,7 +58,7 @@
}
}
- if (value.size() >= PROP_VALUE_MAX && !StartsWith(value, "ro.")) {
+ if (value.size() >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
std::cerr << "Value '" << value << "' is too long, " << value.size()
<< " bytes vs a max of " << PROP_VALUE_MAX << std::endl;
return EXIT_FAILURE;
diff --git a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
index 6b8f90f..dec64e1 100644
--- a/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
+++ b/trusty/keymaster/set_attestation_ids/set_attestation_ids.cpp
@@ -247,6 +247,7 @@
return EXIT_FAILURE;
} else {
printf("done\n");
+ printf("\nNOTE: device reboot may be required before changes take effect.\n");
return EXIT_SUCCESS;
}
}
diff --git a/trusty/keymint/src/keymint_hal_main.rs b/trusty/keymint/src/keymint_hal_main.rs
index eda986a..ef0c598 100644
--- a/trusty/keymint/src/keymint_hal_main.rs
+++ b/trusty/keymint/src/keymint_hal_main.rs
@@ -82,7 +82,7 @@
}
fn main() {
- if let Err(e) = inner_main() {
+ if let Err(HalServiceError(e)) = inner_main() {
panic!("HAL service failed: {:?}", e);
}
}
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index dabe118..3cf0c05 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -37,7 +37,7 @@
#define BENCH_RESULT_TPL \
"{" \
" \"schema_version\": 3," \
-" \"suite_name\": \"crypto\"," \
+" \"suite_name\": \"tipc\"," \
" \"bench_name\": \"%s\"," \
" \"results\": [" \
" {" \
@@ -1041,7 +1041,7 @@
}
avg /= params->bench;
- fprintf(stderr, BENCH_RESULT_TPL, params->test_name, min, max, avg, cold, min, max, avg, cold);
+ printf(BENCH_RESULT_TPL, params->test_name, min, max, avg, cold, min, max, avg, cold);
return rc;
}
diff --git a/trusty/line-coverage/coverage.cpp b/trusty/line-coverage/coverage.cpp
index 5f7b3a3..e4db59c 100644
--- a/trusty/line-coverage/coverage.cpp
+++ b/trusty/line-coverage/coverage.cpp
@@ -174,7 +174,7 @@
}
uintptr_t* begin = (uintptr_t*)((char *)shm_ + sizeof(struct control));
- bool ret = WriteFully(output_fd, begin, record_len_);
+ bool ret = WriteFully(output_fd, begin, record_len_ - sizeof(struct control));
if(!ret) {
fprintf(stderr, "Coverage write to file failed\n");
}
diff --git a/trusty/secretkeeper/src/hal_main.rs b/trusty/secretkeeper/src/hal_main.rs
index df30493..b31db13 100644
--- a/trusty/secretkeeper/src/hal_main.rs
+++ b/trusty/secretkeeper/src/hal_main.rs
@@ -91,7 +91,7 @@
}
fn main() {
- if let Err(e) = inner_main() {
+ if let Err(HalServiceError(e)) = inner_main() {
panic!("HAL service failed: {:?}", e);
}
}
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 67e935e..6cb72d5 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -41,9 +41,13 @@
static const char* trusty_devname;
static const char* rpmb_devname;
static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT;
+static const char* max_file_size_from;
static enum dev_type dev_type = MMC_RPMB;
+/* List head for storage mapping, elements added at init, and never removed */
+static struct storage_mapping_node* storage_mapping_head;
+
static enum dev_type parse_dev_type(const char* dev_type_name) {
if (!strcmp(dev_type_name, "mmc")) {
return MMC_RPMB;
@@ -58,17 +62,61 @@
}
}
-static const char* _sopts = "hp:d:r:t:";
+static int parse_and_append_file_mapping(const char* file_mapping) {
+ if (file_mapping == NULL) {
+ ALOGE("Provided file mapping is null\n");
+ return -1;
+ }
+ char* file_mapping_dup = strdup(file_mapping);
+ if (file_mapping_dup == NULL) {
+ ALOGE("Couldn't duplicate string: %s\n", file_mapping);
+ return -1;
+ }
+ const char* file_name = strtok(file_mapping_dup, ":");
+ if (file_name == NULL) {
+ ALOGE("No file name found\n");
+ return -1;
+ }
+ const char* backing_storage = strtok(NULL, ":");
+ if (backing_storage == NULL) {
+ ALOGE("No backing storage found\n");
+ return -1;
+ }
+
+ struct storage_mapping_node* new_node = malloc(sizeof(struct storage_mapping_node));
+ if (new_node == NULL) {
+ ALOGE("Couldn't allocate additional storage_mapping_node\n");
+ return -1;
+ }
+ *new_node = (struct storage_mapping_node){.file_name = file_name,
+ .backing_storage = backing_storage,
+ .next = storage_mapping_head,
+ .fd = -1};
+ storage_mapping_head = new_node;
+ return 0;
+}
+
+static const char* _sopts = "hp:d:r:t:m:f:";
static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'},
{"trusty_dev", required_argument, NULL, 'd'},
{"data_path", required_argument, NULL, 'p'},
{"rpmb_dev", required_argument, NULL, 'r'},
{"dev_type", required_argument, NULL, 't'},
+ {"max_file_size_from", required_argument, NULL, 'm'},
+ {"file_storage_mapping", required_argument, NULL, 'f'},
{0, 0, 0, 0}};
static void show_usage_and_exit(int code) {
- ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type>\n");
+ ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type> [-m "
+ "<file>] [-f <file>:<mapping>]\n");
ALOGE("Available dev types: mmc, virt\n");
+ ALOGE("-f = Maps secure storage files like `0` and `persist/0`\n"
+ "to block devices. Storageproxyd will handle creating the\n"
+ "appropriate symlinks in the root datapath.\n");
+ ALOGE("-m = Specifies the max size constraint for file backed storages.\n"
+ "The constraint is chosen by giving a file, this allows for passing a\n"
+ "block device for which a max file size can be queried. File based\n"
+ "storages will be constrained to that size as well.\n");
exit(code);
}
@@ -187,6 +235,7 @@
static void parse_args(int argc, char* argv[]) {
int opt;
int oidx = 0;
+ int rc = 0;
while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
switch (opt) {
@@ -210,6 +259,18 @@
}
break;
+ case 'f':
+ rc = parse_and_append_file_mapping(optarg);
+ if (rc < 0) {
+ ALOGE("Failed to parse file mapping: %s\n", optarg);
+ show_usage_and_exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'm':
+ max_file_size_from = strdup(optarg);
+ break;
+
default:
ALOGE("unrecognized option (%c):\n", opt);
show_usage_and_exit(EXIT_FAILURE);
@@ -225,6 +286,12 @@
ALOGI("storage data root: %s\n", ss_data_root);
ALOGI("trusty dev: %s\n", trusty_devname);
ALOGI("rpmb dev: %s\n", rpmb_devname);
+ ALOGI("File Mappings: \n");
+ const struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ ALOGI("\t%s -> %s\n", curr->file_name, curr->backing_storage);
+ }
+ ALOGI("max file size from: %s\n", max_file_size_from ? max_file_size_from : "(unset)");
}
int main(int argc, char* argv[]) {
@@ -252,7 +319,7 @@
ABinderProcess_startThreadPool();
/* initialize secure storage directory */
- rc = storage_init(ss_data_root);
+ rc = storage_init(ss_data_root, storage_mapping_head, max_file_size_from);
if (rc < 0) return EXIT_FAILURE;
/* open rpmb device */
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index 8c8edb7..6d0c616 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <assert.h>
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
@@ -39,16 +40,20 @@
#define ALTERNATE_DATA_DIR "alternate/"
/* Maximum file size for filesystem backed storage (i.e. not block dev backed storage) */
-#define MAX_FILE_SIZE (0x10000000000)
+static uint64_t max_file_size = 0x10000000000;
enum sync_state {
SS_UNUSED = -1,
- SS_CLEAN = 0,
- SS_DIRTY = 1,
+ SS_CLEAN = 0,
+ SS_DIRTY = 1,
+ SS_CLEAN_NEED_SYMLINK = 2,
};
static const char *ssdir_name;
+/* List head for storage mapping, elements added at init, and never removed */
+static struct storage_mapping_node* storage_mapping_head;
+
/*
* Property set to 1 after we have opened a file under ssdir_name. The backing
* files for both TD and TDP are currently located under /data/vendor/ss and can
@@ -75,24 +80,103 @@
uint8_t data[MAX_READ_SIZE];
} read_rsp;
-static uint32_t insert_fd(int open_flags, int fd)
-{
+static uint32_t insert_fd(int open_flags, int fd, struct storage_mapping_node* node) {
uint32_t handle = fd;
if (handle < FD_TBL_SIZE) {
- fd_state[fd] = SS_CLEAN; /* fd clean */
- if (open_flags & O_TRUNC) {
- fd_state[fd] = SS_DIRTY; /* set fd dirty */
- }
+ fd_state[fd] = SS_CLEAN; /* fd clean */
+ if (open_flags & O_TRUNC) {
+ assert(node == NULL);
+ fd_state[fd] = SS_DIRTY; /* set fd dirty */
+ }
+
+ if (node != NULL) {
+ fd_state[fd] = SS_CLEAN_NEED_SYMLINK;
+ }
} else {
ALOGW("%s: untracked fd %u\n", __func__, fd);
if (open_flags & (O_TRUNC | O_CREAT)) {
fs_state = SS_DIRTY;
}
}
+
+ if (node != NULL) {
+ node->fd = fd;
+ }
+
return handle;
}
+static void clear_fd_symlink_status(uint32_t handle, struct storage_mapping_node* entry) {
+ /* Always clear FD, in case fd is not in FD_TBL */
+ entry->fd = -1;
+
+ if (handle >= FD_TBL_SIZE) {
+ ALOGE("%s: untracked fd=%u\n", __func__, handle);
+ return;
+ }
+
+ if (fd_state[handle] == SS_CLEAN_NEED_SYMLINK) {
+ fd_state[handle] = SS_CLEAN;
+ }
+}
+
+static struct storage_mapping_node* get_pending_symlink_mapping(uint32_t handle) {
+ /* Fast lookup failure, is it in FD TBL */
+ if (handle < FD_TBL_SIZE && fd_state[handle] != SS_CLEAN_NEED_SYMLINK) {
+ return NULL;
+ }
+
+ /* Go find our mapping */
+ struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (curr->fd == handle) {
+ return curr;
+ }
+ }
+
+ /* Safety check: state inconsistent if we get here with handle inside table range */
+ assert(handle >= FD_TBL_SIZE);
+
+ return NULL;
+};
+
+static int possibly_symlink_and_clear_mapping(uint32_t handle) {
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ if (entry == NULL) {
+ /* No mappings pending */
+ return 0;
+ }
+
+ /* Create full path */
+ char* path = NULL;
+ int rc = asprintf(&path, "%s/%s", ssdir_name, entry->file_name);
+ if (rc < 0) {
+ ALOGE("%s: asprintf failed\n", __func__);
+ return -1;
+ }
+
+ /* Try and setup the symlinking */
+ ALOGI("Creating symlink %s->%s\n", path, entry->backing_storage);
+ rc = symlink(entry->backing_storage, path);
+ if (rc < 0) {
+ ALOGE("%s: error symlinking %s->%s (%s)\n", __func__, path, entry->backing_storage,
+ strerror(errno));
+ free(path);
+ return rc;
+ }
+ free(path);
+
+ clear_fd_symlink_status(handle, entry);
+
+ return rc;
+}
+
+static bool is_pending_symlink(uint32_t handle) {
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ return entry != NULL;
+}
+
static int lookup_fd(uint32_t handle, bool dirty)
{
if (dirty) {
@@ -107,6 +191,12 @@
static int remove_fd(uint32_t handle)
{
+ /* Cleanup fd in symlink mapping if it exists */
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ if (entry != NULL) {
+ entry->fd = -1;
+ }
+
if (handle < FD_TBL_SIZE) {
fd_state[handle] = SS_UNUSED; /* set to uninstalled */
}
@@ -247,11 +337,73 @@
watch_progress(watcher, "done syncing parent");
}
+static struct storage_mapping_node* get_storage_mapping_entry(const char* source) {
+ struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (!strcmp(source, curr->file_name)) {
+ ALOGI("Found backing file %s for %s\n", curr->backing_storage, source);
+ return curr;
+ }
+ }
+ return NULL;
+}
+
+static bool is_backing_storage_mapped(const char* source) {
+ const struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (!strcmp(source, curr->backing_storage)) {
+ ALOGI("Backed storage mapping exists for %s\n", curr->backing_storage);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Attempts to open a backed file, if mapped, without creating the symlink. Symlink will be created
+ * later on the first write. This allows us to continue reporting zero read sizes until the first
+ * write. */
+static int open_possibly_mapped_file(const char* short_path, const char* full_path, int open_flags,
+ struct storage_mapping_node** entry) {
+ /* See if mapping exists, report upstream if there is no mapping. */
+ struct storage_mapping_node* mapping_entry = get_storage_mapping_entry(short_path);
+ if (mapping_entry == NULL) {
+ return TEMP_FAILURE_RETRY(open(full_path, open_flags, S_IRUSR | S_IWUSR));
+ }
+
+ /* Check for existence of root path, we don't allow mappings during early boot */
+ struct stat buf = {0};
+ if (stat(ssdir_name, &buf) != 0) {
+ ALOGW("Root path not accessible yet, refuse to open mappings for now.\n");
+ return -1;
+ }
+
+ /* We don't support exclusive opening of mapped files */
+ if (open_flags & O_EXCL) {
+ ALOGE("Requesting exclusive open on backed storage isn't supported: %s\n", full_path);
+ return -1;
+ }
+
+ /* Try and open mapping file */
+ open_flags &= ~(O_CREAT | O_EXCL);
+ ALOGI("%s Attempting to open mapped file: %s\n", __func__, mapping_entry->backing_storage);
+ int fd =
+ TEMP_FAILURE_RETRY(open(mapping_entry->backing_storage, open_flags, S_IRUSR | S_IWUSR));
+ if (fd < 0) {
+ ALOGE("%s Failed to open mapping file: %s\n", __func__, mapping_entry->backing_storage);
+ return -1;
+ }
+
+ /* Let caller know which entry we used for opening */
+ *entry = mapping_entry;
+ return fd;
+}
+
int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len,
struct watcher* watcher) {
char* path = NULL;
const struct storage_file_open_req *req = r;
struct storage_file_open_resp resp = {0};
+ struct storage_mapping_node* mapping_entry = NULL;
if (req_len < sizeof(*req)) {
ALOGE("%s: invalid request length (%zd < %zd)\n",
@@ -321,14 +473,18 @@
if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
/* create exclusive */
open_flags |= O_CREAT | O_EXCL;
- rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+
+ /* Look for and attempt opening a mapping, else just do normal open. */
+ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry);
} else {
/* try open first */
rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
if (rc == -1 && errno == ENOENT) {
/* then try open with O_CREATE */
open_flags |= O_CREAT;
- rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+
+ /* Look for and attempt opening a mapping, else just do normal open. */
+ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry);
}
}
@@ -356,7 +512,7 @@
/* at this point rc contains storage file fd */
msg->result = STORAGE_NO_ERROR;
- resp.handle = insert_fd(open_flags, rc);
+ resp.handle = insert_fd(open_flags, rc, mapping_entry);
ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
__func__, path, rc, resp.handle);
@@ -433,6 +589,14 @@
goto err_response;
}
+ /* Handle any delayed symlinking for this handle if any */
+ rc = possibly_symlink_and_clear_mapping(req->handle);
+ if (rc < 0) {
+ ALOGE("Failed to symlink storage\n");
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+
int fd = lookup_fd(req->handle, true);
watch_progress(watcher, "writing");
if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
@@ -479,6 +643,14 @@
goto err_response;
}
+ /* If this handle has a delayed symlink we should report 0 size reads until first write occurs
+ */
+ if (is_pending_symlink(req->handle)) {
+ ALOGI("Pending symlink: Forcing read result 0.\n");
+ msg->result = STORAGE_NO_ERROR;
+ return ipc_respond(msg, &read_rsp, sizeof(read_rsp.hdr));
+ }
+
int fd = lookup_fd(req->handle, false);
watch_progress(watcher, "reading");
ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
@@ -592,7 +764,7 @@
goto err_response;
}
} else {
- max_size = MAX_FILE_SIZE;
+ max_size = max_file_size;
}
resp.max_size = max_size;
@@ -603,17 +775,79 @@
return ipc_respond(msg, NULL, 0);
}
-int storage_init(const char *dirname)
-{
+int determine_max_file_size(const char* max_file_size_from) {
+ /* Use default if none passed in */
+ if (max_file_size_from == NULL) {
+ ALOGI("No max file source given, continuing to use default: 0x%" PRIx64 "\n",
+ max_file_size);
+ return 0;
+ }
+
+ /* Check that max_file_size_from is part of our mapping list. */
+ if (!is_backing_storage_mapped(max_file_size_from)) {
+ ALOGE("%s: file doesn't match mapped storages (filename=%s)\n", __func__,
+ max_file_size_from);
+ return -1;
+ }
+
+ ALOGI("Using %s to determine max file size.\n", max_file_size_from);
+
+ /* Error if max file size source not found, possible misconfig. */
+ struct stat buf = {0};
+ int rc = stat(max_file_size_from, &buf);
+ if (rc < 0) {
+ ALOGE("%s: error stat'ing file (filename=%s): %s\n", __func__, max_file_size_from,
+ strerror(errno));
+ return -1;
+ }
+
+ /* Currently only support block device as max file size source */
+ if ((buf.st_mode & S_IFMT) != S_IFBLK) {
+ ALOGE("Unsupported max file size source type: %d\n", buf.st_mode);
+ return -1;
+ }
+
+ ALOGI("%s is a block device, determining block device size\n", max_file_size_from);
+ uint64_t max_size = 0;
+ int fd = TEMP_FAILURE_RETRY(open(max_file_size_from, O_RDONLY | O_NONBLOCK));
+ if (fd < 0) {
+ ALOGE("%s: failed to open backing file %s for ioctl: %s\n", __func__, max_file_size_from,
+ strerror(errno));
+ return -1;
+ }
+ rc = ioctl(fd, BLKGETSIZE64, &max_size);
+ if (rc < 0) {
+ ALOGE("%s: error calling ioctl on file (fd=%d): %s\n", __func__, fd, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ max_file_size = max_size;
+
+ ALOGI("Using 0x%" PRIx64 " as max file size\n", max_file_size);
+ return 0;
+}
+
+int storage_init(const char* dirname, struct storage_mapping_node* mappings,
+ const char* max_file_size_from) {
/* If there is an active DSU image, use the alternate fs mode. */
alternate_mode = is_gsi_running();
fs_state = SS_CLEAN;
for (uint i = 0; i < FD_TBL_SIZE; i++) {
- fd_state[i] = SS_UNUSED; /* uninstalled */
+ fd_state[i] = SS_UNUSED; /* uninstalled */
}
ssdir_name = dirname;
+
+ storage_mapping_head = mappings;
+
+ /* Set the max file size based on incoming configuration */
+ int rc = determine_max_file_size(max_file_size_from);
+ if (rc < 0) {
+ return rc;
+ }
+
return 0;
}
@@ -623,17 +857,17 @@
watch_progress(watcher, "sync fd table");
/* sync fd table and reset it to clean state first */
for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
- if (fd_state[fd] == SS_DIRTY) {
- if (fs_state == SS_CLEAN) {
- /* need to sync individual fd */
- rc = fsync(fd);
- if (rc < 0) {
- ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
- return rc;
- }
- }
- fd_state[fd] = SS_CLEAN; /* set to clean */
- }
+ if (fd_state[fd] == SS_DIRTY) {
+ if (fs_state == SS_CLEAN) {
+ /* need to sync individual fd */
+ rc = fsync(fd);
+ if (rc < 0) {
+ ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
+ return rc;
+ }
+ }
+ fd_state[fd] = SS_CLEAN; /* set to clean */
+ }
}
/* check if we need to sync all filesystems */
diff --git a/trusty/storage/proxy/storage.h b/trusty/storage/proxy/storage.h
index f29fdf2..6dbfe37 100644
--- a/trusty/storage/proxy/storage.h
+++ b/trusty/storage/proxy/storage.h
@@ -21,6 +21,14 @@
/* Defined in watchdog.h */
struct watcher;
+/* Is used for managing alternate backing storage, generally will be a block device. */
+struct storage_mapping_node {
+ struct storage_mapping_node* next;
+ const char* file_name;
+ const char* backing_storage;
+ int fd;
+};
+
int storage_file_delete(struct storage_msg* msg, const void* req, size_t req_len,
struct watcher* watcher);
@@ -45,6 +53,7 @@
int storage_file_get_max_size(struct storage_msg* msg, const void* req, size_t req_len,
struct watcher* watcher);
-int storage_init(const char* dirname);
+int storage_init(const char* dirname, struct storage_mapping_node* head,
+ const char* max_file_size_from);
int storage_sync_checkpoint(struct watcher* watcher);