Merge changes from topic "vapex_stop_service"
* changes:
Remove and add service and action during apex load and unload
Stop services when unload an apex
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad0231d..c15146b 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -204,6 +204,7 @@
header_libs: [
"bionic_libc_platform_headers",
"gwp_asan_headers",
+ "liblog_headers",
],
static_libs: [
@@ -212,7 +213,6 @@
"liblzma",
"libbase",
"libcutils",
- "liblog",
],
runtime_libs: [
"libdexfile", // libdexfile_support dependency
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/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index c0e3161..1f54f5b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -889,7 +889,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(const Fstab& fstab, int start_idx, int* end_idx,
+static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx,
int* attempted_idx) {
unsigned long i;
int mount_errno = 0;
@@ -909,6 +909,14 @@
continue;
}
+ // fstab[start_idx].blk_device is already updated to /dev/dm-<N> by
+ // AVB related functions. Copy it from start_idx to the current index i.
+ if ((i != start_idx) && fstab[i].fs_mgr_flags.logical &&
+ fstab[start_idx].fs_mgr_flags.logical &&
+ (fstab[i].logical_partition_name == fstab[start_idx].logical_partition_name)) {
+ fstab[i].blk_device = fstab[start_idx].blk_device;
+ }
+
int fs_stat = prepare_fs_for_mount(fstab[i].blk_device, fstab[i]);
if (fs_stat & FS_STAT_INVALID_MAGIC) {
LERROR << __FUNCTION__
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 07eaf58..354d02a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -81,10 +81,17 @@
return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
}
+const auto kLowerdirOption = "lowerdir="s;
+const auto kUpperdirOption = "upperdir="s;
+
} // namespace
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
+bool fs_mgr_wants_overlayfs(FstabEntry*) {
+ return false;
+}
+
Fstab fs_mgr_overlayfs_candidate_list(const Fstab&) {
return {};
}
@@ -93,7 +100,7 @@
return false;
}
-bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) {
+bool fs_mgr_overlayfs_setup(const char*, bool* change, bool) {
if (change) *change = false;
return false;
}
@@ -324,9 +331,6 @@
return "";
}
-const auto kLowerdirOption = "lowerdir="s;
-const auto kUpperdirOption = "upperdir="s;
-
static inline bool KernelSupportsUserXattrs() {
struct utsname uts;
uname(&uts);
@@ -366,48 +370,6 @@
return ret;
}
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
- Fstab fstab;
- auto save_errno = errno;
- if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
- return false;
- }
- errno = save_errno;
- const auto lowerdir = kLowerdirOption + mount_point;
- for (const auto& entry : fstab) {
- if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
- if (mount_point != entry.mount_point) continue;
- if (!overlay_only) return true;
- const auto options = android::base::Split(entry.fs_options, ",");
- for (const auto& opt : options) {
- if (opt == lowerdir) {
- return true;
- }
- }
- }
- return false;
-}
-
-bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
- // Don't check entries that are managed by vold.
- if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
-
- // *_other doesn't want overlayfs.
- if (entry->fs_mgr_flags.slot_select_other) return false;
-
- // Only concerned with readonly partitions.
- if (!(entry->flags & MS_RDONLY)) return false;
-
- // If unbindable, do not allow overlayfs as this could expose us to
- // security issues. On Android, this could also be used to turn off
- // the ability to overlay an otherwise acceptable filesystem since
- // /system and /vendor are never bound(sic) to.
- if (entry->flags & MS_UNBINDABLE) return false;
-
- if (!fs_mgr_overlayfs_enabled(entry)) return false;
-
- return true;
-}
constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
@@ -1284,9 +1246,45 @@
} // namespace
+bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
+ // Don't check entries that are managed by vold.
+ if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
+
+ // *_other doesn't want overlayfs.
+ if (entry->fs_mgr_flags.slot_select_other) return false;
+
+ // Only concerned with readonly partitions.
+ if (!(entry->flags & MS_RDONLY)) return false;
+
+ // If unbindable, do not allow overlayfs as this could expose us to
+ // security issues. On Android, this could also be used to turn off
+ // the ability to overlay an otherwise acceptable filesystem since
+ // /system and /vendor are never bound(sic) to.
+ if (entry->flags & MS_UNBINDABLE) return false;
+
+ if (!fs_mgr_overlayfs_enabled(entry)) return false;
+
+ return true;
+}
+
Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
+ android::fs_mgr::Fstab mounts;
+ if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+ PLOG(ERROR) << "Failed to read /proc/mounts";
+ return {};
+ }
+
Fstab candidates;
for (const auto& entry : fstab) {
+ // Filter out partitions whose type doesn't match what's mounted.
+ // This avoids spammy behavior on devices which can mount different
+ // filesystems for each partition.
+ auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
+ auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
+ if (!mounted || mounted->fs_type != entry.fs_type) {
+ continue;
+ }
+
FstabEntry new_entry = entry;
if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
!fs_mgr_wants_overlayfs(&new_entry)) {
@@ -1359,8 +1357,7 @@
// Returns false if setup not permitted, errno set to last error.
// If something is altered, set *change.
-bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change,
- bool force) {
+bool fs_mgr_overlayfs_setup(const char* mount_point, bool* change, bool force) {
if (change) *change = false;
auto ret = false;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
@@ -1397,7 +1394,6 @@
std::string dir;
for (const auto& overlay_mount_point : OverlayMountPoints()) {
- if (backing && backing[0] && (overlay_mount_point != backing)) continue;
if (overlay_mount_point == kScratchMountPoint) {
if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
} else {
@@ -1693,6 +1689,28 @@
#endif // ALLOW_ADBD_DISABLE_VERITY != 0
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
+ Fstab fstab;
+ auto save_errno = errno;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ return false;
+ }
+ errno = save_errno;
+ const auto lowerdir = kLowerdirOption + mount_point;
+ for (const auto& entry : fstab) {
+ if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
+ if (mount_point != entry.mount_point) continue;
+ if (!overlay_only) return true;
+ const auto options = android::base::Split(entry.fs_options, ",");
+ for (const auto& opt : options) {
+ if (opt == lowerdir) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
struct statfs fs;
if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index deaf5f7..4a927d0 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -43,6 +43,8 @@
#include <libgsi/libgsid.h>
using namespace std::literals;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
namespace {
@@ -62,22 +64,12 @@
::exit(exit_status);
}
-bool remountable_partition(const android::fs_mgr::FstabEntry& entry) {
- if (entry.fs_mgr_flags.vold_managed) return false;
- if (entry.fs_mgr_flags.recovery_only) return false;
- if (entry.fs_mgr_flags.slot_select_other) return false;
- if (!(entry.flags & MS_RDONLY)) return false;
- if (entry.fs_type == "vfat") return false;
- return true;
-}
-
const std::string system_mount_point(const android::fs_mgr::FstabEntry& entry) {
if (entry.mount_point == "/") return "/system";
return entry.mount_point;
}
-const android::fs_mgr::FstabEntry* is_wrapped(const android::fs_mgr::Fstab& overlayfs_candidates,
- const android::fs_mgr::FstabEntry& entry) {
+const FstabEntry* GetWrappedEntry(const Fstab& overlayfs_candidates, const FstabEntry& entry) {
auto mount_point = system_mount_point(entry);
auto it = std::find_if(overlayfs_candidates.begin(), overlayfs_candidates.end(),
[&mount_point](const auto& entry) {
@@ -99,12 +91,8 @@
logd(id, severity, tag, file, line, message);
}
-[[noreturn]] void reboot(bool overlayfs = false) {
- if (overlayfs) {
- LOG(INFO) << "Successfully setup overlayfs\nrebooting device";
- } else {
- LOG(INFO) << "Successfully disabled verity\nrebooting device";
- }
+[[noreturn]] void reboot() {
+ LOG(INFO) << "Rebooting device for new settings to take effect";
::sync();
android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,remount");
::sleep(60);
@@ -140,15 +128,368 @@
BAD_OVERLAY,
NO_MOUNTS,
REMOUNT_FAILED,
- MUST_REBOOT,
BINDER_ERROR,
CHECKPOINTING,
GSID_ERROR,
- CLEAN_SCRATCH_FILES,
};
-static int do_remount(int argc, char* argv[]) {
- RemountStatus retval = REMOUNT_SUCCESS;
+static bool ReadFstab(const char* fstab_file, android::fs_mgr::Fstab* fstab) {
+ if (fstab_file) {
+ return android::fs_mgr::ReadFstabFromFile(fstab_file, fstab);
+ }
+ if (!android::fs_mgr::ReadDefaultFstab(fstab)) {
+ return false;
+ }
+
+ // Manufacture a / entry from /proc/mounts if missing.
+ if (!GetEntryForMountPoint(fstab, "/system") && !GetEntryForMountPoint(fstab, "/")) {
+ android::fs_mgr::Fstab mounts;
+ if (android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+ if (auto entry = GetEntryForMountPoint(&mounts, "/")) {
+ if (entry->fs_type != "rootfs") fstab->emplace_back(*entry);
+ }
+ }
+ }
+ return true;
+}
+
+static RemountStatus VerifyCheckpointing() {
+ if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false) &&
+ !android::base::GetBoolProperty("ro.virtual_ab.retrofit", false)) {
+ return REMOUNT_SUCCESS;
+ }
+
+ // Virtual A/B devices can use /data as backing storage; make sure we're
+ // not checkpointing.
+ auto vold = GetVold();
+ bool checkpointing = false;
+ if (!vold->isCheckpointing(&checkpointing).isOk()) {
+ LOG(ERROR) << "Could not determine checkpointing status.";
+ return BINDER_ERROR;
+ }
+ if (checkpointing) {
+ LOG(ERROR) << "Cannot use remount when a checkpoint is in progress.";
+ return CHECKPOINTING;
+ }
+ return REMOUNT_SUCCESS;
+}
+
+static bool IsRemountable(Fstab& candidates, const FstabEntry& entry) {
+ if (entry.fs_mgr_flags.vold_managed || entry.fs_mgr_flags.recovery_only ||
+ entry.fs_mgr_flags.slot_select_other) {
+ return false;
+ }
+ if (!(entry.flags & MS_RDONLY)) {
+ return false;
+ }
+ if (entry.fs_type == "vfat") {
+ return false;
+ }
+ if (auto candidate_entry = GetEntryForMountPoint(&candidates, entry.mount_point)) {
+ return candidate_entry->fs_type == entry.fs_type;
+ }
+ if (GetWrappedEntry(candidates, entry)) {
+ return false;
+ }
+ return true;
+}
+
+static Fstab::const_iterator FindPartition(const Fstab& fstab, const std::string& partition) {
+ Fstab mounts;
+ if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+ LOG(ERROR) << "Failed to read /proc/mounts";
+ return fstab.end();
+ }
+
+ for (auto iter = fstab.begin(); iter != fstab.end(); iter++) {
+ const auto mount_point = system_mount_point(*iter);
+ if (partition == mount_point || partition == android::base::Basename(mount_point)) {
+ // In case fstab has multiple entries, pick the one that matches the
+ // actual mounted filesystem type.
+ auto proc_mount_point = (iter->mount_point == "/system") ? "/" : iter->mount_point;
+ auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
+ if (mounted && mounted->fs_type == iter->fs_type) {
+ return iter;
+ }
+ }
+ }
+ return fstab.end();
+}
+
+static Fstab GetAllRemountablePartitions(Fstab& fstab) {
+ auto candidates = fs_mgr_overlayfs_candidate_list(fstab);
+
+ Fstab partitions;
+ for (const auto& entry : fstab) {
+ if (IsRemountable(candidates, entry)) {
+ partitions.emplace_back(entry);
+ }
+ }
+ return partitions;
+}
+
+static RemountStatus GetRemountList(const Fstab& fstab, const std::vector<std::string>& argv,
+ Fstab* partitions) {
+ auto candidates = fs_mgr_overlayfs_candidate_list(fstab);
+
+ for (const auto& arg : argv) {
+ std::string partition = arg;
+ if (partition == "/") {
+ partition = "/system";
+ }
+
+ auto it = FindPartition(fstab, partition);
+ if (it == fstab.end()) {
+ LOG(ERROR) << "Unknown partition " << arg;
+ return UNKNOWN_PARTITION;
+ }
+
+ const FstabEntry* entry = &*it;
+ if (auto wrap = GetWrappedEntry(candidates, *entry); wrap != nullptr) {
+ LOG(INFO) << "partition " << arg << " covered by overlayfs for " << wrap->mount_point
+ << ", switching";
+ entry = wrap;
+ }
+
+ // If it's already remounted, include it so it gets gracefully skipped
+ // later on.
+ if (!fs_mgr_overlayfs_already_mounted(entry->mount_point) &&
+ !IsRemountable(candidates, *entry)) {
+ LOG(ERROR) << "Invalid partition " << arg;
+ return INVALID_PARTITION;
+ }
+ if (GetEntryForMountPoint(partitions, entry->mount_point) != nullptr) {
+ continue;
+ }
+ partitions->emplace_back(*entry);
+ }
+
+ return REMOUNT_SUCCESS;
+}
+
+struct RemountCheckResult {
+ bool reboot_later = false;
+ bool setup_overlayfs = false;
+ bool disabled_verity = false;
+ bool verity_error = false;
+ bool remounted_anything = false;
+};
+
+static RemountStatus CheckVerity(const FstabEntry& entry, RemountCheckResult* result) {
+ if (!fs_mgr_is_verity_enabled(entry)) {
+ return REMOUNT_SUCCESS;
+ }
+ if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
+ return VERITY_PARTITION;
+ }
+
+ bool ok = false;
+
+ std::unique_ptr<AvbOps, decltype(&::avb_ops_user_free)> ops(avb_ops_user_new(),
+ &::avb_ops_user_free);
+ if (ops) {
+ auto suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
+ ok = avb_user_verity_set(ops.get(), suffix.c_str(), false);
+ }
+ if (!ok && fs_mgr_set_blk_ro(entry.blk_device, false)) {
+ fec::io fh(entry.blk_device.c_str(), O_RDWR);
+ ok = fh && fh.set_verity_status(false);
+ }
+ if (!ok) {
+ return VERITY_PARTITION;
+ }
+ result->disabled_verity = true;
+ result->reboot_later = true;
+ return REMOUNT_SUCCESS;
+}
+
+static RemountStatus CheckVerityAndOverlayfs(Fstab* partitions, RemountCheckResult* result) {
+ RemountStatus status = REMOUNT_SUCCESS;
+ for (auto it = partitions->begin(); it != partitions->end();) {
+ auto& entry = *it;
+ const auto& mount_point = entry.mount_point;
+
+ if (auto rv = CheckVerity(entry, result); rv != REMOUNT_SUCCESS) {
+ LOG(ERROR) << "Skipping verified partition " << mount_point << " for remount";
+ status = rv;
+ it = partitions->erase(it);
+ continue;
+ }
+
+ if (fs_mgr_wants_overlayfs(&entry)) {
+ bool change = false;
+ bool force = result->disabled_verity;
+ if (!fs_mgr_overlayfs_setup(mount_point.c_str(), &change, force)) {
+ LOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
+ status = BAD_OVERLAY;
+ it = partitions->erase(it);
+ continue;
+ }
+ if (change) {
+ LOG(INFO) << "Using overlayfs for " << mount_point;
+ result->reboot_later = true;
+ result->setup_overlayfs = true;
+ }
+ }
+ it++;
+ }
+ return status;
+}
+
+static RemountStatus EnableDsuIfNeeded() {
+ auto gsid = android::gsi::GetGsiService();
+ if (!gsid) {
+ return REMOUNT_SUCCESS;
+ }
+
+ auto dsu_running = false;
+ if (auto status = gsid->isGsiRunning(&dsu_running); !status.isOk()) {
+ LOG(ERROR) << "Failed to get DSU running state: " << status;
+ return BINDER_ERROR;
+ }
+ auto dsu_enabled = false;
+ if (auto status = gsid->isGsiEnabled(&dsu_enabled); !status.isOk()) {
+ LOG(ERROR) << "Failed to get DSU enabled state: " << status;
+ return BINDER_ERROR;
+ }
+ if (dsu_running && !dsu_enabled) {
+ std::string dsu_slot;
+ if (auto status = gsid->getActiveDsuSlot(&dsu_slot); !status.isOk()) {
+ LOG(ERROR) << "Failed to get active DSU slot: " << status;
+ return BINDER_ERROR;
+ }
+ LOG(INFO) << "DSU is running but disabled, enable DSU so that we stay within the "
+ "DSU guest system after reboot";
+ int error = 0;
+ if (auto status = gsid->enableGsi(/* oneShot = */ true, dsu_slot, &error);
+ !status.isOk() || error != android::gsi::IGsiService::INSTALL_OK) {
+ LOG(ERROR) << "Failed to enable DSU: " << status << ", error code: " << error;
+ return !status.isOk() ? BINDER_ERROR : GSID_ERROR;
+ }
+ LOG(INFO) << "Successfully enabled DSU (one-shot mode)";
+ }
+ return REMOUNT_SUCCESS;
+}
+
+static RemountStatus RemountPartition(Fstab& fstab, Fstab& mounts, FstabEntry& entry) {
+ // unlock the r/o key for the mount point device
+ if (entry.fs_mgr_flags.logical) {
+ fs_mgr_update_logical_partition(&entry);
+ }
+ auto blk_device = entry.blk_device;
+ auto mount_point = entry.mount_point;
+
+ auto found = false;
+ for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
+ auto& rentry = *it;
+ if (mount_point == rentry.mount_point) {
+ blk_device = rentry.blk_device;
+ found = true;
+ break;
+ }
+ // Find overlayfs mount point?
+ if ((mount_point == "/" && rentry.mount_point == "/system") ||
+ (mount_point == "/system" && rentry.mount_point == "/")) {
+ blk_device = rentry.blk_device;
+ mount_point = "/system";
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ PLOG(INFO) << "skip unmounted partition dev:" << blk_device << " mnt:" << mount_point;
+ return REMOUNT_SUCCESS;
+ }
+ if (blk_device == "/dev/root") {
+ auto from_fstab = GetEntryForMountPoint(&fstab, mount_point);
+ if (from_fstab) blk_device = from_fstab->blk_device;
+ }
+ fs_mgr_set_blk_ro(blk_device, false);
+
+ // Find system-as-root mount point?
+ if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
+ GetEntryForMountPoint(&mounts, "/")) {
+ mount_point = "/";
+ }
+
+ // Now remount!
+ if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
+ nullptr) == 0) {
+ return REMOUNT_SUCCESS;
+ }
+ if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
+ mount_point = entry.mount_point;
+ if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
+ nullptr) == 0) {
+ return REMOUNT_SUCCESS;
+ }
+ }
+
+ PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
+ return REMOUNT_FAILED;
+}
+
+static int do_remount(Fstab& fstab, const std::vector<std::string>& partition_args,
+ RemountCheckResult* check_result) {
+ Fstab partitions;
+ if (partition_args.empty()) {
+ partitions = GetAllRemountablePartitions(fstab);
+ } else {
+ if (auto rv = GetRemountList(fstab, partition_args, &partitions); rv != REMOUNT_SUCCESS) {
+ return rv;
+ }
+ }
+
+ // Check verity and optionally setup overlayfs backing.
+ auto retval = CheckVerityAndOverlayfs(&partitions, check_result);
+
+ if (partitions.empty() || check_result->disabled_verity) {
+ if (partitions.empty()) {
+ LOG(WARNING) << "No remountable partitions were found.";
+ }
+ return retval;
+ }
+
+ // Mount overlayfs.
+ errno = 0;
+ if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) {
+ PLOG(ERROR) << "Can not mount overlayfs for partitions";
+ return BAD_OVERLAY;
+ }
+
+ // Get actual mounts _after_ overlayfs has been added.
+ android::fs_mgr::Fstab mounts;
+ if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts) || mounts.empty()) {
+ PLOG(ERROR) << "Failed to read /proc/mounts";
+ return NO_MOUNTS;
+ }
+
+ // Remount selected partitions.
+ for (auto& entry : partitions) {
+ if (auto rv = RemountPartition(fstab, mounts, entry); rv != REMOUNT_SUCCESS) {
+ retval = rv;
+ } else {
+ check_result->remounted_anything = true;
+ }
+ }
+ return retval;
+}
+
+int main(int argc, char* argv[]) {
+ // Do not use MyLogger() when running as clean_scratch_files, as stdout/stderr of daemon process
+ // are discarded.
+ if (argc > 0 && android::base::Basename(argv[0]) == "clean_scratch_files"s) {
+ android::fs_mgr::CleanupOldScratchFiles();
+ return 0;
+ }
+
+ android::base::InitLogging(argv, MyLogger);
+
+ // Make sure we are root.
+ if (::getuid() != 0) {
+ LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
+ return NOT_ROOT;
+ }
// If somehow this executable is delivered on a "user" build, it can
// not function, so providing a clear message to the caller rather than
@@ -159,14 +500,14 @@
}
const char* fstab_file = nullptr;
- auto can_reboot = false;
+ auto auto_reboot = false;
+ std::vector<std::string> partition_args;
struct option longopts[] = {
{"fstab", required_argument, nullptr, 'T'},
{"help", no_argument, nullptr, 'h'},
{"reboot", no_argument, nullptr, 'R'},
{"verbose", no_argument, nullptr, 'v'},
- {"clean_scratch_files", no_argument, nullptr, 'C'},
{0, 0, nullptr, 0},
};
for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
@@ -175,7 +516,7 @@
usage(SUCCESS);
break;
case 'R':
- can_reboot = true;
+ auto_reboot = true;
break;
case 'T':
if (fstab_file) {
@@ -187,8 +528,6 @@
case 'v':
verbose = true;
break;
- case 'C':
- return CLEAN_SCRATCH_FILES;
default:
LOG(ERROR) << "Bad Argument -" << char(opt);
usage(BADARG);
@@ -196,310 +535,51 @@
}
}
- // Make sure we are root.
- if (::getuid() != 0) {
- LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
- return NOT_ROOT;
+ for (; argc > optind; ++optind) {
+ partition_args.emplace_back(argv[optind]);
+ }
+
+ // Make sure checkpointing is disabled if necessary.
+ if (auto rv = VerifyCheckpointing(); rv != REMOUNT_SUCCESS) {
+ return rv;
}
// Read the selected fstab.
- android::fs_mgr::Fstab fstab;
- auto fstab_read = false;
- if (fstab_file) {
- fstab_read = android::fs_mgr::ReadFstabFromFile(fstab_file, &fstab);
- } else {
- fstab_read = android::fs_mgr::ReadDefaultFstab(&fstab);
- // Manufacture a / entry from /proc/mounts if missing.
- if (!GetEntryForMountPoint(&fstab, "/system") && !GetEntryForMountPoint(&fstab, "/")) {
- android::fs_mgr::Fstab mounts;
- if (android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
- if (auto entry = GetEntryForMountPoint(&mounts, "/")) {
- if (entry->fs_type != "rootfs") fstab.emplace_back(*entry);
- }
- }
- }
- }
- if (!fstab_read || fstab.empty()) {
+ Fstab fstab;
+ if (!ReadFstab(fstab_file, &fstab) || fstab.empty()) {
PLOG(ERROR) << "Failed to read fstab";
return NO_FSTAB;
}
- if (android::base::GetBoolProperty("ro.virtual_ab.enabled", false) &&
- !android::base::GetBoolProperty("ro.virtual_ab.retrofit", false)) {
- // Virtual A/B devices can use /data as backing storage; make sure we're
- // not checkpointing.
- auto vold = GetVold();
- bool checkpointing = false;
- if (!vold->isCheckpointing(&checkpointing).isOk()) {
- LOG(ERROR) << "Could not determine checkpointing status.";
- return BINDER_ERROR;
- }
- if (checkpointing) {
- LOG(ERROR) << "Cannot use remount when a checkpoint is in progress.";
- return CHECKPOINTING;
- }
+ RemountCheckResult check_result;
+ int result = do_remount(fstab, partition_args, &check_result);
+
+ if (check_result.disabled_verity && check_result.setup_overlayfs) {
+ LOG(INFO) << "Verity disabled; overlayfs enabled.";
+ } else if (check_result.disabled_verity) {
+ LOG(INFO) << "Verity disabled.";
+ } else if (check_result.setup_overlayfs) {
+ LOG(INFO) << "Overlayfs enabled.";
}
- // Generate the list of supported overlayfs mount points.
- auto overlayfs_candidates = fs_mgr_overlayfs_candidate_list(fstab);
-
- // Generate the all remountable partitions sub-list
- android::fs_mgr::Fstab all;
- for (auto const& entry : fstab) {
- if (!remountable_partition(entry)) continue;
- if (overlayfs_candidates.empty() ||
- GetEntryForMountPoint(&overlayfs_candidates, entry.mount_point) ||
- (is_wrapped(overlayfs_candidates, entry) == nullptr)) {
- all.emplace_back(entry);
- }
- }
-
- // Parse the unique list of valid partition arguments.
- android::fs_mgr::Fstab partitions;
- for (; argc > optind; ++optind) {
- auto partition = std::string(argv[optind]);
- if (partition.empty()) continue;
- if (partition == "/") partition = "/system";
- auto find_part = [&partition](const auto& entry) {
- const auto mount_point = system_mount_point(entry);
- if (partition == mount_point) return true;
- if (partition == android::base::Basename(mount_point)) return true;
- return false;
- };
- // Do we know about the partition?
- auto it = std::find_if(fstab.begin(), fstab.end(), find_part);
- if (it == fstab.end()) {
- LOG(ERROR) << "Unknown partition " << argv[optind] << ", skipping";
- retval = UNKNOWN_PARTITION;
- continue;
- }
- // Is that one covered by an existing overlayfs?
- auto wrap = is_wrapped(overlayfs_candidates, *it);
- if (wrap) {
- LOG(INFO) << "partition " << argv[optind] << " covered by overlayfs for "
- << wrap->mount_point << ", switching";
- partition = system_mount_point(*wrap);
- }
- // Is it a remountable partition?
- it = std::find_if(all.begin(), all.end(), find_part);
- if (it == all.end()) {
- LOG(ERROR) << "Invalid partition " << argv[optind] << ", skipping";
- retval = INVALID_PARTITION;
- continue;
- }
- if (GetEntryForMountPoint(&partitions, it->mount_point) == nullptr) {
- partitions.emplace_back(*it);
- }
- }
-
- if (partitions.empty() && !retval) {
- partitions = all;
- }
-
- // Check verity and optionally setup overlayfs backing.
- auto reboot_later = false;
- auto user_please_reboot_later = false;
- auto setup_overlayfs = false;
- auto just_disabled_verity = false;
- for (auto it = partitions.begin(); it != partitions.end();) {
- auto& entry = *it;
- auto& mount_point = entry.mount_point;
- if (fs_mgr_is_verity_enabled(entry)) {
- retval = VERITY_PARTITION;
- auto ret = false;
- if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") != "locked") {
- if (AvbOps* ops = avb_ops_user_new()) {
- ret = avb_user_verity_set(
- ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(),
- false);
- avb_ops_user_free(ops);
- }
- if (!ret && fs_mgr_set_blk_ro(entry.blk_device, false)) {
- fec::io fh(entry.blk_device.c_str(), O_RDWR);
- ret = fh && fh.set_verity_status(false);
- }
- if (ret) {
- LOG(WARNING) << "Disabling verity for " << mount_point;
- just_disabled_verity = true;
- reboot_later = can_reboot;
- user_please_reboot_later = true;
- }
+ if (check_result.reboot_later) {
+ if (auto_reboot) {
+ // If (1) remount requires a reboot to take effect, (2) system is currently
+ // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
+ // next reboot would not take us back to the host system but stay within
+ // the guest system.
+ if (auto rv = EnableDsuIfNeeded(); rv != REMOUNT_SUCCESS) {
+ LOG(ERROR) << "Unable to automatically enable DSU";
+ return rv;
}
- if (!ret) {
- LOG(ERROR) << "Skipping " << mount_point << " for remount";
- it = partitions.erase(it);
- continue;
- }
+ reboot();
+ } else {
+ LOG(INFO) << "Now reboot your device for settings to take effect";
}
-
- auto change = false;
- errno = 0;
- if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, just_disabled_verity)) {
- if (change) {
- LOG(INFO) << "Using overlayfs for " << mount_point;
- reboot_later = can_reboot;
- user_please_reboot_later = true;
- setup_overlayfs = true;
- }
- } else if (errno) {
- PLOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
- retval = BAD_OVERLAY;
- it = partitions.erase(it);
- continue;
- }
- ++it;
+ return REMOUNT_SUCCESS;
}
-
- // If (1) remount requires a reboot to take effect, (2) system is currently
- // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
- // next reboot would not take us back to the host system but stay within
- // the guest system.
- if (reboot_later) {
- if (auto gsid = android::gsi::GetGsiService()) {
- auto dsu_running = false;
- if (auto status = gsid->isGsiRunning(&dsu_running); !status.isOk()) {
- LOG(ERROR) << "Failed to get DSU running state: " << status;
- return BINDER_ERROR;
- }
- auto dsu_enabled = false;
- if (auto status = gsid->isGsiEnabled(&dsu_enabled); !status.isOk()) {
- LOG(ERROR) << "Failed to get DSU enabled state: " << status;
- return BINDER_ERROR;
- }
- if (dsu_running && !dsu_enabled) {
- std::string dsu_slot;
- if (auto status = gsid->getActiveDsuSlot(&dsu_slot); !status.isOk()) {
- LOG(ERROR) << "Failed to get active DSU slot: " << status;
- return BINDER_ERROR;
- }
- LOG(INFO) << "DSU is running but disabled, enable DSU so that we stay within the "
- "DSU guest system after reboot";
- int error = 0;
- if (auto status = gsid->enableGsi(/* oneShot = */ true, dsu_slot, &error);
- !status.isOk() || error != android::gsi::IGsiService::INSTALL_OK) {
- LOG(ERROR) << "Failed to enable DSU: " << status << ", error code: " << error;
- return !status.isOk() ? BINDER_ERROR : GSID_ERROR;
- }
- LOG(INFO) << "Successfully enabled DSU (one-shot mode)";
- }
- }
- }
-
- if (partitions.empty() || just_disabled_verity) {
- if (reboot_later) reboot(setup_overlayfs);
- if (user_please_reboot_later) {
- return MUST_REBOOT;
- }
- LOG(WARNING) << "No partitions to remount";
- return retval;
- }
-
- // Mount overlayfs.
- errno = 0;
- if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) {
- retval = BAD_OVERLAY;
- PLOG(ERROR) << "Can not mount overlayfs for partitions";
- }
-
- // Get actual mounts _after_ overlayfs has been added.
- android::fs_mgr::Fstab mounts;
- if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts) || mounts.empty()) {
- PLOG(ERROR) << "Failed to read /proc/mounts";
- retval = NO_MOUNTS;
- }
-
- // Remount selected partitions.
- for (auto& entry : partitions) {
- // unlock the r/o key for the mount point device
- if (entry.fs_mgr_flags.logical) {
- fs_mgr_update_logical_partition(&entry);
- }
- auto blk_device = entry.blk_device;
- auto mount_point = entry.mount_point;
-
- auto found = false;
- for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
- auto& rentry = *it;
- if (mount_point == rentry.mount_point) {
- blk_device = rentry.blk_device;
- found = true;
- break;
- }
- // Find overlayfs mount point?
- if ((mount_point == "/" && rentry.mount_point == "/system") ||
- (mount_point == "/system" && rentry.mount_point == "/")) {
- blk_device = rentry.blk_device;
- mount_point = "/system";
- found = true;
- break;
- }
- }
- if (!found) {
- PLOG(INFO) << "skip unmounted partition dev:" << blk_device << " mnt:" << mount_point;
- continue;
- }
- if (blk_device == "/dev/root") {
- auto from_fstab = GetEntryForMountPoint(&fstab, mount_point);
- if (from_fstab) blk_device = from_fstab->blk_device;
- }
- fs_mgr_set_blk_ro(blk_device, false);
-
- // Find system-as-root mount point?
- if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
- GetEntryForMountPoint(&mounts, "/")) {
- mount_point = "/";
- }
-
- // Now remount!
- if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
- nullptr) == 0) {
- continue;
- }
- if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
- mount_point = entry.mount_point;
- if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
- nullptr) == 0) {
- continue;
- }
- }
- PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
- // If errno is EROFS at this point, we are dealing with r/o
- // filesystem types like squashfs, erofs or ext4 dedupe. We will
- // consider such a device that does not have CONFIG_OVERLAY_FS
- // in the kernel as a misconfigured.
- if (errno == EROFS) {
- LOG(ERROR) << "Consider providing all the dependencies to enable overlayfs";
- }
- retval = REMOUNT_FAILED;
- }
-
- if (reboot_later) reboot(setup_overlayfs);
- if (user_please_reboot_later) {
- LOG(INFO) << "Now reboot your device for settings to take effect";
- return 0;
- }
-
- return retval;
-}
-
-static int do_clean_scratch_files() {
- android::fs_mgr::CleanupOldScratchFiles();
- return 0;
-}
-
-int main(int argc, char* argv[]) {
- android::base::InitLogging(argv, MyLogger);
- if (argc > 0 && android::base::Basename(argv[0]) == "clean_scratch_files"s) {
- return do_clean_scratch_files();
- }
- int result = do_remount(argc, argv);
- if (result == MUST_REBOOT) {
- LOG(INFO) << "Now reboot your device for settings to take effect";
- result = 0;
- } else if (result == REMOUNT_SUCCESS) {
+ if (result == REMOUNT_SUCCESS) {
printf("remount succeeded\n");
- } else if (result == CLEAN_SCRATCH_FILES) {
- return do_clean_scratch_files();
} else {
printf("remount failed\n");
}
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 6caab1f..ec1d78f 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -26,12 +26,14 @@
android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
+bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
- bool* change = nullptr, bool force = true);
+bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* change = nullptr,
+ bool force = true);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
bool fs_mgr_overlayfs_is_setup();
bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
std::string fs_mgr_get_context(const std::string& mount_point);
enum class OverlayfsValidResult {
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 6ee8d4a..b3763ae 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -97,8 +97,8 @@
// This is non-zero when |state| == MERGING or MERGE_COMPLETED.
uint64 metadata_sectors = 8;
- // True if compression is enabled, false otherwise.
- bool compression_enabled = 9;
+ // True if using snapuserd, false otherwise.
+ bool using_snapuserd = 9;
// The old partition size (if none existed, this will be zero).
uint64 old_partition_size = 10;
@@ -184,7 +184,7 @@
uint64 metadata_sectors = 4;
// Whether compression/dm-user was used for any snapshots.
- bool compression_enabled = 5;
+ bool using_snapuserd = 5;
// Merge phase (if state == MERGING).
MergePhase merge_phase = 6;
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 653492c..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),
- merge_op_blocks_(std::make_shared<std::vector<uint32_t>>()),
- reader_flag_(reader_flag) {}
+ block_pos_index_(std::make_shared<std::vector<int>>()),
+ reader_flag_(reader_flag),
+ is_merge_(is_merge) {}
static void SHA256(const void*, size_t, uint8_t[]) {
#if 0
@@ -58,13 +59,13 @@
cow->fd_size_ = fd_size_;
cow->last_label_ = last_label_;
cow->ops_ = ops_;
- cow->merge_op_blocks_ = merge_op_blocks_;
cow->merge_op_start_ = merge_op_start_;
- cow->block_map_ = block_map_;
cow->num_total_data_ops_ = num_total_data_ops_;
cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_;
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;
}
@@ -415,10 +416,10 @@
// Replace-op-4, Zero-op-9, Replace-op-5 }
//==============================================================
bool CowReader::PrepMergeOps() {
- auto merge_op_blocks = std::make_shared<std::vector<uint32_t>>();
+ auto merge_op_blocks = std::make_unique<std::vector<uint32_t>>();
std::vector<int> other_ops;
auto seq_ops_set = std::unordered_set<uint32_t>();
- auto block_map = std::make_shared<std::unordered_map<uint32_t, int>>();
+ auto block_map = std::make_unique<std::unordered_map<uint32_t, int>>();
size_t num_seqs = 0;
size_t read;
@@ -482,8 +483,26 @@
merge_op_start_ = header_.num_merge_ops;
}
- block_map_ = block_map;
- merge_op_blocks_ = merge_op_blocks;
+ 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();
+
return true;
}
@@ -544,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;
@@ -558,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() {
@@ -589,9 +608,7 @@
class CowRevMergeOpIter final : public ICowOpIter {
public:
explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start);
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -602,17 +619,15 @@
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::reverse_iterator block_riter_;
+ std::vector<int>::reverse_iterator block_riter_;
+ std::shared_ptr<std::vector<int>> cow_op_index_vec_;
uint64_t start_;
};
class CowMergeOpIter final : public ICowOpIter {
public:
explicit CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map, uint64_t start);
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -623,26 +638,21 @@
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::iterator block_iter_;
+ std::vector<int>::iterator block_iter_;
+ std::shared_ptr<std::vector<int>> cow_op_index_vec_;
uint64_t start_;
};
CowMergeOpIter::CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start) {
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start) {
ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
start_ = start;
-
- block_iter_ = merge_op_blocks->begin() + start;
+ cow_op_index_vec_ = block_pos_index;
+ block_iter_ = cow_op_index_vec_->begin() + start;
}
bool CowMergeOpIter::RDone() {
- return block_iter_ == merge_op_blocks_->begin();
+ return block_iter_ == cow_op_index_vec_->begin();
}
void CowMergeOpIter::Prev() {
@@ -651,7 +661,7 @@
}
bool CowMergeOpIter::Done() {
- return block_iter_ == merge_op_blocks_->end();
+ return block_iter_ == cow_op_index_vec_->end();
}
void CowMergeOpIter::Next() {
@@ -661,23 +671,20 @@
const CowOperation& CowMergeOpIter::Get() {
CHECK(!Done());
- return ops_->data()[map_->at(*block_iter_)];
+ return ops_->data()[*block_iter_];
}
CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
+ std::shared_ptr<std::vector<int>> block_pos_index,
uint64_t start) {
ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
start_ = start;
-
- block_riter_ = merge_op_blocks->rbegin();
+ cow_op_index_vec_ = block_pos_index;
+ block_riter_ = cow_op_index_vec_->rbegin();
}
bool CowRevMergeOpIter::RDone() {
- return block_riter_ == merge_op_blocks_->rbegin();
+ return block_riter_ == cow_op_index_vec_->rbegin();
}
void CowRevMergeOpIter::Prev() {
@@ -686,7 +693,7 @@
}
bool CowRevMergeOpIter::Done() {
- return block_riter_ == merge_op_blocks_->rend() - start_;
+ return block_riter_ == cow_op_index_vec_->rend() - start_;
}
void CowRevMergeOpIter::Next() {
@@ -696,20 +703,20 @@
const CowOperation& CowRevMergeOpIter::Get() {
CHECK(!Done());
- return ops_->data()[map_->at(*block_riter_)];
+ 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) {
- return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ return std::make_unique<CowRevMergeOpIter>(ops_, block_pos_index_,
ignore_progress ? 0 : merge_op_start_);
}
std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
- return std::make_unique<CowMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ return std::make_unique<CowMergeOpIter>(ops_, block_pos_index_,
ignore_progress ? 0 : merge_op_start_);
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index f4d5c72..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;
@@ -170,14 +170,14 @@
uint64_t fd_size_;
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
uint64_t merge_op_start_{};
- std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
+ std::shared_ptr<std::vector<int>> block_pos_index_;
uint64_t num_total_data_ops_{};
uint64_t num_ordered_ops_to_merge_{};
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/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index be18b42..f850b94 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -17,6 +17,7 @@
#include <memory>
#include <optional>
#include <string>
+#include <unordered_map>
#include <unordered_set>
#include <android-base/file.h>
@@ -165,27 +166,25 @@
android::dm::IDeviceMapper& impl_;
};
-class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
+class SnapshotTestPropertyFetcher : public android::fs_mgr::IPropertyFetcher {
public:
- SnapshotTestPropertyFetcher(const std::string& slot_suffix) {
- using testing::Return;
- ON_CALL(*this, GetProperty("ro.boot.slot_suffix", _)).WillByDefault(Return(slot_suffix));
- ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions", _))
- .WillByDefault(Return(true));
- ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
- .WillByDefault(Return(false));
- ON_CALL(*this, GetBoolProperty("ro.virtual_ab.enabled", _)).WillByDefault(Return(true));
- }
+ explicit SnapshotTestPropertyFetcher(const std::string& slot_suffix,
+ std::unordered_map<std::string, std::string>&& props = {});
+
+ std::string GetProperty(const std::string& key, const std::string& defaultValue) override;
+ bool GetBoolProperty(const std::string& key, bool defaultValue) override;
static void SetUp(const std::string& slot_suffix = "_a") { Reset(slot_suffix); }
-
static void TearDown() { Reset("_a"); }
private:
static void Reset(const std::string& slot_suffix) {
IPropertyFetcher::OverrideForTesting(
- std::make_unique<NiceMock<SnapshotTestPropertyFetcher>>(slot_suffix));
+ std::make_unique<SnapshotTestPropertyFetcher>(slot_suffix));
}
+
+ private:
+ std::unordered_map<std::string, std::string> properties_;
};
// Helper for error-spam-free cleanup.
@@ -196,9 +195,10 @@
// Expect space of |path| is multiple of 4K.
bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
std::string* hash = nullptr);
-bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);
std::string HashSnapshot(ISnapshotWriter* writer);
+std::string ToHexString(const uint8_t* buf, size_t len);
+
std::optional<std::string> GetHash(const std::string& path);
// Add partitions and groups described by |manifest|.
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 5569da0..7057223 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -143,7 +143,7 @@
}
std::optional<uint64_t> PartitionCowCreator::GetCowSize() {
- if (compression_enabled) {
+ if (using_snapuserd) {
if (update == nullptr || !update->has_estimate_cow_size()) {
LOG(ERROR) << "Update manifest does not include a COW size";
return std::nullopt;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h
index 34b39ca..949e6c5 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -56,8 +56,8 @@
// Extra extents that are going to be invalidated during the update
// process.
std::vector<ChromeOSExtent> extra_extents = {};
- // True if compression is enabled.
- bool compression_enabled = false;
+ // True if snapuserd COWs are enabled.
+ bool using_snapuserd = false;
std::string compression_algorithm;
struct Return {
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index de35c13..cf26a16 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -249,7 +249,7 @@
.target_partition = system_b,
.current_metadata = builder_a.get(),
.current_suffix = "_a",
- .compression_enabled = true,
+ .using_snapuserd = true,
.update = &update};
auto ret = creator.Run();
@@ -275,7 +275,7 @@
.target_partition = system_b,
.current_metadata = builder_a.get(),
.current_suffix = "_a",
- .compression_enabled = true,
+ .using_snapuserd = true,
.update = nullptr};
auto ret = creator.Run();
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index ab3e210..bc3efd9 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -398,7 +398,7 @@
status->set_state(SnapshotState::CREATED);
status->set_sectors_allocated(0);
status->set_metadata_sectors(0);
- status->set_compression_enabled(cow_creator->compression_enabled);
+ status->set_using_snapuserd(cow_creator->using_snapuserd);
status->set_compression_algorithm(cow_creator->compression_algorithm);
if (!WriteSnapshotStatus(lock, *status)) {
@@ -788,7 +788,7 @@
}
}
- bool compression_enabled = false;
+ bool using_snapuserd = false;
std::vector<std::string> first_merge_group;
@@ -809,7 +809,7 @@
return false;
}
- compression_enabled |= snapshot_status.compression_enabled();
+ using_snapuserd |= snapshot_status.using_snapuserd();
if (DecideMergePhase(snapshot_status) == MergePhase::FIRST_PHASE) {
first_merge_group.emplace_back(snapshot);
}
@@ -817,7 +817,7 @@
SnapshotUpdateStatus initial_status = ReadSnapshotUpdateStatus(lock.get());
initial_status.set_state(UpdateState::Merging);
- initial_status.set_compression_enabled(compression_enabled);
+ initial_status.set_using_snapuserd(using_snapuserd);
if (!UpdateUsesUserSnapshots(lock.get())) {
initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
@@ -1364,7 +1364,7 @@
}
MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status) {
- if (!status.compression_enabled()) {
+ if (!status.using_snapuserd()) {
// Do not try to verify old-style COWs yet.
return MergeFailureCode::Ok;
}
@@ -1625,7 +1625,7 @@
// as unmap will fail since dm-user itself was a snapshot device prior
// to switching of tables. Unmap will fail as the device will be mounted
// by system partitions
- if (status.compression_enabled()) {
+ if (status.using_snapuserd()) {
auto dm_user_name = GetDmUserCowName(name, GetSnapshotDriver(lock));
UnmapDmUserDevice(dm_user_name);
}
@@ -2115,8 +2115,10 @@
}
bool SnapshotManager::UpdateUsesCompression(LockedFile* lock) {
+ // This returns true even if compression is "none", since update_engine is
+ // really just trying to see if snapuserd is in use.
SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- return update_status.compression_enabled();
+ return update_status.using_snapuserd();
}
bool SnapshotManager::UpdateUsesIouring(LockedFile* lock) {
@@ -2436,13 +2438,13 @@
remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
- if (context == SnapshotContext::Update && live_snapshot_status->compression_enabled()) {
+ if (context == SnapshotContext::Update && live_snapshot_status->using_snapuserd()) {
// Stop here, we can't run dm-user yet, the COW isn't built.
created_devices.Release();
return true;
}
- if (live_snapshot_status->compression_enabled()) {
+ if (live_snapshot_status->using_snapuserd()) {
// Get the source device (eg the view of the partition from before it was resized).
std::string source_device_path;
if (live_snapshot_status->old_partition_size() > 0) {
@@ -2944,7 +2946,7 @@
// build fingerprint.
if (!(state == UpdateState::Initiated || state == UpdateState::None)) {
SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
- status.set_compression_enabled(old_status.compression_enabled());
+ status.set_using_snapuserd(old_status.using_snapuserd());
status.set_source_build_fingerprint(old_status.source_build_fingerprint());
status.set_merge_phase(old_status.merge_phase());
status.set_userspace_snapshots(old_status.userspace_snapshots());
@@ -3198,18 +3200,42 @@
LOG(INFO) << " dap_metadata.cow_version(): " << dap_metadata.cow_version()
<< " writer.GetCowVersion(): " << writer.GetCowVersion();
- bool use_compression = IsCompressionEnabled() && dap_metadata.vabc_enabled() &&
- !device_->IsRecovery() && cow_format_support;
+ // Deduce supported features.
+ bool userspace_snapshots = CanUseUserspaceSnapshots();
+ bool legacy_compression = GetLegacyCompressionEnabledProperty();
+
+ std::string vabc_disable_reason;
+ if (!dap_metadata.vabc_enabled()) {
+ vabc_disable_reason = "not enabled metadata";
+ } else if (device_->IsRecovery()) {
+ vabc_disable_reason = "recovery";
+ } else if (!cow_format_support) {
+ vabc_disable_reason = "cow format not supported";
+ }
+
+ if (!vabc_disable_reason.empty()) {
+ if (userspace_snapshots) {
+ LOG(INFO) << "Userspace snapshots disabled: " << vabc_disable_reason;
+ }
+ if (legacy_compression) {
+ LOG(INFO) << "Compression disabled: " << vabc_disable_reason;
+ }
+ userspace_snapshots = false;
+ legacy_compression = false;
+ }
+
+ const bool using_snapuserd = userspace_snapshots || legacy_compression;
+ if (!using_snapuserd) {
+ LOG(INFO) << "Using legacy Virtual A/B (dm-snapshot)";
+ }
std::string compression_algorithm;
- if (use_compression) {
+ if (using_snapuserd) {
compression_algorithm = dap_metadata.vabc_compression_param();
if (compression_algorithm.empty()) {
// Older OTAs don't set an explicit compression type, so default to gz.
compression_algorithm = "gz";
}
- } else {
- compression_algorithm = "none";
}
PartitionCowCreator cow_creator{
@@ -3220,7 +3246,7 @@
.current_suffix = current_suffix,
.update = nullptr,
.extra_extents = {},
- .compression_enabled = use_compression,
+ .using_snapuserd = using_snapuserd,
.compression_algorithm = compression_algorithm,
};
@@ -3245,11 +3271,11 @@
return Return::Error();
}
- // If compression is enabled, we need to retain a copy of the old metadata
+ // If snapuserd is enabled, we need to retain a copy of the old metadata
// so we can access original blocks in case they are moved around. We do
// not want to rely on the old super metadata slot because we don't
// guarantee its validity after the slot switch is successful.
- if (cow_creator.compression_enabled) {
+ if (using_snapuserd) {
auto metadata = current_metadata->Export();
if (!metadata) {
LOG(ERROR) << "Could not export current metadata";
@@ -3265,70 +3291,36 @@
SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock.get());
status.set_state(update_state);
- status.set_compression_enabled(cow_creator.compression_enabled);
- if (cow_creator.compression_enabled) {
- if (!device()->IsTestDevice()) {
- bool userSnapshotsEnabled = IsUserspaceSnapshotsEnabled();
- const std::string UNKNOWN = "unknown";
- const std::string vendor_release = android::base::GetProperty(
- "ro.vendor.build.version.release_or_codename", UNKNOWN);
+ status.set_using_snapuserd(using_snapuserd);
- // No user-space snapshots if vendor partition is on Android 12
- if (vendor_release.find("12") != std::string::npos) {
- LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
- << vendor_release;
- userSnapshotsEnabled = false;
- }
+ if (userspace_snapshots) {
+ status.set_userspace_snapshots(true);
+ LOG(INFO) << "Virtual A/B using userspace snapshots";
- // Userspace snapshots is enabled only if compression is enabled
- status.set_userspace_snapshots(userSnapshotsEnabled);
- if (userSnapshotsEnabled) {
- is_snapshot_userspace_ = true;
- status.set_io_uring_enabled(IsIouringEnabled());
- LOG(INFO) << "Userspace snapshots enabled";
- } else {
- is_snapshot_userspace_ = false;
- LOG(INFO) << "Userspace snapshots disabled";
- }
+ if (GetIouringEnabledProperty()) {
+ status.set_io_uring_enabled(true);
+ LOG(INFO) << "io_uring for snapshots enabled";
+ }
+ } else if (legacy_compression) {
+ LOG(INFO) << "Virtual A/B using legacy snapuserd";
+ } else {
+ LOG(INFO) << "Virtual A/B using dm-snapshot";
+ }
- // Terminate stale daemon if any
- std::unique_ptr<SnapuserdClient> snapuserd_client =
- SnapuserdClient::Connect(kSnapuserdSocket, 5s);
- if (snapuserd_client) {
- snapuserd_client->DetachSnapuserd();
- snapuserd_client->CloseConnection();
- snapuserd_client = nullptr;
- }
+ is_snapshot_userspace_.emplace(userspace_snapshots);
- // Clear the cached client if any
- if (snapuserd_client_) {
- snapuserd_client_->CloseConnection();
- snapuserd_client_ = nullptr;
- }
- } else {
- bool userSnapshotsEnabled = true;
- const std::string UNKNOWN = "unknown";
- const std::string vendor_release = android::base::GetProperty(
- "ro.vendor.build.version.release_or_codename", UNKNOWN);
-
- // No user-space snapshots if vendor partition is on Android 12
- if (vendor_release.find("12") != std::string::npos) {
- LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
- << vendor_release;
- userSnapshotsEnabled = false;
- }
-
- userSnapshotsEnabled = (userSnapshotsEnabled && !IsDmSnapshotTestingEnabled());
- status.set_userspace_snapshots(userSnapshotsEnabled);
- if (!userSnapshotsEnabled) {
- is_snapshot_userspace_ = false;
- LOG(INFO) << "User-space snapshots disabled for testing";
- } else {
- is_snapshot_userspace_ = true;
- LOG(INFO) << "User-space snapshots enabled for testing";
- }
+ if (!device()->IsTestDevice() && using_snapuserd) {
+ // Terminate stale daemon if any
+ std::unique_ptr<SnapuserdClient> snapuserd_client = std::move(snapuserd_client_);
+ if (!snapuserd_client) {
+ snapuserd_client = SnapuserdClient::Connect(kSnapuserdSocket, 5s);
+ }
+ if (snapuserd_client) {
+ snapuserd_client->DetachSnapuserd();
+ snapuserd_client->CloseConnection();
}
}
+
if (!WriteSnapshotUpdateStatus(lock.get(), status)) {
LOG(ERROR) << "Unable to write new update state";
return Return::Error();
@@ -3521,7 +3513,7 @@
return Return::Error();
}
- if (it->second.compression_enabled()) {
+ if (it->second.using_snapuserd()) {
unique_fd fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
if (fd < 0) {
PLOG(ERROR) << "open " << cow_path << " failed for snapshot "
@@ -3567,8 +3559,8 @@
if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
return false;
}
- if (status.compression_enabled()) {
- LOG(ERROR) << "Cannot use MapUpdateSnapshot with compressed snapshots";
+ if (status.using_snapuserd()) {
+ LOG(ERROR) << "Cannot use MapUpdateSnapshot with snapuserd";
return false;
}
@@ -3625,7 +3617,7 @@
return nullptr;
}
- if (status.compression_enabled()) {
+ if (status.using_snapuserd()) {
return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
status, paths);
}
@@ -3755,7 +3747,10 @@
auto update_status = ReadSnapshotUpdateStatus(file.get());
ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
- ss << "Compression: " << update_status.compression_enabled() << std::endl;
+ ss << "Using snapuserd: " << update_status.using_snapuserd() << std::endl;
+ ss << "Using userspace snapshots: " << update_status.userspace_snapshots() << std::endl;
+ ss << "Using io_uring: " << update_status.io_uring_enabled() << std::endl;
+ ss << "Using XOR compression: " << GetXorCompressionEnabledProperty() << std::endl;
ss << "Current slot: " << device_->GetSlotSuffix() << std::endl;
ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl;
ss << "Rollback indicator: "
@@ -3976,7 +3971,7 @@
if (!ReadSnapshotStatus(lock, snapshot, &status)) {
return false;
}
- if (status.compression_enabled()) {
+ if (status.using_snapuserd()) {
continue;
}
@@ -4140,7 +4135,7 @@
if (!lock) return false;
auto status = ReadSnapshotUpdateStatus(lock.get());
- return status.state() != UpdateState::None && status.compression_enabled();
+ return status.state() != UpdateState::None && status.using_snapuserd();
}
bool SnapshotManager::DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv) {
@@ -4166,7 +4161,7 @@
}
MergePhase SnapshotManager::DecideMergePhase(const SnapshotStatus& status) {
- if (status.compression_enabled() && status.device_size() < status.old_partition_size()) {
+ if (status.using_snapuserd() && status.device_size() < status.old_partition_size()) {
return MergePhase::FIRST_PHASE;
}
return MergePhase::SECOND_PHASE;
@@ -4208,8 +4203,7 @@
SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
stats->report()->set_iouring_used(update_status.io_uring_enabled());
stats->report()->set_userspace_snapshots_used(update_status.userspace_snapshots());
- stats->report()->set_xor_compression_used(
- android::base::GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false));
+ stats->report()->set_xor_compression_used(GetXorCompressionEnabledProperty());
}
bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index b889fd4..2233a38 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -40,6 +40,7 @@
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
+#include <openssl/sha.h>
#include <storage_literals/storage_literals.h>
#include <android/snapshot/snapshot.pb.h>
@@ -52,9 +53,11 @@
#include <libsnapshot/mock_device_info.h>
#include <libsnapshot/mock_snapshot.h>
-DEFINE_string(force_config, "", "Force testing mode (dmsnap, vab, vabc) ignoring device config.");
+DEFINE_string(force_mode, "",
+ "Force testing older modes (vab-legacy, vabc-legacy) ignoring device config.");
DEFINE_string(force_iouring_disable, "",
"Force testing mode (iouring_disabled) - disable io_uring");
+DEFINE_string(compression_method, "gz", "Default compression algorithm.");
namespace android {
namespace snapshot {
@@ -91,8 +94,6 @@
std::string fake_super;
void MountMetadata();
-bool ShouldUseCompression();
-bool IsDaemonRequired();
class SnapshotTest : public ::testing::Test {
public:
@@ -108,7 +109,7 @@
void SetUp() override {
SKIP_IF_NON_VIRTUAL_AB();
- SnapshotTestPropertyFetcher::SetUp();
+ SetupProperties();
InitializeState();
CleanupTestArtifacts();
FormatFakeSuper();
@@ -116,6 +117,38 @@
ASSERT_TRUE(sm->BeginUpdate());
}
+ void SetupProperties() {
+ std::unordered_map<std::string, std::string> properties;
+
+ ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "0"))
+ << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
+ ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0"))
+ << "Failed to set property: snapuserd.test.io_uring.disabled";
+
+ if (FLAGS_force_mode == "vabc-legacy") {
+ ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "1"))
+ << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
+ properties["ro.virtual_ab.compression.enabled"] = "true";
+ properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
+ } else if (FLAGS_force_mode == "vab-legacy") {
+ properties["ro.virtual_ab.compression.enabled"] = "false";
+ properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
+ }
+
+ if (FLAGS_force_iouring_disable == "iouring_disabled") {
+ ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1"))
+ << "Failed to set property: snapuserd.test.io_uring.disabled";
+ properties["ro.virtual_ab.io_uring.enabled"] = "false";
+ }
+
+ auto fetcher = std::make_unique<SnapshotTestPropertyFetcher>("_a", std::move(properties));
+ IPropertyFetcher::OverrideForTesting(std::move(fetcher));
+
+ if (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots()) {
+ snapuserd_required_ = true;
+ }
+ }
+
void TearDown() override {
RETURN_IF_NON_VIRTUAL_AB();
@@ -316,7 +349,7 @@
}
AssertionResult DeleteDevice(const std::string& device) {
- if (!dm_.DeleteDeviceIfExists(device)) {
+ if (!sm->DeleteDeviceIfExists(device, 1s)) {
return AssertionFailure() << "Can't delete " << device;
}
return AssertionSuccess();
@@ -358,8 +391,11 @@
DeltaArchiveManifest manifest;
auto dynamic_partition_metadata = manifest.mutable_dynamic_partition_metadata();
- dynamic_partition_metadata->set_vabc_enabled(IsCompressionEnabled());
+ dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
+ if (snapuserd_required_) {
+ dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
+ }
auto group = dynamic_partition_metadata->add_groups();
group->set_name("group");
@@ -397,7 +433,7 @@
if (!res) {
return res;
}
- } else if (!IsCompressionEnabled()) {
+ } else if (!snapuserd_required_) {
std::string ignore;
if (!MapUpdateSnapshot("test_partition_b", &ignore)) {
return AssertionFailure() << "Failed to map test_partition_b";
@@ -450,15 +486,16 @@
std::unique_ptr<SnapshotManager::LockedFile> lock_;
android::fiemap::IImageManager* image_manager_ = nullptr;
std::string fake_super_;
+ bool snapuserd_required_ = false;
};
TEST_F(SnapshotTest, CreateSnapshot) {
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator;
- cow_creator.compression_enabled = ShouldUseCompression();
- if (cow_creator.compression_enabled) {
- cow_creator.compression_algorithm = "gz";
+ cow_creator.using_snapuserd = snapuserd_required_;
+ if (cow_creator.using_snapuserd) {
+ cow_creator.compression_algorithm = FLAGS_compression_method;
} else {
cow_creator.compression_algorithm = "none";
}
@@ -484,7 +521,7 @@
ASSERT_EQ(status.state(), SnapshotState::CREATED);
ASSERT_EQ(status.device_size(), kDeviceSize);
ASSERT_EQ(status.snapshot_size(), kDeviceSize);
- ASSERT_EQ(status.compression_enabled(), cow_creator.compression_enabled);
+ ASSERT_EQ(status.using_snapuserd(), cow_creator.using_snapuserd);
ASSERT_EQ(status.compression_algorithm(), cow_creator.compression_algorithm);
}
@@ -497,7 +534,7 @@
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator;
- cow_creator.compression_enabled = ShouldUseCompression();
+ cow_creator.using_snapuserd = snapuserd_required_;
static const uint64_t kDeviceSize = 1024 * 1024;
SnapshotStatus status;
@@ -624,10 +661,10 @@
SnapshotStatus status;
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
ASSERT_EQ(status.state(), SnapshotState::CREATED);
- if (ShouldUseCompression()) {
- ASSERT_EQ(status.compression_algorithm(), "gz");
+ if (snapuserd_required_) {
+ ASSERT_EQ(status.compression_algorithm(), FLAGS_compression_method);
} else {
- ASSERT_EQ(status.compression_algorithm(), "none");
+ ASSERT_EQ(status.compression_algorithm(), "");
}
DeviceMapper::TargetInfo target;
@@ -898,8 +935,11 @@
opener_ = std::make_unique<TestPartitionOpener>(fake_super);
auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
- dynamic_partition_metadata->set_vabc_enabled(ShouldUseCompression());
+ dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
+ if (snapuserd_required_) {
+ dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
+ }
// Create a fake update package metadata.
// Not using full name "system", "vendor", "product" because these names collide with the
@@ -1031,7 +1071,7 @@
}
AssertionResult MapOneUpdateSnapshot(const std::string& name) {
- if (ShouldUseCompression()) {
+ if (snapuserd_required_) {
std::unique_ptr<ISnapshotWriter> writer;
return MapUpdateSnapshot(name, &writer);
} else {
@@ -1040,14 +1080,25 @@
}
}
- AssertionResult WriteSnapshotAndHash(const std::string& name) {
- if (ShouldUseCompression()) {
+ AssertionResult WriteSnapshots() {
+ for (const auto& partition : {sys_, vnd_, prd_}) {
+ auto res = WriteSnapshotAndHash(partition);
+ if (!res) {
+ return res;
+ }
+ }
+ return AssertionSuccess();
+ }
+
+ AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
+ std::string name = partition->partition_name() + "_b";
+ if (snapuserd_required_) {
std::unique_ptr<ISnapshotWriter> writer;
auto res = MapUpdateSnapshot(name, &writer);
if (!res) {
return res;
}
- if (!WriteRandomData(writer.get(), &hashes_[name])) {
+ if (!WriteRandomSnapshotData(writer.get(), &hashes_[name])) {
return AssertionFailure() << "Unable to write random data to snapshot " << name;
}
if (!writer->Finalize()) {
@@ -1071,6 +1122,42 @@
<< ", hash: " << hashes_[name];
}
+ bool WriteRandomSnapshotData(ICowWriter* writer, std::string* hash) {
+ unique_fd rand(open("/dev/urandom", O_RDONLY));
+ if (rand < 0) {
+ PLOG(ERROR) << "open /dev/urandom";
+ return false;
+ }
+
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+
+ if (!writer->options().max_blocks) {
+ LOG(ERROR) << "CowWriter must specify maximum number of blocks";
+ return false;
+ }
+ const auto num_blocks = writer->options().max_blocks.value();
+
+ const auto block_size = writer->options().block_size;
+ std::string block(block_size, '\0');
+ for (uint64_t i = 0; i < num_blocks; i++) {
+ if (!ReadFully(rand, block.data(), block.size())) {
+ PLOG(ERROR) << "read /dev/urandom";
+ return false;
+ }
+ if (!writer->AddRawBlocks(i, block.data(), block.size())) {
+ LOG(ERROR) << "Failed to add raw block " << i;
+ return false;
+ }
+ SHA256_Update(&ctx, block.data(), block.size());
+ }
+
+ uint8_t out[32];
+ SHA256_Final(out, &ctx);
+ *hash = ToHexString(out, sizeof(out));
+ return true;
+ }
+
// Generate a snapshot that moves all the upper blocks down to the start.
// It doesn't really matter the order, we just want copies that reference
// blocks that won't exist if the partition shrinks.
@@ -1179,9 +1266,7 @@
ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
+ ASSERT_TRUE(WriteSnapshots());
// Assert that source partitions aren't affected.
for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -1209,7 +1294,7 @@
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
+ ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
{
// We should have started in SECOND_PHASE since nothing shrinks.
ASSERT_TRUE(AcquireLock());
@@ -1236,8 +1321,8 @@
}
TEST_F(SnapshotUpdateTest, DuplicateOps) {
- if (!ShouldUseCompression()) {
- GTEST_SKIP() << "Compression-only test";
+ if (!snapuserd_required_) {
+ GTEST_SKIP() << "snapuserd-only test";
}
// Execute the update.
@@ -1245,9 +1330,7 @@
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
+ ASSERT_TRUE(WriteSnapshots());
std::vector<PartitionUpdate*> partitions = {sys_, vnd_, prd_};
for (auto* partition : partitions) {
@@ -1280,9 +1363,9 @@
// Test that shrinking and growing partitions at the same time is handled
// correctly in VABC.
TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
- if (!ShouldUseCompression()) {
+ if (!snapuserd_required_) {
// b/179111359
- GTEST_SKIP() << "Skipping Virtual A/B Compression test";
+ GTEST_SKIP() << "Skipping snapuserd test";
}
auto old_sys_size = GetSize(sys_);
@@ -1311,8 +1394,8 @@
ASSERT_EQ(status.old_partition_size(), 3145728);
}
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
- ASSERT_TRUE(WriteSnapshotAndHash("vnd_b"));
+ ASSERT_TRUE(WriteSnapshotAndHash(sys_));
+ ASSERT_TRUE(WriteSnapshotAndHash(vnd_));
ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size));
sync();
@@ -1343,7 +1426,7 @@
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
+ ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
{
// Check that the merge phase is FIRST_PHASE until at least one call
// to ProcessUpdateState() occurs.
@@ -1397,9 +1480,9 @@
// Test that a transient merge consistency check failure can resume properly.
TEST_F(SnapshotUpdateTest, ConsistencyCheckResume) {
- if (!ShouldUseCompression()) {
+ if (!snapuserd_required_) {
// b/179111359
- GTEST_SKIP() << "Skipping Virtual A/B Compression test";
+ GTEST_SKIP() << "Skipping snapuserd test";
}
auto old_sys_size = GetSize(sys_);
@@ -1415,8 +1498,8 @@
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
- ASSERT_TRUE(WriteSnapshotAndHash("vnd_b"));
+ ASSERT_TRUE(WriteSnapshotAndHash(sys_));
+ ASSERT_TRUE(WriteSnapshotAndHash(vnd_));
ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size));
sync();
@@ -1451,7 +1534,7 @@
// Initiate the merge and wait for it to be completed.
ASSERT_TRUE(init->InitiateMerge());
- ASSERT_EQ(init->IsSnapuserdRequired(), IsDaemonRequired());
+ ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
{
// Check that the merge phase is FIRST_PHASE until at least one call
// to ProcessUpdateState() occurs.
@@ -1577,9 +1660,7 @@
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
+ ASSERT_TRUE(WriteSnapshots());
// Assert that source partitions aren't affected.
for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -1738,9 +1819,7 @@
ASSERT_FALSE(image_manager_->BackingImageExists("prd_b-cow-img"));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
+ ASSERT_TRUE(WriteSnapshots());
// Assert that source partitions aren't affected.
for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -2012,9 +2091,7 @@
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name)) << name;
- }
+ ASSERT_TRUE(WriteSnapshots());
ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
@@ -2054,17 +2131,15 @@
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name)) << name;
- }
+ ASSERT_TRUE(WriteSnapshots());
// Create a stale snapshot that should not exist.
{
ASSERT_TRUE(AcquireLock());
PartitionCowCreator cow_creator = {
- .compression_enabled = ShouldUseCompression(),
- .compression_algorithm = ShouldUseCompression() ? "gz" : "none",
+ .using_snapuserd = snapuserd_required_,
+ .compression_algorithm = snapuserd_required_ ? FLAGS_compression_method : "",
};
SnapshotStatus status;
status.set_name("sys_a");
@@ -2139,7 +2214,7 @@
// Map and write some data to target partition.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+ ASSERT_TRUE(WriteSnapshotAndHash(sys_));
// Finish update.
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
@@ -2160,8 +2235,8 @@
// Test for overflow bit after update
TEST_F(SnapshotUpdateTest, Overflow) {
- if (ShouldUseCompression()) {
- GTEST_SKIP() << "No overflow bit set for userspace COWs";
+ if (snapuserd_required_) {
+ GTEST_SKIP() << "No overflow bit set for snapuserd COWs";
}
const auto actual_write_size = GetSize(sys_);
@@ -2175,7 +2250,7 @@
// Map and write some data to target partitions.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+ ASSERT_TRUE(WriteSnapshotAndHash(sys_));
std::vector<android::dm::DeviceMapper::TargetInfo> table;
ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
@@ -2235,8 +2310,8 @@
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
// Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
+ for (const auto& partition : {sys_, vnd_, prd_, dlkm}) {
+ ASSERT_TRUE(WriteSnapshotAndHash(partition));
}
// Assert that source partitions aren't affected.
@@ -2295,8 +2370,8 @@
};
TEST_F(SnapshotUpdateTest, DaemonTransition) {
- if (!ShouldUseCompression()) {
- GTEST_SKIP() << "Skipping Virtual A/B Compression test";
+ if (!snapuserd_required_) {
+ GTEST_SKIP() << "Skipping snapuserd test";
}
// Ensure a connection to the second-stage daemon, but use the first-stage
@@ -2360,9 +2435,7 @@
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
+ ASSERT_TRUE(WriteSnapshots());
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
ASSERT_TRUE(sm->MapAllSnapshots(10s));
@@ -2412,13 +2485,6 @@
// fit in super, but not |prd|.
constexpr uint64_t partition_size = 3788_KiB;
SetSize(sys_, partition_size);
- SetSize(vnd_, partition_size);
- SetSize(prd_, 18_MiB);
-
- // Make sure |prd| does not fit in super at all. On VABC, this means we
- // fake an extra large COW for |vnd| to fill up super.
- vnd_->set_estimate_cow_size(30_MiB);
- prd_->set_estimate_cow_size(30_MiB);
AddOperationForPartitions();
@@ -2430,23 +2496,7 @@
GTEST_SKIP() << "Test does not apply to userspace snapshots";
}
- // Test that partitions prioritize using space in super.
- auto tgt = MetadataBuilder::New(*opener_, "super", 1);
- ASSERT_NE(tgt, nullptr);
- ASSERT_NE(nullptr, tgt->FindPartition("sys_b-cow"));
- ASSERT_NE(nullptr, tgt->FindPartition("vnd_b-cow"));
- ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- // Assert that source partitions aren't affected.
- for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
- ASSERT_TRUE(IsPartitionUnchanged(name));
- }
-
+ ASSERT_TRUE(WriteSnapshots());
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
ASSERT_TRUE(UnmapAll());
@@ -2610,7 +2660,6 @@
}
void TearDown() override {
RETURN_IF_NON_VIRTUAL_AB();
- return; // BUG(149738928)
EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
image_manager_->DeleteBackingImage(kImageName));
@@ -2619,19 +2668,6 @@
std::unique_ptr<LowSpaceUserdata> userdata_;
};
-TEST_P(ImageManagerTest, CreateImageEnoughAvailSpace) {
- if (userdata_->available_space() == 0) {
- GTEST_SKIP() << "/data is full (" << userdata_->available_space()
- << " bytes available), skipping";
- }
- ASSERT_TRUE(image_manager_->CreateBackingImage(kImageName, userdata_->available_space(),
- IImageManager::CREATE_IMAGE_DEFAULT))
- << "Should be able to create image with size = " << userdata_->available_space()
- << " bytes";
- ASSERT_TRUE(image_manager_->DeleteBackingImage(kImageName))
- << "Should be able to delete created image";
-}
-
TEST_P(ImageManagerTest, CreateImageNoSpace) {
uint64_t to_allocate = userdata_->free_space() + userdata_->bsize();
auto res = image_manager_->CreateBackingImage(kImageName, to_allocate,
@@ -2751,41 +2787,17 @@
}
}
-bool IsDaemonRequired() {
- if (FLAGS_force_config == "dmsnap") {
- return false;
+void KillSnapuserd() {
+ auto status = android::base::GetProperty("init.svc.snapuserd", "stopped");
+ if (status == "stopped") {
+ return;
}
-
- if (!IsCompressionEnabled()) {
- return false;
+ auto snapuserd_client = SnapuserdClient::Connect(kSnapuserdSocket, 5s);
+ if (!snapuserd_client) {
+ return;
}
-
- const std::string UNKNOWN = "unknown";
- const std::string vendor_release =
- android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
-
- // No userspace snapshots if vendor partition is on Android 12
- // However, for GRF devices, snapuserd daemon will be on
- // vendor ramdisk in Android 12.
- if (vendor_release.find("12") != std::string::npos) {
- return true;
- }
-
- if (!FLAGS_force_config.empty()) {
- return true;
- }
-
- return IsUserspaceSnapshotsEnabled();
-}
-
-bool ShouldUseCompression() {
- if (FLAGS_force_config == "vab" || FLAGS_force_config == "dmsnap") {
- return false;
- }
- if (FLAGS_force_config == "vabc") {
- return true;
- }
- return IsCompressionEnabled();
+ snapuserd_client->DetachSnapuserd();
+ snapuserd_client->CloseConnection();
}
} // namespace snapshot
@@ -2798,35 +2810,20 @@
android::base::SetProperty("ctl.stop", "snapuserd");
- std::unordered_set<std::string> configs = {"", "dmsnap", "vab", "vabc"};
- if (configs.count(FLAGS_force_config) == 0) {
+ std::unordered_set<std::string> modes = {"", "vab-legacy", "vabc-legacy"};
+ if (modes.count(FLAGS_force_mode) == 0) {
std::cerr << "Unexpected force_config argument\n";
return 1;
}
- if (FLAGS_force_config == "dmsnap") {
- if (!android::base::SetProperty("snapuserd.test.dm.snapshots", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
- }
- }
-
- if (FLAGS_force_iouring_disable == "iouring_disabled") {
- if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
- return testing::AssertionFailure()
- << "Failed to disable property: snapuserd.test.io_uring.disabled";
- }
- }
+ // This is necessary if the configuration we're testing doesn't match the device.
+ android::snapshot::KillSnapuserd();
int ret = RUN_ALL_TESTS();
- if (FLAGS_force_config == "dmsnap") {
- android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
- }
+ android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
+ android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
- if (FLAGS_force_iouring_disable == "iouring_disabled") {
- android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
- }
-
+ android::snapshot::KillSnapuserd();
return ret;
}
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 17f3c4f..d57f434 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -71,16 +71,16 @@
}
bool Worker::MergeReplaceZeroOps() {
- // Flush every 8192 ops. Since all ops are independent and there is no
+ // Flush after merging 2MB. 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 file for every 8192 ops. If there is a crash,
- // we will end up replaying some of the COW ops which were already merged.
- // That is ok.
+ // 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.
//
- // Why 8192 ops ? Increasing this may improve merge time 3-4 seconds but
- // we need to make sure that we checkpoint; 8k ops seems optimal. In-case
- // if there is a crash merge should always make forward progress.
- int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ) * 32;
+ // Although increasing this greater than 2MB 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 num_ops_merged = 0;
SNAP_LOG(INFO) << "MergeReplaceZeroOps started....";
@@ -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/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 71fe124..b05123a 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -18,10 +18,12 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parsebool.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
+#include <liblp/property_fetcher.h>
#include <openssl/sha.h>
#include <payload_consumer/file_descriptor.h>
@@ -128,48 +130,6 @@
return true;
}
-bool WriteRandomData(ICowWriter* writer, std::string* hash) {
- unique_fd rand(open("/dev/urandom", O_RDONLY));
- if (rand < 0) {
- PLOG(ERROR) << "open /dev/urandom";
- return false;
- }
-
- SHA256_CTX ctx;
- if (hash) {
- SHA256_Init(&ctx);
- }
-
- if (!writer->options().max_blocks) {
- LOG(ERROR) << "CowWriter must specify maximum number of blocks";
- return false;
- }
- uint64_t num_blocks = writer->options().max_blocks.value();
-
- size_t block_size = writer->options().block_size;
- std::string block(block_size, '\0');
- for (uint64_t i = 0; i < num_blocks; i++) {
- if (!ReadFully(rand, block.data(), block.size())) {
- PLOG(ERROR) << "read /dev/urandom";
- return false;
- }
- if (!writer->AddRawBlocks(i, block.data(), block.size())) {
- LOG(ERROR) << "Failed to add raw block " << i;
- return false;
- }
- if (hash) {
- SHA256_Update(&ctx, block.data(), block.size());
- }
- }
-
- if (hash) {
- uint8_t out[32];
- SHA256_Final(out, &ctx);
- *hash = ToHexString(out, sizeof(out));
- }
- return true;
-}
-
std::string HashSnapshot(ISnapshotWriter* writer) {
auto reader = writer->OpenReader();
if (!reader) {
@@ -320,5 +280,38 @@
return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
}
+SnapshotTestPropertyFetcher::SnapshotTestPropertyFetcher(
+ const std::string& slot_suffix, std::unordered_map<std::string, std::string>&& props)
+ : properties_(std::move(props)) {
+ properties_["ro.boot.slot_suffix"] = slot_suffix;
+ properties_["ro.boot.dynamic_partitions"] = "true";
+ properties_["ro.boot.dynamic_partitions_retrofit"] = "false";
+ properties_["ro.virtual_ab.enabled"] = "true";
+}
+
+std::string SnapshotTestPropertyFetcher::GetProperty(const std::string& key,
+ const std::string& defaultValue) {
+ auto iter = properties_.find(key);
+ if (iter == properties_.end()) {
+ return android::base::GetProperty(key, defaultValue);
+ }
+ return iter->second;
+}
+
+bool SnapshotTestPropertyFetcher::GetBoolProperty(const std::string& key, bool defaultValue) {
+ auto iter = properties_.find(key);
+ if (iter == properties_.end()) {
+ return android::base::GetBoolProperty(key, defaultValue);
+ }
+ switch (android::base::ParseBool(iter->second)) {
+ case android::base::ParseBoolResult::kTrue:
+ return true;
+ case android::base::ParseBoolResult::kFalse:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index f01bec9..0a1be0d 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -26,6 +26,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr/roots.h>
+#include <liblp/property_fetcher.h>
using android::dm::kSectorSize;
using android::fiemap::FiemapStatus;
@@ -33,6 +34,7 @@
using android::fs_mgr::EnsurePathUnmounted;
using android::fs_mgr::Fstab;
using android::fs_mgr::GetEntryForPath;
+using android::fs_mgr::IPropertyFetcher;
using android::fs_mgr::MetadataBuilder;
using android::fs_mgr::Partition;
using android::fs_mgr::ReadDefaultFstab;
@@ -184,16 +186,50 @@
new_extent->set_num_blocks(num_blocks);
}
-bool IsCompressionEnabled() {
- return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+bool GetLegacyCompressionEnabledProperty() {
+ auto fetcher = IPropertyFetcher::GetInstance();
+ return fetcher->GetBoolProperty("ro.virtual_ab.compression.enabled", false);
}
-bool IsUserspaceSnapshotsEnabled() {
- return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
+bool GetUserspaceSnapshotsEnabledProperty() {
+ auto fetcher = IPropertyFetcher::GetInstance();
+ return fetcher->GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
}
-bool IsIouringEnabled() {
- return android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
+bool CanUseUserspaceSnapshots() {
+ if (!GetUserspaceSnapshotsEnabledProperty()) {
+ return false;
+ }
+
+ auto fetcher = IPropertyFetcher::GetInstance();
+
+ const std::string UNKNOWN = "unknown";
+ const std::string vendor_release =
+ fetcher->GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+
+ // No user-space snapshots if vendor partition is on Android 12
+ if (vendor_release.find("12") != std::string::npos) {
+ LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
+ << vendor_release;
+ return false;
+ }
+
+ if (IsDmSnapshotTestingEnabled()) {
+ LOG(INFO) << "Userspace snapshots disabled for testing";
+ return false;
+ }
+
+ return true;
+}
+
+bool GetIouringEnabledProperty() {
+ auto fetcher = IPropertyFetcher::GetInstance();
+ return fetcher->GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
+}
+
+bool GetXorCompressionEnabledProperty() {
+ auto fetcher = IPropertyFetcher::GetInstance();
+ return fetcher->GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false);
}
std::string GetOtherPartitionName(const std::string& name) {
@@ -205,7 +241,8 @@
}
bool IsDmSnapshotTestingEnabled() {
- return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
+ auto fetcher = IPropertyFetcher::GetInstance();
+ return fetcher->GetBoolProperty("snapuserd.test.dm.snapshots", false);
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 0ef3234..eff6f10 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -59,7 +59,6 @@
// On destruct, delete |name| from device mapper.
AutoUnmapDevice(android::dm::IDeviceMapper* dm, const std::string& name)
: AutoDevice(name), dm_(dm) {}
- AutoUnmapDevice(AutoUnmapDevice&& other) = default;
~AutoUnmapDevice();
private:
@@ -72,7 +71,6 @@
// On destruct, delete |name| from image manager.
AutoUnmapImage(android::fiemap::IImageManager* images, const std::string& name)
: AutoDevice(name), images_(images) {}
- AutoUnmapImage(AutoUnmapImage&& other) = default;
~AutoUnmapImage();
private:
@@ -86,7 +84,6 @@
AutoDeleteSnapshot(SnapshotManager* manager, SnapshotManager::LockedFile* lock,
const std::string& name)
: AutoDevice(name), manager_(manager), lock_(lock) {}
- AutoDeleteSnapshot(AutoDeleteSnapshot&& other);
~AutoDeleteSnapshot();
private:
@@ -129,15 +126,16 @@
void AppendExtent(google::protobuf::RepeatedPtrField<chromeos_update_engine::Extent>* extents,
uint64_t start_block, uint64_t num_blocks);
-bool IsCompressionEnabled();
+bool GetLegacyCompressionEnabledProperty();
+bool GetUserspaceSnapshotsEnabledProperty();
+bool GetIouringEnabledProperty();
+bool GetXorCompressionEnabledProperty();
-bool IsUserspaceSnapshotsEnabled();
-
+bool CanUseUserspaceSnapshots();
bool IsDmSnapshotTestingEnabled();
-bool IsIouringEnabled();
-
// Swap the suffix of a partition name.
std::string GetOtherPartitionName(const std::string& name);
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 9542bc1..0157f46 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -59,6 +59,7 @@
print_time=false
start_time=`date +%s`
ACTIVE_SLOT=
+OVERLAYFS_BACKING="cache mnt/scratch"
ADB_WAIT=4m
FASTBOOT_WAIT=2m
@@ -68,6 +69,43 @@
## Helper Functions
##
+[ "USAGE: LOG [RUN|OK|PASSED|WARNING|ERROR|FAILED|INFO] [message]..." ]
+LOG() {
+ case "${1}" in
+ R*)
+ shift
+ echo "${GREEN}[ RUN ]${NORMAL}" "${@}"
+ ;;
+ OK)
+ shift
+ echo "${GREEN}[ OK ]${NORMAL}" "${@}"
+ ;;
+ P*)
+ shift
+ echo "${GREEN}[ PASSED ]${NORMAL}" "${@}"
+ ;;
+ W*)
+ shift
+ echo "${YELLOW}[ WARNING ]${NORMAL}" "${@}"
+ ;;
+ E*)
+ shift
+ echo "${RED}[ ERROR ]${NORMAL}" "${@}"
+ ;;
+ F*)
+ shift
+ echo "${RED}[ FAILED ]${NORMAL}" "${@}"
+ ;;
+ I*)
+ shift
+ echo "${BLUE}[ INFO ]${NORMAL}" "${@}"
+ ;;
+ *)
+ echo "${BLUE}[ INFO ]${NORMAL}" "${@}"
+ ;;
+ esac >&2
+}
+
[ "USAGE: inFastboot
Returns: true if device is in fastboot mode" ]
@@ -143,7 +181,7 @@
Returns: the logcat output" ]
adb_logcat() {
- echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
+ LOG INFO "logcat ${*}"
adb logcat "${@}" </dev/null |
tr -d '\r' |
grep -v 'logd : logdr: UID=' |
@@ -164,7 +202,7 @@
if [ -z "${L}" ]; then
return
fi
- echo "${YELLOW}[ WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
+ LOG WARNING "unlabeled sepolicy violations:"
echo "${L}" | sed "s/^/${INDENT}/" >&2
}
@@ -241,15 +279,15 @@
if [ X"${duration}" != X"${duration%s}" ]; then
duration=${duration%s}
elif [ X"${duration}" != X"${duration%m}" ]; then
- duration=`expr ${duration%m} \* 60`
+ duration=$(( ${duration%m} * 60 ))
elif [ X"${duration}" != X"${duration%h}" ]; then
- duration=`expr ${duration%h} \* 3600`
+ duration=$(( ${duration%h} * 3600 ))
elif [ X"${duration}" != X"${duration%d}" ]; then
- duration=`expr ${duration%d} \* 86400`
+ duration=$(( ${duration%d} * 86400 ))
fi
- local seconds=`expr ${duration} % 60`
- local minutes=`expr \( ${duration} / 60 \) % 60`
- local hours=`expr ${duration} / 3600`
+ local seconds=$(( ${duration} % 60 ))
+ local minutes=$(( ( ${duration} / 60 ) % 60 ))
+ local hours=$(( ${duration} / 3600 ))
if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
if [ 1 -eq ${duration} ]; then
echo 1 second
@@ -265,10 +303,10 @@
return
fi
if [ 0 -eq ${hours} ]; then
- echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
+ echo ${minutes}:$(( ${seconds} / 10 ))$(( ${seconds} % 10 ))
return
fi
- echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10`
+ echo ${hours}:$(( ${minutes} / 10 ))$(( ${minutes} % 10 )):$(( ${seconds} / 10 ))$(( ${seconds} % 10))
}
[ "USAGE: USB_DEVICE=\`usb_devnum [--next]\`
@@ -282,7 +320,7 @@
if [ -n "${usb_device}" ]; then
USB_DEVICE=dev${usb_device}
elif [ -n "${USB_DEVICE}" -a "${1}" ]; then
- USB_DEVICE=dev`expr ${USB_DEVICE#dev} + 1`
+ USB_DEVICE=dev$(( ${USB_DEVICE#dev} + 1 ))
fi
echo "${USB_DEVICE}"
fi
@@ -298,10 +336,10 @@
if [ -n "${1}" -a -n "`which timeout`" ]; then
USB_DEVICE=`usb_devnum --next`
duration=`format_duration ${1}`
- echo -n ". . . waiting ${duration}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
+ echo -n ". . . waiting ${duration}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}" >&2
timeout --preserve-status --signal=KILL ${1} adb wait-for-device 2>/dev/null
ret=${?}
- echo -n " ${CR}"
+ echo -n " ${CR}" >&2
else
adb wait-for-device
ret=${?}
@@ -310,11 +348,11 @@
if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
local active_slot=`get_active_slot`
if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2
+ LOG WARNING "Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
fi
fi
local end=`date +%s`
- local diff_time=`expr ${end} - ${start}`
+ local diff_time=$(( ${end} - ${start} ))
local _print_time=${print_time}
if [ ${diff_time} -lt 15 ]; then
_print_time=false
@@ -339,8 +377,8 @@
;;
esac
if ${_print_time} || [ -n "${reason}" ]; then
- echo "${BLUE}[ INFO ]${NORMAL} adb wait duration ${diff_time}${reason}"
- fi >&2
+ LOG INFO "adb wait duration ${diff_time}${reason}"
+ fi
return ${ret}
}
@@ -413,8 +451,8 @@
if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
local active_slot=`get_active_slot`
if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
- fi >&2
+ LOG WARNING "Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+ fi
fi
return ${ret}
}
@@ -438,8 +476,8 @@
if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
local active_slot=`get_active_slot`
if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
- fi >&2
+ LOG WARNING "Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+ fi
fi
return ${ret}
}
@@ -494,10 +532,10 @@
break
fi
fi
- counter=`expr ${counter} + 1`
+ counter=$(( ${counter} + 1 ))
if [ ${counter} -gt ${timeout} ]; then
${exit_function}
- echo "ERROR: wait_for_screen() timed out (`format_duration ${timeout}`)" >&2
+ LOG ERROR "wait_for_screen() timed out ($(format_duration ${timeout}))"
return 1
fi
sleep 1
@@ -593,12 +631,12 @@
Returns: reports duration" ]
test_duration() {
if ${print_time}; then
- echo "${BLUE}[ INFO ]${NORMAL} end `date`"
+ LOG INFO "end $(date)"
[ -n "${start_time}" ] || return
end_time=`date +%s`
- local diff_time=`expr ${end_time} - ${start_time}`
- echo "${BLUE}[ INFO ]${NORMAL} duration `format_duration ${diff_time}`"
- fi >&2
+ local diff_time=$(( ${end_time} - ${start_time} ))
+ LOG INFO "duration $(format_duration ${diff_time})"
+ fi
}
[ "USAGE: die [-d|-t <epoch>] [message] >/dev/stderr
@@ -618,121 +656,68 @@
fi
shift 2
fi >&2
- echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
+ LOG FAILED "${@}"
cleanup
restore
test_duration
exit 1
}
-[ "USAGE: EXPECT_EQ <lval> <rval> [--warning [message]]
-
-Returns true if (regex) lval matches rval" ]
-EXPECT_EQ() {
- local lval="${1}"
- local rval="${2}"
- shift 2
- local error=1
- local prefix="${RED}[ ERROR ]${NORMAL}"
- if [ X"${1}" = X"--warning" ]; then
- prefix="${RED}[ WARNING ]${NORMAL}"
- error=0
- shift 1
- fi
- if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
- if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
-*}" ]; then
- echo "${prefix} expected \"${lval}\""
- echo "${prefix} got \"${rval}\"" |
- sed ": again
- N
- s/\(\n\)\([^ ]\)/\1${INDENT}\2/
- t again"
- if [ -n "${*}" ] ; then
- echo "${prefix} ${*}"
- fi
- else
- echo "${prefix} expected \"${lval}\" got \"${rval}\" ${*}"
- fi >&2
- return ${error}
- fi
- if [ -n "${*}" ] ; then
- prefix="${GREEN}[ INFO ]${NORMAL}"
- if [ X"${lval}" != X"${rval}" ]; then # we were supplied a regex?
- if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
- echo "${prefix} ok \"${lval}\""
- echo " = \"${rval}\"" |
- sed ": again
- N
- s/\(\n\)\([^ ]\)/\1${INDENT}\2/
- t again"
- if [ -n "${*}" ] ; then
- echo "${prefix} ${*}"
- fi
- else
- echo "${prefix} ok \"${lval}\" = \"${rval}\" ${*}"
- fi
- else
- echo "${prefix} ok \"${lval}\" ${*}"
- fi >&2
- fi
- return 0
-}
-
-[ "USAGE: EXPECT_NE <lval> <rval> [--warning [message]]
-
-Returns true if lval matches rval" ]
-EXPECT_NE() {
- local lval="${1}"
- local rval="${2}"
- shift 2
- local error=1
- local prefix="${RED}[ ERROR ]${NORMAL}"
- if [ X"${1}" = X"--warning" ]; then
- prefix="${RED}[ WARNING ]${NORMAL}"
- error=0
- shift 1
- fi
- if [ X"${rval}" = X"${lval}" ]; then
- echo "${prefix} did not expect \"${lval}\" ${*}" >&2
- return ${error}
- fi
- if [ -n "${*}" ] ; then
- echo "${prefix} ok \"${lval}\" not \"${rval}\" ${*}" >&2
- fi
- return 0
-}
-
[ "USAGE: check_eq <lval> <rval> [--warning [message]]
-Exits if (regex) lval mismatches rval" ]
+Exits if (regex) lval mismatches rval.
+
+Returns: true if lval matches rval" ]
check_eq() {
local lval="${1}"
local rval="${2}"
shift 2
+ if [[ "${rval}" =~ ^${lval}$ ]]; then
+ return 0
+ fi
+
+ local error=true
+ local logt=ERROR
if [ X"${1}" = X"--warning" ]; then
- EXPECT_EQ "${lval}" "${rval}" ${*}
- return
+ shift 1
+ error=false
+ logt=WARNING
fi
- if ! EXPECT_EQ "${lval}" "${rval}"; then
- die "${@}"
+ if [ $(( ${#lval} + ${#rval} )) -gt 40 ]; then
+ LOG "${logt}" "expected \"${lval}\"
+${INDENT}got \"${rval}\""
+ else
+ LOG "${logt}" "expected \"${lval}\" got \"${rval}\""
fi
+ ${error} && die "${*}"
+ [ -n "${*}" ] && LOG "${logt}" "${*}"
+ return 1
}
[ "USAGE: check_ne <lval> <rval> [--warning [message]]
-Exits if lval matches rval" ]
+Exits if (regex) lval matches rval.
+
+Returns: true if lval mismatches rval" ]
check_ne() {
local lval="${1}"
local rval="${2}"
shift 2
+ if ! [[ "${rval}" =~ ^${lval}$ ]]; then
+ return 0
+ fi
+
+ local error=true
+ local logt=ERROR
if [ X"${1}" = X"--warning" ]; then
- EXPECT_NE "${lval}" "${rval}" ${*}
- return
+ shift 1
+ error=false
+ logt=WARNING
fi
- if ! EXPECT_NE "${lval}" "${rval}"; then
- die "${@}"
- fi
+ LOG "${logt}" "unexpected \"${rval}\""
+ ${error} && die "${*}"
+ [ -n "${*}" ] && LOG "${logt}" "${*}"
+ return 1
}
[ "USAGE: join_with <delimiter> <strings>
@@ -788,6 +773,41 @@
grep -v "[%] /\(data_mirror\|apex\|bionic\|system\|vendor\)/[^ ][^ ]*$"
}
+[ "USAGE: surgically_wipe_overlayfs
+
+Surgically wipe any mounted overlayfs scratch files.
+
+Returns: true if wiped anything" ]
+surgically_wipe_overlayfs() {
+ local wiped_anything=false
+ for d in ${OVERLAYFS_BACKING}; do
+ if adb_su test -d "/${d}/overlay" </dev/null; then
+ LOG INFO "/${d}/overlay is setup, surgically wiping"
+ adb_su rm -rf "/${d}/overlay" </dev/null
+ wiped_anything=true
+ fi
+ done
+ ${wiped_anything}
+}
+
+[ "USAGE: is_overlayfs_mounted
+
+Returns: true if overlayfs is mounted" ]
+is_overlayfs_mounted() {
+ local df_output=$(adb_su df -k </dev/null)
+ local df_header_line=$(echo "${df_output}" | head -1)
+ local overlay_mounts=$(echo "${df_output}" | tail +2 |
+ skip_unrelated_mounts |
+ awk '$1 == "overlay" || $6 == "/mnt/scratch"')
+ if ! echo "${overlay_mounts}" | grep -q '^overlay '; then
+ return 1
+ fi >/dev/null 2>/dev/null
+ ( echo "${df_header_line}"
+ echo "${overlay_mounts}"
+ ) >&2
+ return 0
+}
+
##
## MAINLINE
##
@@ -874,24 +894,21 @@
NORMAL=""
fi
-# Set an ERR trap handler to report any unhandled error
-trap 'die "line ${LINENO}: unhandled error"' ERR
-
if ${print_time}; then
- echo "${BLUE}[ INFO ]${NORMAL}" start `date` >&2
+ LOG INFO "start $(date)"
fi
inFastboot && die "device in fastboot mode"
inRecovery && die "device in recovery mode"
if ! inAdb; then
- echo "${YELLOW}[ WARNING ]${NORMAL} device not in adb mode" >&2
+ LOG WARNING "device not in adb mode"
adb_wait ${ADB_WAIT}
fi
inAdb || die "specified device not in adb mode"
isDebuggable || die "device not a debug build"
enforcing=true
if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
- echo "${YELLOW}[ WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2
+ LOG WARNING "device does not have sepolicy in enforcing mode"
enforcing=false
fi
@@ -917,16 +934,16 @@
fi
[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] ||
USB_DEVICE=`usb_devnum`
- echo "${BLUE}[ INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} >&2
+ LOG INFO "${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE}"
BUILD_DESCRIPTION=`get_property ro.build.description`
[ -z "${BUILD_DESCRIPTION}" ] ||
- echo "${BLUE}[ INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
+ LOG INFO "${BUILD_DESCRIPTION}"
KERNEL_VERSION="`adb_su cat /proc/version </dev/null 2>/dev/null`"
[ -z "${KERNEL_VERSION}" ] ||
- echo "${BLUE}[ INFO ]${NORMAL} ${KERNEL_VERSION}" >&2
+ LOG INFO "${KERNEL_VERSION}"
ACTIVE_SLOT=`get_active_slot`
[ -z "${ACTIVE_SLOT}" ] ||
- echo "${BLUE}[ INFO ]${NORMAL} active slot is ${ACTIVE_SLOT}" >&2
+ LOG INFO "active slot is ${ACTIVE_SLOT}"
# Acquire list of system partitions
@@ -943,7 +960,7 @@
echo /${i}
done |
tr '\n' ' '`"
-echo "${BLUE}[ INFO ]${NORMAL} System Partitions list: ${PARTITIONS}" >&2
+LOG INFO "System Partitions list: ${PARTITIONS}"
# Report existing partition sizes
adb_sh ls -l /dev/block/by-name/ /dev/block/mapper/ </dev/null 2>/dev/null |
@@ -964,66 +981,65 @@
;;
esac
size=`adb_su cat /sys/block/${device}/size 2>/dev/null </dev/null` &&
- size=`expr ${size} / 2` &&
- echo "${BLUE}[ INFO ]${NORMAL} partition ${name} device ${device} size ${size}K" >&2
+ size=$(( ${size} / 2 )) &&
+ LOG INFO "partition ${name} device ${device} size ${size}K"
done
+overlayfs_supported=true
+can_restore_verity=false
+
+restore() {
+ LOG INFO "restoring device"
+ ${overlayfs_supported} || return 0
+ inFastboot &&
+ fastboot reboot &&
+ adb_wait "${ADB_WAIT}" ||
+ true
+ if ! inAdb; then
+ LOG ERROR "expect adb device"
+ return 1
+ fi
+ adb_root || true
+ local reboot=false
+ if surgically_wipe_overlayfs; then
+ reboot=true
+ fi
+ if ${can_restore_verity}; then
+ if ! adb enable-verity; then
+ LOG ERROR "adb enable-verity"
+ return 1
+ fi
+ LOG INFO "restored verity"
+ reboot=true
+ fi >&2
+ if ${reboot}; then
+ adb_reboot &&
+ adb_wait "${ADB_WAIT}"
+ fi
+}
+
# If reboot too soon after fresh flash, could trip device update failure logic
if ${screen_wait}; then
- echo "${YELLOW}[ WARNING ]${NORMAL} waiting for screen to come up. Consider --no-wait-screen option" >&2
+ LOG WARNING "waiting for screen to come up. Consider --no-wait-screen option"
fi
if ! wait_for_screen && ${screen_wait}; then
screen_wait=false
- echo "${YELLOW}[ WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2
+ LOG WARNING "not healthy, no launcher, skipping wait for screen"
fi
# Can we test remount -R command?
-OVERLAYFS_BACKING="cache mnt/scratch"
-overlayfs_supported=true
-if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
- "2" != "`get_property partition.system.verified`" ]; then
- restore() {
- ${overlayfs_supported} || return 0
- inFastboot &&
- fastboot reboot &&
- adb_wait ${ADB_WAIT} ||
- true
- if inAdb; then
- reboot=false
- for d in ${OVERLAYFS_BACKING}; do
- if adb_test -d /${d}/overlay; then
- adb_su rm -rf /${d}/overlay </dev/null
- reboot=true
- fi
- done
- if ${reboot}; then
- adb_reboot &&
- adb_wait ${ADB_WAIT}
- fi
- fi
- }
-else
- restore() {
- ${overlayfs_supported} || return 0
- inFastboot &&
- fastboot reboot &&
- adb_wait ${ADB_WAIT} ||
- true
- inAdb &&
- adb_root &&
- adb enable-verity >/dev/null 2>/dev/null &&
- adb_reboot &&
- adb_wait ${ADB_WAIT}
- }
+if [ "orange" = "$(get_property ro.boot.verifiedbootstate)" ] &&
+ [ "2" = "$(get_property partition.system.verified)" ]; then
+ can_restore_verity=true
- echo "${GREEN}[ RUN ]${NORMAL} Testing adb shell su root remount -R command" >&2
+ LOG RUN "Testing adb shell su root remount -R command"
avc_check
T=`adb_date`
adb_su remount -R system </dev/null
err=${?}
if [ "${err}" != 0 ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
+ LOG WARNING "adb shell su root remount -R system = ${err}, likely did not reboot!"
T="-t ${T}"
else
# Rebooted, logcat will be meaningless, and last logcat will likely be clear
@@ -1039,10 +1055,10 @@
${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
fi
- echo "${GREEN}[ OK ]${NORMAL} adb shell su root remount -R command" >&2
+ LOG OK "adb shell su root remount -R command"
fi
-echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
+LOG RUN "Testing kernel support for overlayfs"
adb_wait || die "wait for device failed"
adb_root ||
@@ -1050,57 +1066,45 @@
adb_test -d /sys/module/overlay ||
adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
- echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
+ LOG OK "overlay module present" ||
(
- echo "${YELLOW}[ WARNING ]${NORMAL} overlay module not present" >&2 &&
+ LOG WARNING "overlay module not present" &&
false
) ||
overlayfs_supported=false
if ${overlayfs_supported}; then
adb_test -f /sys/module/overlay/parameters/override_creds &&
- echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
+ LOG OK "overlay module supports override_creds" ||
case `adb_sh uname -r </dev/null` in
4.[456789].* | 4.[1-9][0-9]* | [56789].*)
- echo "${YELLOW}[ WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
+ LOG WARNING "overlay module does not support override_creds" &&
overlayfs_supported=false
;;
*)
- echo "${GREEN}[ OK ]${NORMAL} overlay module uses caller's creds" >&2
+ LOG OK "overlay module uses caller's creds"
;;
esac
fi
-echo "${GREEN}[ RUN ]${NORMAL} Checking current overlayfs status" >&2
+LOG RUN "Checking current overlayfs status"
# We can not universally use adb enable-verity to ensure device is
# in a overlayfs disabled state since it can prevent reboot on
# devices that remount the physical content rather than overlayfs.
# So lets do our best to surgically wipe the overlayfs state without
# having to go through enable-verity transition.
-reboot=false
-for d in ${OVERLAYFS_BACKING}; do
- if adb_test -d /${d}/overlay; then
- echo "${YELLOW}[ WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
- adb_sh rm -rf /${d}/overlay </dev/null ||
- die "/${d}/overlay wipe"
- reboot=true
- fi
-done
-if ${reboot}; then
- echo "${YELLOW}[ WARNING ]${NORMAL} rebooting before test" >&2
+if surgically_wipe_overlayfs; then
+ LOG WARNING "rebooting before test"
adb_reboot &&
adb_wait ${ADB_WAIT} ||
die "lost device after reboot after wipe `usb_status`"
adb_root ||
die "lost device after elevation to root after wipe `usb_status`"
fi
-D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` &&
- echo "${H}" &&
- echo "${D}" &&
- echo "${YELLOW}[ WARNING ]${NORMAL} overlays present before setup" >&2 ||
- echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2
+is_overlayfs_mounted &&
+ die "overlay takeover unexpected at this phase"
+LOG OK "no overlay present before setup"
+
overlayfs_needed=true
D=`adb_sh cat /proc/mounts </dev/null |
skip_administrative_mounts data`
@@ -1117,92 +1121,43 @@
done
D=`adb_sh df -k ${D} </dev/null |
sed 's@\([%] /\)\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$@\1@'`
-echo "${D}"
+echo "${D}" >&2
if [ X"${D}" = X"${D##* 100[%] }" ] && ${no_dedupe} ; then
overlayfs_needed=false
# if device does not need overlays, then adb enable-verity will brick device
- restore() {
- ${overlayfs_supported} || return 0
- inFastboot &&
- fastboot reboot &&
- adb_wait ${ADB_WAIT}
- inAdb &&
- adb_wait ${ADB_WAIT}
- }
+ can_restore_verity=false
elif ! ${overlayfs_supported}; then
die "need overlayfs, but do not have it"
fi
-echo "${GREEN}[ RUN ]${NORMAL} disable verity" >&2
+LOG RUN "disable-verity -R"
-T=`adb_date`
-H=`adb disable-verity 2>&1`
-err=${?}
L=
-D="${H%?Now reboot your device for settings to take effect*}"
-if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
- echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
-fi
-if [ ${err} != 0 ]; then
- echo "${H}"
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
- die -t "${T}" "disable-verity"
-fi
-rebooted=false
-if [ X"${D}" != X"${H}" ]; then
- echo "${H}"
- if [ X"${D}" != X"${D##*setup failed}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} overlayfs setup whined" >&2
- fi
- D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
- [ -z "${D}" ] ||
- ( echo "${H}" && echo "${D}" && false ) ||
- die -t ${T} "overlay takeover unexpected at this phase"
- echo "${GREEN}[ INFO ]${NORMAL} rebooting as requested" >&2
- L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
- adb_reboot &&
- adb_wait ${ADB_WAIT} ||
- die "lost device after reboot requested `usb_status`"
- adb_root ||
- die "lost device after elevation to root `usb_status`"
- rebooted=true
- # re-disable verity to see the setup remarks expected
- T=`adb_date`
- H=`adb disable-verity 2>&1`
- err=${?}
- D="${H%?Now reboot your device for settings to take effect*}"
- if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
- echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
- fi
- if [ ${err} != 0 ]; then
- T=
- fi
-fi
-if ${overlayfs_supported} && ${overlayfs_needed} && [ X"${D}" != X"${D##*setup failed}" ]; then
- echo "${D}"
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
- die -t "${T}" "setup for overlay"
-fi
-if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
- echo "${H}"
- D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
- [ -z "${D}" ] ||
- ( echo "${H}" && echo "${D}" && false ) ||
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
- die -t "${T}" "overlay takeover unexpected"
- [ -n "${L}" ] && echo "${L}"
- die -t "${T}" "unexpected report of verity being disabled a second time"
-elif ${rebooted}; then
- echo "${GREEN}[ OK ]${NORMAL} verity already disabled" >&2
-else
- echo "${YELLOW}[ WARNING ]${NORMAL} verity already disabled" >&2
+T=$(adb_date)
+H=$(adb_su disable-verity -R 2>&1)
+err="${?}"
+echo "${H}" >&2
+
+if [ "${err}" != 0 ]; then
+ die -t "${T}" "disable-verity -R"
fi
-echo "${GREEN}[ RUN ]${NORMAL} remount" >&2
+# Fuzzy search for a line that contains "overlay" and "fail". Informational only.
+if echo "${H}" | grep -i "overlay" | grep -iq "fail"; then
+ LOG WARNING "overlayfs setup whined"
+fi
+
+adb_wait "${ADB_WAIT}" &&
+ adb_root ||
+ die "lost device after adb shell su root disable-verity -R $(usb_status)"
+
+if ${overlayfs_needed}; then
+ if ! is_overlayfs_mounted; then
+ die "no overlay being setup after disable-verity -R"
+ fi
+fi
+
+LOG RUN "remount"
# Feed log with selinux denials as baseline before overlays
adb_unroot
@@ -1211,15 +1166,15 @@
D=`adb remount 2>&1`
ret=${?}
-echo "${D}"
+echo "${D}" >&2
[ ${ret} != 0 ] ||
[ X"${D}" = X"${D##*remount failed}" ] ||
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) >&2 ||
die -t "${T}" "adb remount failed"
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | skip_unrelated_mounts | grep "^overlay "` ||
- ( [ -n "${L}" ] && echo "${L}" && false )
+ ( [ -n "${L}" ] && echo "${L}" && false ) >&2
ret=${?}
uses_dynamic_scratch=false
scratch_partition=
@@ -1229,17 +1184,17 @@
die -t ${T} "overlay takeover failed"
fi
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- echo "${YELLOW}[ WARNING ]${NORMAL} overlay takeover not complete" >&2
+ LOG WARNING "overlay takeover not complete"
if [ -z "${virtual_ab}" ]; then
scratch_partition=scratch
fi
if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
- echo "${BLUE}[ INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
+ LOG INFO "using ${scratch_partition} dynamic partition for overrides"
fi
M=`adb_sh cat /proc/mounts </dev/null |
sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
[ -n "${M}" ] &&
- echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}"
+ LOG INFO "scratch filesystem ${M}"
uses_dynamic_scratch=true
if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
uses_dynamic_scratch=false
@@ -1253,15 +1208,16 @@
done` &&
[ -n "${scratch_size}" ] ||
die "scratch size"
- echo "${BLUE}[ INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
+ LOG INFO "scratch size ${scratch_size}KB"
for d in ${OVERLAYFS_BACKING}; do
if adb_test -d /${d}/overlay/system/upper; then
- echo "${BLUE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
+ LOG INFO "/${d}/overlay is setup"
fi
done
- echo "${H}" &&
- echo "${D}" &&
+ ( echo "${H}" &&
+ echo "${D}"
+ ) >&2 &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay takeover after remount"
!(adb_sh grep "^overlay " /proc/mounts </dev/null |
@@ -1296,7 +1252,7 @@
D=`adb_sh df -k ${D} </dev/null |
sed -e 's@\([%] /\)\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$@\1@' \
-e 's/^Filesystem /Filesystem (rw) /'`
- [ -z "${D}" ] || echo "${D}"
+ [ -z "${D}" ] || echo "${D}" >&2
${bad_rw} && die "remount overlayfs missed a spot (rw)"
else
if [ ${ret} = 0 ]; then
@@ -1306,7 +1262,7 @@
# Check something.
-echo "${GREEN}[ RUN ]${NORMAL} push content to ${MOUNTS}" >&2
+LOG RUN "push content to ${MOUNTS}"
A="Hello World! $(date)"
for i in ${MOUNTS}; do
@@ -1319,26 +1275,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.
@@ -1357,11 +1296,11 @@
diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null ||
die "libc.so differ"
-echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
+LOG RUN "reboot to confirm content persistent"
fixup_from_recovery() {
inRecovery || return 1
- echo "${YELLOW}[ ERROR ]${NORMAL} Device in recovery" >&2
+ LOG ERROR "Device in recovery"
adb reboot </dev/null
adb_wait ${ADB_WAIT}
}
@@ -1375,14 +1314,14 @@
D=`adb_su df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` ||
- ( echo "${L}" && false ) ||
+ ( echo "${L}" && false ) >&2 ||
die -d "overlay takeover failed after reboot"
adb_su sed -n '1,/overlay \/system/p' /proc/mounts </dev/null |
skip_administrative_mounts |
grep -v ' \(erofs\|squashfs\|ext4\|f2fs\|vfat\) ' &&
- echo "${YELLOW}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
- echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+ LOG WARNING "overlay takeover after first stage init" ||
+ LOG OK "overlay takeover in first stage init"
fi
if ${enforcing}; then
@@ -1390,7 +1329,7 @@
die "device not in unroot'd state"
B="`adb_cat /vendor/hello 2>&1`"
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
- echo "${GREEN}[ OK ]${NORMAL} /vendor content correct MAC after reboot" >&2
+ LOG OK "/vendor content correct MAC after reboot"
# Feed unprivileged log with selinux denials as a result of overlays
wait_for_screen
adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null || true
@@ -1408,16 +1347,11 @@
for i in ${MOUNTS}; do
B="`adb_cat ${i}/hello`"
check_eq "${A}" "${B}" ${i#/} after reboot
- echo "${GREEN}[ OK ]${NORMAL} ${i} content remains after reboot" >&2
+ LOG OK "${i} content remains after reboot"
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
@@ -1431,9 +1365,9 @@
cleanup() {
true
}
-echo "${GREEN}[ OK ]${NORMAL} /system/lib/bootstrap/libc.so content remains after reboot" >&2
+LOG OK "/system/lib/bootstrap/libc.so content remains after reboot"
-echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
+LOG RUN "flash vendor, confirm its content disappears"
H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
is_bootloader_fastboot=false
@@ -1442,20 +1376,20 @@
is_userspace_fastboot=false
if ! ${is_bootloader_fastboot}; then
- echo "${YELLOW}[ WARNING ]${NORMAL} does not support fastboot, skipping"
+ LOG WARNING "does not support fastboot, skipping"
elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} build tree not setup, skipping"
+ LOG WARNING "build tree not setup, skipping"
elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} vendor image missing, skipping"
+ LOG WARNING "vendor image missing, skipping"
elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} wrong vendor image, skipping"
+ LOG WARNING "wrong vendor image, skipping"
elif [ -z "${ANDROID_HOST_OUT}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} please run lunch, skipping"
+ LOG WARNING "please run lunch, skipping"
elif ! (
adb_cat /vendor/build.prop |
cmp -s ${ANDROID_PRODUCT_OUT}/vendor/build.prop
) >/dev/null 2>/dev/null; then
- echo "${YELLOW}[ WARNING ]${NORMAL} vendor image signature mismatch, skipping"
+ LOG WARNING "vendor image signature mismatch, skipping"
else
wait_for_screen
avc_check
@@ -1469,7 +1403,7 @@
die "fastboot flash vendor"
fastboot_getvar is-userspace yes &&
is_userspace_fastboot=true
- if [ -n "${scratch_paritition}" ]; then
+ if [ -n "${scratch_partition}" ]; then
fastboot_getvar partition-type:${scratch_partition} raw ||
( fastboot reboot && false) ||
die "fastboot can not see ${scratch_partition} parameters"
@@ -1489,19 +1423,19 @@
die "Reboot into fastboot"
fi
if ${uses_dynamic_scratch}; then
- echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
+ LOG INFO "expect fastboot erase ${scratch_partition} to fail"
fastboot erase ${scratch_partition} &&
( fastboot reboot || true) &&
die "fastboot can erase ${scratch_partition}"
fi
- echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
+ LOG INFO "expect fastboot format ${scratch_partition} to fail"
fastboot format ${scratch_partition} &&
( fastboot reboot || true) &&
die "fastboot can format ${scratch_partition}"
fi
fastboot reboot ||
die "can not reboot out of fastboot"
- echo "${YELLOW}[ WARNING ]${NORMAL} adb after fastboot"
+ LOG WARNING "adb after fastboot"
adb_wait ${ADB_WAIT} ||
fixup_from_recovery ||
die "did not reboot after formatting ${scratch_partition} `usb_status`"
@@ -1510,16 +1444,17 @@
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | skip_unrelated_mounts | grep "^overlay "` &&
- echo "${H}" &&
- echo "${D}" &&
+ ( echo "${H}" &&
+ echo "${D}"
+ ) >&2 &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay /system takeover after flash vendor"
echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
if ${is_userspace_fastboot}; then
die "overlay supposed to be minus /vendor takeover after flash vendor"
else
- echo "${YELLOW}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
- echo "${YELLOW}[ WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2
+ LOG WARNING "user fastboot missing required to invalidate, ignoring a failure"
+ LOG WARNING "overlay supposed to be minus /vendor takeover after flash vendor"
fi
fi
B="`adb_cat /system/hello`"
@@ -1537,20 +1472,17 @@
check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
vendor content after flash vendor
else
- echo "${YELLOW}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+ LOG WARNING "user fastboot missing required to invalidate, ignoring a failure"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
--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
wait_for_screen
-echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
+LOG RUN "remove test content (cleanup)"
T=`adb_date`
H=`adb remount 2>&1`
@@ -1558,7 +1490,7 @@
L=
D="${H%?Now reboot your device for settings to take effect*}"
if [ X"${H}" != X"${D}" ]; then
- echo "${YELLOW}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
+ LOG WARNING "adb remount requires a reboot after partial flash (legacy avb)"
L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
adb_reboot &&
adb_wait ${ADB_WAIT} &&
@@ -1568,11 +1500,11 @@
H=`adb remount 2>&1`
err=${?}
fi
-echo "${H}"
+echo "${H}" >&2
[ ${err} = 0 ] &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
adb_sh rm /system/hello /system/priv-app/hello </dev/null ||
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) >&2 ||
die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`"
check_eq "cat: /system/hello: No such file or directory" "${B}" after rm
@@ -1586,7 +1518,7 @@
if ${is_bootloader_fastboot} && [ -n "${scratch_partition}" ]; then
- echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition} recovery" >&2
+ LOG RUN "test fastboot flash to ${scratch_partition} recovery"
avc_check
adb reboot fastboot </dev/null ||
@@ -1616,7 +1548,7 @@
err=${?}
if [ X"${D}" != "${D%?Now reboot your device for settings to take effect*}" ]
then
- echo "${YELLOW}[ WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash"
+ LOG WARNING "adb disable-verity requires a reboot after partial flash"
adb_reboot &&
adb_wait ${ADB_WAIT} &&
adb_root ||
@@ -1627,32 +1559,32 @@
err=${?}
fi
- echo "${D}"
+ echo "${D}" >&2
[ ${err} = 0 ] &&
[ X"${D}" = X"${D##*setup failed}" ] &&
[ X"${D}" != X"${D##*[Uu]sing overlayfs}" ] &&
- echo "${GREEN}[ OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
+ LOG OK "${scratch_partition} recreated" ||
die -t ${T} "setup for overlayfs"
D=`adb remount 2>&1`
err=${?}
- echo "${D}"
+ echo "${D}" >&2
[ ${err} != 0 ] ||
[ X"${D}" = X"${D##*remount failed}" ] ||
- ( echo "${D}" && false ) ||
+ ( echo "${D}" && false ) >&2 ||
die -t ${T} "remount failed"
fi
-echo "${GREEN}[ RUN ]${NORMAL} test raw remount commands" >&2
+LOG RUN "test raw remount commands"
fixup_from_fastboot() {
inFastboot || return 1
if [ -n "${ACTIVE_SLOT}" ]; then
local active_slot=`get_active_slot`
if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
- echo "${YELLOW}[ ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+ LOG WARNING "Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
else
- echo "${YELLOW}[ ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}"
- fi >&2
+ LOG WARNING "Active slot to be set to ${ACTIVE_SLOT}"
+ fi
fastboot --set-active=${ACTIVE_SLOT}
fi
fastboot reboot
@@ -1670,7 +1602,7 @@
die "remount command"
adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
die "/vendor is not read-write"
-echo "${GREEN}[ OK ]${NORMAL} mount -o rw,remount command works" >&2
+LOG OK "mount -o rw,remount command works"
# Prerequisite is a prepped device from above.
adb_reboot &&
@@ -1685,17 +1617,12 @@
die "/vendor is not read-write"
adb_sh grep " /system .* rw," /proc/mounts >/dev/null </dev/null &&
die "/vendor is not read-only"
-echo "${GREEN}[ OK ]${NORMAL} remount command works from setup" >&2
+LOG OK "remount command works from setup"
# Prerequisite is an overlayfs deconstructed device but with verity disabled.
# This also saves a lot of 'noise' from the command doing a mkfs on backing
# storage and all the related tuning and adjustment.
-for d in ${OVERLAYFS_BACKING}; do
- if adb_test -d /${d}/overlay; then
- adb_su rm -rf /${d}/overlay </dev/null ||
- die "/${d}/overlay wipe"
- fi
-done
+surgically_wipe_overlayfs || true
adb_reboot &&
adb_wait ${ADB_WAIT} ||
fixup_from_fastboot ||
@@ -1704,12 +1631,12 @@
die "/vendor is not read-only"
adb_su remount vendor </dev/null ||
die "remount command"
-adb_su df -k </dev/null | skip_unrelated_mounts
+adb_su df -k </dev/null | skip_unrelated_mounts >&2
adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
die "/vendor is not read-write"
adb_sh grep " \(/system\|/\) .* rw," /proc/mounts >/dev/null </dev/null &&
die "/system is not read-only"
-echo "${GREEN}[ OK ]${NORMAL} remount command works from scratch" >&2
+LOG OK "remount command works from scratch"
if ! restore; then
restore() {
@@ -1721,7 +1648,7 @@
err=0
if ${overlayfs_supported}; then
- echo "${GREEN}[ RUN ]${NORMAL} test 'adb remount -R'" >&2
+ LOG RUN "test 'adb remount -R'"
avc_check
adb_root ||
die "adb root in preparation for adb remount -R"
@@ -1743,7 +1670,7 @@
${INDENT}partition.system.verified=\"`get_property partition.system.verified`\""
fi
- echo "${GREEN}[ OK ]${NORMAL} 'adb remount -R' command" >&2
+ LOG OK "'adb remount -R' command"
restore
err=${?}
@@ -1756,6 +1683,6 @@
[ ${err} = 0 ] ||
die "failed to restore verity"
-echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
+LOG PASSED "adb remount test"
test_duration
diff --git a/healthd/Android.bp b/healthd/Android.bp
index f180006..a090b74 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -342,20 +342,20 @@
],
}
-// /vendor/etc/res/images/charger/battery_fail.png
+// /vendor/etc/res/images/default/charger/battery_fail.png
prebuilt_etc {
name: "system_core_charger_res_images_battery_fail.png_default_vendor",
src: "images/battery_fail.png",
- relative_install_path: "res/images/charger/default",
+ relative_install_path: "res/images/default/charger",
vendor: true,
filename: "battery_fail.png",
}
-// /vendor/etc/res/images/charger/battery_scale.png
+// /vendor/etc/res/images/default/charger/battery_scale.png
prebuilt_etc {
name: "system_core_charger_res_images_battery_scale.png_default_vendor",
src: "images/battery_scale.png",
- relative_install_path: "res/images/charger/default",
+ relative_install_path: "res/images/default/charger",
vendor: true,
filename: "battery_scale.png",
}
diff --git a/init/Android.bp b/init/Android.bp
index 6d36945..dfc90da 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -224,8 +224,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/TEST_MAPPING b/init/TEST_MAPPING
index 36ca379..402b501 100644
--- a/init/TEST_MAPPING
+++ b/init/TEST_MAPPING
@@ -8,6 +8,14 @@
},
{
"name": "MicrodroidHostTestCases"
+ },
+ {
+ "name": "CtsSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.security.cts.SeamendcHostTest"
+ }
+ ]
}
],
"hwasan-presubmit": [
@@ -19,6 +27,14 @@
},
{
"name": "MicrodroidHostTestCases"
+ },
+ {
+ "name": "CtsSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.security.cts.SeamendcHostTest"
+ }
+ ]
}
]
}
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 129cf48..9411b47 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>
@@ -736,10 +739,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();
@@ -757,7 +760,7 @@
return;
}
break;
- }
+ } while (!one_off);
switch (siginfo.ssi_signo) {
case SIGCHLD:
@@ -817,7 +820,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();
}
}
@@ -946,6 +951,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();
@@ -1155,11 +1186,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/persistent_properties.cpp b/init/persistent_properties.cpp
index 716f62e..d33a6b8 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -155,19 +155,33 @@
return *file_contents;
}
+Result<PersistentProperties> ParsePersistentPropertyFile(const std::string& file_contents) {
+ PersistentProperties persistent_properties;
+ if (!persistent_properties.ParseFromString(file_contents)) {
+ return Error() << "Unable to parse persistent property file: Could not parse protobuf";
+ }
+ for (auto& prop : persistent_properties.properties()) {
+ if (!StartsWith(prop.name(), "persist.")) {
+ return Error() << "Unable to load persistent property file: property '" << prop.name()
+ << "' doesn't start with 'persist.'";
+ }
+ }
+ return persistent_properties;
+}
+
} // namespace
Result<PersistentProperties> LoadPersistentPropertyFile() {
auto file_contents = ReadPersistentPropertyFile();
if (!file_contents.ok()) return file_contents.error();
- PersistentProperties persistent_properties;
- if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties;
-
- // If the file cannot be parsed in either format, then we don't have any recovery
- // mechanisms, so we delete it to allow for future writes to take place successfully.
- unlink(persistent_property_filename.c_str());
- return Error() << "Unable to parse persistent property file: Could not parse protobuf";
+ auto persistent_properties = ParsePersistentPropertyFile(*file_contents);
+ if (!persistent_properties.ok()) {
+ // If the file cannot be parsed in either format, then we don't have any recovery
+ // mechanisms, so we delete it to allow for future writes to take place successfully.
+ unlink(persistent_property_filename.c_str());
+ }
+ return persistent_properties;
}
Result<void> WritePersistentPropertyFile(const PersistentProperties& persistent_properties) {
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 60cecde..e5d26db 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -155,5 +155,28 @@
EXPECT_FALSE(it == read_back_properties.properties().end());
}
+TEST(persistent_properties, RejectNonPersistProperty) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ persistent_property_filename = tf.path;
+
+ WritePersistentProperty("notpersist.sys.locale", "pt-BR");
+
+ auto read_back_properties = LoadPersistentProperties();
+ EXPECT_EQ(read_back_properties.properties().size(), 0);
+
+ WritePersistentProperty("persist.sys.locale", "pt-BR");
+
+ read_back_properties = LoadPersistentProperties();
+ EXPECT_GT(read_back_properties.properties().size(), 0);
+
+ auto it = std::find_if(read_back_properties.properties().begin(),
+ read_back_properties.properties().end(), [](const auto& entry) {
+ return entry.name() == "persist.sys.locale" &&
+ entry.value() == "pt-BR";
+ });
+ EXPECT_FALSE(it == read_back_properties.properties().end());
+}
+
} // namespace init
} // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index 730b6b6..99a0367 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
@@ -651,6 +653,11 @@
<< ") failed for service '" << name_ << "'";
}
+ // When the blkio controller is mounted in the v1 hierarchy, NormalIoPriority is
+ // the default (/dev/blkio). When the blkio controller is mounted in the v2 hierarchy, the
+ // NormalIoPriority profile has to be applied explicitly.
+ SetProcessProfiles(proc_attr_.uid, pid_, {"NormalIoPriority"});
+
if (use_memcg) {
ConfigureMemcg();
}
diff --git a/init/service.h b/init/service.h
index 7af3615..6d9a0ca 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/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 3054d2b..e071c96 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -440,12 +440,12 @@
}
// Another option to load kernel modules. load in independent modules in parallel
-// and then load modules which only have soft dependency, third update dependency list of other
-// remaining modules, repeat these steps until all modules are loaded.
+// and then update dependency list of other remaining modules, repeat these steps
+// until all modules are loaded.
bool Modprobe::LoadModulesParallel(int num_threads) {
bool ret = true;
+ int count = -1;
std::map<std::string, std::set<std::string>> mod_with_deps;
- std::map<std::string, std::set<std::string>> mod_with_softdeps;
// Get dependencies
for (const auto& module : module_load_) {
@@ -458,26 +458,36 @@
// Get soft dependencies
for (const auto& [it_mod, it_softdep] : module_pre_softdep_) {
- mod_with_softdeps[MakeCanonical(it_mod)].emplace(it_softdep);
+ if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) {
+ mod_with_deps[MakeCanonical(it_mod)].emplace(
+ GetDependencies(MakeCanonical(it_softdep))[0]);
+ }
}
// Get soft post dependencies
for (const auto& [it_mod, it_softdep] : module_post_softdep_) {
- mod_with_softdeps[MakeCanonical(it_mod)].emplace(it_softdep);
+ if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) {
+ mod_with_deps[MakeCanonical(it_softdep)].emplace(
+ GetDependencies(MakeCanonical(it_mod))[0]);
+ }
}
- while (!mod_with_deps.empty()) {
+ while (!mod_with_deps.empty() && count != module_loaded_.size()) {
std::vector<std::thread> threads;
std::vector<std::string> mods_path_to_load;
- std::vector<std::string> mods_with_softdep_to_load;
std::mutex vector_lock;
+ count = module_loaded_.size();
- // Find independent modules and modules only having soft dependencies
+ // Find independent modules
for (const auto& [it_mod, it_dep] : mod_with_deps) {
- if (it_dep.size() == 1 && mod_with_softdeps[it_mod].empty()) {
- mods_path_to_load.emplace_back(*(it_dep.begin()));
- } else if (it_dep.size() == 1) {
- mods_with_softdep_to_load.emplace_back(it_mod);
+ if (it_dep.size() == 1) {
+ if (module_options_[it_mod].find("load_sequential=1") != std::string::npos) {
+ if (!LoadWithAliases(it_mod, true) && !IsBlocklisted(it_mod)) {
+ return false;
+ }
+ } else {
+ mods_path_to_load.emplace_back(it_mod);
+ }
}
}
@@ -485,12 +495,16 @@
auto thread_function = [&] {
std::unique_lock lk(vector_lock);
while (!mods_path_to_load.empty()) {
- auto mod_path_to_load = std::move(mods_path_to_load.back());
+ auto ret_load = true;
+ auto mod_to_load = std::move(mods_path_to_load.back());
mods_path_to_load.pop_back();
lk.unlock();
- ret &= Insmod(mod_path_to_load, "");
+ ret_load &= LoadWithAliases(mod_to_load, true);
lk.lock();
+ if (!ret_load && !IsBlocklisted(mod_to_load)) {
+ ret &= ret_load;
+ }
}
};
@@ -502,21 +516,12 @@
thread.join();
}
- // Since we cannot assure if these soft dependencies tree are overlap,
- // we loaded these modules one by one.
- for (auto dep = mods_with_softdep_to_load.rbegin(); dep != mods_with_softdep_to_load.rend();
- dep++) {
- ret &= LoadWithAliases(*dep, true);
- }
+ if (!ret) return ret;
std::lock_guard guard(module_loaded_lock_);
// Remove loaded module form mod_with_deps and soft dependencies of other modules
for (const auto& module_loaded : module_loaded_) {
mod_with_deps.erase(module_loaded);
-
- for (auto& [mod, softdeps] : mod_with_softdeps) {
- softdeps.erase(module_loaded);
- }
}
// Remove loaded module form dependencies of other modules which are not loaded yet
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 7b0e0d3..c6a0737 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,6 +2,17 @@
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",
+ ],
+}
+
cc_library_headers {
name: "libprocessgroup_headers",
vendor_available: true,
@@ -62,11 +73,7 @@
export_header_lib_headers: [
"libprocessgroup_headers",
],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wexit-time-destructors",
- ],
+ defaults: ["libprocessgroup_defaults"],
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -77,12 +84,7 @@
cc_test {
name: "task_profiles_test",
host_supported: true,
- cflags: [
- "-Wall",
- "-Werror",
- "-Wexit-time-destructors",
- "-Wno-unused-parameter",
- ],
+ defaults: ["libprocessgroup_defaults"],
srcs: [
"task_profiles_test.cpp",
],
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 39b9f3f..45a723f 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -18,7 +18,10 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <initializer_list>
+#include <span>
#include <string>
+#include <string_view>
#include <vector>
__BEGIN_DECLS
@@ -33,6 +36,19 @@
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+__END_DECLS
+
+bool SetTaskProfiles(int tid, std::initializer_list<std::string_view> profiles,
+ bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list<std::string_view> profiles);
+#if _LIBCPP_STD_VER > 17
+bool SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
+ bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const std::string_view> profiles);
+#endif
+
+__BEGIN_DECLS
+
#ifndef __ANDROID_VNDK__
bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 51c810e..bdda102 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -148,14 +148,35 @@
}
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+ return TaskProfiles::GetInstance().SetProcessProfiles(
+ uid, pid, std::span<const std::string>(profiles), false);
+}
+
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list<std::string_view> profiles) {
+ return TaskProfiles::GetInstance().SetProcessProfiles(
+ uid, pid, std::span<const std::string_view>(profiles), false);
+}
+
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const std::string_view> profiles) {
return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, false);
}
bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, true);
+ return TaskProfiles::GetInstance().SetProcessProfiles(
+ uid, pid, std::span<const std::string>(profiles), true);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
+ return TaskProfiles::GetInstance().SetTaskProfiles(tid, std::span<const std::string>(profiles),
+ use_fd_cache);
+}
+
+bool SetTaskProfiles(int tid, std::initializer_list<std::string_view> profiles, bool use_fd_cache) {
+ return TaskProfiles::GetInstance().SetTaskProfiles(
+ tid, std::span<const std::string_view>(profiles), use_fd_cache);
+}
+
+bool SetTaskProfiles(int tid, std::span<const std::string_view> profiles, bool use_fd_cache) {
return TaskProfiles::GetInstance().SetTaskProfiles(tid, profiles, use_fd_cache);
}
@@ -166,12 +187,12 @@
// https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3574427/5/src/linux/android.rs#12
extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_profiles,
const char* profiles[]) {
- std::vector<std::string> profiles_;
+ std::vector<std::string_view> profiles_;
profiles_.reserve(num_profiles);
for (size_t i = 0; i < num_profiles; i++) {
profiles_.emplace_back(profiles[i]);
}
- return SetProcessProfiles(uid, pid, profiles_);
+ return SetProcessProfiles(uid, pid, std::span<const std::string_view>(profiles_));
}
static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 8589a8d..15f95fc 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -76,6 +76,21 @@
"Name": "FreezerState",
"Controller": "freezer",
"File": "cgroup.freeze"
+ },
+ {
+ "Name": "BfqWeight",
+ "Controller": "io",
+ "File": "io.bfq.weight"
+ },
+ {
+ "Name": "CfqGroupIdle",
+ "Controller": "io",
+ "File": "io.group_idle"
+ },
+ {
+ "Name": "CfqWeight",
+ "Controller": "io",
+ "File": "io.weight"
}
],
@@ -444,6 +459,33 @@
{
"Controller": "blkio",
"Path": "background"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "10",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "200",
+ "Optional": "true"
}
}
]
@@ -457,6 +499,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
@@ -470,6 +539,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
@@ -483,6 +579,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 3831ef2..304248a 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -410,7 +410,7 @@
// Make sure we do this only one time. No need for std::call_once because
// init is a single-threaded process
if (access(CGROUPS_RC_PATH, F_OK) == 0) {
- LOG(WARNING) << "Attempt to call SetupCgroups more than once";
+ LOG(WARNING) << "Attempt to call CgroupSetup() more than once";
return true;
}
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index e1c5934..744710f 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -786,7 +786,7 @@
return true;
}
-TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
+TaskProfile* TaskProfiles::GetProfile(std::string_view name) const {
auto iter = profiles_.find(name);
if (iter != profiles_.end()) {
@@ -795,7 +795,7 @@
return nullptr;
}
-const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
+const IProfileAttribute* TaskProfiles::GetAttribute(std::string_view name) const {
auto iter = attributes_.find(name);
if (iter != attributes_.end()) {
@@ -804,8 +804,9 @@
return nullptr;
}
-bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
- const std::vector<std::string>& profiles, bool use_fd_cache) {
+template <typename T>
+bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles,
+ bool use_fd_cache) {
bool success = true;
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
@@ -825,8 +826,8 @@
return success;
}
-bool TaskProfiles::SetTaskProfiles(int tid, const std::vector<std::string>& profiles,
- bool use_fd_cache) {
+template <typename T>
+bool TaskProfiles::SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache) {
bool success = true;
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
@@ -845,3 +846,14 @@
}
return success;
}
+
+template bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
+ std::span<const std::string> profiles,
+ bool use_fd_cache);
+template bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
+ std::span<const std::string_view> profiles,
+ bool use_fd_cache);
+template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string> profiles,
+ bool use_fd_cache);
+template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
+ bool use_fd_cache);
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index df08f65..85b3f91 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -18,9 +18,12 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <functional>
#include <map>
#include <mutex>
+#include <span>
#include <string>
+#include <string_view>
#include <vector>
#include <android-base/unique_fd.h>
@@ -206,18 +209,19 @@
// Should be used by all users
static TaskProfiles& GetInstance();
- TaskProfile* GetProfile(const std::string& name) const;
- const IProfileAttribute* GetAttribute(const std::string& name) const;
+ TaskProfile* GetProfile(std::string_view name) const;
+ const IProfileAttribute* GetAttribute(std::string_view name) const;
void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
- bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
- bool use_fd_cache);
- bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
+ template <typename T>
+ bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles, bool use_fd_cache);
+ template <typename T>
+ bool SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache);
private:
- std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
- std::map<std::string, std::unique_ptr<IProfileAttribute>> attributes_;
-
TaskProfiles();
bool Load(const CgroupMap& cg_map, const std::string& file_name);
+
+ std::map<std::string, std::shared_ptr<TaskProfile>, std::less<>> profiles_;
+ std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
};
diff --git a/libstats/pull_lazy/TEST_MAPPING b/libstats/pull_lazy/TEST_MAPPING
index 92f1e6a..0282a03 100644
--- a/libstats/pull_lazy/TEST_MAPPING
+++ b/libstats/pull_lazy/TEST_MAPPING
@@ -4,7 +4,7 @@
"name" : "libstatspull_lazy_test"
}
],
- "hwasan-postsubmit" : [
+ "hwasan-presubmit" : [
{
"name" : "libstatspull_lazy_test"
}
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
index 4ffa98d..a3ef131 100644
--- a/libstats/pull_rust/Android.bp
+++ b/libstats/pull_rust/Android.bp
@@ -22,6 +22,10 @@
name: "libstatspull_bindgen",
wrapper_src: "statslog.h",
crate_name: "statspull_bindgen",
+ visibility: [
+ "//frameworks/proto_logging/stats/stats_log_api_gen",
+ "//packages/modules/Virtualization/libs/statslog_virtualization",
+ ],
source_stem: "bindings",
bindgen_flags: [
"--size_t-is-usize",
@@ -48,7 +52,7 @@
apex_available: [
"//apex_available:platform",
"com.android.virt",
- ]
+ ],
}
rust_library {
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/RefBase.cpp b/libutils/RefBase.cpp
index 4ddac3d..ed5b2a9 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -149,6 +149,29 @@
// Same for weak counts.
#define BAD_WEAK(c) ((c) == 0 || ((c) & (~MAX_COUNT)) != 0)
+// name kept because prebuilts used to use it from inlining sp<> code
+void sp_report_stack_pointer() { LOG_ALWAYS_FATAL("RefBase used with stack pointer argument"); }
+
+// Check whether address is definitely on the calling stack. We actually check whether it is on
+// the same 4K page as the frame pointer.
+//
+// Assumptions:
+// - Pages are never smaller than 4K (MIN_PAGE_SIZE)
+// - Malloced memory never shares a page with a stack.
+//
+// It does not appear safe to broaden this check to include adjacent pages; apparently this code
+// is used in environments where there may not be a guard page below (at higher addresses than)
+// the bottom of the stack.
+static void check_not_on_stack(const void* ptr) {
+ static constexpr int MIN_PAGE_SIZE = 0x1000; // 4K. Safer than including sys/user.h.
+ static constexpr uintptr_t MIN_PAGE_MASK = ~static_cast<uintptr_t>(MIN_PAGE_SIZE - 1);
+ uintptr_t my_frame_address =
+ reinterpret_cast<uintptr_t>(__builtin_frame_address(0 /* this frame */));
+ if (((reinterpret_cast<uintptr_t>(ptr) ^ my_frame_address) & MIN_PAGE_MASK) == 0) {
+ sp_report_stack_pointer();
+ }
+}
+
// ---------------------------------------------------------------------------
class RefBase::weakref_impl : public RefBase::weakref_type
@@ -432,6 +455,8 @@
return;
}
+ check_not_on_stack(this);
+
int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
// A decStrong() must still happen after us.
ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
@@ -744,21 +769,27 @@
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
- } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
- // We never acquired a strong reference on this object.
+ } else {
+ int32_t strongs = mRefs->mStrong.load(std::memory_order_relaxed);
- // TODO: make this fatal, but too much code in Android manages RefBase with
- // new/delete manually (or using other mechanisms such as std::make_unique).
- // However, this is dangerous because it's also common for code to use the
- // sp<T>(T*) constructor, assuming that if the object is around, it is already
- // owned by an sp<>.
- ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
- "object.",
- mRefs->mWeak.load(), this);
+ if (strongs == INITIAL_STRONG_VALUE) {
+ // We never acquired a strong reference on this object.
+
+ // It would be nice to make this fatal, but many places use RefBase on the stack.
+ // However, this is dangerous because it's also common for code to use the
+ // sp<T>(T*) constructor, assuming that if the object is around, it is already
+ // owned by an sp<>.
+ ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
+ "object.",
+ mRefs->mWeak.load(), this);
#if CALLSTACK_ENABLED
- CallStack::logStack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
#endif
+ } else if (strongs != 0) {
+ LOG_ALWAYS_FATAL("RefBase: object %p with strong count %d deleted. Double owned?", this,
+ strongs);
+ }
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
@@ -766,6 +797,8 @@
void RefBase::extendObjectLifetime(int32_t mode)
{
+ check_not_on_stack(this);
+
// Must be happens-before ordered with respect to construction or any
// operation that could destroy the object.
mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index 93f9654..aed3b9b 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -265,6 +265,21 @@
delete foo;
}
+TEST(RefBase, DoubleOwnershipDeath) {
+ bool isDeleted;
+ auto foo = sp<Foo>::make(&isDeleted);
+
+ // if something else thinks it owns foo, should die
+ EXPECT_DEATH(delete foo.get(), "");
+
+ EXPECT_FALSE(isDeleted);
+}
+
+TEST(RefBase, StackOwnershipDeath) {
+ bool isDeleted;
+ EXPECT_DEATH({ Foo foo(&isDeleted); foo.incStrong(nullptr); }, "");
+}
+
// Set up a situation in which we race with visit2AndRremove() to delete
// 2 strong references. Bar destructor checks that there are no early
// deletions and prior updates are visible to destructor.
diff --git a/libutils/StrongPointer.cpp b/libutils/StrongPointer.cpp
index ef46723..ba52502 100644
--- a/libutils/StrongPointer.cpp
+++ b/libutils/StrongPointer.cpp
@@ -21,7 +21,4 @@
namespace android {
void sp_report_race() { LOG_ALWAYS_FATAL("sp<> assignment detected data race"); }
-
-void sp_report_stack_pointer() { LOG_ALWAYS_FATAL("sp<> constructed with stack pointer argument"); }
-
}
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/LruCache.h b/libutils/include/utils/LruCache.h
index 36775d0..b4243a3 100644
--- a/libutils/include/utils/LruCache.h
+++ b/libutils/include/utils/LruCache.h
@@ -84,13 +84,13 @@
const TKey& getKey() const final { return key; }
};
- struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
+ struct HashForEntry {
size_t operator() (const KeyedEntry* entry) const {
return hash_type(entry->getKey());
};
};
- struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
+ struct EqualityForHashedEntries {
bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
return lhs->getKey() == rhs->getKey();
};
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/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index bb1941b..54aa691 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -120,7 +120,6 @@
template<typename Y> friend class sp;
template<typename Y> friend class wp;
void set_pointer(T* ptr);
- static inline void check_not_on_stack(const void* ptr);
T* m_ptr;
};
@@ -185,32 +184,10 @@
// For code size reasons, we do not want these inlined or templated.
void sp_report_race();
-void sp_report_stack_pointer();
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
-// Check whether address is definitely on the calling stack. We actually check whether it is on
-// the same 4K page as the frame pointer.
-//
-// Assumptions:
-// - Pages are never smaller than 4K (MIN_PAGE_SIZE)
-// - Malloced memory never shares a page with a stack.
-//
-// It does not appear safe to broaden this check to include adjacent pages; apparently this code
-// is used in environments where there may not be a guard page below (at higher addresses than)
-// the bottom of the stack.
-template <typename T>
-void sp<T>::check_not_on_stack(const void* ptr) {
- static constexpr int MIN_PAGE_SIZE = 0x1000; // 4K. Safer than including sys/user.h.
- static constexpr uintptr_t MIN_PAGE_MASK = ~static_cast<uintptr_t>(MIN_PAGE_SIZE - 1);
- uintptr_t my_frame_address =
- reinterpret_cast<uintptr_t>(__builtin_frame_address(0 /* this frame */));
- if (((reinterpret_cast<uintptr_t>(ptr) ^ my_frame_address) & MIN_PAGE_MASK) == 0) {
- sp_report_stack_pointer();
- }
-}
-
// TODO: Ideally we should find a way to increment the reference count before running the
// constructor, so that generating an sp<> to this in the constructor is no longer dangerous.
template <typename T>
@@ -219,14 +196,13 @@
T* t = new T(std::forward<Args>(args)...);
sp<T> result;
result.m_ptr = t;
- t->incStrong(t); // bypass check_not_on_stack for heap allocation
+ t->incStrong(t);
return result;
}
template <typename T>
sp<T> sp<T>::fromExisting(T* other) {
if (other) {
- check_not_on_stack(other);
other->incStrongRequireStrong(other);
sp<T> result;
result.m_ptr = other;
@@ -240,7 +216,6 @@
sp<T>::sp(T* other)
: m_ptr(other) {
if (other) {
- check_not_on_stack(other);
other->incStrong(this);
}
}
@@ -249,7 +224,6 @@
template <typename U>
sp<T>::sp(U* other) : m_ptr(other) {
if (other) {
- check_not_on_stack(other);
(static_cast<T*>(other))->incStrong(this);
}
}
@@ -258,7 +232,6 @@
sp<T>& sp<T>::operator=(T* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
if (other) {
- check_not_on_stack(other);
other->incStrong(this);
}
if (oldPtr) oldPtr->decStrong(this);
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"
]
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 660f18c..60bf57b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -723,9 +723,13 @@
# Multi-installed APEXes are selected using persist props.
# Load persist properties and override properties (if enabled) from /data,
# before starting apexd.
+ # /data/property should be created before `load_persist_props`
+ mkdir /data/property 0700 root root encryption=Require
load_persist_props
+
start logd
start logd-reinit
+
# Some existing vendor rc files use 'on load_persist_props_action' to know
# when persist props are ready. These are difficult to change due to GRF,
# so continue triggering this action here even though props are already loaded
@@ -852,7 +856,6 @@
mkdir /data/app-asec 0700 root root encryption=Require
mkdir /data/app-lib 0771 system system encryption=Require
mkdir /data/app 0771 system system encryption=Require
- mkdir /data/property 0700 root root encryption=Require
# create directory for updated font files.
mkdir /data/fonts/ 0771 root root encryption=Require
diff --git a/set-verity-state/Android.bp b/set-verity-state/Android.bp
index f0df350..f40118b 100644
--- a/set-verity-state/Android.bp
+++ b/set-verity-state/Android.bp
@@ -9,17 +9,18 @@
srcs: ["set-verity-state.cpp"],
shared_libs: [
"libbase",
+ "libbinder",
"libcrypto",
"libcrypto_utils",
- "libcutils",
- "libfec",
"libfs_mgr_binder",
- "liblog",
"libutils",
],
static_libs: [
"libavb_user",
],
+ header_libs: [
+ "libcutils_headers",
+ ],
cflags: ["-Werror"],
cppflags: [
diff --git a/set-verity-state/OWNERS b/set-verity-state/OWNERS
new file mode 100644
index 0000000..e849450
--- /dev/null
+++ b/set-verity-state/OWNERS
@@ -0,0 +1,3 @@
+dvander@google.com
+yochiang@google.com
+bowgotsai@google.com
diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp
index 52a7f74..de9a452 100644
--- a/set-verity-state/set-verity-state.cpp
+++ b/set-verity-state/set-verity-state.cpp
@@ -14,242 +14,230 @@
* limitations under the License.
*/
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libavb_user/libavb_user.h>
-#include <stdarg.h>
+#include <getopt.h>
#include <stdio.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr.h>
+#include <binder/ProcessState.h>
+#include <cutils/android_reboot.h>
#include <fs_mgr_overlayfs.h>
-#include <fstab/fstab.h>
-#include <log/log_properties.h>
+#include <libavb_user/libavb_user.h>
-#include "fec/io.h"
+using namespace std::string_literals;
+
+namespace {
+
+void print_usage() {
+ printf(
+ "Usage:\n"
+ "\tdisable-verity\n"
+ "\tenable-verity\n"
+ "\tset-verity-state [0|1]\n"
+ "Options:\n"
+ "\t-h --help\tthis help\n"
+ "\t-R --reboot\tautomatic reboot if needed for new settings to take effect\n"
+ "\t-v --verbose\tbe noisy\n");
+}
#ifdef ALLOW_DISABLE_VERITY
-static const bool kAllowDisableVerity = true;
+const bool kAllowDisableVerity = true;
#else
-static const bool kAllowDisableVerity = false;
+const bool kAllowDisableVerity = false;
#endif
-using android::base::unique_fd;
-
-static void suggest_run_adb_root() {
- if (getuid() != 0) printf("Maybe run adb root?\n");
-}
-
-static bool make_block_device_writable(const std::string& dev) {
- unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
- if (fd == -1) {
- return false;
- }
-
- int OFF = 0;
- bool result = (ioctl(fd.get(), BLKROSET, &OFF) != -1);
- return result;
-}
-
-/* Turn verity on/off */
-static bool set_verity_enabled_state(const char* block_device, const char* mount_point,
- bool enable) {
- if (!make_block_device_writable(block_device)) {
- printf("Could not make block device %s writable (%s).\n", block_device, strerror(errno));
- return false;
- }
-
- fec::io fh(block_device, O_RDWR);
-
- if (!fh) {
- printf("Could not open block device %s (%s).\n", block_device, strerror(errno));
- suggest_run_adb_root();
- return false;
- }
-
- fec_verity_metadata metadata;
-
- if (!fh.get_verity_metadata(metadata)) {
- printf("Couldn't find verity metadata!\n");
- return false;
- }
-
- if (!enable && metadata.disabled) {
- printf("Verity already disabled on %s\n", mount_point);
- return false;
- }
-
- if (enable && !metadata.disabled) {
- printf("Verity already enabled on %s\n", mount_point);
- return false;
- }
-
- if (!fh.set_verity_status(enable)) {
- printf("Could not set verity %s flag on device %s with error %s\n",
- enable ? "enabled" : "disabled", block_device, strerror(errno));
- return false;
- }
-
- auto change = false;
- errno = 0;
- if (enable ? fs_mgr_overlayfs_teardown(mount_point, &change)
- : fs_mgr_overlayfs_setup(nullptr, mount_point, &change)) {
- if (change) {
- printf("%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
- }
- } else if (errno) {
- int expected_errno = enable ? EBUSY : ENOENT;
- if (errno != expected_errno) {
- printf("Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
- mount_point, strerror(errno));
- }
- }
- printf("Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
- return true;
-}
-
/* Helper function to get A/B suffix, if any. If the device isn't
* using A/B the empty string is returned. Otherwise either "_a",
* "_b", ... is returned.
*/
-static std::string get_ab_suffix() {
+std::string get_ab_suffix() {
return android::base::GetProperty("ro.boot.slot_suffix", "");
}
-static bool is_avb_device_locked() {
+bool is_avb_device_locked() {
return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
}
-static bool overlayfs_setup(bool enable) {
+bool is_debuggable() {
+ return android::base::GetBoolProperty("ro.debuggable", false);
+}
+
+bool is_using_avb() {
+ // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
+ // contract, androidboot.vbmeta.digest is set by the bootloader
+ // when using AVB).
+ return !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
+}
+
+[[noreturn]] void reboot(const std::string& name) {
+ LOG(INFO) << "Rebooting device for new settings to take effect";
+ ::sync();
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot," + name);
+ ::sleep(60);
+ LOG(ERROR) << "Failed to reboot";
+ ::exit(1);
+}
+
+bool overlayfs_setup(bool enable) {
auto change = false;
errno = 0;
- if (enable ? fs_mgr_overlayfs_teardown(nullptr, &change)
- : fs_mgr_overlayfs_setup(nullptr, nullptr, &change)) {
+ if (enable ? fs_mgr_overlayfs_setup(nullptr, &change)
+ : fs_mgr_overlayfs_teardown(nullptr, &change)) {
if (change) {
- printf("%s overlayfs\n", enable ? "disabling" : "using");
+ LOG(INFO) << (enable ? "Enabled" : "Disabled") << " overlayfs";
}
- } else if (errno) {
- printf("Overlayfs %s failed with error %s\n", enable ? "teardown" : "setup", strerror(errno));
- suggest_run_adb_root();
+ } else {
+ LOG(ERROR) << "Failed to " << (enable ? "enable" : "disable") << " overlayfs";
}
return change;
}
+struct SetVerityStateResult {
+ bool success = false;
+ bool want_reboot = false;
+};
+
/* Use AVB to turn verity on/off */
-static bool set_avb_verity_enabled_state(AvbOps* ops, bool enable_verity) {
+SetVerityStateResult SetVerityState(bool enable_verity) {
std::string ab_suffix = get_ab_suffix();
- bool verity_enabled;
+ bool verity_enabled = false;
if (is_avb_device_locked()) {
- printf("Device is locked. Please unlock the device first\n");
- return false;
+ LOG(ERROR) << "Device must be bootloader unlocked to change verity state";
+ return {};
}
- if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
- printf("Error getting verity state. Try adb root first?\n");
- return false;
+ std::unique_ptr<AvbOps, decltype(&avb_ops_user_free)> ops(avb_ops_user_new(), &avb_ops_user_free);
+ if (!ops) {
+ LOG(ERROR) << "Error getting AVB ops";
+ return {};
+ }
+
+ if (!avb_user_verity_get(ops.get(), ab_suffix.c_str(), &verity_enabled)) {
+ LOG(ERROR) << "Error getting verity state";
+ return {};
}
if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) {
- printf("verity is already %s\n", verity_enabled ? "enabled" : "disabled");
- return false;
+ LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled");
+ return {.success = true, .want_reboot = false};
}
- if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) {
- printf("Error setting verity\n");
- return false;
+ if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) {
+ LOG(ERROR) << "Error setting verity state";
+ return {};
}
- overlayfs_setup(enable_verity);
- printf("Successfully %s verity\n", enable_verity ? "enabled" : "disabled");
- return true;
+ LOG(INFO) << "Successfully " << (enable_verity ? "enabled" : "disabled") << " verity";
+ return {.success = true, .want_reboot = true};
}
+class MyLogger {
+ public:
+ explicit MyLogger(bool verbose) : verbose_(verbose) {}
+
+ void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+ const char* file, unsigned int line, const char* message) {
+ // Hide log starting with '[fs_mgr]' unless it's an error.
+ if (verbose_ || severity >= android::base::ERROR || message[0] != '[') {
+ fprintf(stderr, "%s\n", message);
+ }
+ logd_(id, severity, tag, file, line, message);
+ }
+
+ private:
+ android::base::LogdLogger logd_;
+ bool verbose_;
+};
+
+} // namespace
+
int main(int argc, char* argv[]) {
- if (argc == 0) {
- LOG(FATAL) << "set-verity-state called with empty argv";
- }
+ bool auto_reboot = false;
+ bool verbose = false;
- std::optional<bool> enable_opt;
- std::string procname = android::base::Basename(argv[0]);
- if (procname == "enable-verity") {
- enable_opt = true;
- } else if (procname == "disable-verity") {
- enable_opt = false;
- }
-
- if (!enable_opt.has_value()) {
- if (argc != 2) {
- printf("usage: %s [1|0]\n", argv[0]);
- return 1;
- }
-
- if (strcmp(argv[1], "1") == 0) {
- enable_opt = true;
- } else if (strcmp(argv[1], "0") == 0) {
- enable_opt = false;
- } else {
- printf("usage: %s [1|0]\n", argv[0]);
- return 1;
+ struct option longopts[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {"reboot", no_argument, nullptr, 'R'},
+ {"verbose", no_argument, nullptr, 'v'},
+ {0, 0, nullptr, 0},
+ };
+ for (int opt; (opt = ::getopt_long(argc, argv, "hRv", longopts, nullptr)) != -1;) {
+ switch (opt) {
+ case 'h':
+ print_usage();
+ return 0;
+ case 'R':
+ auto_reboot = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ print_usage();
+ return 1;
}
}
- bool enable = enable_opt.value();
+ android::base::InitLogging(argv, MyLogger(verbose));
- bool any_changed = false;
-
- // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
- // contract, androidboot.vbmeta.digest is set by the bootloader
- // when using AVB).
- bool using_avb = !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
-
- // If using AVB, dm-verity is used on any build so we want it to
- // be possible to disable/enable on any build (except USER). For
- // VB1.0 dm-verity is only enabled on certain builds.
- if (!using_avb) {
- if (!kAllowDisableVerity) {
- printf("%s only works for userdebug builds\n", argv[0]);
- }
-
- if (!android::base::GetBoolProperty("ro.secure", false)) {
- overlayfs_setup(enable);
- printf("verity not enabled - ENG build\n");
- return 0;
- }
+ bool enable_verity = false;
+ const std::string progname = getprogname();
+ if (progname == "enable-verity") {
+ enable_verity = true;
+ } else if (progname == "disable-verity") {
+ enable_verity = false;
+ } else if (optind < argc && (argv[optind] == "1"s || argv[optind] == "0"s)) {
+ // progname "set-verity-state"
+ enable_verity = (argv[optind] == "1"s);
+ } else {
+ print_usage();
+ return 1;
}
- // Should never be possible to disable dm-verity on a USER build
- // regardless of using AVB or VB1.0.
- if (!__android_log_is_debuggable()) {
- printf("verity cannot be disabled/enabled - USER build\n");
- return 0;
+ if (!kAllowDisableVerity || !is_debuggable()) {
+ errno = EPERM;
+ PLOG(ERROR) << "Cannot disable/enable verity on user build";
+ return 1;
}
- if (using_avb) {
- // Yep, the system is using AVB.
- AvbOps* ops = avb_ops_user_new();
- if (ops == nullptr) {
- printf("Error getting AVB ops\n");
- return 1;
+ if (getuid() != 0) {
+ errno = EACCES;
+ PLOG(ERROR) << "Must be running as root (adb root)";
+ return 1;
+ }
+
+ if (!is_using_avb()) {
+ LOG(ERROR) << "Expected AVB device, VB1.0 is no longer supported";
+ return 1;
+ }
+
+ int exit_code = 0;
+ bool want_reboot = false;
+
+ auto ret = SetVerityState(enable_verity);
+ if (ret.success) {
+ want_reboot |= ret.want_reboot;
+ } else {
+ exit_code = 1;
+ }
+
+ // Disable any overlayfs unconditionally if we want verity enabled.
+ // Enable overlayfs only if verity is successfully disabled or is already disabled.
+ if (enable_verity || ret.success) {
+ // Start a threadpool to service waitForService() callbacks as
+ // fs_mgr_overlayfs_* might call waitForService() to get the image service.
+ android::ProcessState::self()->startThreadPool();
+ want_reboot |= overlayfs_setup(!enable_verity);
+ }
+
+ if (want_reboot) {
+ if (auto_reboot) {
+ reboot(progname);
}
- if (set_avb_verity_enabled_state(ops, enable)) {
- any_changed = true;
- }
- avb_ops_user_free(ops);
- }
- if (!any_changed) any_changed = overlayfs_setup(enable);
-
- if (any_changed) {
- printf("Now reboot your device for settings to take effect\n");
+ printf("Reboot the device for new settings to take effect\n");
}
- return 0;
+ return exit_code;
}
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 5c4e03a..61b97c6 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1,9 +1,11 @@
armellel@google.com
arve@android.com
+danielangell@google.com
gmar@google.com
marcone@google.com
mmaurer@google.com
ncbray@google.com
swillden@google.com
+thurston@google.com
trong@google.com
wenhaowang@google.com
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 278499f..17d083c 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -226,6 +226,9 @@
case APPLOADER_ERR_POLICY_VIOLATION:
LOG(ERROR) << "Error: loading denied by policy engine";
break;
+ case APPLOADER_ERR_NOT_ENCRYPTED:
+ LOG(ERROR) << "Error: unmet application encryption requirement";
+ break;
default:
LOG(ERROR) << "Unrecognized error: " << resp.error;
break;
diff --git a/trusty/apploader/apploader_ipc.h b/trusty/apploader/apploader_ipc.h
index 306596e..f037692 100644
--- a/trusty/apploader/apploader_ipc.h
+++ b/trusty/apploader/apploader_ipc.h
@@ -45,6 +45,10 @@
* @APPLOADER_ERR_INTERNAL: miscellaneous or internal apploader
* error not covered by the above
* @APPLOADER_ERR_INVALID_VERSION: invalid application version
+ * @APPLOADER_ERR_POLICY_VIOLATION: signature verification succeeded but
+ * key+manifest combination not allowed
+ * by app loader policy engine
+ * @APPLOADER_ERR_NOT_ENCRYPTED: unmet application encryption requirement
*/
enum apploader_error : uint32_t {
APPLOADER_NO_ERROR = 0,
@@ -57,6 +61,7 @@
APPLOADER_ERR_INTERNAL,
APPLOADER_ERR_INVALID_VERSION,
APPLOADER_ERR_POLICY_VIOLATION,
+ APPLOADER_ERR_NOT_ENCRYPTED,
};
/**
diff --git a/trusty/metrics/metrics_test.cpp b/trusty/metrics/metrics_test.cpp
index 9897950..0c6db7f 100644
--- a/trusty/metrics/metrics_test.cpp
+++ b/trusty/metrics/metrics_test.cpp
@@ -61,6 +61,18 @@
virtual void SetUp() override {
auto ret = Open();
ASSERT_TRUE(ret.ok()) << ret.error();
+
+ /* Drain events (if any) and reset state */
+ DrainEvents();
+ crashed_app_.clear();
+ event_drop_count_ = 0;
+ }
+
+ void DrainEvents() {
+ while (WaitForEvent(1000 /* 1 second timeout */).ok()) {
+ auto ret = HandleEvent();
+ ASSERT_TRUE(ret.ok()) << ret.error();
+ }
}
void WaitForAndHandleEvent() {
@@ -79,6 +91,9 @@
TriggerCrash();
WaitForAndHandleEvent();
+ /* Check that no event was dropped. */
+ ASSERT_EQ(event_drop_count_, 0);
+
/* Check that correct TA crashed. */
ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher");
}
@@ -110,6 +125,9 @@
auto ret = HandleEvent();
ASSERT_TRUE(ret.ok()) << ret.error();
+ /* Check that no event was dropped. */
+ ASSERT_EQ(event_drop_count_, 0);
+
/* Check that correct TA crashed. */
ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher");
}
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
index 3f1dcb8..255ade1 100644
--- a/trusty/storage/interface/include/trusty/interface/storage.h
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -70,6 +70,9 @@
* @STORAGE_ERR_TRANSACT returned by various operations to indicate that current transaction
* is in error state. Such state could be only cleared by sending
* STORAGE_END_TRANSACTION message.
+ * @STORAGE_ERR_SYNC_FAILURE indicates that the current operation failed to sync
+ * to disk. Only returned if STORAGE_MSG_FLAG_PRE_COMMIT or
+ * STORAGE_MSG_FLAG_POST_COMMIT was set for the request.
*/
enum storage_err {
STORAGE_NO_ERROR = 0,
@@ -80,6 +83,7 @@
STORAGE_ERR_NOT_FOUND = 5,
STORAGE_ERR_EXIST = 6,
STORAGE_ERR_TRANSACT = 7,
+ STORAGE_ERR_SYNC_FAILURE = 8,
};
/**
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 7cbc24f..b970406 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -73,10 +73,11 @@
static int handle_req(struct storage_msg* msg, const void* req, size_t req_len) {
int rc;
- if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && (msg->cmd != STORAGE_RPMB_SEND)) {
+ if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && msg->cmd != STORAGE_RPMB_SEND &&
+ msg->cmd != STORAGE_FILE_WRITE) {
/*
- * handling post commit messages on non rpmb commands are not
- * implemented as there is no use case for this yet.
+ * handling post commit messages on commands other than rpmb and write
+ * operations are not implemented as there is no use case for this yet.
*/
ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
msg->result = STORAGE_ERR_UNIMPLEMENTED;
@@ -86,7 +87,7 @@
if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
rc = storage_sync_checkpoint();
if (rc < 0) {
- msg->result = STORAGE_ERR_GENERIC;
+ msg->result = STORAGE_ERR_SYNC_FAILURE;
return ipc_respond(msg, NULL, 0);
}
}
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index c00c399..c531cfd 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -407,6 +407,14 @@
goto err_response;
}
+ if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+ rc = storage_sync_checkpoint();
+ if (rc < 0) {
+ msg->result = STORAGE_ERR_SYNC_FAILURE;
+ goto err_response;
+ }
+ }
+
msg->result = STORAGE_NO_ERROR;
err_response:
diff --git a/trusty/test/binder/aidl/ByteEnum.aidl b/trusty/test/binder/aidl/ByteEnum.aidl
new file mode 100644
index 0000000..d3a13ac
--- /dev/null
+++ b/trusty/test/binder/aidl/ByteEnum.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/*
+ * Hello, world!
+ */
+@Backing(type="byte")
+enum ByteEnum {
+ // Comment about FOO.
+ FOO = 1,
+ BAR = 2,
+ BAZ,
+}
diff --git a/trusty/test/binder/aidl/ITestService.aidl b/trusty/test/binder/aidl/ITestService.aidl
new file mode 100644
index 0000000..c6a99c8
--- /dev/null
+++ b/trusty/test/binder/aidl/ITestService.aidl
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+
+import ByteEnum;
+import IntEnum;
+import LongEnum;
+
+interface ITestService {
+ const @utf8InCpp String PORT = "com.android.trusty.binder.test.service";
+
+ const int TEST_CONSTANT = 42;
+ const int TEST_CONSTANT2 = -42;
+ const int TEST_CONSTANT3 = +42;
+ const int TEST_CONSTANT4 = +4;
+ const int TEST_CONSTANT5 = -4;
+ const int TEST_CONSTANT6 = -0;
+ const int TEST_CONSTANT7 = +0;
+ const int TEST_CONSTANT8 = 0;
+ const int TEST_CONSTANT9 = 0x56;
+ const int TEST_CONSTANT10 = 0xa5;
+ const int TEST_CONSTANT11 = 0xFA;
+ const int TEST_CONSTANT12 = 0xffffffff;
+
+ const byte BYTE_TEST_CONSTANT = 17;
+ const long LONG_TEST_CONSTANT = 1L << 40;
+
+ const String STRING_TEST_CONSTANT = "foo";
+ const String STRING_TEST_CONSTANT2 = "bar";
+
+ // Test that primitives work as parameters and return types.
+ boolean RepeatBoolean(boolean token);
+ byte RepeatByte(byte token);
+ char RepeatChar(char token);
+ int RepeatInt(int token);
+ long RepeatLong(long token);
+ float RepeatFloat(float token);
+ double RepeatDouble(double token);
+ String RepeatString(String token);
+ ByteEnum RepeatByteEnum(ByteEnum token);
+ IntEnum RepeatIntEnum(IntEnum token);
+ LongEnum RepeatLongEnum(LongEnum token);
+
+ // Test that arrays work as parameters and return types.
+ boolean[] ReverseBoolean(in boolean[] input, out boolean[] repeated);
+ byte[] ReverseByte(in byte[] input, out byte[] repeated);
+ char[] ReverseChar(in char[] input, out char[] repeated);
+ int[] ReverseInt(in int[] input, out int[] repeated);
+ long[] ReverseLong(in long[] input, out long[] repeated);
+ float[] ReverseFloat(in float[] input, out float[] repeated);
+ double[] ReverseDouble(in double[] input, out double[] repeated);
+ String[] ReverseString(in String[] input, out String[] repeated);
+ ByteEnum[] ReverseByteEnum(in ByteEnum[] input, out ByteEnum[] repeated);
+ IntEnum[] ReverseIntEnum(in IntEnum[] input, out IntEnum[] repeated);
+ LongEnum[] ReverseLongEnum(in LongEnum[] input, out LongEnum[] repeated);
+}
diff --git a/trusty/test/binder/aidl/IntEnum.aidl b/trusty/test/binder/aidl/IntEnum.aidl
new file mode 100644
index 0000000..120e44f
--- /dev/null
+++ b/trusty/test/binder/aidl/IntEnum.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum IntEnum {
+ FOO = 1000,
+ BAR = 2000,
+ BAZ,
+ /** @deprecated do not use this */
+ QUX,
+}
diff --git a/trusty/test/binder/aidl/LongEnum.aidl b/trusty/test/binder/aidl/LongEnum.aidl
new file mode 100644
index 0000000..0e9e933
--- /dev/null
+++ b/trusty/test/binder/aidl/LongEnum.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+@Backing(type="long")
+enum LongEnum {
+ FOO = 100000000000,
+ BAR = 200000000000,
+ BAZ,
+}
diff --git a/trusty/test/binder/aidl/rules.mk b/trusty/test/binder/aidl/rules.mk
new file mode 100644
index 0000000..6154abb
--- /dev/null
+++ b/trusty/test/binder/aidl/rules.mk
@@ -0,0 +1,26 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_AIDLS := \
+ $(LOCAL_DIR)/ByteEnum.aidl \
+ $(LOCAL_DIR)/IntEnum.aidl \
+ $(LOCAL_DIR)/ITestService.aidl \
+ $(LOCAL_DIR)/LongEnum.aidl \
+
+include make/aidl.mk
diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h
index 300e05a..fc1c9d7 100644
--- a/trusty/utils/acvp/acvp_ipc.h
+++ b/trusty/utils/acvp/acvp_ipc.h
@@ -45,7 +45,7 @@
* This must be at least as long as the longest reply from the ACVP service
* (currently the reply from getConfig()).
*/
-#define ACVP_MIN_SHARED_MEMORY 16384
+#define ACVP_MIN_SHARED_MEMORY 32768
/**
* acvp_req - Request for the Trusty ACVP app