diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 6fed09cbc..e5e0e18da 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -1498,6 +1498,7 @@ void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) { if (UpdateUsesUserSnapshots(lock) && !device()->IsTestDevice()) { if (snapuserd_client_) { snapuserd_client_->DetachSnapuserd(); + snapuserd_client_->RemoveTransitionedDaemonIndicator(); snapuserd_client_ = nullptr; } } diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 64e0b8aff..a67e37c1b 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -37,11 +37,13 @@ cc_defaults { cc_library_static { name: "libsnapshot_snapuserd", defaults: [ + "fs_mgr_defaults", "libsnapshot_snapuserd_defaults", ], recovery_available: true, static_libs: [ "libcutils_sockets", + "libfs_mgr", ], shared_libs: [ "libbase", @@ -49,6 +51,7 @@ cc_library_static { ], export_include_dirs: ["include"], ramdisk_available: true, + vendor_ramdisk_available: true, } cc_defaults { @@ -86,6 +89,7 @@ cc_defaults { "libgflags", "liblog", "libsnapshot_cow", + "libsnapshot_snapuserd", "libz", "liblz4", "libext4_utils", diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h index 4b62b20e2..fb2251e2e 100644 --- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h +++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h @@ -32,6 +32,7 @@ static constexpr uint32_t PACKET_SIZE = 512; static constexpr char kSnapuserdSocket[] = "snapuserd"; static constexpr char kSnapuserdSocketProxy[] = "snapuserd_proxy"; +static constexpr char kDaemonAliveIndicator[] = "daemon-alive-indicator"; // Ensure that the second-stage daemon for snapuserd is running. bool EnsureSnapuserdStarted(); @@ -44,9 +45,11 @@ class SnapuserdClient { std::string Receivemsg(); bool ValidateConnection(); + std::string GetDaemonAliveIndicatorPath(); public: explicit SnapuserdClient(android::base::unique_fd&& sockfd); + SnapuserdClient(){}; static std::unique_ptr Connect(const std::string& socket_name, std::chrono::milliseconds timeout_ms); @@ -91,6 +94,17 @@ class SnapuserdClient { // Check the update verification status - invoked by update_verifier during // boot bool QueryUpdateVerification(); + + // Check if Snapuser daemon is ready post selinux transition after OTA boot + // This is invoked only by init as there is no sockets setup yet during + // selinux transition + bool IsTransitionedDaemonReady(); + + // Remove the daemon-alive-indicator path post snapshot merge + bool RemoveTransitionedDaemonIndicator(); + + // Notify init that snapuserd daemon is ready post selinux transition + void NotifyTransitionDaemonIsReady(); }; } // namespace snapshot diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp index e08cf9b59..695b5817f 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp @@ -29,10 +29,12 @@ #include #include +#include #include #include #include #include +#include #include namespace android { @@ -279,5 +281,42 @@ bool SnapuserdClient::QueryUpdateVerification() { return response == "success"; } +std::string SnapuserdClient::GetDaemonAliveIndicatorPath() { + return "/metadata/ota/" + std::string(kDaemonAliveIndicator); +} + +bool SnapuserdClient::IsTransitionedDaemonReady() { + if (!android::fs_mgr::WaitForFile(GetDaemonAliveIndicatorPath(), 10s)) { + LOG(ERROR) << "Timed out waiting for daemon indicator path: " + << GetDaemonAliveIndicatorPath(); + return false; + } + + return true; +} + +bool SnapuserdClient::RemoveTransitionedDaemonIndicator() { + std::string error; + std::string filePath = GetDaemonAliveIndicatorPath(); + if (!android::base::RemoveFileIfExists(filePath, &error)) { + LOG(ERROR) << "Failed to remove DaemonAliveIndicatorPath - error: " << error; + return false; + } + + if (!android::fs_mgr::WaitForFileDeleted(filePath, 5s)) { + LOG(ERROR) << "Timed out waiting for " << filePath << " to unlink"; + return false; + } + + return true; +} + +void SnapuserdClient::NotifyTransitionDaemonIsReady() { + if (!android::base::WriteStringToFile("1", GetDaemonAliveIndicatorPath())) { + PLOG(ERROR) << "Unable to write daemon alive indicator path: " + << GetDaemonAliveIndicatorPath(); + } +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index 2f7775cd1..bfe93ebc3 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -119,6 +119,12 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar } } + // We reach this point only during selinux transition during device boot. + // At this point, all threads are spin up and are ready to serve the I/O + // requests for dm-user. Lets inform init. + auto client = std::make_unique(); + client->NotifyTransitionDaemonIsReady(); + // Skip the accept() call to avoid spurious log spam. The server will still // run until all handlers have completed. return user_server_.WaitForSocket(); diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp index 6972f3069..3a9ff5bd7 100644 --- a/init/snapuserd_transition.cpp +++ b/init/snapuserd_transition.cpp @@ -112,6 +112,10 @@ void LaunchFirstStageSnapuserd(SnapshotDriver driver) { setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1); + if (!client->RemoveTransitionedDaemonIndicator()) { + LOG(ERROR) << "RemoveTransitionedDaemonIndicator failed"; + } + LOG(INFO) << "Relaunched snapuserd with pid: " << pid; } @@ -263,6 +267,19 @@ void SnapuserdSelinuxHelper::FinishTransition() { * we may see audit logs. */ bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() { + // Wait for the daemon to be fully up. Daemon will write to path + // /metadata/ota/daemon-alive-indicator only when all the threads + // are ready and attached to dm-user. + // + // This check will fail for GRF devices with vendor on Android S. + // snapuserd binary from Android S won't be able to communicate + // and hence, we will fallback and issue I/O to verify + // the presence of daemon. + auto client = std::make_unique(); + if (!client->IsTransitionedDaemonReady()) { + LOG(ERROR) << "IsTransitionedDaemonReady failed"; + } + std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix(); android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT)); if (fd < 0) {