diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:33:00 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:33:00 +0000 |
commit | b92fc9a6a12c27ae83c95ff94f0a32b5e9401d63 (patch) | |
tree | 770486c47fbedcf2f8a330268ad751fb39df6635 | |
parent | 577ba9df7df91f1ebcfbac39dfb0783d041a925a (diff) | |
parent | 4f5062b78124bf51c38572ebd0576622ff4790c0 (diff) | |
download | core-android-platform-13.0.0_r9.tar.gz |
Snap for 10276566 from 4f5062b78124bf51c38572ebd0576622ff4790c0 to tm-platform-releaseandroid-platform-13.0.0_r9android-platform-13.0.0_r8android-platform-13.0.0_r15android-platform-13.0.0_r14android-platform-13.0.0_r13android-platform-13.0.0_r12android-platform-13.0.0_r11android-platform-13.0.0_r10
Change-Id: I02e320245207cf89a25d55f98c7a350405a87035
-rw-r--r-- | debuggerd/debuggerd_test.cpp | 60 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/tombstone_proto_to_text.cpp | 10 | ||||
-rw-r--r-- | fastboot/device/usb.cpp | 10 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/Android.bp | 1 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapshot_test.cpp | 14 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/Android.bp | 7 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h | 4 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp | 10 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp | 242 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h | 45 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp | 26 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h | 3 | ||||
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp | 222 | ||||
-rwxr-xr-x[-rw-r--r--] | fs_mgr/libsnapshot/vts_ota_config_test.cpp | 3 | ||||
-rw-r--r-- | rootdir/init.rc | 61 | ||||
-rw-r--r-- | rootdir/init.zygote32.rc | 3 | ||||
-rw-r--r-- | rootdir/init.zygote64.rc | 3 |
17 files changed, 438 insertions, 286 deletions
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index e11330819..9163ca0ab 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -36,6 +36,7 @@ #include <string> #include <thread> +#include <android/dlext.h> #include <android/fdsan.h> #include <android/set_abort_message.h> #include <bionic/malloc.h> @@ -1842,7 +1843,7 @@ TEST_F(CrasherTest, stack_overflow) { ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)"); } -static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { +static std::string GetTestLibraryPath() { std::string test_lib(testing::internal::GetArgvs()[0]); auto const value = test_lib.find_last_of('/'); if (value == std::string::npos) { @@ -1850,7 +1851,62 @@ static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { } else { test_lib = test_lib.substr(0, value + 1) + "./"; } - test_lib += "libcrash_test.so"; + return test_lib + "libcrash_test.so"; +} + +static void CreateEmbeddedLibrary(int out_fd) { + std::string test_lib(GetTestLibraryPath()); + android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_NE(fd.get(), -1); + off_t file_size = lseek(fd, 0, SEEK_END); + ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0); + std::vector<uint8_t> contents(file_size); + ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size())); + + // Put the shared library data at a pagesize() offset. + ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize()); + ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size()); +} + +TEST_F(CrasherTest, non_zero_offset_in_library) { + int intercept_result; + unique_fd output_fd; + TemporaryFile tf; + CreateEmbeddedLibrary(tf.fd); + StartProcess([&tf]() { + android_dlextinfo extinfo{}; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd = tf.fd; + extinfo.library_fd_offset = 4 * getpagesize(); + void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo); + if (handle == nullptr) { + _exit(1); + } + void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash")); + if (crash_func == nullptr) { + _exit(1); + } + crash_func(); + }); + + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGSEGV); + FinishIntercept(&intercept_result); + + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + + // Verify the crash includes an offset value in the backtrace. + std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)", + tf.path, 4 * getpagesize()); + ASSERT_MATCH(result, match_str); +} + +static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) { + std::string test_lib(GetTestLibraryPath()); *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so"; std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir); diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 026564112..0696601bc 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -168,8 +168,14 @@ static void print_backtrace(CallbackType callback, const Tombstone& tombstone, build_id = StringPrintf(" (BuildId: %s)", frame.build_id().c_str()); } - CB(should_log, " #%02d pc %0*" PRIx64 " %s%s%s", index++, pointer_width(tombstone) * 2, - frame.rel_pc(), frame.file_name().c_str(), function.c_str(), build_id.c_str()); + std::string line = + StringPrintf(" #%02d pc %0*" PRIx64 " %s", index++, pointer_width(tombstone) * 2, + frame.rel_pc(), frame.file_name().c_str()); + if (frame.file_map_offset() != 0) { + line += StringPrintf(" (offset 0x%" PRIx64 ")", frame.file_map_offset()); + } + line += function + build_id; + CB(should_log, "%s", line.c_str()); } } diff --git a/fastboot/device/usb.cpp b/fastboot/device/usb.cpp index 4115a6d28..1257055de 100644 --- a/fastboot/device/usb.cpp +++ b/fastboot/device/usb.cpp @@ -171,6 +171,16 @@ static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) { if (num_bufs == 1 && aiob->events[0].res == -EINTR) { continue; } + if (read && aiob->events[0].res == -EPIPE) { + // On initial connection, some clients will send a ClearFeature(HALT) to + // attempt to resynchronize host and device after the fastboot server is killed. + // On newer device kernels, the reads we've already dispatched will be cancelled. + // Instead of treating this as a failure, which will tear down the interface and + // lead to the client doing the same thing again, just resubmit if this happens + // before we've actually read anything. + PLOG(ERROR) << "aio: got -EPIPE on first read attempt. Re-submitting read... "; + continue; + } int ret = 0; for (int i = 0; i < num_bufs; i++) { if (aiob->events[i].res < 0) { diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 6db8f139f..0d8828a47 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -257,6 +257,7 @@ cc_defaults { }, auto_gen_config: true, require_root: true, + compile_multilib: "first", } cc_test { diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index c145da718..e7ffb1600 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2609,7 +2609,6 @@ class ImageManagerTest : public SnapshotTest, public WithParamInterface<uint64_t } void TearDown() override { RETURN_IF_NON_VIRTUAL_AB(); - return; // BUG(149738928) EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) || image_manager_->DeleteBackingImage(kImageName)); @@ -2618,19 +2617,6 @@ class ImageManagerTest : public SnapshotTest, public WithParamInterface<uint64_t 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, diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index bc2bcebbf..d751fb88f 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -47,6 +47,7 @@ cc_library_static { "libbase", "liblog", ], + export_include_dirs: ["include"], ramdisk_available: true, } @@ -68,6 +69,7 @@ cc_defaults { "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_server.cpp", + "user-space-merge/snapuserd_verify.cpp", ], cflags: [ @@ -88,6 +90,11 @@ cc_defaults { "libext4_utils", "liburing", ], + + header_libs: [ + "libstorage_literals_headers", + ], + include_dirs: ["bionic/libc/kernel"], } diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h index cebda1ccb..9a69d588c 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h @@ -89,6 +89,10 @@ class SnapuserdClient { // Return the status of the snapshot std::string QuerySnapshotStatus(const std::string& misc_name); + + // Check the update verification status - invoked by update_verifier during + // boot + bool QueryUpdateVerification(); }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp index 7b1c7a3a6..e08cf9b59 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp @@ -269,5 +269,15 @@ std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) { return Receivemsg(); } +bool SnapuserdClient::QueryUpdateVerification() { + std::string msg = "update-verify"; + if (!Sendmsg(msg)) { + LOG(ERROR) << "Failed to send message " << msg << " to snapuserd"; + return false; + } + std::string response = Receivemsg(); + return response == "success"; +} + } // namespace snapshot } // namespace android 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 718c13ce0..8939b786c 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp @@ -18,6 +18,7 @@ #include <sys/utsname.h> +#include <android-base/chrono_utils.h> #include <android-base/properties.h> #include <android-base/scopeguard.h> #include <android-base/strings.h> @@ -70,6 +71,9 @@ bool SnapshotHandler::InitializeWorkers() { read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); + + update_verify_ = std::make_unique<UpdateVerify>(misc_name_); + return true; } @@ -307,206 +311,6 @@ bool SnapshotHandler::InitCowDevice() { return ReadMetadata(); } -void SnapshotHandler::FinalizeIouring() { - io_uring_queue_exit(ring_.get()); -} - -bool SnapshotHandler::InitializeIouring(int io_depth) { - ring_ = std::make_unique<struct io_uring>(); - - int ret = io_uring_queue_init(io_depth, ring_.get(), 0); - if (ret) { - LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret; - return false; - } - - LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth; - return true; -} - -bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device, - const std::string& partition_name, size_t size) { - // 64k block size with io_depth of 64 is optimal - // for a single thread. We just need a single thread - // to read all the blocks from all dynamic partitions. - size_t io_depth = 64; - size_t bs = (64 * 1024); - - if (!InitializeIouring(io_depth)) { - return false; - } - - LOG(INFO) << "ReadBlockAsync start " - << " Block-device: " << dm_block_device << " Partition-name: " << partition_name - << " Size: " << size; - - auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); }); - - std::vector<std::unique_ptr<struct iovec>> vecs; - using AlignedBuf = std::unique_ptr<void, decltype(free)*>; - std::vector<AlignedBuf> alignedBufVector; - - /* - * TODO: We need aligned memory for DIRECT-IO. However, if we do - * a DIRECT-IO and verify the blocks then we need to inform - * update-verifier that block verification has been done and - * there is no need to repeat the same. We are not there yet - * as we need to see if there are any boot time improvements doing - * a DIRECT-IO. - * - * Also, we could you the same function post merge for block verification; - * again, we can do a DIRECT-IO instead of thrashing page-cache and - * hurting other applications. - * - * For now, we will just create aligned buffers but rely on buffered - * I/O until we have perf numbers to justify DIRECT-IO. - */ - for (int i = 0; i < io_depth; i++) { - auto iovec = std::make_unique<struct iovec>(); - vecs.push_back(std::move(iovec)); - - struct iovec* iovec_ptr = vecs[i].get(); - - if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) { - LOG(ERROR) << "posix_memalign failed"; - return false; - } - - iovec_ptr->iov_len = bs; - alignedBufVector.push_back( - std::unique_ptr<void, decltype(free)*>(iovec_ptr->iov_base, free)); - } - - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); - if (fd.get() == -1) { - SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device - << " partition-name: " << partition_name; - return false; - } - - loff_t offset = 0; - size_t remain = size; - size_t read_sz = io_depth * bs; - - while (remain > 0) { - size_t to_read = std::min(remain, read_sz); - size_t queue_size = to_read / bs; - - for (int i = 0; i < queue_size; i++) { - struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get()); - if (!sqe) { - SNAP_LOG(ERROR) << "io_uring_get_sqe() failed"; - return false; - } - - struct iovec* iovec_ptr = vecs[i].get(); - - io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset); - sqe->flags |= IOSQE_ASYNC; - offset += bs; - } - - int ret = io_uring_submit(ring_.get()); - if (ret != queue_size) { - SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size; - return false; - } - - for (int i = 0; i < queue_size; i++) { - struct io_uring_cqe* cqe; - - int ret = io_uring_wait_cqe(ring_.get(), &cqe); - if (ret) { - SNAP_PLOG(ERROR) << "wait_cqe failed" << ret; - return false; - } - - if (cqe->res < 0) { - SNAP_LOG(ERROR) << "io failed with res: " << cqe->res; - return false; - } - io_uring_cqe_seen(ring_.get(), cqe); - } - - remain -= to_read; - } - - LOG(INFO) << "ReadBlockAsync complete: " - << " Block-device: " << dm_block_device << " Partition-name: " << partition_name - << " Size: " << size; - return true; -} - -void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device, - const std::string& partition_name, off_t offset, - size_t size) { - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); - if (fd.get() == -1) { - SNAP_PLOG(ERROR) << "Error reading " << dm_block_device - << " partition-name: " << partition_name; - return; - } - - size_t remain = size; - off_t file_offset = offset; - // We pick 4M I/O size based on the fact that the current - // update_verifier has a similar I/O size. - size_t read_sz = 1024 * BLOCK_SZ; - std::vector<uint8_t> buf(read_sz); - - while (remain > 0) { - size_t to_read = std::min(remain, read_sz); - - if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) { - SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device - << " at offset: " << file_offset - << " partition-name: " << partition_name << " total-size: " << size - << " remain_size: " << remain; - return; - } - - file_offset += to_read; - remain -= to_read; - } - - SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device - << " partition: " << partition_name << " size: " << size - << " offset: " << offset; -} - -void SnapshotHandler::ReadBlocks(const std::string partition_name, - const std::string& dm_block_device) { - SNAP_LOG(DEBUG) << "Reading partition: " << partition_name - << " Block-Device: " << dm_block_device; - - uint64_t dev_sz = 0; - - unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - SNAP_LOG(ERROR) << "Cannot open block device"; - return; - } - - dev_sz = get_block_device_size(fd.get()); - if (!dev_sz) { - SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; - return; - } - - int num_threads = 2; - size_t num_blocks = dev_sz >> BLOCK_SHIFT; - size_t num_blocks_per_thread = num_blocks / num_threads; - size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT; - off_t offset = 0; - - for (int i = 0; i < num_threads; i++) { - std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device, - partition_name, offset, read_sz_per_thread); - - offset += read_sz_per_thread; - } -} - /* * Entry point to launch threads */ @@ -527,42 +331,22 @@ bool SnapshotHandler::Start() { std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get())); } - bool second_stage_init = true; + bool partition_verification = true; - // We don't want to read the blocks during first stage init. + // We don't want to read the blocks during first stage init or + // during post-install phase. if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) { - second_stage_init = false; - } - - if (second_stage_init) { - SNAP_LOG(INFO) << "Reading blocks to cache...."; - auto& dm = DeviceMapper::Instance(); - auto dm_block_devices = dm.FindDmPartitions(); - if (dm_block_devices.empty()) { - SNAP_LOG(ERROR) << "No dm-enabled block device is found."; - } else { - auto parts = android::base::Split(misc_name_, "-"); - std::string partition_name = parts[0]; - - const char* suffix_b = "_b"; - const char* suffix_a = "_a"; - - partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); - partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); - - if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { - SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; - } else { - ReadBlocks(partition_name, dm_block_devices.at(partition_name)); - } - } - } else { - SNAP_LOG(INFO) << "Not reading block device into cache"; + partition_verification = false; } std::future<bool> merge_thread = std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get()); + // Now that the worker threads are up, scan the partitions. + if (partition_verification) { + update_verify_->VerifyUpdatePartition(); + } + bool ret = true; for (auto& t : threads) { ret = t.get() && ret; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h index c6805e5d9..42237ef60 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -45,12 +45,14 @@ #include <liburing.h> #include <snapuserd/snapuserd_buffer.h> #include <snapuserd/snapuserd_kernel.h> +#include <storage_literals/storage_literals.h> namespace android { namespace snapshot { using android::base::unique_fd; using namespace std::chrono_literals; +using namespace android::storage_literals; static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20); static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ); @@ -170,6 +172,36 @@ class ReadAhead { std::unique_ptr<struct io_uring> ring_; }; +class UpdateVerify { + public: + UpdateVerify(const std::string& misc_name); + void VerifyUpdatePartition(); + bool CheckPartitionVerification(); + + private: + enum class UpdateVerifyState { + VERIFY_UNKNOWN, + VERIFY_FAILED, + VERIFY_SUCCESS, + }; + + std::string misc_name_; + UpdateVerifyState state_; + std::mutex m_lock_; + std::condition_variable m_cv_; + + int kMinThreadsToVerify = 1; + int kMaxThreadsToVerify = 4; + uint64_t kThresholdSize = 512_MiB; + uint64_t kBlockSizeVerify = 1_MiB; + + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + void UpdatePartitionVerificationState(UpdateVerifyState state); + bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); + bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, + off_t offset, int skip_blocks, uint64_t dev_sz); +}; + class Worker { public: Worker(const std::string& cow_device, const std::string& backing_device, @@ -352,24 +384,16 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer); bool IsIouringSupported(); + bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } private: bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } - bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } + bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } struct BufferState* GetBufferState(); void UpdateMergeCompletionPercentage(); - void ReadBlocks(const std::string partition_name, const std::string& dm_block_device); - void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, - off_t offset, size_t size); - - bool InitializeIouring(int io_depth); - void FinalizeIouring(); - bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, - size_t size); - // COW device std::string cow_device_; // Source device @@ -422,6 +446,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { bool scratch_space_ = false; std::unique_ptr<struct io_uring> ring_; + std::unique_ptr<UpdateVerify> update_verify_; }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp index 5d93f01a7..1e7daed39 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -55,6 +55,7 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) { if (input == "initiate_merge") return DaemonOps::INITIATE; if (input == "merge_percent") return DaemonOps::PERCENTAGE; if (input == "getstatus") return DaemonOps::GETSTATUS; + if (input == "update-verify") return DaemonOps::UPDATE_VERIFY; return DaemonOps::INVALID; } @@ -290,6 +291,14 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, merge_status); } } + case DaemonOps::UPDATE_VERIFY: { + std::lock_guard<std::mutex> lock(lock_); + if (!UpdateVerification(&lock)) { + return Sendmsg(fd, "fail"); + } + + return Sendmsg(fd, "success"); + } default: { LOG(ERROR) << "Received unknown message type from client"; Sendmsg(fd, "fail"); @@ -750,5 +759,22 @@ bool UserSnapshotServer::RunForSocketHandoff() { return true; } +bool UserSnapshotServer::UpdateVerification(std::lock_guard<std::mutex>* proof_of_lock) { + CHECK(proof_of_lock); + + bool status = true; + for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) { + auto& th = (*iter)->thread(); + if (th.joinable() && status) { + status = (*iter)->snapuserd()->CheckPartitionVerification() && status; + } else { + // return immediately if there is a failure + return false; + } + } + + return status; +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index e0844aeb1..c2af61fbf 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -50,6 +50,7 @@ enum class DaemonOps { INITIATE, PERCENTAGE, GETSTATUS, + UPDATE_VERIFY, INVALID, }; @@ -130,6 +131,8 @@ class UserSnapshotServer { double GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock); void TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock); + bool UpdateVerification(std::lock_guard<std::mutex>* proof_of_lock); + public: UserSnapshotServer(); ~UserSnapshotServer(); diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp new file mode 100644 index 000000000..18c1dfcd9 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp @@ -0,0 +1,222 @@ +/* + * 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 "snapuserd_core.h" + +#include <android-base/chrono_utils.h> +#include <android-base/scopeguard.h> +#include <android-base/strings.h> + +namespace android { +namespace snapshot { + +using namespace android; +using namespace android::dm; +using android::base::unique_fd; + +UpdateVerify::UpdateVerify(const std::string& misc_name) + : misc_name_(misc_name), state_(UpdateVerifyState::VERIFY_UNKNOWN) {} + +bool UpdateVerify::CheckPartitionVerification() { + auto now = std::chrono::system_clock::now(); + auto deadline = now + 10s; + { + std::unique_lock<std::mutex> cv_lock(m_lock_); + while (state_ == UpdateVerifyState::VERIFY_UNKNOWN) { + auto status = m_cv_.wait_until(cv_lock, deadline); + if (status == std::cv_status::timeout) { + return false; + } + } + } + + return (state_ == UpdateVerifyState::VERIFY_SUCCESS); +} + +void UpdateVerify::UpdatePartitionVerificationState(UpdateVerifyState state) { + { + std::lock_guard<std::mutex> lock(m_lock_); + state_ = state; + } + m_cv_.notify_all(); +} + +void UpdateVerify::VerifyUpdatePartition() { + bool succeeded = false; + + auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void { + if (!succeeded) { + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED); + } + }); + + auto& dm = DeviceMapper::Instance(); + auto dm_block_devices = dm.FindDmPartitions(); + if (dm_block_devices.empty()) { + SNAP_LOG(ERROR) << "No dm-enabled block device is found."; + return; + } + + const auto parts = android::base::Split(misc_name_, "-"); + std::string partition_name = parts[0]; + + constexpr auto&& suffix_b = "_b"; + constexpr auto&& suffix_a = "_a"; + + partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); + partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); + + if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { + SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; + return; + } + + if (!VerifyPartition(partition_name, dm_block_devices.at(partition_name))) { + SNAP_LOG(ERROR) << "Partition: " << partition_name + << " Block-device: " << dm_block_devices.at(partition_name) + << " verification failed"; + } + succeeded = true; +} + +bool UpdateVerify::VerifyBlocks(const std::string& partition_name, + const std::string& dm_block_device, off_t offset, int skip_blocks, + uint64_t dev_sz) { + unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT))); + if (fd < 0) { + SNAP_LOG(ERROR) << "open failed: " << dm_block_device; + return false; + } + + loff_t file_offset = offset; + const uint64_t read_sz = kBlockSizeVerify; + + void* addr; + ssize_t page_size = getpagesize(); + if (posix_memalign(&addr, page_size, read_sz) < 0) { + SNAP_PLOG(ERROR) << "posix_memalign failed " + << " page_size: " << page_size << " read_sz: " << read_sz; + return false; + } + + std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free); + + uint64_t bytes_read = 0; + + while (true) { + size_t to_read = std::min((dev_sz - file_offset), read_sz); + + if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) { + SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device + << " partition-name: " << partition_name + << " at offset: " << file_offset << " read-size: " << to_read + << " block-size: " << dev_sz; + return false; + } + + bytes_read += to_read; + file_offset += (skip_blocks * kBlockSizeVerify); + if (file_offset >= dev_sz) { + break; + } + } + + SNAP_LOG(DEBUG) << "Verification success with bytes-read: " << bytes_read + << " dev_sz: " << dev_sz << " partition_name: " << partition_name; + + return true; +} + +bool UpdateVerify::VerifyPartition(const std::string& partition_name, + const std::string& dm_block_device) { + android::base::Timer timer; + + SNAP_LOG(INFO) << "VerifyPartition: " << partition_name << " Block-device: " << dm_block_device; + + bool succeeded = false; + auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void { + if (!succeeded) { + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED); + } + }); + + unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT))); + if (fd < 0) { + SNAP_LOG(ERROR) << "open failed: " << dm_block_device; + return false; + } + + uint64_t dev_sz = get_block_device_size(fd.get()); + if (!dev_sz) { + SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; + return false; + } + + if (!IsBlockAligned(dev_sz)) { + SNAP_LOG(ERROR) << "dev_sz: " << dev_sz << " is not block aligned"; + return false; + } + + /* + * Not all partitions are of same size. Some partitions are as small as + * 100Mb. We can just finish them in a single thread. For bigger partitions + * such as product, 4 threads are sufficient enough. + * + * TODO: With io_uring SQ_POLL support, we can completely cut this + * down to just single thread for all partitions and potentially verify all + * the partitions with zero syscalls. Additionally, since block layer + * supports polling, IO_POLL could be used which will further cut down + * latency. + */ + int num_threads = kMinThreadsToVerify; + if (dev_sz > kThresholdSize) { + num_threads = kMaxThreadsToVerify; + } + + std::vector<std::future<bool>> threads; + off_t start_offset = 0; + const int skip_blocks = num_threads; + + while (num_threads) { + threads.emplace_back(std::async(std::launch::async, &UpdateVerify::VerifyBlocks, this, + partition_name, dm_block_device, start_offset, skip_blocks, + dev_sz)); + start_offset += kBlockSizeVerify; + num_threads -= 1; + if (start_offset >= dev_sz) { + break; + } + } + + bool ret = true; + for (auto& t : threads) { + ret = t.get() && ret; + } + + if (ret) { + succeeded = true; + UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_SUCCESS); + SNAP_LOG(INFO) << "Partition: " << partition_name << " Block-device: " << dm_block_device + << " Size: " << dev_sz + << " verification success. Duration : " << timer.duration().count() << " ms"; + return true; + } + + return false; +} + +} // namespace snapshot +} // namespace android diff --git a/fs_mgr/libsnapshot/vts_ota_config_test.cpp b/fs_mgr/libsnapshot/vts_ota_config_test.cpp index 02bcc3438..d387eb32d 100644..100755 --- a/fs_mgr/libsnapshot/vts_ota_config_test.cpp +++ b/fs_mgr/libsnapshot/vts_ota_config_test.cpp @@ -22,6 +22,9 @@ static int GetVsrLevel() { } TEST(VAB, Enabled) { + if (!android::base::GetBoolProperty("ro.build.ab_update", false) && (GetVsrLevel() < __ANDROID_API_T__)) { + GTEST_SKIP(); + } ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.enabled", false)); if (GetVsrLevel() < __ANDROID_API_T__) { GTEST_SKIP(); diff --git a/rootdir/init.rc b/rootdir/init.rc index 02e51d2c4..2b53d883e 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -86,32 +86,6 @@ on early-init mkdir /dev/sys/fs 0755 system system mkdir /dev/sys/block 0755 system system -# Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610 -on early-init && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test32 -on early-init && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test64 -on property:apexd.status=ready && property:ro.product.cpu.abilist32=* - exec_start boringssl_self_test_apex32 -on property:apexd.status=ready && property:ro.product.cpu.abilist64=* - exec_start boringssl_self_test_apex64 - -service boringssl_self_test32 /system/bin/boringssl_self_test32 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test64 /system/bin/boringssl_self_test64 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - -service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64 - reboot_on_failure reboot,boringssl-self-check-failed - stdio_to_kmsg - on init sysclktz 0 @@ -502,6 +476,33 @@ on init start hwservicemanager start vndservicemanager +# Run boringssl self test for each ABI. Any failures trigger reboot to firmware. +on init && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test32 +on init && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test64 +on property:apexd.status=ready && property:ro.product.cpu.abilist32=* + exec_start boringssl_self_test_apex32 +on property:apexd.status=ready && property:ro.product.cpu.abilist64=* + exec_start boringssl_self_test_apex64 + +service boringssl_self_test32 /system/bin/boringssl_self_test32 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test64 /system/bin/boringssl_self_test64 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + +service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64 + reboot_on_failure reboot,boringssl-self-check-failed + stdio_to_kmsg + + # Healthd can trigger a full boot from charger mode by signaling this # property when the power button is held. on property:sys.boot_from_charger_mode=1 @@ -1269,11 +1270,13 @@ service console /system/bin/sh setenv HOSTNAME console on property:ro.debuggable=1 - # Give writes to anyone for the trace folder on debug builds. + # Give writes to the same group for the trace folder on debug builds, + # it's further protected by selinux policy. # The folder is used to store method traces. chmod 0773 /data/misc/trace - # Give reads to anyone for the window trace folder on debug builds. - chmod 0775 /data/misc/wmtrace + # Give writes and reads to anyone for the window trace folder on debug builds, + # it's further protected by selinux policy. + chmod 0777 /data/misc/wmtrace # Give reads to anyone for the accessibility trace folder on debug builds. chmod 0775 /data/misc/a11ytrace diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 63b09c0d6..2f0ec8a17 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -7,6 +7,9 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on + # NOTE: If the wakelock name here is changed, then also + # update it in SystemSuspend.cpp + onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 5bde5f469..805267d1d 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -7,6 +7,9 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on + # NOTE: If the wakelock name here is changed, then also + # update it in SystemSuspend.cpp + onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media |