Merge "Enable header_abi_checker for libutils explicitly" into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 31e284d..7d20995 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -32,9 +32,10 @@
recovery_available: true,
vendor_ramdisk_available: true,
apex_available: [
+ "com.android.runtime",
"com.android.virt",
"//apex_available:platform",
- ],
+ ],
}
cc_library_shared {
@@ -85,6 +86,7 @@
export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["tombstoned/include"],
+ apex_available: ["com.android.runtime"],
}
// Core implementation, linked into libdebuggerd_handler and the dynamic linker.
@@ -110,6 +112,9 @@
export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["include"],
+ apex_available: [
+ "com.android.runtime",
+ ],
}
// Implementation with a no-op fallback.
@@ -311,6 +316,9 @@
header_libs: ["scudo_headers"],
},
},
+ apex_available: [
+ "com.android.runtime",
+ ],
}
cc_binary {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index a6d8226..c0522aa 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -2221,28 +2221,10 @@
ASSERT_MATCH(result, match_str);
}
-TEST(tombstoned, proto) {
- const pid_t self = getpid();
- unique_fd tombstoned_socket, text_fd, proto_fd;
- ASSERT_TRUE(
- tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
-
- tombstoned_notify_completion(tombstoned_socket.get());
-
- ASSERT_NE(-1, text_fd.get());
- ASSERT_NE(-1, proto_fd.get());
-
- struct stat text_st;
- ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
-
- // Give tombstoned some time to link the files into place.
- std::this_thread::sleep_for(100ms);
-
- // Find the tombstone.
- std::optional<std::string> tombstone_file;
+void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
+ static std::regex tombstone_re("tombstone_\\d+");
std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
ASSERT_TRUE(dir_h != nullptr);
- std::regex tombstone_re("tombstone_\\d+");
dirent* entry;
while ((entry = readdir(dir_h.get())) != nullptr) {
if (!std::regex_match(entry->d_name, tombstone_re)) {
@@ -2260,8 +2242,38 @@
break;
}
}
+}
- ASSERT_TRUE(tombstone_file);
+TEST(tombstoned, proto) {
+ const pid_t self = getpid();
+ unique_fd tombstoned_socket, text_fd, proto_fd;
+ ASSERT_TRUE(
+ tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
+
+ tombstoned_notify_completion(tombstoned_socket.get());
+
+ ASSERT_NE(-1, text_fd.get());
+ ASSERT_NE(-1, proto_fd.get());
+
+ struct stat text_st;
+ ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
+
+ std::optional<std::string> tombstone_file;
+ // Allow up to 5 seconds for the tombstone to be written to the system.
+ const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
+ const auto start = std::chrono::high_resolution_clock::now();
+ while (true) {
+ std::this_thread::sleep_for(100ms);
+ CheckForTombstone(text_st, tombstone_file);
+ if (tombstone_file) {
+ break;
+ }
+ if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
+ break;
+ }
+ }
+
+ ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
std::string proto_path = tombstone_file.value() + ".pb";
struct stat proto_fd_st;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 235d723..12a1ddc 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -571,7 +571,8 @@
" Format a flash partition.\n"
" set_active SLOT Set the active slot.\n"
" oem [COMMAND...] Execute OEM-specific command.\n"
- " gsi wipe|disable Wipe or disable a GSI installation (fastbootd only).\n"
+ " gsi wipe|disable|status Wipe, disable or show status of a GSI installation\n"
+ " (fastbootd only).\n"
" wipe-super [SUPER_EMPTY] Wipe the super partition. This will reset it to\n"
" contain an empty set of default dynamic partitions.\n"
" create-logical-partition NAME SIZE\n"
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index edecd7c..1989a5c 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -42,9 +42,6 @@
"name": "liblp_test"
},
{
- "name": "vts_libsnapshot_test"
- },
- {
"name": "vab_legacy_tests"
},
// TODO(b/279009697):
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index af2b35a..8c0c1ef 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -16,7 +16,6 @@
#include "fs_mgr.h"
-#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -819,9 +818,13 @@
// __mount(): wrapper around the mount() system call which also
// sets the underlying block device to read-only if the mount is read-only.
// See "man 2 mount" for return values.
-static int __mount(const std::string& source, const std::string& target, const FstabEntry& entry) {
+static int __mount(const std::string& source, const std::string& target, const FstabEntry& entry,
+ bool read_only = false) {
errno = 0;
unsigned long mountflags = entry.flags;
+ if (read_only) {
+ mountflags |= MS_RDONLY;
+ }
int ret = 0;
int save_errno = 0;
int gc_allowance = 0;
@@ -915,6 +918,10 @@
return true;
}
+static bool should_use_metadata_encryption(const FstabEntry& entry) {
+ return !entry.metadata_key_dir.empty() && entry.fs_mgr_flags.file_encryption;
+}
+
// Tries to mount any of the consecutive fstab entries that match
// the mountpoint of the one given by fstab[start_idx].
//
@@ -922,8 +929,7 @@
// attempted_idx: On return, will indicate which fstab entry
// succeeded. In case of failure, it will be the start_idx.
// Sets errno to match the 1st mount failure on failure.
-static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx,
- int* attempted_idx) {
+static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx, int* attempted_idx) {
unsigned long i;
int mount_errno = 0;
bool mounted = false;
@@ -961,8 +967,15 @@
}
int retry_count = 2;
+ const auto read_only = should_use_metadata_encryption(fstab[i]);
+ if (read_only) {
+ LOG(INFO) << "Mount point " << fstab[i].blk_device << " @ " << fstab[i].mount_point
+ << " uses metadata encryption, which means we need to unmount it later and "
+ "call encryptFstab/encrypt_inplace. To avoid file operations before "
+ "encryption, we will mount it as read-only first";
+ }
while (retry_count-- > 0) {
- if (!__mount(fstab[i].blk_device, fstab[i].mount_point, fstab[i])) {
+ if (!__mount(fstab[i].blk_device, fstab[i].mount_point, fstab[i], read_only)) {
*attempted_idx = i;
mounted = true;
if (i != start_idx) {
@@ -1054,10 +1067,6 @@
return false;
}
-static bool should_use_metadata_encryption(const FstabEntry& entry) {
- return !entry.metadata_key_dir.empty() && entry.fs_mgr_flags.file_encryption;
-}
-
// Check to see if a mountable volume has encryption requirements
static int handle_encryptable(const FstabEntry& entry) {
if (should_use_metadata_encryption(entry)) {
@@ -1541,6 +1550,7 @@
}
encryptable = status;
if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+ fs_mgr_set_blk_ro(attempted_entry.blk_device, false);
if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
attempted_entry.mount_point, wiped ? "true" : "false",
attempted_entry.fs_type, attempted_entry.zoned_device},
@@ -1978,6 +1988,8 @@
if (retry_count <= 0) break; // run check_fs only once
if (!first_mount_errno) first_mount_errno = errno;
mount_errors++;
+ PERROR << "Cannot mount filesystem on " << n_blk_device << " at " << mount_point
+ << " with fstype " << fstab_entry.fs_type;
fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
// try again after fsck
check_fs(n_blk_device, fstab_entry.fs_type, mount_point, &fs_stat);
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 7ba4d2b..733ba2f 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -380,8 +380,8 @@
// Now remount!
for (const auto& mnt_point : {mount_point, entry.mount_point}) {
- if (::mount(blk_device.c_str(), mnt_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
- nullptr) == 0) {
+ if (::mount(blk_device.c_str(), mnt_point.c_str(), entry.fs_type.c_str(),
+ MS_REMOUNT | MS_NOATIME, nullptr) == 0) {
LOG(INFO) << "Remounted " << mnt_point << " as RW";
return true;
}
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index c522eaf..a0129c2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -580,9 +580,18 @@
ASSERT_TRUE(dm.GetDmDevicePathByName("libdm-test-dm-linear", &path));
ASSERT_EQ(0, access(path.c_str(), F_OK));
+ std::string unique_path;
+ ASSERT_TRUE(dm.GetDeviceUniquePath("libdm-test-dm-linear", &unique_path));
+ ASSERT_EQ(0, access(unique_path.c_str(), F_OK));
+
ASSERT_TRUE(dm.DeleteDevice("libdm-test-dm-linear", 5s));
ASSERT_EQ(DmDeviceState::INVALID, dm.GetState("libdm-test-dm-linear"));
- ASSERT_NE(0, access(path.c_str(), F_OK));
+ // Check that unique path of this device has been deleteted.
+ // Previously this test case used to check that dev node (i.e. /dev/block/dm-XX) has been
+ // deleted. However, this introduces a race condition, ueventd will remove the unique symlink
+ // (i.e. /dev/block/mapper/by-uuid/...) **before** removing the device node, while DeleteDevice
+ // API synchronizes on the unique symlink being deleted.
+ ASSERT_NE(0, access(unique_path.c_str(), F_OK));
ASSERT_EQ(ENOENT, errno);
}
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index fa04c43..7e97dc0 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -114,6 +114,9 @@
// Enable batching for COW writes
bool batched_writes = 14;
+
+ // Size of v3 operation buffer. Needs to be determined during writer initialization
+ uint64 estimated_ops_buffer_size = 15;
}
// Next: 8
@@ -250,4 +253,7 @@
// Whether this update attempt used io_uring.
bool iouring_used = 13;
+
+ // Size of v3 operation buffer. Needs to be determined during writer initialization
+ uint64 estimated_op_count_max = 14;
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 5b1e56c..7df976d 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -33,7 +33,10 @@
namespace android {
namespace snapshot {
-
+struct CowSizeInfo {
+ uint64_t cow_size;
+ uint64_t op_count_max;
+};
struct CowOptions {
uint32_t block_size = 4096;
std::string compression;
@@ -56,7 +59,7 @@
bool batch_write = false;
// Size of the cow operation buffer; used in v3 only.
- uint32_t op_count_max = 0;
+ uint64_t op_count_max = 0;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -92,8 +95,9 @@
// to ensure that the correct headers and footers are written.
virtual bool Finalize() = 0;
- // Return number of bytes the cow image occupies on disk.
- virtual uint64_t GetCowSize() = 0;
+ // Return number of bytes the cow image occupies on disk + the size of sequence && ops buffer
+ // The latter two fields are used in v3 cow format and left as 0 for v2 cow format
+ virtual CowSizeInfo GetCowSizeInfo() const = 0;
virtual uint32_t GetBlockSize() const = 0;
virtual std::optional<uint32_t> GetMaxBlocks() const = 0;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
index c58c654..8491fb0 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
@@ -24,8 +24,7 @@
using FileDescriptor = chromeos_update_engine::FileDescriptor;
MOCK_METHOD(bool, Finalize, (), (override));
-
- MOCK_METHOD(uint64_t, GetCowSize, (), (override));
+ MOCK_METHOD(CowSizeInfo, GetCowSizeInfo, (), (const, override));
MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override));
MOCK_METHOD(bool, AddRawBlocks, (uint64_t, const void*, size_t), (override));
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
index 49d86d8..1d1d24c 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
@@ -601,14 +601,14 @@
ASSERT_TRUE(writer.AddCopy(10, 20));
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
- auto size_before = writer.GetCowSize();
+ auto size_before = writer.GetCowSizeInfo().cow_size;
ASSERT_TRUE(writer.Finalize());
- auto size_after = writer.GetCowSize();
+ auto size_after = writer.GetCowSizeInfo().cow_size;
ASSERT_EQ(size_before, size_after);
struct stat buf;
ASSERT_GE(fstat(cow_->fd, &buf), 0) << strerror(errno);
- ASSERT_EQ(buf.st_size, writer.GetCowSize());
+ ASSERT_EQ(buf.st_size, writer.GetCowSizeInfo().cow_size);
}
TEST_F(CowTest, AppendLabelSmall) {
@@ -637,7 +637,7 @@
struct stat buf;
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
- ASSERT_EQ(buf.st_size, writer->GetCowSize());
+ ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size);
// Read back both operations, and label.
CowReader reader;
@@ -690,7 +690,7 @@
ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
ASSERT_TRUE(writer->AddLabel(1));
// Drop the tail end of the last op header, corrupting it.
- ftruncate(cow_->fd, writer->GetCowSize() - sizeof(CowFooter) - 3);
+ ftruncate(cow_->fd, writer->GetCowSizeInfo().cow_size - sizeof(CowFooter) - 3);
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
@@ -705,7 +705,7 @@
struct stat buf;
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
- ASSERT_EQ(buf.st_size, writer->GetCowSize());
+ ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size);
// Read back both operations.
CowReader reader;
@@ -763,7 +763,7 @@
struct stat buf;
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
- ASSERT_EQ(buf.st_size, writer->GetCowSize());
+ ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size);
// Read back all valid operations
CowReader reader;
@@ -812,7 +812,7 @@
struct stat buf;
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
- ASSERT_EQ(buf.st_size, writer->GetCowSize());
+ ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size);
// Read back all ops
CowReader reader;
@@ -989,7 +989,7 @@
struct stat buf;
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
- ASSERT_EQ(buf.st_size, writer->GetCowSize());
+ ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size);
// Read back both operations, plus cluster op at end
CowReader reader;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index 3383a58..8cf46f4 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -658,14 +658,14 @@
options.compression = "none";
auto estimator = android::snapshot::CreateCowEstimator(3, options);
ASSERT_TRUE(estimator->AddZeroBlocks(0, 1024 * 1024));
- const auto cow_size = estimator->GetCowSize();
+ const auto cow_size = estimator->GetCowSizeInfo().cow_size;
options.op_count_max = 1024 * 1024;
options.max_blocks = 1024 * 1024;
CowWriterV3 writer(options, GetCowFd());
ASSERT_TRUE(writer.Initialize());
ASSERT_TRUE(writer.AddZeroBlocks(0, 1024 * 1024));
- ASSERT_LE(writer.GetCowSize(), cow_size);
+ ASSERT_LE(writer.GetCowSizeInfo().cow_size, cow_size);
}
TEST_F(CowTestV3, CopyOpMany) {
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index f9a4e47..75cd111 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -576,12 +576,14 @@
return Sync();
}
-uint64_t CowWriterV2::GetCowSize() {
+CowSizeInfo CowWriterV2::GetCowSizeInfo() const {
+ CowSizeInfo info;
if (current_data_size_ > 0) {
- return next_data_pos_ + sizeof(footer_);
+ info.cow_size = next_data_pos_ + sizeof(footer_);
} else {
- return next_op_pos_ + sizeof(footer_);
+ info.cow_size = next_op_pos_ + sizeof(footer_);
}
+ return info;
}
bool CowWriterV2::GetDataPos(uint64_t* pos) {
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
index 50e635f..05de2ad 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h
@@ -27,7 +27,7 @@
bool Initialize(std::optional<uint64_t> label = {}) override;
bool Finalize() override;
- uint64_t GetCowSize() override;
+ CowSizeInfo GetCowSizeInfo() const override;
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index d99e6e6..be6b6da 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -34,6 +34,7 @@
#include <zlib.h>
#include <fcntl.h>
+#include <libsnapshot/cow_compress.h>
#include <libsnapshot_cow/parser_v3.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
@@ -55,11 +56,35 @@
using android::base::unique_fd;
+// Divide |x| by |y| and round up to the nearest integer.
+constexpr uint64_t DivRoundUp(uint64_t x, uint64_t y) {
+ return (x + y - 1) / y;
+}
+
CowWriterV3::CowWriterV3(const CowOptions& options, unique_fd&& fd)
: CowWriterBase(options, std::move(fd)), batch_size_(std::max<size_t>(options.cluster_ops, 1)) {
SetupHeaders();
}
+void CowWriterV3::InitWorkers() {
+ if (num_compress_threads_ <= 1) {
+ LOG_INFO << "Not creating new threads for compression.";
+ return;
+ }
+ compress_threads_.reserve(num_compress_threads_);
+ compress_threads_.clear();
+ threads_.reserve(num_compress_threads_);
+ threads_.clear();
+ for (size_t i = 0; i < num_compress_threads_; i++) {
+ std::unique_ptr<ICompressor> compressor =
+ ICompressor::Create(compression_, header_.block_size);
+ auto&& wt = compress_threads_.emplace_back(
+ std::make_unique<CompressWorker>(std::move(compressor), header_.block_size));
+ threads_.emplace_back(std::thread([wt = wt.get()]() { wt->RunThread(); }));
+ }
+ LOG(INFO) << num_compress_threads_ << " thread used for compression";
+}
+
void CowWriterV3::SetupHeaders() {
header_ = {};
header_.prefix.magic = kCowMagicNumber;
@@ -135,10 +160,24 @@
} else {
LOG(INFO) << "Batch writes: disabled";
}
+ if (android::base::GetBoolProperty("ro.virtual_ab.compression.threads", false) &&
+ options_.num_compress_threads) {
+ num_compress_threads_ = options_.num_compress_threads;
+ }
+ InitWorkers();
return true;
}
-CowWriterV3::~CowWriterV3() {}
+CowWriterV3::~CowWriterV3() {
+ for (const auto& t : compress_threads_) {
+ t->Finalize();
+ }
+ for (auto& t : threads_) {
+ if (t.joinable()) {
+ t.join();
+ }
+ }
+}
bool CowWriterV3::Initialize(std::optional<uint64_t> label) {
if (!InitFd() || !ParseOptions()) {
@@ -289,19 +328,24 @@
<< " but compressor is uninitialized.";
return false;
}
+ const auto bytes = reinterpret_cast<const uint8_t*>(data);
const size_t num_blocks = (size / header_.block_size);
for (size_t i = 0; i < num_blocks;) {
const auto blocks_to_write =
std::min<size_t>(batch_size_ - cached_data_.size(), num_blocks - i);
size_t compressed_bytes = 0;
+ auto&& blocks = CompressBlocks(blocks_to_write, bytes + header_.block_size * i);
+ if (blocks.size() != blocks_to_write) {
+ LOG(ERROR) << "Failed to compress blocks " << new_block_start + i << ", "
+ << blocks_to_write << ", actual number of blocks received from compressor "
+ << blocks.size();
+ return false;
+ }
for (size_t j = 0; j < blocks_to_write; j++) {
- const uint8_t* const iter =
- reinterpret_cast<const uint8_t*>(data) + (header_.block_size * (i + j));
-
CowOperation& op = cached_ops_.emplace_back();
auto& vec = data_vec_.emplace_back();
- auto& compressed_data = cached_data_.emplace_back();
+ auto& compressed_data = cached_data_.emplace_back(std::move(blocks[j]));
op.new_block = new_block_start + i + j;
op.set_type(type);
@@ -310,20 +354,6 @@
} else {
op.set_source(next_data_pos_ + compressed_bytes);
}
- if (compression_.algorithm == kCowCompressNone) {
- compressed_data.resize(header_.block_size);
- } else {
- compressed_data = compressor_->Compress(iter, header_.block_size);
- if (compressed_data.empty()) {
- LOG(ERROR) << "Compression failed during EmitBlocks(" << new_block_start << ", "
- << num_blocks << ");";
- return false;
- }
- }
- if (compressed_data.size() >= header_.block_size) {
- compressed_data.resize(header_.block_size);
- std::memcpy(compressed_data.data(), iter, header_.block_size);
- }
vec = {.iov_base = compressed_data.data(), .iov_len = compressed_data.size()};
op.data_length = vec.iov_len;
compressed_bytes += op.data_length;
@@ -392,7 +422,6 @@
}
bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) {
- // TODO: size sequence buffer based on options
if (header_.op_count > 0 || !cached_ops_.empty()) {
LOG(ERROR) << "There's " << header_.op_count << " operations written to disk and "
<< cached_ops_.size()
@@ -400,8 +429,14 @@
"operation writes.";
return false;
}
+
header_.sequence_data_count = num_ops;
+
+ // Ensure next_data_pos_ is updated as previously initialized + the newly added sequence buffer.
+ CHECK_EQ(next_data_pos_ + header_.sequence_data_count * sizeof(uint32_t),
+ GetDataOffset(header_));
next_data_pos_ = GetDataOffset(header_);
+
if (!android::base::WriteFullyAtOffset(fd_, data, sizeof(data[0]) * num_ops,
GetSequenceOffset(header_))) {
PLOG(ERROR) << "writing sequence buffer failed";
@@ -438,6 +473,57 @@
return true;
}
+std::vector<std::basic_string<uint8_t>> CowWriterV3::CompressBlocks(const size_t num_blocks,
+ const void* data) {
+ const size_t num_threads = (num_blocks == 1) ? 1 : num_compress_threads_;
+ const size_t blocks_per_thread = DivRoundUp(num_blocks, num_threads);
+ std::vector<std::basic_string<uint8_t>> compressed_buf;
+ compressed_buf.clear();
+ const uint8_t* const iter = reinterpret_cast<const uint8_t*>(data);
+ if (compression_.algorithm == kCowCompressNone) {
+ for (size_t i = 0; i < num_blocks; i++) {
+ auto& buf = compressed_buf.emplace_back();
+ buf.resize(header_.block_size);
+ std::memcpy(buf.data(), iter + i * header_.block_size, header_.block_size);
+ }
+ return compressed_buf;
+ }
+ if (num_threads <= 1) {
+ if (!CompressWorker::CompressBlocks(compressor_.get(), header_.block_size, data, num_blocks,
+ &compressed_buf)) {
+ return {};
+ }
+ } else {
+ // Submit the blocks per thread. The retrieval of
+ // compressed buffers has to be done in the same order.
+ // We should not poll for completed buffers in a different order as the
+ // buffers are tightly coupled with block ordering.
+ for (size_t i = 0; i < num_threads; i++) {
+ CompressWorker* worker = compress_threads_[i].get();
+ const auto blocks_in_batch =
+ std::min(num_blocks - i * blocks_per_thread, blocks_per_thread);
+ worker->EnqueueCompressBlocks(iter + i * blocks_per_thread * header_.block_size,
+ blocks_in_batch);
+ }
+
+ for (size_t i = 0; i < num_threads; i++) {
+ CompressWorker* worker = compress_threads_[i].get();
+ if (!worker->GetCompressedBuffers(&compressed_buf)) {
+ return {};
+ }
+ }
+ }
+ for (size_t i = 0; i < num_blocks; i++) {
+ auto& block = compressed_buf[i];
+ if (block.size() >= header_.block_size) {
+ block.resize(header_.block_size);
+ std::memcpy(block.data(), iter + header_.block_size * i, header_.block_size);
+ }
+ }
+
+ return compressed_buf;
+}
+
bool CowWriterV3::WriteOperation(std::basic_string_view<CowOperationV3> ops,
std::basic_string_view<struct iovec> data) {
const auto total_data_size =
@@ -491,8 +577,11 @@
return Sync();
}
-uint64_t CowWriterV3::GetCowSize() {
- return next_data_pos_;
+CowSizeInfo CowWriterV3::GetCowSizeInfo() const {
+ CowSizeInfo info;
+ info.cow_size = next_data_pos_;
+ info.op_count_max = header_.op_count_max;
+ return info;
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
index 3a7b877..b19af60 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h
@@ -16,6 +16,7 @@
#include <android-base/logging.h>
#include <string_view>
+#include <thread>
#include <vector>
#include "writer_base.h"
@@ -30,7 +31,7 @@
bool Initialize(std::optional<uint64_t> label = {}) override;
bool Finalize() override;
- uint64_t GetCowSize() override;
+ CowSizeInfo GetCowSizeInfo() const override;
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
@@ -51,12 +52,14 @@
std::basic_string_view<struct iovec> data);
bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block,
uint16_t offset, CowOperationType type);
- bool CompressBlocks(size_t num_blocks, const void* data);
bool CheckOpCount(size_t op_count);
private:
+ std::vector<std::basic_string<uint8_t>> CompressBlocks(const size_t num_blocks,
+ const void* data);
bool ReadBackVerification();
bool FlushCacheOps();
+ void InitWorkers();
CowHeaderV3 header_{};
CowCompression compression_;
// in the case that we are using one thread for compression, we can store and re-use the same
@@ -75,6 +78,8 @@
std::vector<CowOperationV3> cached_ops_;
std::vector<std::basic_string<uint8_t>> cached_data_;
std::vector<struct iovec> data_vec_;
+
+ std::vector<std::thread> threads_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 5bc7e65..c0d2073 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -217,6 +217,7 @@
if (update && update->has_estimate_cow_size()) {
ret.snapshot_status.set_estimated_cow_size(update->estimate_cow_size());
+ ret.snapshot_status.set_estimated_ops_buffer_size(update->estimate_op_count_max());
}
if (ret.snapshot_status.snapshot_size() == 0) {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e33bdff..9eb41b2 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3551,6 +3551,9 @@
options.scratch_space = false;
}
options.compression = it->second.compression_algorithm();
+ if (cow_version >= 3) {
+ options.op_count_max = it->second.estimated_ops_buffer_size();
+ }
auto writer = CreateCowWriter(cow_version, options, std::move(fd));
if (!writer->Finalize()) {
@@ -3662,9 +3665,7 @@
cow_options.max_blocks = {status.device_size() / cow_options.block_size};
cow_options.batch_write = status.batched_writes();
cow_options.num_compress_threads = status.enable_threading() ? 2 : 1;
- // TODO(b/313962438) Improve op_count estimate. For now, use number of
- // blocks as an upper bound.
- cow_options.op_count_max = status.device_size() / cow_options.block_size;
+ cow_options.op_count_max = status.estimated_ops_buffer_size();
// Disable scratch space for vts tests
if (device()->IsTestDevice()) {
cow_options.scratch_space = false;
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 6b8e084..bd296a3 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -86,10 +86,15 @@
"libext4_utils",
"libsnapshot_cow",
"liburing",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libcgrouprc",
+ "libcgrouprc_format",
],
include_dirs: ["bionic/libc/kernel"],
export_include_dirs: ["include"],
header_libs: [
+ "libcutils_headers",
"libstorage_literals_headers",
],
ramdisk_available: true,
@@ -126,6 +131,10 @@
"liblog",
"libsnapshot_cow",
"libsnapuserd",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libcgrouprc",
+ "libcgrouprc_format",
"libsnapuserd_client",
"libz",
"liblz4",
@@ -135,6 +144,7 @@
],
header_libs: [
+ "libcutils_headers",
"libstorage_literals_headers",
],
@@ -251,6 +261,10 @@
"libgtest",
"libsnapshot_cow",
"libsnapuserd",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libcgrouprc",
+ "libcgrouprc_format",
"liburing",
"libz",
],
@@ -261,6 +275,7 @@
header_libs: [
"libstorage_literals_headers",
"libfiemap_headers",
+ "libcutils_headers",
],
test_options: {
min_shipping_api_level: 30,
@@ -320,6 +335,10 @@
"libgflags",
"libsnapshot_cow",
"libsnapuserd",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libcgrouprc",
+ "libcgrouprc_format",
"liburing",
"libz",
],
@@ -330,5 +349,6 @@
header_libs: [
"libstorage_literals_headers",
"libfiemap_headers",
+ "libcutils_headers",
],
}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
index bcf9aab..1e7d0c0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
@@ -80,16 +80,16 @@
}
bool MergeWorker::MergeReplaceZeroOps() {
- // Flush after merging 2MB. Since all ops are independent and there is no
+ // Flush after merging 1MB. Since all ops are independent and there is no
// dependency between COW ops, we will flush the data and the number
// of ops merged in COW block device. If there is a crash, we will
// end up replaying some of the COW ops which were already merged. That is
// ok.
//
- // Although increasing this greater than 2MB may help in improving merge
+ // Although increasing this greater than 1MB may help in improving merge
// times; however, on devices with low memory, this can be problematic
// when there are multiple merge threads in parallel.
- int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ) * 2;
+ int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ);
int num_ops_merged = 0;
SNAP_LOG(INFO) << "MergeReplaceZeroOps started....";
@@ -561,6 +561,10 @@
SNAP_PLOG(ERROR) << "Failed to set thread priority";
}
+ if (!SetProfiles({"CPUSET_SP_BACKGROUND"})) {
+ SNAP_PLOG(ERROR) << "Failed to assign task profile to Mergeworker thread";
+ }
+
SNAP_LOG(INFO) << "Merge starting..";
bufsink_.Initialize(PAYLOAD_BUFFER_SZ);
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index c08c1b1..2baf20d 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -782,6 +782,10 @@
SNAP_PLOG(ERROR) << "Failed to set thread priority";
}
+ if (!SetProfiles({"CPUSET_SP_BACKGROUND"})) {
+ SNAP_PLOG(ERROR) << "Failed to assign task profile to readahead thread";
+ }
+
SNAP_LOG(INFO) << "ReadAhead processing.";
while (!RAIterDone()) {
if (!ReadAheadIOStart()) {
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp
index fcdb69d..684ca3d 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp
@@ -19,6 +19,9 @@
#include <unistd.h>
#include <android-base/file.h>
+#include <processgroup/processgroup.h>
+
+#include <private/android_filesystem_config.h>
namespace android {
namespace snapshot {
@@ -33,6 +36,17 @@
#endif
}
+bool SetProfiles([[maybe_unused]] std::initializer_list<std::string_view> profiles) {
+#ifdef __ANDROID__
+ if (setgid(AID_SYSTEM)) {
+ return false;
+ }
+ return SetTaskProfiles(gettid(), profiles);
+#else
+ return true;
+#endif
+}
+
bool KernelSupportsIoUring() {
struct utsname uts {};
unsigned int major, minor;
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h
index 255aee1..c3c3cba 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.h
+++ b/fs_mgr/libsnapshot/snapuserd/utility.h
@@ -14,10 +14,14 @@
#pragma once
+#include <initializer_list>
+#include <string_view>
+
namespace android {
namespace snapshot {
bool SetThreadPriority(int priority);
+bool SetProfiles(std::initializer_list<std::string_view> profiles);
bool KernelSupportsIoUring();
} // namespace snapshot
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c87e564..7ac7a16 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1233,6 +1233,12 @@
adb_sh grep -q " /vendor [^ ]* rw," /proc/mounts </dev/null &&
die "/vendor is not RO"
+data_device=$(adb_sh awk '$2 == "/data" { print $1; exit }' /proc/mounts)
+RO=$(adb_sh grep " ro," /proc/mounts </dev/null |
+ grep -v "^${data_device}" |
+ skip_administrative_mounts |
+ awk '{ print $1 }')
+
T=$(adb_date)
adb remount >&2 ||
die -t "${T}" "adb remount"
@@ -1241,6 +1247,12 @@
adb_sh grep -q " /vendor [^ ]* rw," /proc/mounts </dev/null ||
die -t "${T}" "/vendor is not RW"
+# Only find mounts that are remounted RO -> RW
+RW=$(adb_sh grep " rw," /proc/mounts </dev/null |
+ grep -v "^${data_device}" |
+ skip_administrative_mounts |
+ grep -E "^($(join_with '|' ${RO})) ")
+
scratch_on_super=false
if ${overlayfs_needed}; then
is_overlayfs_mounted /system ||
@@ -1287,27 +1299,19 @@
fi
done
- data_device=$(adb_sh awk '$2 == "/data" { print $1; exit }' /proc/mounts)
# KISS (we do not support sub-mounts for system partitions currently)
adb_sh grep "^overlay " /proc/mounts </dev/null |
grep -vE "^overlay.* /(apex|system|vendor)/[^ ]" |
grep " overlay ro," &&
die "expected overlay to be RW after remount"
- adb_sh grep -v noatime /proc/mounts </dev/null |
- grep -v "^${data_device}" |
- skip_administrative_mounts |
- grep -v ' ro,' &&
- die "mounts are not noatime"
- D=$(adb_sh grep " rw," /proc/mounts </dev/null |
- grep -v "^${data_device}" |
- skip_administrative_mounts |
+ D=$(echo "${RW}" |
awk '{ print $1 }' |
sed 's|/dev/root|/|' |
sort -u)
if [ -n "${D}" ]; then
adb_sh df -k ${D} </dev/null |
- sed -e 's/^Filesystem /Filesystem (rw) /'
+ sed -e 's/^Filesystem /Filesystem (rw)/'
fi >&2
for d in ${D}; do
if adb_sh tune2fs -l "${d}" </dev/null 2>&1 | grep -q "Filesystem features:.*shared_blocks" ||
@@ -1319,6 +1323,10 @@
is_overlayfs_mounted && die -t "${T}" "unexpected overlay takeover"
fi
+echo -n "${RW}" |
+ grep -v noatime &&
+ die "mounts (rw) are not noatime"
+
LOG OK "adb remount RW"
################################################################################
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 8f15220..9503072 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -99,12 +99,7 @@
ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/super", &super_bdev));
ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev));
- std::vector<std::string> must_be_f2fs = {"/data"};
- if (vsr_level >= __ANDROID_API_U__ &&
- !DeviceSupportsFeature("android.hardware.type.automotive")) {
- must_be_f2fs.emplace_back("/metadata");
- }
-
+ std::vector<std::string> data_fs = {"/data", "/metadata"};
for (const auto& entry : fstab) {
std::string parent_bdev = entry.blk_device;
while (true) {
@@ -138,11 +133,10 @@
std::vector<std::string> allowed = {"erofs", "ext4", "f2fs"};
EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end())
<< entry.mount_point;
- } else {
- if (std::find(must_be_f2fs.begin(), must_be_f2fs.end(), entry.mount_point) !=
- must_be_f2fs.end()) {
- EXPECT_EQ(entry.fs_type, "f2fs") << entry.mount_point;
- }
+ } else if (std::find(data_fs.begin(), data_fs.end(), entry.mount_point) != data_fs.end()) {
+ std::vector<std::string> allowed = {"ext4", "f2fs"};
+ EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end())
+ << entry.mount_point << ", " << entry.fs_type;
}
}
}
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 427ac48..e158e07 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -100,44 +100,6 @@
],
}
-cc_defaults {
- name: "android.hardware.health@2.0-service_defaults",
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- static_libs: [
- "android.hardware.health@2.0-impl",
- "android.hardware.health@1.0-convert",
- "libhealthservice",
- "libhealthstoragedefault",
- "libbatterymonitor",
- ],
-
- shared_libs: [
- "libbase",
- "libcutils",
- "libhidlbase",
- "liblog",
- "libutils",
- "android.hardware.health@2.0",
- ],
-}
-
-cc_binary {
- name: "android.hardware.health@2.0-service",
- defaults: ["android.hardware.health@2.0-service_defaults"],
-
- vendor: true,
- relative_install_path: "hw",
- init_rc: ["android.hardware.health@2.0-service.rc"],
- srcs: [
- "HealthServiceDefault.cpp",
- ],
-}
-
cc_library_static {
name: "libhealthd_charger_nops",
recovery_available: true,
diff --git a/healthd/HealthServiceDefault.cpp b/healthd/HealthServiceDefault.cpp
deleted file mode 100644
index 89ecc2f..0000000
--- a/healthd/HealthServiceDefault.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <health2/service.h>
-#include <healthd/healthd.h>
-
-void healthd_board_init(struct healthd_config*) {
- // Implementation-defined init logic goes here.
- // 1. config->periodic_chores_interval_* variables
- // 2. config->battery*Path variables
- // 3. config->energyCounter. In this implementation, energyCounter is not defined.
-
- // use defaults
-}
-
-int healthd_board_battery_update(struct android::BatteryProperties*) {
- // Implementation-defined update logic goes here. An implementation
- // can make modifications to prop before broadcasting it to all callbacks.
-
- // return 0 to log periodic polled battery status to kernel log
- return 0;
-}
-
-int main() {
- return health_service_main();
-}
diff --git a/healthd/android.hardware.health@2.0-service.rc b/healthd/android.hardware.health@2.0-service.rc
deleted file mode 100644
index 762771e..0000000
--- a/healthd/android.hardware.health@2.0-service.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service
- class hal
- user system
- group system
- capabilities WAKE_ALARM BLOCK_SUSPEND
- file /dev/kmsg w
diff --git a/init/Android.bp b/init/Android.bp
index e5512e6..a7278d6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -188,7 +188,6 @@
"libfs_mgr",
"libgsi",
"libhidl-gen-utils",
- "libkeyutils",
"liblog",
"liblogwrap",
"liblp",
@@ -197,6 +196,7 @@
"libselinux",
"libunwindstack",
"libutils",
+ "libvendorsupport",
],
header_libs: ["bionic_libc_platform_headers"],
bootstrap: true,
diff --git a/init/builtins.cpp b/init/builtins.cpp
index a95a4a3..606ea8c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -592,9 +592,6 @@
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED ||
code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED ||
code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
- if (!FscryptInstallKeyring()) {
- return Error() << "FscryptInstallKeyring() failed";
- }
SetProperty("ro.crypto.state", "encrypted");
// Although encrypted, vold has already set the device up, so we do not need to
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
index fbd8189..6a561e5 100644
--- a/init/fscrypt_init_extensions.cpp
+++ b/init/fscrypt_init_extensions.cpp
@@ -34,28 +34,12 @@
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <fscrypt/fscrypt.h>
-#include <keyutils.h>
#include <logwrap/logwrap.h>
#define TAG "fscrypt"
using namespace android::fscrypt;
-bool FscryptInstallKeyring() {
- if (keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0) != -1) {
- LOG(INFO) << "Keyring is already created";
- return true;
- }
- key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0, KEY_SPEC_SESSION_KEYRING);
-
- if (device_keyring == -1) {
- PLOG(ERROR) << "Failed to create keyring";
- return false;
- }
- LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
- return true;
-}
-
// TODO(b/139378601): use a single central implementation of this.
static void delete_dir_contents(const std::string& dir) {
char* const paths[2] = {const_cast<char*>(dir.c_str()), nullptr};
diff --git a/init/fscrypt_init_extensions.h b/init/fscrypt_init_extensions.h
index d357bb2..5e0269a 100644
--- a/init/fscrypt_init_extensions.h
+++ b/init/fscrypt_init_extensions.h
@@ -25,6 +25,5 @@
kDeleteIfNecessary,
};
-bool FscryptInstallKeyring();
bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
const std::string& dir);
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
index 856ca8c..9916246 100644
--- a/init/fuzzer/Android.bp
+++ b/init/fuzzer/Android.bp
@@ -32,7 +32,6 @@
"libbase",
"libfs_mgr",
"libhidl-gen-utils",
- "libkeyutils",
"liblog",
"libprocessgroup",
"libselinux",
diff --git a/init/init.cpp b/init/init.cpp
index aeccd66..19e909f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -54,7 +54,6 @@
#include <android-base/thread_annotations.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr_vendor_overlay.h>
-#include <keyutils.h>
#include <libavb/libavb.h>
#include <libgsi/libgsi.h>
#include <libsnapshot/snapshot.h>
@@ -971,11 +970,6 @@
<< " to /proc/1/oom_score_adj: " << result.error();
}
- // Set up a session keyring that all processes will have access to. It
- // will hold things like FBE encryption keys. No process should override
- // its session keyring.
- keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
-
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e2cff95..30ad800 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -63,6 +63,7 @@
#include <selinux/android.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
+#include <vendorsupport/api_level.h>
#include "debug_ramdisk.h"
#include "epoll.h"
@@ -113,7 +114,6 @@
constexpr auto LEGACY_ID_PROP = "ro.build.legacy.id";
constexpr auto VBMETA_DIGEST_PROP = "ro.boot.vbmeta.digest";
constexpr auto DIGEST_SIZE_USED = 8;
-constexpr auto MAX_VENDOR_API_LEVEL = 1000000;
static bool persistent_properties_loaded = false;
@@ -1085,25 +1085,13 @@
}
}
-static int vendor_api_level_of(int sdk_api_level) {
- if (sdk_api_level < __ANDROID_API_V__) {
- return sdk_api_level;
- }
- // In Android V, vendor API level started with version 202404.
- // The calculation assumes that the SDK api level bumps once a year.
- if (sdk_api_level < __ANDROID_API_FUTURE__) {
- return 202404 + ((sdk_api_level - __ANDROID_API_V__) * 100);
- }
- return MAX_VENDOR_API_LEVEL;
-}
-
static void property_initialize_ro_vendor_api_level() {
// ro.vendor.api_level shows the api_level that the vendor images (vendor, odm, ...) are
// required to support.
constexpr auto VENDOR_API_LEVEL_PROP = "ro.vendor.api_level";
- auto vendor_api_level = GetIntProperty("ro.board.first_api_level", MAX_VENDOR_API_LEVEL);
- if (vendor_api_level != MAX_VENDOR_API_LEVEL) {
+ auto vendor_api_level = GetIntProperty("ro.board.first_api_level", __ANDROID_VENDOR_API_MAX__);
+ if (vendor_api_level != __ANDROID_VENDOR_API_MAX__) {
// Update the vendor_api_level with "ro.board.api_level" only if both "ro.board.api_level"
// and "ro.board.first_api_level" are defined.
vendor_api_level = GetIntProperty("ro.board.api_level", vendor_api_level);
@@ -1118,6 +1106,12 @@
vendor_api_level = std::min(vendor_api_level_of(product_first_api_level), vendor_api_level);
+ if (vendor_api_level < 0) {
+ LOG(ERROR) << "Unexpected vendor api level for " << VENDOR_API_LEVEL_PROP << ". Check "
+ << "ro.product.first_api_level and ro.build.version.sdk.";
+ vendor_api_level = __ANDROID_VENDOR_API_MAX__;
+ }
+
std::string error;
auto res = PropertySetNoSocket(VENDOR_API_LEVEL_PROP, std::to_string(vendor_api_level), &error);
if (res != PROP_SUCCESS) {
diff --git a/janitors/OWNERS b/janitors/OWNERS
index d871201..a28737e 100644
--- a/janitors/OWNERS
+++ b/janitors/OWNERS
@@ -3,5 +3,4 @@
cferris@google.com
dwillemsen@google.com
enh@google.com
-narayan@google.com
sadafebrahimi@google.com
diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp
new file mode 100644
index 0000000..b4457b1
--- /dev/null
+++ b/libvendorsupport/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "libvendorsupport",
+ native_bridge_supported: true,
+ recovery_available: true,
+ llndk: {
+ symbol_file: "libvendorsupport.map.txt",
+ },
+ srcs: ["version_props.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ local_include_dirs: ["include/vendorsupport"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ ],
+}
diff --git a/libvendorsupport/OWNERS b/libvendorsupport/OWNERS
new file mode 100644
index 0000000..2ab18eb
--- /dev/null
+++ b/libvendorsupport/OWNERS
@@ -0,0 +1,2 @@
+jiyong@google.com
+justinyun@google.com
diff --git a/libvendorsupport/TEST_MAPPING b/libvendorsupport/TEST_MAPPING
new file mode 100644
index 0000000..5bd09ba
--- /dev/null
+++ b/libvendorsupport/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "libvendorsupport-tests"
+ }
+ ]
+}
diff --git a/libvendorsupport/include/vendorsupport/api_level.h b/libvendorsupport/include/vendorsupport/api_level.h
new file mode 100644
index 0000000..ba1a6b8
--- /dev/null
+++ b/libvendorsupport/include/vendorsupport/api_level.h
@@ -0,0 +1,51 @@
+// 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
+
+#include <android/api-level.h>
+
+#define __ANDROID_VENDOR_API_MAX__ 1000000
+#define __INVALID_API_LEVEL -1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Find corresponding vendor API level from an SDK API version.
+ *
+ * @details
+ * SDK API versions and vendor API levels are not compatible and not
+ * convertible. However, this function can be used to compare the two versions
+ * to know which one is newer than the other.
+ *
+ * @param sdk_api_level The SDK version int. This must be less than 10000.
+ * @return The corresponding vendor API level of the SDK version. -1 if the SDK
+ * version is invalid or 10000.
+ */
+int vendor_api_level_of(int sdk_api_level);
+
+/**
+ * @brief Find corresponding SDK API version from a vendor API level.
+ *
+ * @param vendor_api_level The vendor API level int.
+ * @return The corresponding SDK API version of the vendor API level. -1 if the
+ * vendor API level is invalid.
+ */
+int sdk_api_level_of(int vendor_api_level);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libvendorsupport/libvendorsupport.map.txt b/libvendorsupport/libvendorsupport.map.txt
new file mode 100644
index 0000000..9a23b94
--- /dev/null
+++ b/libvendorsupport/libvendorsupport.map.txt
@@ -0,0 +1,7 @@
+LIBVENDORSUPPORT {
+ global:
+ vendor_api_level_of; # llndk systemapi
+ sdk_api_level_of; # llndk systemapi
+ local:
+ *;
+};
diff --git a/libvendorsupport/tests/Android.bp b/libvendorsupport/tests/Android.bp
new file mode 100644
index 0000000..42e3371
--- /dev/null
+++ b/libvendorsupport/tests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "libvendorsupport-tests",
+ srcs: [
+ "version_props_test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libvendorsupport",
+ ],
+ test_suites: ["general-tests"],
+}
+
diff --git a/libvendorsupport/tests/version_props_test.cpp b/libvendorsupport/tests/version_props_test.cpp
new file mode 100644
index 0000000..538a2e2
--- /dev/null
+++ b/libvendorsupport/tests/version_props_test.cpp
@@ -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.
+ */
+#include <gtest/gtest.h>
+
+#include <vendorsupport/api_level.h>
+
+using namespace std;
+
+namespace {
+
+TEST(vendorsupport, get_corresponding_vendor_api_level) {
+ ASSERT_EQ(__ANDROID_API_U__, vendor_api_level_of(__ANDROID_API_U__));
+ ASSERT_EQ(202404, vendor_api_level_of(__ANDROID_API_V__));
+ ASSERT_EQ(__INVALID_API_LEVEL, vendor_api_level_of(__ANDROID_API_FUTURE__));
+}
+
+TEST(vendorsupport, get_corresponding_sdk_api_level) {
+ ASSERT_EQ(__ANDROID_API_U__, sdk_api_level_of(__ANDROID_API_U__));
+ ASSERT_EQ(__ANDROID_API_V__, sdk_api_level_of(202404));
+ ASSERT_EQ(__INVALID_API_LEVEL, sdk_api_level_of(__ANDROID_VENDOR_API_MAX__));
+ ASSERT_EQ(__INVALID_API_LEVEL, sdk_api_level_of(35));
+}
+
+} // namespace
\ No newline at end of file
diff --git a/libvendorsupport/version_props.c b/libvendorsupport/version_props.c
new file mode 100644
index 0000000..4d0e45e
--- /dev/null
+++ b/libvendorsupport/version_props.c
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "api_level.h"
+
+#include <log/log.h>
+
+int vendor_api_level_of(int sdk_api_level) {
+ if (sdk_api_level < __ANDROID_API_V__) {
+ return sdk_api_level;
+ }
+ // In Android V, vendor API level started with version 202404.
+ // The calculation assumes that the SDK api level bumps once a year.
+ if (sdk_api_level < __ANDROID_API_FUTURE__) {
+ return 202404 + ((sdk_api_level - __ANDROID_API_V__) * 100);
+ }
+ ALOGE("The SDK version must be less than 10000: %d", sdk_api_level);
+ return __INVALID_API_LEVEL;
+}
+
+int sdk_api_level_of(int vendor_api_level) {
+ if (vendor_api_level < __ANDROID_API_V__) {
+ return vendor_api_level;
+ }
+ if (vendor_api_level >= 202404 && vendor_api_level < __ANDROID_VENDOR_API_MAX__) {
+ return (vendor_api_level - 202404) / 100 + __ANDROID_API_V__;
+ }
+ ALOGE("Unexpected vendor api level: %d", vendor_api_level);
+ return __INVALID_API_LEVEL;
+}
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 87646f9..b4a16d3 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -25,4 +25,8 @@
},
},
export_include_dirs: ["include"],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.runtime",
+ ],
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 12c46eb..a8e867d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -782,7 +782,6 @@
mkdir /data/misc/vpn 0770 system vpn
mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
mkdir /data/misc/systemkeys 0700 system system
- mkdir /data/misc/threadnetwork 0770 thread_network thread_network
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi