Merge "libsnapshot: Remove flaky image creation test."
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 26e6e00..b478e6e 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -154,6 +154,7 @@
"device/flashing.cpp",
"device/main.cpp",
"device/usb.cpp",
+ "device/usb_iouring.cpp",
"device/usb_client.cpp",
"device/tcp_client.cpp",
"device/utility.cpp",
@@ -195,7 +196,9 @@
"liblz4",
"libsnapshot_nobinder",
"update_metadata-protos",
+ "liburing",
],
+ include_dirs: ["bionic/libc/kernel"],
header_libs: [
"avb_headers",
@@ -346,9 +349,7 @@
target: {
not_windows: {
required: [
- "e2fsdroid",
"mke2fs.conf",
- "sload_f2fs",
],
},
windows: {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 10bed6d..cde0cb2 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -19,9 +19,7 @@
#
my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs_casefold
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
$(call dist-for-goals,dist_files sdk,$(my_dist_files))
my_dist_files :=
diff --git a/fastboot/device/usb.cpp b/fastboot/device/usb.cpp
index 4115a6d..b77d772 100644
--- a/fastboot/device/usb.cpp
+++ b/fastboot/device/usb.cpp
@@ -15,6 +15,7 @@
*/
#include "usb.h"
+#include "usb_iouring.h"
#include <dirent.h>
#include <errno.h>
@@ -28,6 +29,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/functionfs.h>
+#include <sys/utsname.h>
#include <algorithm>
#include <atomic>
@@ -38,6 +40,7 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <liburing.h>
using namespace std::chrono_literals;
@@ -65,8 +68,8 @@
}
}
-static int getMaxPacketSize(int ffs_fd) {
- usb_endpoint_descriptor desc;
+int getMaxPacketSize(int ffs_fd) {
+ usb_endpoint_descriptor desc{};
if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
D("[ could not get endpoint descriptor! (%d) ]", errno);
return MAX_PACKET_SIZE_HS;
@@ -128,11 +131,9 @@
static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
- bool zero_packet = false;
int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
const char* cur_data = reinterpret_cast<const char*>(data);
- int packet_size = getMaxPacketSize(aiob->fd);
if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
0) {
@@ -145,17 +146,6 @@
len -= buf_len;
cur_data += buf_len;
-
- if (len == 0 && buf_len % packet_size == 0 && read) {
- // adb does not expect the device to send a zero packet after data transfer,
- // but the host *does* send a zero packet for the device to read.
- zero_packet = h->reads_zero_packets;
- }
- }
- if (zero_packet) {
- io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
- packet_size, 0, read);
- num_bufs += 1;
}
while (true) {
@@ -204,21 +194,46 @@
h->open_new_connection = true;
h->lock.unlock();
h->notify.notify_one();
+ if (h->aio_type == AIOType::IO_URING) {
+ exit_io_uring_ffs(h);
+ }
}
-usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size) {
- usb_handle* h = new usb_handle();
+bool DoesKernelSupportIouring() {
+ struct utsname uts {};
+ unsigned int major = 0, minor = 0;
+ if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
+ return false;
+ }
+ if (major > 5) {
+ return true;
+ }
+ // We will only support kernels from 5.6 onwards as IOSQE_ASYNC flag and
+ // IO_URING_OP_READ/WRITE opcodes were introduced only on 5.6 kernel
+ return minor >= 6;
+}
- if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
+std::unique_ptr<usb_handle> create_usb_handle(unsigned num_bufs, unsigned io_size) {
+ auto h = std::make_unique<usb_handle>();
+ if (DoesKernelSupportIouring() &&
+ android::base::GetBoolProperty("sys.usb.ffs.io_uring_enabled", false)) {
+ init_io_uring_ffs(h.get(), num_bufs);
+ h->aio_type = AIOType::IO_URING;
+ LOG(INFO) << "Using io_uring for usb ffs";
+ } else if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
// Devices on older kernels (< 3.18) will not have aio support for ffs
// unless backported. Fall back on the non-aio functions instead.
h->write = usb_ffs_write;
h->read = usb_ffs_read;
+ h->aio_type = AIOType::SYNC_IO;
+ LOG(INFO) << "Using sync io for usb ffs";
} else {
h->write = usb_ffs_aio_write;
h->read = usb_ffs_aio_read;
aio_block_init(&h->read_aiob, num_bufs);
aio_block_init(&h->write_aiob, num_bufs);
+ h->aio_type = AIOType::AIO;
+ LOG(INFO) << "Using aio for usb ffs";
}
h->io_size = io_size;
h->close = usb_ffs_close;
diff --git a/fastboot/device/usb.h b/fastboot/device/usb.h
index 6c3f542..8996c31 100644
--- a/fastboot/device/usb.h
+++ b/fastboot/device/usb.h
@@ -18,8 +18,10 @@
#include <linux/usb/functionfs.h>
+#include <liburing.h>
#include <atomic>
#include <condition_variable>
+#include <memory>
#include <mutex>
#include <vector>
@@ -35,9 +37,11 @@
int fd;
};
-struct usb_handle {
- usb_handle() {}
+int getMaxPacketSize(int ffs_fd);
+enum class AIOType { SYNC_IO, AIO, IO_URING };
+
+struct usb_handle {
std::condition_variable notify;
std::mutex lock;
bool open_new_connection = true;
@@ -56,8 +60,9 @@
struct aio_block read_aiob;
struct aio_block write_aiob;
- bool reads_zero_packets;
+ io_uring ring;
size_t io_size;
+ AIOType aio_type;
};
-usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size);
+std::unique_ptr<usb_handle> create_usb_handle(unsigned num_bufs, unsigned io_size);
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 3f9b0f0..d1b38d4 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -232,7 +232,6 @@
h->read_aiob.fd = h->bulk_out.get();
h->write_aiob.fd = h->bulk_in.get();
- h->reads_zero_packets = false;
return true;
err:
diff --git a/fastboot/device/usb_iouring.cpp b/fastboot/device/usb_iouring.cpp
new file mode 100644
index 0000000..d987712
--- /dev/null
+++ b/fastboot/device/usb_iouring.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 <android-base/logging.h>
+#include <liburing.h>
+#include "liburing/io_uring.h"
+#include "usb.h"
+
+static int prep_async_read(struct io_uring* ring, int fd, void* data, size_t len, int64_t offset) {
+ if (io_uring_sq_space_left(ring) <= 0) {
+ LOG(ERROR) << "Submission queue run out of space.";
+ return -1;
+ }
+ auto sqe = io_uring_get_sqe(ring);
+ if (sqe == nullptr) {
+ return -1;
+ }
+ io_uring_sqe_set_flags(sqe, IOSQE_IO_LINK | IOSQE_ASYNC);
+ io_uring_prep_read(sqe, fd, data, len, offset);
+ return 0;
+}
+
+static int prep_async_write(struct io_uring* ring, int fd, const void* data, size_t len,
+ int64_t offset) {
+ if (io_uring_sq_space_left(ring) <= 0) {
+ LOG(ERROR) << "Submission queue run out of space.";
+ return -1;
+ }
+ auto sqe = io_uring_get_sqe(ring);
+ if (sqe == nullptr) {
+ return -1;
+ }
+ io_uring_sqe_set_flags(sqe, IOSQE_IO_LINK | IOSQE_ASYNC);
+ io_uring_prep_write(sqe, fd, data, len, offset);
+ return 0;
+}
+
+template <bool read, typename T>
+int prep_async_io(struct io_uring* ring, int fd, T* data, size_t len, int64_t offset) {
+ if constexpr (read) {
+ return prep_async_read(ring, fd, data, len, offset);
+ } else {
+ return prep_async_write(ring, fd, data, len, offset);
+ }
+}
+
+template <typename T>
+static constexpr T DivRoundup(T x, T y) {
+ return (x + y - 1) / y;
+}
+
+extern int getMaxPacketSize(int ffs_fd);
+
+template <bool read, typename T>
+static int usb_ffs_do_aio(usb_handle* h, T* const data, const int len) {
+ const aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
+ const int num_requests = DivRoundup<int>(len, h->io_size);
+ auto cur_data = data;
+ const auto packet_size = getMaxPacketSize(aiob->fd);
+
+ for (int bytes_remain = len; bytes_remain > 0;) {
+ const int buf_len = std::min(bytes_remain, static_cast<int>(h->io_size));
+ const auto ret = prep_async_io<read>(&h->ring, aiob->fd, cur_data, buf_len, 0);
+ if (ret < 0) {
+ PLOG(ERROR) << "Failed to queue io_uring request";
+ return -1;
+ }
+
+ bytes_remain -= buf_len;
+ cur_data = reinterpret_cast<T*>(reinterpret_cast<size_t>(cur_data) + buf_len);
+ }
+ const int ret = io_uring_submit(&h->ring);
+ if (ret <= 0 || ret != num_requests) {
+ PLOG(ERROR) << "io_uring: failed to submit SQE entries to kernel";
+ return -1;
+ }
+ int res = 0;
+ bool success = true;
+ for (int i = 0; i < num_requests; ++i) {
+ struct io_uring_cqe* cqe{};
+ const auto ret = TEMP_FAILURE_RETRY(io_uring_wait_cqe(&h->ring, &cqe));
+ if (ret < 0 || cqe == nullptr) {
+ PLOG(ERROR) << "Failed to get CQE from kernel";
+ success = false;
+ continue;
+ }
+ res += cqe->res;
+ if (cqe->res < 0) {
+ LOG(ERROR) << "io_uring request failed:, i = " << i
+ << ", num_requests = " << num_requests << ", res = " << cqe->res << ": "
+ << strerror(cqe->res) << (read ? " read" : " write")
+ << " request size: " << len << ", io_size: " << h->io_size
+ << " max packet size: " << packet_size << ", fd: " << aiob->fd;
+ success = false;
+ errno = -cqe->res;
+ }
+ io_uring_cqe_seen(&h->ring, cqe);
+ }
+ if (!success) {
+ return -1;
+ }
+ return res;
+}
+
+static int usb_ffs_io_uring_read(usb_handle* h, void* data, int len, bool /* allow_partial */) {
+ return usb_ffs_do_aio<true>(h, data, len);
+}
+
+static int usb_ffs_io_uring_write(usb_handle* h, const void* data, int len) {
+ return usb_ffs_do_aio<false>(h, data, len);
+}
+
+void exit_io_uring_ffs(usb_handle* h) {
+ io_uring_queue_exit(&h->ring);
+}
+
+bool init_io_uring_ffs(usb_handle* h, size_t queue_depth) {
+ const auto err = io_uring_queue_init(queue_depth, &h->ring, 0);
+ if (err) {
+ LOG(ERROR) << "Failed to initialize io_uring of depth " << queue_depth << ": "
+ << strerror(err);
+ return false;
+ }
+ h->write = usb_ffs_io_uring_write;
+ h->read = usb_ffs_io_uring_read;
+ return true;
+}
diff --git a/fastboot/device/usb_iouring.h b/fastboot/device/usb_iouring.h
new file mode 100644
index 0000000..7c14b81
--- /dev/null
+++ b/fastboot/device/usb_iouring.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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 "usb.h"
+
+bool init_io_uring_ffs(usb_handle* h, size_t queue_depth);
+
+void exit_io_uring_ffs(usb_handle* h);
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index c8a0249..45be191 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -34,12 +34,13 @@
namespace android {
namespace snapshot {
-CowReader::CowReader(ReaderFlags reader_flag)
+CowReader::CowReader(ReaderFlags reader_flag, bool is_merge)
: fd_(-1),
header_(),
fd_size_(0),
block_pos_index_(std::make_shared<std::vector<int>>()),
- reader_flag_(reader_flag) {}
+ reader_flag_(reader_flag),
+ is_merge_(is_merge) {}
static void SHA256(const void*, size_t, uint8_t[]) {
#if 0
@@ -64,6 +65,7 @@
cow->has_seq_ops_ = has_seq_ops_;
cow->data_loc_ = data_loc_;
cow->block_pos_index_ = block_pos_index_;
+ cow->is_merge_ = is_merge_;
return cow;
}
@@ -476,15 +478,28 @@
merge_op_blocks->insert(merge_op_blocks->end(), other_ops.begin(), other_ops.end());
- for (auto block : *merge_op_blocks) {
- block_pos_index_->push_back(block_map->at(block));
- }
-
num_total_data_ops_ = merge_op_blocks->size();
if (header_.num_merge_ops > 0) {
merge_op_start_ = header_.num_merge_ops;
}
+ if (is_merge_) {
+ // Metadata ops are not required for merge. Thus, just re-arrange
+ // the ops vector as required for merge operations.
+ auto merge_ops_buffer = std::make_shared<std::vector<CowOperation>>();
+ merge_ops_buffer->reserve(num_total_data_ops_);
+ for (auto block : *merge_op_blocks) {
+ merge_ops_buffer->emplace_back(ops_->data()[block_map->at(block)]);
+ }
+ ops_->clear();
+ ops_ = merge_ops_buffer;
+ ops_->shrink_to_fit();
+ } else {
+ for (auto block : *merge_op_blocks) {
+ block_pos_index_->push_back(block_map->at(block));
+ }
+ }
+
block_map->clear();
merge_op_blocks->clear();
@@ -548,7 +563,7 @@
class CowOpIter final : public ICowOpIter {
public:
- CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops);
+ CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -562,9 +577,9 @@
std::vector<CowOperation>::iterator op_iter_;
};
-CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
+CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start) {
ops_ = ops;
- op_iter_ = ops_->begin();
+ op_iter_ = ops_->begin() + start;
}
bool CowOpIter::RDone() {
@@ -691,8 +706,8 @@
return ops_->data()[*block_riter_];
}
-std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
- return std::make_unique<CowOpIter>(ops_);
+std::unique_ptr<ICowOpIter> CowReader::GetOpIter(bool merge_progress) {
+ return std::make_unique<CowOpIter>(ops_, merge_progress ? merge_op_start_ : 0);
}
std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index fbdd6b9..e8e4d72 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -74,7 +74,7 @@
virtual bool GetLastLabel(uint64_t* label) = 0;
// Return an iterator for retrieving CowOperation entries.
- virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
+ virtual std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress) = 0;
// Return an iterator for retrieving CowOperation entries in reverse merge order
virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress) = 0;
@@ -115,7 +115,7 @@
USERSPACE_MERGE = 1,
};
- CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT);
+ CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT, bool is_merge = false);
~CowReader() { owned_fd_ = {}; }
// Parse the COW, optionally, up to the given label. If no label is
@@ -135,7 +135,7 @@
// CowOperation objects. Get() returns a unique CowOperation object
// whose lifetime depends on the CowOpIter object; the return
// value of these will never be null.
- std::unique_ptr<ICowOpIter> GetOpIter() override;
+ std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress = false) override;
std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress = false) override;
std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress = false) override;
@@ -177,6 +177,7 @@
bool has_seq_ops_{};
std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
ReaderFlags reader_flag_;
+ bool is_merge_{};
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 8939b78..492c43f 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -162,7 +162,7 @@
}
bool SnapshotHandler::ReadMetadata() {
- reader_ = std::make_unique<CowReader>(CowReader::ReaderFlags::USERSPACE_MERGE);
+ reader_ = std::make_unique<CowReader>(CowReader::ReaderFlags::USERSPACE_MERGE, true);
CowHeader header;
CowOptions options;
@@ -193,7 +193,7 @@
UpdateMergeCompletionPercentage();
// Initialize the iterator for reading metadata
- std::unique_ptr<ICowOpIter> cowop_iter = reader_->GetMergeOpIter();
+ std::unique_ptr<ICowOpIter> cowop_iter = reader_->GetOpIter(true);
int num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ);
int ra_index = 0;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
index 63f47d6..d57f434 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -466,7 +466,7 @@
}
bool Worker::Merge() {
- cowop_iter_ = reader_->GetMergeOpIter();
+ cowop_iter_ = reader_->GetOpIter(true);
bool retry = false;
bool ordered_ops_merge_status;
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 b9e4255..fbe57d2 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -772,7 +772,7 @@
}
void ReadAhead::InitializeRAIter() {
- cowop_iter_ = reader_->GetMergeOpIter();
+ cowop_iter_ = reader_->GetOpIter(true);
}
bool ReadAhead::RAIterDone() {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 9542bc1..91024d1 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1319,26 +1319,9 @@
B="`adb_cat /system/priv-app/hello`" ||
die "system priv-app hello"
check_eq "${A}" "${B}" /system/priv-app before reboot
-SYSTEM_DEVT=`adb_sh stat --format=%D /system/hello </dev/null`
-VENDOR_DEVT=`adb_sh stat --format=%D /vendor/hello </dev/null`
SYSTEM_INO=`adb_sh stat --format=%i /system/hello </dev/null`
VENDOR_INO=`adb_sh stat --format=%i /vendor/hello </dev/null`
-BASE_SYSTEM_DEVT=`adb_sh stat --format=%D /system/bin/stat </dev/null`
-BASE_VENDOR_DEVT=`adb_sh stat --format=%D /vendor/bin/stat </dev/null`
-check_eq "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" vendor and system devt
check_ne "${SYSTEM_INO}" "${VENDOR_INO}" vendor and system inode
-if ${overlayfs_needed}; then
- check_ne "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
- check_ne "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
-else
- check_eq "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
- check_eq "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
-fi
-check_ne "${BASE_SYSTEM_DEVT}" "${BASE_VENDOR_DEVT}" --warning system/vendor devt
-[ -n "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
- echo "${YELLOW}[ WARNING ]${NORMAL} system devt ${SYSTEM_DEVT} major 0" >&2
-[ -n "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
- echo "${YELLOW}[ WARNING ]${NORMAL} vendor devt ${VENDOR_DEVT} major 0" >&2
# Download libc.so, append some garbage, push back, and check if the file
# is updated.
@@ -1411,13 +1394,8 @@
echo "${GREEN}[ OK ]${NORMAL} ${i} content remains after reboot" >&2
done
-check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
-check_eq "${VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/hello </dev/null`" vendor devt after reboot
check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
check_eq "${VENDOR_INO}" "`adb_sh stat --format=%i /vendor/hello </dev/null`" vendor inode after reboot
-check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" --warning base system devt after reboot
-check_eq "${BASE_VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/bin/stat </dev/null`" --warning base vendor devt after reboot
-check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" --warning devt for su after reboot
# Feed log with selinux denials as a result of overlays
adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null || true
@@ -1542,10 +1520,7 @@
--warning vendor content after flash vendor
fi
- check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
- check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" --warning base system devt after reboot
- check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" --warning devt for su after reboot
fi
diff --git a/init/Android.bp b/init/Android.bp
index 2dd9683..856fe3e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -222,8 +222,8 @@
],
whole_static_libs: [
"libcap",
- "com.android.sysprop.apex",
- "com.android.sysprop.init",
+ "libcom.android.sysprop.apex",
+ "libcom.android.sysprop.init",
],
header_libs: ["bootimg_headers"],
proto: {
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 74d8aac..0580f86 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -23,6 +23,8 @@
#include <functional>
#include <map>
+#include <android-base/logging.h>
+
namespace android {
namespace init {
@@ -42,8 +44,11 @@
if (!events) {
return Error() << "Must specify events";
}
- auto sp = std::make_shared<decltype(handler)>(std::move(handler));
- auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(sp));
+
+ Info info;
+ info.events = events;
+ info.handler = std::make_shared<decltype(handler)>(std::move(handler));
+ auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(info));
if (!inserted) {
return Error() << "Cannot specify two epoll handlers for a given FD";
}
@@ -84,8 +89,14 @@
}
std::vector<std::shared_ptr<Handler>> pending_functions;
for (int i = 0; i < num_events; ++i) {
- auto sp = *reinterpret_cast<std::shared_ptr<Handler>*>(ev[i].data.ptr);
- pending_functions.emplace_back(std::move(sp));
+ auto& info = *reinterpret_cast<Info*>(ev[i].data.ptr);
+ if ((info.events & (EPOLLIN | EPOLLPRI)) == (EPOLLIN | EPOLLPRI) &&
+ (ev[i].events & EPOLLIN) != ev[i].events) {
+ // This handler wants to know about exception events, and just got one.
+ // Log something informational.
+ LOG(ERROR) << "Received unexpected epoll event set: " << ev[i].events;
+ }
+ pending_functions.emplace_back(info.handler);
}
return pending_functions;
diff --git a/init/epoll.h b/init/epoll.h
index 0df5289..f58ae8d 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -46,8 +46,13 @@
std::optional<std::chrono::milliseconds> timeout);
private:
+ struct Info {
+ std::shared_ptr<Handler> handler;
+ uint32_t events;
+ };
+
android::base::unique_fd epoll_fd_;
- std::map<int, std::shared_ptr<Handler>> epoll_handlers_;
+ std::map<int, Info> epoll_handlers_;
};
} // namespace init
diff --git a/init/init.cpp b/init/init.cpp
index 5f516b7..be99a1c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,7 +33,10 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <filesystem>
+#include <fstream>
#include <functional>
+#include <iostream>
#include <map>
#include <memory>
#include <mutex>
@@ -695,10 +698,10 @@
static constexpr std::chrono::milliseconds kDiagnosticTimeout = 10s;
-static void HandleSignalFd() {
+static void HandleSignalFd(bool one_off) {
signalfd_siginfo siginfo;
auto started = std::chrono::steady_clock::now();
- for (;;) {
+ do {
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
if (bytes_read < 0 && errno == EAGAIN) {
auto now = std::chrono::steady_clock::now();
@@ -716,7 +719,7 @@
return;
}
break;
- }
+ } while (!one_off);
switch (siginfo.ssi_signo) {
case SIGCHLD:
@@ -776,7 +779,9 @@
PLOG(FATAL) << "failed to create signalfd";
}
- if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) {
+ constexpr int flags = EPOLLIN | EPOLLPRI;
+ auto handler = std::bind(HandleSignalFd, false);
+ if (auto result = epoll->RegisterHandler(signal_fd, handler, flags); !result.ok()) {
LOG(FATAL) << result.error();
}
}
@@ -905,6 +910,32 @@
return {};
}
+static void DumpPidFds(const std::string& prefix, pid_t pid) {
+ std::error_code ec;
+ std::string proc_dir = "/proc/" + std::to_string(pid) + "/fd";
+ for (const auto& entry : std::filesystem::directory_iterator(proc_dir)) {
+ std::string target;
+ if (android::base::Readlink(entry.path(), &target)) {
+ LOG(ERROR) << prefix << target;
+ } else {
+ LOG(ERROR) << prefix << entry.path();
+ }
+ }
+}
+
+static void DumpFile(const std::string& prefix, const std::string& file) {
+ std::ifstream fp(file);
+ if (!fp) {
+ LOG(ERROR) << "Could not open " << file;
+ return;
+ }
+
+ std::string line;
+ while (std::getline(fp, line)) {
+ LOG(ERROR) << prefix << line;
+ }
+}
+
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -1114,11 +1145,23 @@
(*function)();
}
} else if (Service::is_exec_service_running()) {
+ static bool dumped_diagnostics = false;
std::chrono::duration<double> waited =
std::chrono::steady_clock::now() - Service::exec_service_started();
if (waited >= kDiagnosticTimeout) {
LOG(ERROR) << "Exec service is hung? Waited " << waited.count()
<< " without SIGCHLD";
+ if (!dumped_diagnostics) {
+ DumpPidFds("exec service opened: ", Service::exec_service_pid());
+
+ std::string status_file =
+ "/proc/" + std::to_string(Service::exec_service_pid()) + "/status";
+ DumpFile("exec service: ", status_file);
+ dumped_diagnostics = true;
+
+ LOG(INFO) << "Attempting to handle any stuck SIGCHLDs...";
+ HandleSignalFd(true);
+ }
}
}
if (!IsShuttingDown()) {
diff --git a/init/service.cpp b/init/service.cpp
index 730b6b6..b36584b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -127,6 +127,7 @@
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
+pid_t Service::exec_service_pid_ = -1;
std::chrono::time_point<std::chrono::steady_clock> Service::exec_service_started_;
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
@@ -395,6 +396,7 @@
flags_ |= SVC_EXEC;
is_exec_service_running_ = true;
+ exec_service_pid_ = pid_;
exec_service_started_ = std::chrono::steady_clock::now();
LOG(INFO) << "SVC_EXEC service '" << name_ << "' pid " << pid_ << " (uid " << proc_attr_.uid
diff --git a/init/service.h b/init/service.h
index f7f32d9..c14b312 100644
--- a/init/service.h
+++ b/init/service.h
@@ -103,6 +103,7 @@
size_t CheckAllCommands() const { return onrestart_.CheckAllCommands(); }
static bool is_exec_service_running() { return is_exec_service_running_; }
+ static pid_t exec_service_pid() { return exec_service_pid_; }
static std::chrono::time_point<std::chrono::steady_clock> exec_service_started() {
return exec_service_started_;
}
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 9b2c7d9..6fc64df 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -95,7 +95,10 @@
LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
}
- if (!service) return pid;
+ if (!service) {
+ LOG(INFO) << name << " did not have an associated service entry and will not be reaped";
+ return pid;
+ }
service->Reap(siginfo);
diff --git a/libutils/Android.bp b/libutils/Android.bp
index f663671..7939e82 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -68,6 +68,7 @@
"-Wall",
"-Werror",
"-Wno-exit-time-destructors",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
header_libs: [
"libbase_headers",
@@ -173,6 +174,10 @@
min_sdk_version: "apex_inherit",
afdo: true,
+
+ header_abi_checker: {
+ diff_flags: ["-allow-adding-removing-weak-symbols"],
+ },
}
cc_library {
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 292425a..1a3f34b 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -117,14 +117,15 @@
int result = pthread_once(& gTLSOnce, initTLSKey);
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
- return (Looper*)pthread_getspecific(gTLSKey);
+ Looper* looper = (Looper*)pthread_getspecific(gTLSKey);
+ return sp<Looper>::fromExisting(looper);
}
sp<Looper> Looper::prepare(int opts) {
bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
sp<Looper> looper = Looper::getForThread();
if (looper == nullptr) {
- looper = new Looper(allowNonCallbacks);
+ looper = sp<Looper>::make(allowNonCallbacks);
Looper::setForThread(looper);
}
if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
@@ -425,7 +426,11 @@
}
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
- return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
+ sp<SimpleLooperCallback> looperCallback;
+ if (callback) {
+ looperCallback = sp<SimpleLooperCallback>::make(callback);
+ }
+ return addFd(fd, ident, events, looperCallback, data);
}
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
index d437a9f..819a603 100644
--- a/libutils/NativeHandle.cpp
+++ b/libutils/NativeHandle.cpp
@@ -20,7 +20,7 @@
namespace android {
sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) {
- return handle ? new NativeHandle(handle, ownsHandle) : nullptr;
+ return handle ? sp<NativeHandle>::make(handle, ownsHandle) : nullptr;
}
NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 4dacdc6..e756fec 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -673,7 +673,7 @@
mThread = thread_id_t(-1);
// hold a strong reference on ourself
- mHoldSelf = this;
+ mHoldSelf = sp<Thread>::fromExisting(this);
mRunning = true;
diff --git a/libutils/include/utils/NativeHandle.h b/libutils/include/utils/NativeHandle.h
index 73fe804..f26a1a4 100644
--- a/libutils/include/utils/NativeHandle.h
+++ b/libutils/include/utils/NativeHandle.h
@@ -39,6 +39,8 @@
private:
// for access to the destructor
friend class LightRefBase<NativeHandle>;
+ // for access to the constructor
+ friend class sp<NativeHandle>;
NativeHandle(native_handle_t* handle, bool ownsHandle);
~NativeHandle();
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 780ace5..c88c7ff 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -31,5 +31,9 @@
"libadb_pairing_auth.so",
"libadb_pairing_connection.so",
"libadb_pairing_server.so"
+ ],
+ "provideLibs": [
+ "libaptX_encoder.so",
+ "libaptXHD_encoder.so"
]
}