From 98430cf0d16c8e6ca203ebe5ccb100758e0dd0c3 Mon Sep 17 00:00:00 2001 From: Lasan Mahaliyana Date: Thu, 25 Jun 2026 18:57:34 +0530 Subject: [PATCH] removed ipc server and daemon service. added dbus sharing service --- sharing/linux/daemon/BUILD | 47 +- sharing/linux/daemon/daemon_service.cc | 453 ------------------ sharing/linux/daemon/daemon_service.h | 172 ------- sharing/linux/daemon/daemon_service_test.cc | 306 ------------ sharing/linux/daemon/ipc_server.cc | 263 ---------- sharing/linux/daemon/ipc_server.h | 53 -- sharing/linux/daemon/ipc_server_test.cc | 452 ----------------- sharing/linux/daemon/main.cc | 57 +-- sharing/linux/daemon/main.h | 45 -- sharing/linux/daemon/nearby_sharing_client.h | 4 +- .../daemon/nearby_sharing_dbus_service.cc | 441 +++++++++++++++++ .../daemon/nearby_sharing_dbus_service.h | 105 ++++ .../nearby_sharing_dbus_service_test.cc | 89 ++++ sharing/linux/daemon/nearby_sharing_server.h | 4 +- 14 files changed, 676 insertions(+), 1815 deletions(-) delete mode 100644 sharing/linux/daemon/daemon_service.cc delete mode 100644 sharing/linux/daemon/daemon_service.h delete mode 100644 sharing/linux/daemon/daemon_service_test.cc delete mode 100644 sharing/linux/daemon/ipc_server.cc delete mode 100644 sharing/linux/daemon/ipc_server.h delete mode 100644 sharing/linux/daemon/ipc_server_test.cc delete mode 100644 sharing/linux/daemon/main.h create mode 100644 sharing/linux/daemon/nearby_sharing_dbus_service.cc create mode 100644 sharing/linux/daemon/nearby_sharing_dbus_service.h create mode 100644 sharing/linux/daemon/nearby_sharing_dbus_service_test.cc diff --git a/sharing/linux/daemon/BUILD b/sharing/linux/daemon/BUILD index bc32c26b..681d734c 100644 --- a/sharing/linux/daemon/BUILD +++ b/sharing/linux/daemon/BUILD @@ -6,8 +6,7 @@ cc_binary( name = "nearby_sharing_daemon", srcs = ["main.cc"], deps = [ - ":daemon_service", - ":ipc_server", + ":nearby_sharing_dbus_service", "//connections/implementation/flags:connections_flags", "//internal/flags:nearby_flags", "//sharing:nearby_sharing_service", @@ -15,14 +14,17 @@ cc_binary( "//sharing/linux:linux_sharing_platform", "//sharing/proto:enums_cc_proto", "@com_google_absl//absl/time", - "@nlohmann_json//:json", + "@sdbus_cpp", ], ) cc_library( - name = "daemon_service", - srcs = ["daemon_service.cc"], - hdrs = ["daemon_service.h"], + name = "nearby_sharing_dbus_service", + srcs = ["nearby_sharing_dbus_service.cc"], + hdrs = [ + "nearby_sharing_dbus_service.h", + "nearby_sharing_server.h", + ], deps = [ "//internal/base:file_path", "//sharing:attachments", @@ -30,43 +32,20 @@ cc_library( "//sharing:transfer_metadata", "//sharing:types", "@com_google_absl//absl/synchronization", - "@com_google_absl//absl/time", - "@nlohmann_json//:json", + "@sdbus_cpp", ], ) cc_test( - name = "daemon_service_test", - srcs = ["daemon_service_test.cc"], + name = "nearby_sharing_dbus_service_test", + srcs = ["nearby_sharing_dbus_service_test.cc"], deps = [ - ":daemon_service", + ":nearby_sharing_dbus_service", "//internal/platform/implementation/linux:linux", "//sharing:attachments", - "//sharing:nearby_sharing_service", "//sharing:transfer_metadata", "//sharing:types", "@com_google_googletest//:gtest_main", - "@nlohmann_json//:json", + "@sdbus_cpp", ], ) - -cc_test( - name = "ipc_server_test", - srcs = ["ipc_server_test.cc"], - deps = [ - ":ipc_server", - "@com_google_googletest//:gtest_main", - "@com_google_absl//absl/synchronization", - "@nlohmann_json//:json", - ], -) - -cc_library( - name = "ipc_server", - hdrs = ["ipc_server.h"], - srcs = ["ipc_server.cc"], - deps = [ - "@com_google_absl//absl/synchronization", - "@nlohmann_json//:json", - ], -) diff --git a/sharing/linux/daemon/daemon_service.cc b/sharing/linux/daemon/daemon_service.cc deleted file mode 100644 index 58b6433c..00000000 --- a/sharing/linux/daemon/daemon_service.cc +++ /dev/null @@ -1,453 +0,0 @@ -#include "sharing/linux/daemon/daemon_service.h" - -#include -#include -#include -#include - -#include "absl/time/time.h" -#include "internal/base/file_path.h" -#include "sharing/advertisement.h" -#include "sharing/file_attachment.h" - -namespace nearby::sharing::linux { -namespace { - -nlohmann::json CommandResult(std::string command, bool ok, - std::string message) { - return nlohmann::json{{"event", "command_result"}, - {"command", std::move(command)}, - {"ok", ok}, - {"message", std::move(message)}}; -} - -std::string StatusCodeToString(NearbySharingService::StatusCodes status) { - return NearbySharingService::StatusCodeToString(status); -} - -template -NearbySharingService::StatusCodes WaitForStatus(Invoker invoker) { - std::mutex mutex; - std::condition_variable cv; - std::optional status; - invoker([&](NearbySharingService::StatusCodes callback_status) { - { - std::lock_guard lock(mutex); - status = callback_status; - } - cv.notify_one(); - }); - - std::unique_lock lock(mutex); - cv.wait(lock, [&] { return status.has_value(); }); - return *status; -} - -std::unique_ptr CreateFileAttachments( - const std::string& file_path) { - AttachmentContainer::Builder builder; - builder.AddFileAttachment(FileAttachment(FilePath(file_path))); - return builder.Build(); -} - -} // namespace - -nlohmann::json ShareTargetToJson(const ShareTarget& share_target) { - return nlohmann::json{ - {"id", share_target.id}, - {"device_name", share_target.device_name}, - {"type", static_cast(share_target.type)}, - {"is_incoming", share_target.is_incoming}, - {"is_known", share_target.is_known}, - {"device_id", share_target.device_id}, - {"for_self_share", share_target.for_self_share}, - {"vendor_id", share_target.vendor_id}, - {"receive_disabled", share_target.receive_disabled}, - }; -} - -nlohmann::json TransferMetadataToJson( - const TransferMetadata& transfer_metadata, - const AttachmentContainer& attachment_container) { - nlohmann::json result{ - {"status", TransferMetadata::StatusToString(transfer_metadata.status())}, - {"progress", transfer_metadata.progress()}, - {"transferred_bytes", transfer_metadata.transferred_bytes()}, - {"total_bytes", attachment_container.GetTotalAttachmentsSize()}, - {"transfer_speed", transfer_metadata.transfer_speed()}, - {"estimated_time_remaining", - transfer_metadata.estimated_time_remaining()}, - {"total_attachments_count", transfer_metadata.total_attachments_count()}, - {"transferred_attachments_count", - transfer_metadata.transferred_attachments_count()}, - {"is_final_status", transfer_metadata.is_final_status()}, - {"is_self_share", transfer_metadata.is_self_share()}, - {"binding_id", transfer_metadata.binding_id()}, - }; - if (transfer_metadata.token().has_value()) { - result["token"] = *transfer_metadata.token(); - } - if (transfer_metadata.in_progress_attachment_id().has_value()) { - result["in_progress_attachment_id"] = - *transfer_metadata.in_progress_attachment_id(); - } - if (transfer_metadata.in_progress_attachment_transferred_bytes() - .has_value()) { - result["in_progress_attachment_transferred_bytes"] = - *transfer_metadata.in_progress_attachment_transferred_bytes(); - } - if (transfer_metadata.in_progress_attachment_total_bytes().has_value()) { - result["in_progress_attachment_total_bytes"] = - *transfer_metadata.in_progress_attachment_total_bytes(); - } - return result; -} - -DaemonService::DaemonService(NearbySharingService& service, - EventSink event_sink) - : service_(service), - event_sink_(std::move(event_sink)), - send_transfer_callback_(*this, /*receive_mode=*/false), - receive_transfer_callback_(*this, /*receive_mode=*/true), - discovery_callback_(*this) {} - -DaemonService::~DaemonService() { Shutdown(); } - -nlohmann::json DaemonService::HandleCommand(const nlohmann::json& request) { - if (!request.is_object() || !request.contains("command") || - !request["command"].is_string()) { - return CommandResult("", false, "missing string field: command"); - } - std::string command = request["command"].get(); - if (command == "status") { - return Status(); - } - if (command == "start_receive") { - return StartReceive(); - } - if (command == "stop_receive") { - return StopReceive(); - } - if (command == "start_discovery") { - return StartDiscovery(); - } - if (command == "stop_discovery") { - return StopDiscovery(); - } - if (command == "send_file") { - return SendFile(request); - } - if (command == "accept") { - return Accept(request); - } - if (command == "reject") { - return Reject(request); - } - if (command == "cancel") { - return Cancel(request); - } - if (command == "shutdown") { - Shutdown(); - return CommandResult(command, true, "daemon service shut down"); - } - return CommandResult(command, false, "unknown command"); -} - -void DaemonService::Shutdown() { - bool stop_receive = false; - bool stop_discovery = false; - { - absl::MutexLock lock(lock_); - if (shutdown_) { - return; - } - shutdown_ = true; - stop_receive = receive_registered_; - stop_discovery = discovery_registered_; - receive_registered_ = false; - discovery_registered_ = false; - targets_.clear(); - active_transfers_.clear(); - } - - if (stop_receive) { - WaitForStatus([&](auto callback) { - service_.UnregisterReceiveSurface(&receive_transfer_callback_, - std::move(callback)); - }); - } - if (stop_discovery) { - WaitForStatus([&](auto callback) { - service_.UnregisterSendSurface(&send_transfer_callback_, - std::move(callback)); - }); - } - WaitForStatus([&](auto callback) { service_.Shutdown(std::move(callback)); }); -} - -nlohmann::json DaemonService::StartReceive() { - { - absl::MutexLock lock(lock_); - if (receive_registered_) { - return CommandResult("start_receive", true, "receive already started"); - } - } - - auto result = InvokeStatusCommand("start_receive", [&](auto callback) { - service_.RegisterReceiveSurface( - &receive_transfer_callback_, - NearbySharingService::ReceiveSurfaceState::kForeground, - Advertisement::BlockedVendorId::kNone, std::move(callback)); - }); - if (result["ok"].get()) { - absl::MutexLock lock(lock_); - receive_registered_ = true; - } - return result; -} - -nlohmann::json DaemonService::StopReceive() { - { - absl::MutexLock lock(lock_); - if (!receive_registered_) { - return CommandResult("stop_receive", true, "receive already stopped"); - } - receive_registered_ = false; - } - - return InvokeStatusCommand("stop_receive", [&](auto callback) { - service_.UnregisterReceiveSurface(&receive_transfer_callback_, - std::move(callback)); - }); -} - -nlohmann::json DaemonService::StartDiscovery() { - { - absl::MutexLock lock(lock_); - if (discovery_registered_) { - return CommandResult("start_discovery", true, "discovery already started"); - } - } - - auto result = InvokeStatusCommand("start_discovery", [&](auto callback) { - service_.RegisterSendSurface( - &send_transfer_callback_, &discovery_callback_, - NearbySharingService::SendSurfaceState::kForeground, - Advertisement::BlockedVendorId::kNone, - /*disable_wifi_hotspot=*/false, std::move(callback)); - }); - if (result["ok"].get()) { - absl::MutexLock lock(lock_); - discovery_registered_ = true; - } - return result; -} - -nlohmann::json DaemonService::StopDiscovery() { - { - absl::MutexLock lock(lock_); - if (!discovery_registered_) { - return CommandResult("stop_discovery", true, "discovery already stopped"); - } - discovery_registered_ = false; - targets_.clear(); - } - - return InvokeStatusCommand("stop_discovery", [&](auto callback) { - service_.UnregisterSendSurface(&send_transfer_callback_, - std::move(callback)); - }); -} - -nlohmann::json DaemonService::SendFile(const nlohmann::json& request) { - nlohmann::json error; - std::optional share_target_id = GetRequiredTargetId(request, error); - if (!share_target_id.has_value()) { - error["command"] = "send_file"; - return error; - } - if (!request.contains("path") || !request["path"].is_string()) { - return CommandResult("send_file", false, "missing string field: path"); - } - - std::string path = request["path"].get(); - std::error_code file_error; - if (!std::filesystem::is_regular_file(path, file_error)) { - return CommandResult("send_file", false, "path is not a regular file"); - } - - { - absl::MutexLock lock(lock_); - if (targets_.find(*share_target_id) == targets_.end()) { - return CommandResult("send_file", false, "unknown share_target_id"); - } - } - - auto attachments = CreateFileAttachments(path); - return InvokeStatusCommand("send_file", [&](auto callback) { - service_.SendAttachments(*share_target_id, std::move(attachments), - std::move(callback)); - }); -} - -nlohmann::json DaemonService::Accept(const nlohmann::json& request) { - nlohmann::json error; - std::optional share_target_id = GetRequiredTargetId(request, error); - if (!share_target_id.has_value()) { - error["command"] = "accept"; - return error; - } - return InvokeStatusCommand("accept", [&](auto callback) { - service_.Accept(*share_target_id, std::move(callback)); - }); -} - -nlohmann::json DaemonService::Reject(const nlohmann::json& request) { - nlohmann::json error; - std::optional share_target_id = GetRequiredTargetId(request, error); - if (!share_target_id.has_value()) { - error["command"] = "reject"; - return error; - } - return InvokeStatusCommand("reject", [&](auto callback) { - service_.Reject(*share_target_id, std::move(callback)); - }); -} - -nlohmann::json DaemonService::Cancel(const nlohmann::json& request) { - nlohmann::json error; - std::optional share_target_id = GetRequiredTargetId(request, error); - if (!share_target_id.has_value()) { - error["command"] = "cancel"; - return error; - } - return InvokeStatusCommand("cancel", [&](auto callback) { - service_.Cancel(*share_target_id, std::move(callback)); - }); -} - -nlohmann::json DaemonService::Status() { - nlohmann::json targets = nlohmann::json::array(); - { - absl::MutexLock lock(lock_); - for (const auto& [id, target] : targets_) { - static_cast(id); - targets.push_back(ShareTargetToJson(target)); - } - return nlohmann::json{{"event", "command_result"}, - {"command", "status"}, - {"ok", true}, - {"receive_registered", receive_registered_}, - {"discovery_registered", discovery_registered_}, - {"is_transferring", service_.IsTransferring()}, - {"is_scanning", service_.IsScanning()}, - {"bluetooth_present", service_.IsBluetoothPresent()}, - {"bluetooth_powered", service_.IsBluetoothPowered()}, - {"lan_connected", service_.IsLanConnected()}, - {"targets", std::move(targets)}}; - } -} - -void DaemonService::OnTransferUpdate( - bool receive_mode, const ShareTarget& share_target, - const AttachmentContainer& attachment_container, - const TransferMetadata& transfer_metadata) { - { - absl::MutexLock lock(lock_); - active_transfers_[share_target.id] = share_target; - if (TransferMetadata::IsFinalStatus(transfer_metadata.status())) { - active_transfers_.erase(share_target.id); - } - } - - std::string event = - receive_mode && - transfer_metadata.status() == - TransferMetadata::Status::kAwaitingLocalConfirmation - ? "incoming_transfer" - : "transfer_update"; - Emit(nlohmann::json{ - {"event", event}, - {"direction", receive_mode ? "receive" : "send"}, - {"share_target", ShareTargetToJson(share_target)}, - {"transfer", - TransferMetadataToJson(transfer_metadata, attachment_container)}, - }); -} - -void DaemonService::OnShareTargetDiscovered(const ShareTarget& share_target) { - { - absl::MutexLock lock(lock_); - targets_[share_target.id] = share_target; - } - Emit(nlohmann::json{{"event", "target_discovered"}, - {"share_target", ShareTargetToJson(share_target)}}); -} - -void DaemonService::OnShareTargetUpdated(const ShareTarget& share_target) { - { - absl::MutexLock lock(lock_); - targets_[share_target.id] = share_target; - } - Emit(nlohmann::json{{"event", "target_updated"}, - {"share_target", ShareTargetToJson(share_target)}}); -} - -void DaemonService::OnShareTargetLost(const ShareTarget& share_target) { - { - absl::MutexLock lock(lock_); - targets_.erase(share_target.id); - } - Emit(nlohmann::json{{"event", "target_lost"}, - {"share_target", ShareTargetToJson(share_target)}}); -} - -nlohmann::json DaemonService::InvokeStatusCommand( - const std::string& command, - std::function)> - invoker) { - NearbySharingService::StatusCodes status = WaitForStatus(std::move(invoker)); - bool ok = status == NearbySharingService::StatusCodes::kOk; - return CommandResult(command, ok, StatusCodeToString(status)); -} - -std::optional DaemonService::GetRequiredTargetId( - const nlohmann::json& request, nlohmann::json& error) const { - if (!request.contains("share_target_id") || - !request["share_target_id"].is_number_integer()) { - error = CommandResult("", false, "missing integer field: share_target_id"); - return std::nullopt; - } - return request["share_target_id"].get(); -} - -void DaemonService::Emit(nlohmann::json event) { - if (event_sink_) { - event_sink_(std::move(event)); - } -} - -void DaemonService::TransferCallback::OnTransferUpdate( - const ShareTarget& share_target, - const AttachmentContainer& attachment_container, - const TransferMetadata& transfer_metadata) { - daemon_.OnTransferUpdate(receive_mode_, share_target, attachment_container, - transfer_metadata); -} - -void DaemonService::DiscoveryCallback::OnShareTargetDiscovered( - const ShareTarget& share_target) { - daemon_.OnShareTargetDiscovered(share_target); -} - -void DaemonService::DiscoveryCallback::OnShareTargetLost( - const ShareTarget& share_target) { - daemon_.OnShareTargetLost(share_target); -} - -void DaemonService::DiscoveryCallback::OnShareTargetUpdated( - const ShareTarget& share_target) { - daemon_.OnShareTargetUpdated(share_target); -} - -} // namespace nearby::sharing::linux diff --git a/sharing/linux/daemon/daemon_service.h b/sharing/linux/daemon/daemon_service.h deleted file mode 100644 index 5348d8b4..00000000 --- a/sharing/linux/daemon/daemon_service.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef SHARING_LINUX_DAEMON_DAEMON_SERVICE_H_ -#define SHARING_LINUX_DAEMON_DAEMON_SERVICE_H_ - -#include -#include -#include -#include -#include - -#include "absl/synchronization/mutex.h" -#include "nlohmann/json.hpp" -#include "sharing/attachment_container.h" -#include "sharing/nearby_sharing_service.h" -#include "sharing/share_target.h" -#include "sharing/share_target_discovered_callback.h" -#include "sharing/transfer_metadata.h" -#include "sharing/transfer_update_callback.h" - -namespace nearby::sharing::linux { - -// Owns the daemon-facing state and translates JSON IPC commands into -// NearbySharingService operations. This class does not own `service`; callers -// must keep the service alive for the lifetime of DaemonService. -class DaemonService { - public: - // Receives asynchronous daemon events, such as discovered targets and - // transfer updates, serialized as JSON objects. - using EventSink = std::function; - - // Creates a daemon adapter around `service` and publishes asynchronous events - // to `event_sink`. - DaemonService(NearbySharingService& service, EventSink event_sink); - - // Stops registered surfaces and shuts down the wrapped Nearby service. - ~DaemonService(); - - DaemonService(const DaemonService&) = delete; - DaemonService& operator=(const DaemonService&) = delete; - - // Handles one JSON IPC command and returns a command_result JSON object. - // The request must contain a string `command` field. - nlohmann::json HandleCommand(const nlohmann::json& request); - - // Idempotently unregisters active surfaces, clears daemon state, and shuts - // down the wrapped Nearby service. - void Shutdown(); - - private: - // Receives send or receive transfer updates from NearbySharingService and - // forwards them back into DaemonService with direction context. - class TransferCallback final : public TransferUpdateCallback { - public: - // Creates a transfer callback. `receive_mode` distinguishes receive events - // from send events when serializing daemon events. - explicit TransferCallback(DaemonService& daemon, bool receive_mode) - : daemon_(daemon), receive_mode_(receive_mode) {} - - // Forwards a Nearby transfer update to the daemon event pipeline. - void OnTransferUpdate(const ShareTarget& share_target, - const AttachmentContainer& attachment_container, - const TransferMetadata& transfer_metadata) override; - - private: - DaemonService& daemon_; - bool receive_mode_; - }; - - // Receives discovered target lifecycle events from NearbySharingService and - // forwards them back into DaemonService. - class DiscoveryCallback final : public ShareTargetDiscoveredCallback { - public: - // Creates a discovery callback bound to `daemon`. - explicit DiscoveryCallback(DaemonService& daemon) : daemon_(daemon) {} - - // Records and emits a newly discovered share target. - void OnShareTargetDiscovered(const ShareTarget& share_target) override; - - // Removes and emits a lost share target. - void OnShareTargetLost(const ShareTarget& share_target) override; - - // Updates and emits an existing share target. - void OnShareTargetUpdated(const ShareTarget& share_target) override; - - private: - DaemonService& daemon_; - }; - - // Registers the foreground receive surface used for incoming transfers. - nlohmann::json StartReceive(); - - // Unregisters the foreground receive surface if it is active. - nlohmann::json StopReceive(); - - // Registers the foreground send surface used for discovery and outgoing - // transfer updates. - nlohmann::json StartDiscovery(); - - // Unregisters the foreground send surface and clears discovered targets. - nlohmann::json StopDiscovery(); - - // Sends the regular file named by request field `path` to request field - // `share_target_id`. - nlohmann::json SendFile(const nlohmann::json& request); - - // Accepts an incoming share identified by request field `share_target_id`. - nlohmann::json Accept(const nlohmann::json& request); - - // Rejects an incoming share identified by request field `share_target_id`. - nlohmann::json Reject(const nlohmann::json& request); - - // Cancels a transfer identified by request field `share_target_id`. - nlohmann::json Cancel(const nlohmann::json& request); - - // Returns current daemon/service state, including registered surfaces and - // discovered targets. - nlohmann::json Status(); - - // Updates active transfer state and emits either `incoming_transfer` or - // `transfer_update`. - void OnTransferUpdate(bool receive_mode, const ShareTarget& share_target, - const AttachmentContainer& attachment_container, - const TransferMetadata& transfer_metadata); - - // Stores and emits a newly discovered target. - void OnShareTargetDiscovered(const ShareTarget& share_target); - - // Stores and emits an updated target. - void OnShareTargetUpdated(const ShareTarget& share_target); - - // Removes and emits a lost target. - void OnShareTargetLost(const ShareTarget& share_target); - - // Runs an asynchronous Nearby operation synchronously and converts its status - // callback into a command_result JSON object. - nlohmann::json InvokeStatusCommand( - const std::string& command, - std::function)> - invoker); - - // Extracts request field `share_target_id`; writes a command_result-style - // error object and returns nullopt when the field is absent or not integral. - std::optional GetRequiredTargetId(const nlohmann::json& request, - nlohmann::json& error) const; - - // Publishes an asynchronous event through the configured EventSink. - void Emit(nlohmann::json event); - - NearbySharingService& service_; - EventSink event_sink_; - TransferCallback send_transfer_callback_; - TransferCallback receive_transfer_callback_; - DiscoveryCallback discovery_callback_; - mutable absl::Mutex lock_; - std::unordered_map targets_; - std::unordered_map active_transfers_; - bool receive_registered_ = false; - bool discovery_registered_ = false; - bool shutdown_ = false; -}; - -// Serializes the subset of ShareTarget fields exposed through daemon IPC. -nlohmann::json ShareTargetToJson(const ShareTarget& share_target); - -// Serializes transfer progress and attachment totals exposed through daemon -// IPC. -nlohmann::json TransferMetadataToJson( - const TransferMetadata& transfer_metadata, - const AttachmentContainer& attachment_container); - -} // namespace nearby::sharing::linux - -#endif // SHARING_LINUX_DAEMON_DAEMON_SERVICE_H_ diff --git a/sharing/linux/daemon/daemon_service_test.cc b/sharing/linux/daemon/daemon_service_test.cc deleted file mode 100644 index 77c86a7d..00000000 --- a/sharing/linux/daemon/daemon_service_test.cc +++ /dev/null @@ -1,306 +0,0 @@ -#include "sharing/linux/daemon/daemon_service.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/time/time.h" -#include "nlohmann/json.hpp" -#include "sharing/attachment_container.h" -#include "sharing/nearby_sharing_service.h" -#include "sharing/share_target.h" -#include "sharing/share_target_discovered_callback.h" -#include "sharing/transfer_metadata.h" -#include "sharing/transfer_metadata_builder.h" -#include "sharing/transfer_update_callback.h" - -namespace nearby::sharing::linux { -namespace { - -ShareTarget MakeTarget(int64_t id, std::string name = "Pixel") { - ShareTarget target; - target.id = id; - target.device_name = std::move(name); - return target; -} - -std::unique_ptr MakeAttachments() { - AttachmentContainer::Builder builder; - return builder.Build(); -} - -TransferMetadata MakeMetadata(TransferMetadata::Status status) { - return TransferMetadataBuilder() - .set_status(status) - .set_progress(status == TransferMetadata::Status::kComplete ? 100 : 25) - .set_total_attachments_count(1) - .build(); -} - -class FakeDaemonNearbySharingService final : public NearbySharingService { - public: - void AddObserver(Observer* observer) override { static_cast(observer); } - void RemoveObserver(Observer* observer) override { - static_cast(observer); - } - void Shutdown(std::function callback) override { - shutdown_called = true; - callback(StatusCodes::kOk); - } - void RegisterSendSurface( - TransferUpdateCallback* transfer_callback, - ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, - Advertisement::BlockedVendorId blocked_vendor_id, - bool disable_wifi_hotspot, - absl::AnyInvocable callback) override { - static_cast(blocked_vendor_id); - static_cast(disable_wifi_hotspot); - send_transfer_callback = transfer_callback; - this->discovery_callback = discovery_callback; - send_state = state; - callback(StatusCodes::kOk); - } - void UnregisterSendSurface( - TransferUpdateCallback* transfer_callback, - absl::AnyInvocable callback) override { - if (send_transfer_callback == transfer_callback) { - send_transfer_callback = nullptr; - discovery_callback = nullptr; - } - callback(StatusCodes::kOk); - } - void RegisterReceiveSurface( - TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, - Advertisement::BlockedVendorId vendor_id, - absl::AnyInvocable callback) override { - static_cast(vendor_id); - receive_transfer_callback = transfer_callback; - receive_state = state; - callback(StatusCodes::kOk); - } - void UnregisterReceiveSurface( - TransferUpdateCallback* transfer_callback, - absl::AnyInvocable callback) override { - if (receive_transfer_callback == transfer_callback) { - receive_transfer_callback = nullptr; - } - callback(StatusCodes::kOk); - } - void ClearForegroundReceiveSurfaces( - absl::AnyInvocable callback) override { - callback(StatusCodes::kOk); - } - bool IsTransferring() const override { return false; } - bool IsScanning() const override { return discovery_callback != nullptr; } - bool IsBluetoothPresent() const override { return true; } - bool IsBluetoothPowered() const override { return true; } - bool IsExtendedAdvertisingSupported() const override { return true; } - bool IsLanConnected() const override { return true; } - std::string GetQrCodeUrl() const override { return ""; } - void SendAttachments( - int64_t share_target_id, - std::unique_ptr attachment_container, - std::function callback) override { - last_send_target_id = share_target_id; - last_attachment_count = attachment_container == nullptr - ? 0 - : attachment_container->GetAttachmentCount(); - callback(StatusCodes::kOk); - } - void Accept(int64_t share_target_id, - std::function callback) override { - last_accept_target_id = share_target_id; - callback(StatusCodes::kOk); - } - void Reject(int64_t share_target_id, - std::function callback) override { - last_reject_target_id = share_target_id; - callback(StatusCodes::kOk); - } - void Cancel(int64_t share_target_id, - std::function callback) override { - last_cancel_target_id = share_target_id; - callback(StatusCodes::kOk); - } - void InitiatePairing( - int64_t share_target_id, - service::proto::BindingRequest::Type binding_type, - absl::AnyInvocable callback) override { - static_cast(share_target_id); - static_cast(binding_type); - std::move(callback)(StatusCodes::kOk); - } - void SetVisibility( - proto::DeviceVisibility visibility, absl::Duration expiration, - absl::AnyInvocable callback) override { - static_cast(visibility); - static_cast(expiration); - std::move(callback)(StatusCodes::kOk); - } - std::string Dump() const override { return ""; } - void UpdateFilePathsInProgress(bool update_file_paths) override { - static_cast(update_file_paths); - } - NearbyShareSettings* GetSettings() override { return nullptr; } - NearbyShareCertificateManager* GetCertificateManager() override { - return nullptr; - } - AccountManager* GetAccountManager() override { return nullptr; } - Clock& GetClock() override { throw std::logic_error("unused"); } - void SetAlternateServiceUuidForDiscovery(uint16_t uuid) override { - static_cast(uuid); - } - SyncManager& sync_manager() override { throw std::logic_error("unused"); } - OutgoingTargetsManager& outgoing_targets_manager() override { - throw std::logic_error("unused"); - } - void UpdateBackupSavePath( - absl::string_view binding_id, absl::string_view save_path, - absl::AnyInvocable callback) - override { - static_cast(binding_id); - static_cast(save_path); - callback(StatusCodes::kOk); - } - - void FireShareTargetDiscovered(const ShareTarget& target) { - discovery_callback->OnShareTargetDiscovered(target); - } - void FireShareTargetLost(const ShareTarget& target) { - discovery_callback->OnShareTargetLost(target); - } - void FireReceiveTransferUpdate(const ShareTarget& target, - const AttachmentContainer& attachments, - const TransferMetadata& metadata) { - receive_transfer_callback->OnTransferUpdate(target, attachments, metadata); - } - - TransferUpdateCallback* send_transfer_callback = nullptr; - TransferUpdateCallback* receive_transfer_callback = nullptr; - ShareTargetDiscoveredCallback* discovery_callback = nullptr; - SendSurfaceState send_state = SendSurfaceState::kUnknown; - ReceiveSurfaceState receive_state = ReceiveSurfaceState::kUnknown; - bool shutdown_called = false; - int64_t last_send_target_id = 0; - size_t last_attachment_count = 0; - int64_t last_accept_target_id = 0; - int64_t last_reject_target_id = 0; - int64_t last_cancel_target_id = 0; -}; - -class DaemonServiceTest : public ::testing::Test { - protected: - DaemonServiceTest() - : daemon_(service_, [this](const nlohmann::json& event) { - events_.push_back(event); - }) {} - - FakeDaemonNearbySharingService service_; - std::vector events_; - DaemonService daemon_; -}; - -TEST_F(DaemonServiceTest, StartDiscoveryPublishesDiscoveredTargets) { - nlohmann::json result = - daemon_.HandleCommand({{"command", "start_discovery"}}); - ASSERT_TRUE(result["ok"].get()); - - service_.FireShareTargetDiscovered(MakeTarget(42)); - - ASSERT_EQ(events_.size(), 1u); - EXPECT_EQ(events_[0]["event"], "target_discovered"); - EXPECT_EQ(events_[0]["share_target"]["id"], 42); - EXPECT_EQ(events_[0]["share_target"]["device_name"], "Pixel"); - - nlohmann::json status = daemon_.HandleCommand({{"command", "status"}}); - ASSERT_TRUE(status["ok"].get()); - ASSERT_EQ(status["targets"].size(), 1u); - EXPECT_EQ(status["targets"][0]["id"], 42); -} - -TEST_F(DaemonServiceTest, TargetLostRemovesTargetFromStatus) { - ASSERT_TRUE( - daemon_.HandleCommand({{"command", "start_discovery"}})["ok"].get()); - ShareTarget target = MakeTarget(7); - service_.FireShareTargetDiscovered(target); - service_.FireShareTargetLost(target); - - ASSERT_EQ(events_.size(), 2u); - EXPECT_EQ(events_[1]["event"], "target_lost"); - - nlohmann::json status = daemon_.HandleCommand({{"command", "status"}}); - ASSERT_TRUE(status["ok"].get()); - EXPECT_TRUE(status["targets"].empty()); -} - -TEST_F(DaemonServiceTest, ReceiveAwaitingConfirmationPublishesIncomingTransfer) { - ASSERT_TRUE( - daemon_.HandleCommand({{"command", "start_receive"}})["ok"].get()); - - auto attachments = MakeAttachments(); - service_.FireReceiveTransferUpdate( - MakeTarget(9), *attachments, - MakeMetadata(TransferMetadata::Status::kAwaitingLocalConfirmation)); - - ASSERT_EQ(events_.size(), 1u); - EXPECT_EQ(events_[0]["event"], "incoming_transfer"); - EXPECT_EQ(events_[0]["direction"], "receive"); - EXPECT_EQ(events_[0]["share_target"]["id"], 9); - EXPECT_EQ(events_[0]["transfer"]["status"], "kAwaitingLocalConfirmation"); -} - -TEST_F(DaemonServiceTest, AcceptRejectAndCancelReturnCommandResults) { - EXPECT_TRUE(daemon_.HandleCommand({{"command", "accept"}, - {"share_target_id", 1}})["ok"] - .get()); - EXPECT_EQ(service_.last_accept_target_id, 1); - EXPECT_TRUE(daemon_.HandleCommand({{"command", "reject"}, - {"share_target_id", 1}})["ok"] - .get()); - EXPECT_EQ(service_.last_reject_target_id, 1); - EXPECT_TRUE(daemon_.HandleCommand({{"command", "cancel"}, - {"share_target_id", 1}})["ok"] - .get()); - EXPECT_EQ(service_.last_cancel_target_id, 1); -} - -TEST_F(DaemonServiceTest, SendFileRejectsUnknownTarget) { - nlohmann::json result = daemon_.HandleCommand( - {{"command", "send_file"}, {"share_target_id", 404}, {"path", "/tmp/x"}}); - EXPECT_FALSE(result["ok"].get()); -} - -TEST_F(DaemonServiceTest, SendFileToKnownTargetReturnsOkForRegularFile) { - ASSERT_TRUE( - daemon_.HandleCommand({{"command", "start_discovery"}})["ok"].get()); - service_.FireShareTargetDiscovered(MakeTarget(12)); - - const std::string path = "/tmp/nearby_daemon_service_test_file"; - { - std::ofstream file(path); - file << "hello"; - } - - nlohmann::json result = daemon_.HandleCommand( - {{"command", "send_file"}, {"share_target_id", 12}, {"path", path}}); - EXPECT_TRUE(result["ok"].get()) << result.dump(); - EXPECT_EQ(service_.last_send_target_id, 12); - EXPECT_EQ(service_.last_attachment_count, 1u); - std::remove(path.c_str()); -} - -TEST_F(DaemonServiceTest, MalformedCommandReturnsError) { - nlohmann::json result = daemon_.HandleCommand({{"path", "/tmp/x"}}); - EXPECT_FALSE(result["ok"].get()); -} - -} // namespace -} // namespace nearby::sharing::linux diff --git a/sharing/linux/daemon/ipc_server.cc b/sharing/linux/daemon/ipc_server.cc deleted file mode 100644 index 83c47b94..00000000 --- a/sharing/linux/daemon/ipc_server.cc +++ /dev/null @@ -1,263 +0,0 @@ -#include "ipc_server.h" - -#include -#include -#include -#include - -namespace { - -nlohmann::json CommandResult(std::string command, bool ok, - std::string message) { - return nlohmann::json{{"event", "command_result"}, - {"command", std::move(command)}, - {"ok", ok}, - {"message", std::move(message)}}; -} - -} // namespace - -std::string IPCServer::Read() { - std::string cmd; - absl::MutexLock lock(lock_); - - size_t pos = read_buf.find('\n'); - - if (pos != std::string::npos) { - cmd = read_buf.substr(0, pos); - read_buf.erase(0, pos + 1); - } - - return cmd; -} - -void IPCServer::Stop() { - running_.store(false); - - { - absl::MutexLock write_lock(write_lock_); - if (client_fd_ >= 0) { - shutdown(client_fd_, SHUT_RDWR); - close(client_fd_); - client_fd_ = -1; - } - - if (sock_fd_ >= 0) { - shutdown(sock_fd_, SHUT_RDWR); - close(sock_fd_); - sock_fd_ = -1; - } - } - - unlink(SOCK_PATH.data()); -} - -void IPCServer::InitialiseSock() { - sock_fd_ = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock_fd_ == -1) { - return; - } - - unlink(SOCK_PATH.data()); - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, SOCK_PATH.data(), sizeof(addr.sun_path) - 1); - - if (bind(sock_fd_, reinterpret_cast(&addr), sizeof(addr)) == -1) { - close(sock_fd_); - sock_fd_ = -1; - return; - } - - if (listen(sock_fd_, 1) == -1) { - close(sock_fd_); - sock_fd_ = -1; - return; - } -} -void IPCServer::Recv() { - while (running_.load()) { - pollfd pfd{}; - pfd.fd = client_fd_; - pfd.events = POLLIN; - - int poll_result = poll(&pfd, 1, 100); - - if (!running_.load()) { - return; - } - - if (poll_result < 0) { - if (errno == EINTR) { - continue; - } - return; - } - - if (poll_result == 0) { - continue; - } - - if (pfd.revents & (POLLNVAL | POLLERR)) { - return; - } - - if (pfd.revents & (POLLIN | POLLHUP)) { - char buf[1024]{}; - - ssize_t n = recv(client_fd_, buf, sizeof(buf), 0); - - if (n > 0) { - absl::MutexLock lock(lock_); - read_buf.append(buf, static_cast(n)); - continue; - } - - if (n == 0) { - return; - } - - if (errno == EINTR) { - continue; - } - - if (errno == EAGAIN || errno == EWOULDBLOCK) { - continue; - } - - return; - } - } -} - -void IPCServer::StartEventLoop() { - started_.store(true); - running_.store(true); - - InitialiseSock(); - - if (sock_fd_ < 0) { - running_.store(false); - return; - } - - while (running_.load()) { - sockaddr_un client_addr{}; - socklen_t addr_len = sizeof(client_addr); - - int accepted_fd = - accept(sock_fd_, reinterpret_cast(&client_addr), &addr_len); - - if (!running_.load()) { - if (accepted_fd >= 0) { - close(accepted_fd); - } - break; - } - - if (accepted_fd < 0) { - if (errno == EINTR) { - continue; - } - break; - } - - { - absl::MutexLock write_lock(write_lock_); - client_fd_ = accepted_fd; - } - - Recv(); - - { - absl::MutexLock write_lock(write_lock_); - if (client_fd_ >= 0) { - close(client_fd_); - client_fd_ = -1; - } - } - } - - Stop(); -} - -bool IPCServer::SendLine(std::string_view line) { - absl::MutexLock write_lock(write_lock_); - if (client_fd_ < 0) { - return false; - } - - std::string data(line); - if (data.empty() || data.back() != '\n') { - data.push_back('\n'); - } - - size_t total_sent = 0; - while (total_sent < data.size()) { - ssize_t sent = - send(client_fd_, data.data() + total_sent, data.size() - total_sent, 0); - if (sent > 0) { - total_sent += static_cast(sent); - continue; - } - if (sent < 0 && errno == EINTR) { - continue; - } - return false; - } - - return true; -} - -bool IPCServer::SendJson(const nlohmann::json& message) { - return SendLine(message.dump()); -} - -void IPCServer::DispatchOne(const std::string& line) { - nlohmann::json request; - try { - request = nlohmann::json::parse(line); - } catch (const nlohmann::json::exception& e) { - SendJson(CommandResult("", false, std::string("malformed JSON: ") + e.what())); - return; - } - - if (!request.is_object() || !request.contains("command") || - !request["command"].is_string()) { - SendJson(CommandResult("", false, "missing string field: command")); - return; - } - std::string command = request["command"].get(); - - Handler handler; - - { - absl::MutexLock lock(lock_); - - auto it = handlers_.find(command); - if (it == handlers_.end()) { - SendJson(CommandResult(command, false, "unknown command")); - return; - } - - handler = it->second; - } - - handler(request); -} -void IPCServer::DispatchLoop() { - while (true) { - std::string line = Read(); - - if (line.empty()) { - if (!running_.load() && started_.load()) { - return; - } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - continue; - } - - DispatchOne(line); - } -} diff --git a/sharing/linux/daemon/ipc_server.h b/sharing/linux/daemon/ipc_server.h deleted file mode 100644 index 8c833710..00000000 --- a/sharing/linux/daemon/ipc_server.h +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "absl/synchronization/mutex.h" -#include "gtest/gtest_prod.h" -#include "nlohmann/json.hpp" - -constexpr std::string_view SOCK_PATH = "/tmp/nearby_sharing_sock"; - -class IPCServer { - public: - IPCServer() = default; - - ~IPCServer() { Stop(); } - void Stop(); - void StartEventLoop(); - using Handler = std::function; - - void RegisterHandler(std::string command, Handler handler) { - absl::MutexLock lock(lock_); - handlers_[std::move(command)] = std::move(handler); - } - - bool SendLine(std::string_view line); - bool SendJson(const nlohmann::json& message); - void DispatchLoop(); - - private: - friend class IPCServerTest; - - void DispatchOne(const std::string& line); - void InitialiseSock(); - void Recv(); - std::string Read(); - - int sock_fd_ = -1; - int client_fd_ = -1; - sockaddr_un addr{}; - std::string read_buf; - absl::Mutex lock_; - absl::Mutex write_lock_; - std::unordered_map handlers_; - std::atomic running_{false}; - std::atomic started_{false}; -}; diff --git a/sharing/linux/daemon/ipc_server_test.cc b/sharing/linux/daemon/ipc_server_test.cc deleted file mode 100644 index 793fb546..00000000 --- a/sharing/linux/daemon/ipc_server_test.cc +++ /dev/null @@ -1,452 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ipc_server.h" - -class IPCServerTest : public ::testing::Test { - protected: - static std::string Read(IPCServer& server) { - return server.Read(); - } - - static void DispatchOne(IPCServer& server, const std::string& line) { - server.DispatchOne(line); - } - - static void SetReadBuffer(IPCServer& server, std::string value) { - absl::MutexLock lock(server.lock_); - server.read_buf = std::move(value); - } - - static void SetRunning(IPCServer& server, bool running) { - server.running_.store(running); - server.started_.store(true); - } - - static bool IsRunning(IPCServer& server) { - return server.running_.load(); - } - - static std::string WaitRead(IPCServer& server) { - for (int i = 0; i < 100; ++i) { - std::string cmd = Read(server); - - if (!cmd.empty()) { - return cmd; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - return ""; - } - - static bool WaitUntilTrue(const std::function& condition) { - for (int i = 0; i < 100; ++i) { - if (condition()) { - return true; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - return false; - } -}; - -namespace { - -int ConnectClientWithRetry() { - int client_fd = socket(AF_UNIX, SOCK_STREAM, 0); - EXPECT_GE(client_fd, 0); - - sockaddr_un addr {}; - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, SOCK_PATH.data(), sizeof(addr.sun_path) - 1); - - for (int i = 0; i < 100; ++i) { - int result = connect( - client_fd, - reinterpret_cast(&addr), - sizeof(addr)); - - if (result == 0) { - return client_fd; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - ADD_FAILURE() << "connect failed: " << strerror(errno); - close(client_fd); - return -1; -} - -void SendAll(int fd, std::string_view data) { - size_t total_sent = 0; - - while (total_sent < data.size()) { - ssize_t sent = send( - fd, - data.data() + total_sent, - data.size() - total_sent, - 0); - - ASSERT_GT(sent, 0) << "send failed: " << strerror(errno); - - total_sent += static_cast(sent); - } -} - -void StopAndJoin(IPCServer& server, std::thread& server_thread) { - server.Stop(); - - if (server_thread.joinable()) { - server_thread.join(); - } - - unlink(SOCK_PATH.data()); -} - -} // namespace - -TEST_F(IPCServerTest, ServerCanReadMultipleCommands) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - SendAll(client_fd, "A\nB\nC\n"); - - EXPECT_EQ(WaitRead(server), "A"); - EXPECT_EQ(WaitRead(server), "B"); - EXPECT_EQ(WaitRead(server), "C"); - - close(client_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, PartialCommandIsBufferedUntilDelimiter) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - SendAll(client_fd, "PIN"); - - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - - EXPECT_EQ(Read(server), ""); - - SendAll(client_fd, "G\n"); - - EXPECT_EQ(WaitRead(server), "PING"); - - close(client_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, LargeCommandAcrossMultipleRecvCalls) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - std::string large(8192, 'A'); - SendAll(client_fd, large + "\n"); - - EXPECT_EQ(WaitRead(server), large); - - close(client_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, MultipleCommandsSplitAcrossSends) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - SendAll(client_fd, "A\nB"); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - SendAll(client_fd, "\nC\n"); - - EXPECT_EQ(WaitRead(server), "A"); - EXPECT_EQ(WaitRead(server), "B"); - EXPECT_EQ(WaitRead(server), "C"); - - close(client_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, ClientDisconnectDoesNotCrashServer) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - close(client_fd); - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - StopAndJoin(server, server_thread); - - SUCCEED(); -} - -TEST_F(IPCServerTest, ClientCanReconnectAfterDisconnect) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client1_fd = ConnectClientWithRetry(); - ASSERT_GE(client1_fd, 0); - - SendAll(client1_fd, "FIRST\n"); - EXPECT_EQ(WaitRead(server), "FIRST"); - - close(client1_fd); - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - int client2_fd = ConnectClientWithRetry(); - ASSERT_GE(client2_fd, 0); - - SendAll(client2_fd, "SECOND\n"); - EXPECT_EQ(WaitRead(server), "SECOND"); - - close(client2_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, StopEndsEventLoopThread) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - - StopAndJoin(server, server_thread); - - SUCCEED(); -} - -TEST_F(IPCServerTest, StopWhileClientConnected) { - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - SendAll(client_fd, "PING\n"); - EXPECT_EQ(WaitRead(server), "PING"); - - StopAndJoin(server, server_thread); - - close(client_fd); - - SUCCEED(); -} - -TEST_F(IPCServerTest, StaleSocketPathIsCleanedUp) { - unlink(SOCK_PATH.data()); - - { - std::ofstream stale_file{SOCK_PATH.data()}; - ASSERT_TRUE(stale_file.is_open()); - stale_file << "stale"; - } - - struct stat before {}; - ASSERT_EQ(stat(SOCK_PATH.data(), &before), 0); - ASSERT_TRUE(S_ISREG(before.st_mode)); - - IPCServer server; - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - struct stat after {}; - ASSERT_EQ(stat(SOCK_PATH.data(), &after), 0); - EXPECT_TRUE(S_ISSOCK(after.st_mode)); - - close(client_fd); - StopAndJoin(server, server_thread); -} - -TEST_F(IPCServerTest, DispatchOneCallsRegisteredHandler) { - IPCServer server; - - bool called = false; - - server.RegisterHandler("PING", [&](const nlohmann::json& request) { - EXPECT_EQ(request.value("command", ""), "PING"); - called = true; - }); - - DispatchOne(server, R"({"command":"PING"})"); - - EXPECT_TRUE(called); -} - -TEST_F(IPCServerTest, DispatchOnePassesArguments) { - IPCServer server; - - std::string received_args; - - server.RegisterHandler("ECHO", [&](const nlohmann::json& request) { - received_args = request.value("args", ""); - }); - - DispatchOne(server, R"({"command":"ECHO","args":"hello world"})"); - - EXPECT_EQ(received_args, "hello world"); -} - -TEST_F(IPCServerTest, DispatchOneHandlesCommandWithoutArgs) { - IPCServer server; - - std::string received_args = "not empty"; - - server.RegisterHandler("PING", [&](const nlohmann::json& request) { - received_args = request.value("args", ""); - }); - - DispatchOne(server, R"({"command":"PING"})"); - - EXPECT_EQ(received_args, ""); -} - -TEST_F(IPCServerTest, DispatchOneIgnoresUnknownCommand) { - IPCServer server; - - bool called = false; - - server.RegisterHandler("PING", [&](const nlohmann::json& request) { - called = true; - }); - - DispatchOne(server, R"({"command":"UNKNOWN","args":"something"})"); - - EXPECT_FALSE(called); -} - -TEST_F(IPCServerTest, DispatchLoopDispatchesBufferedCommand) { - IPCServer server; - - std::atomic called{false}; - std::string received_args; - - server.RegisterHandler("ECHO", [&](const nlohmann::json& request) { - received_args = request.value("args", ""); - called.store(true); - }); - - SetReadBuffer(server, R"({"command":"ECHO","args":"hello"})" - "\n"); - SetRunning(server, true); - - std::thread dispatch_thread([&server]() { - server.DispatchLoop(); - }); - - ASSERT_TRUE(WaitUntilTrue([&]() { - return called.load(); - })); - - SetRunning(server, false); - - dispatch_thread.join(); - - EXPECT_EQ(received_args, "hello"); -} - -TEST_F(IPCServerTest, SocketCommandReachesRegisteredHandler) { - IPCServer server; - - std::atomic called{false}; - std::string received_args; - - server.RegisterHandler("ECHO", [&](const nlohmann::json& request) { - received_args = request.value("args", ""); - called.store(true); - }); - - std::thread server_thread([&server]() { - server.StartEventLoop(); - }); - - int client_fd = ConnectClientWithRetry(); - ASSERT_GE(client_fd, 0); - - std::thread dispatch_thread([&server]() { - server.DispatchLoop(); - }); - - SendAll(client_fd, R"({"command":"ECHO","args":"from socket"})" - "\n"); - - ASSERT_TRUE(WaitUntilTrue([&]() { - return called.load(); - })); - - EXPECT_EQ(received_args, "from socket"); - - close(client_fd); - - server.Stop(); - - if (server_thread.joinable()) { - server_thread.join(); - } - - if (dispatch_thread.joinable()) { - dispatch_thread.join(); - } - - unlink(SOCK_PATH.data()); -} diff --git a/sharing/linux/daemon/main.cc b/sharing/linux/daemon/main.cc index 7ff4ef2f..45efdf16 100644 --- a/sharing/linux/daemon/main.cc +++ b/sharing/linux/daemon/main.cc @@ -8,14 +8,14 @@ #include #include #include -#include + +#include #include "absl/time/time.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "internal/flags/nearby_flags.h" #include "sharing/flags/generated/nearby_sharing_feature_flags.h" -#include "sharing/linux/daemon/daemon_service.h" -#include "sharing/linux/daemon/ipc_server.h" +#include "sharing/linux/daemon/nearby_sharing_dbus_service.h" #include "sharing/linux/nearby_noop_analytics_recorder.h" #include "sharing/linux/platform/linux_sharing_platform.h" #include "sharing/nearby_sharing_service.h" @@ -27,13 +27,13 @@ namespace nearby::sharing::linux { namespace { std::atomic g_interrupted = false; -IPCServer* g_ipc_server = nullptr; +sdbus::IConnection* g_bus = nullptr; void HandleSignal(int signal) { static_cast(signal); g_interrupted = true; - if (g_ipc_server != nullptr) { - g_ipc_server->Stop(); + if (g_bus != nullptr) { + g_bus->leaveEventLoop(); } } @@ -140,35 +140,26 @@ int main(int argc, char** argv) { return 1; } - IPCServer ipc_server; - nearby::sharing::linux::g_ipc_server = &ipc_server; - nearby::sharing::linux::DaemonService daemon( - *service, [&](const nlohmann::json& event) { ipc_server.SendJson(event); }); + auto bus = sdbus::createSessionBusConnection( + sdbus::ServiceName("com.google.nearby.sharing")); + nearby::sharing::linux::g_bus = bus.get(); + auto object = sdbus::createObject( + *bus, sdbus::ObjectPath("/com/google/nearby/sharing")); + nearby::sharing::linux::NearbySharingDbusService dbus_service( + *object, *service, [&bus]() { bus->leaveEventLoop(); }); + dbus_service.EmitStatusChanged(); - const std::string commands[] = { - "status", "start_receive", "stop_receive", "start_discovery", - "stop_discovery", "send_file", "accept", "reject", - "cancel", "shutdown", - }; - for (const std::string& command : commands) { - ipc_server.RegisterHandler(command, [&](const nlohmann::json& request) { - nlohmann::json result = daemon.HandleCommand(request); - ipc_server.SendJson(result); - if (request.value("command", "") == "shutdown") { - ipc_server.Stop(); - } - }); + try { + bus->enterEventLoop(); + } catch (const sdbus::Error& error) { + std::cerr << "D-Bus event loop failed: " << error.getName() << ": " + << error.getMessage() << std::endl; + dbus_service.ShutdownService(); + nearby::sharing::linux::g_bus = nullptr; + return 1; } - std::thread server_thread([&ipc_server]() { ipc_server.StartEventLoop(); }); - std::thread dispatch_thread([&ipc_server]() { ipc_server.DispatchLoop(); }); - - server_thread.join(); - ipc_server.Stop(); - if (dispatch_thread.joinable()) { - dispatch_thread.join(); - } - daemon.Shutdown(); - nearby::sharing::linux::g_ipc_server = nullptr; + dbus_service.ShutdownService(); + nearby::sharing::linux::g_bus = nullptr; return nearby::sharing::linux::g_interrupted ? 130 : 0; } diff --git a/sharing/linux/daemon/main.h b/sharing/linux/daemon/main.h deleted file mode 100644 index aa7a8ec1..00000000 --- a/sharing/linux/daemon/main.h +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "absl/time/time.h" -#include "connections/implementation/flags/nearby_connections_feature_flags.h" -#include "internal/base/file_path.h" -#include "internal/flags/nearby_flags.h" -#include "sharing/advertisement.h" -#include "sharing/attachment_container.h" -#include "sharing/common/nearby_share_enums.h" -#include "sharing/file_attachment.h" -#include "sharing/linux/platform/linux_sharing_platform.h" -#include "sharing/linux/nearby_noop_analytics_recorder.h" -#include "sharing/flags/generated/nearby_sharing_feature_flags.h" -#include "sharing/nearby_sharing_service.h" -#include "sharing/nearby_sharing_service_factory.h" -#include "sharing/nearby_sharing_settings.h" -#include "sharing/share_target.h" -#include "sharing/share_target_discovered_callback.h" -#include "sharing/transfer_metadata.h" -#include "sharing/transfer_update_callback.h" -#include "sharing/proto/enums.pb.h" - -namespace nearby { -namespace sharing { -namespace linux { - -} -} // namespace sharing -} // namespace nearby - diff --git a/sharing/linux/daemon/nearby_sharing_client.h b/sharing/linux/daemon/nearby_sharing_client.h index 732dd39a..ff3ef2cf 100644 --- a/sharing/linux/daemon/nearby_sharing_client.h +++ b/sharing/linux/daemon/nearby_sharing_client.h @@ -3,8 +3,8 @@ * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! */ -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_sharing_linux_daemon_nearby_sharing_client_h__proxy__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_sharing_linux_daemon_nearby_sharing_client_h__proxy__H__ +#ifndef __sdbuscpp___sharing_linux_daemon_nearby_sharing_client_h__proxy__H__ +#define __sdbuscpp___sharing_linux_daemon_nearby_sharing_client_h__proxy__H__ #include #include diff --git a/sharing/linux/daemon/nearby_sharing_dbus_service.cc b/sharing/linux/daemon/nearby_sharing_dbus_service.cc new file mode 100644 index 00000000..9c7f3260 --- /dev/null +++ b/sharing/linux/daemon/nearby_sharing_dbus_service.cc @@ -0,0 +1,441 @@ +#include "sharing/linux/daemon/nearby_sharing_dbus_service.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "internal/base/file_path.h" +#include "sharing/advertisement.h" +#include "sharing/file_attachment.h" + +namespace nearby::sharing::linux { +namespace { + +std::string StatusCodeToString(NearbySharingService::StatusCodes status) { + return NearbySharingService::StatusCodeToString(status); +} + +std::tuple StatusResult( + NearbySharingService::StatusCodes status) { + return {status == NearbySharingService::StatusCodes::kOk, + StatusCodeToString(status)}; +} + +std::unique_ptr CreateFileAttachments( + const std::string& file_path) { + AttachmentContainer::Builder builder; + builder.AddFileAttachment(FileAttachment(FilePath(file_path))); + return builder.Build(); +} + +template +NearbySharingService::StatusCodes WaitForStatus(Invoker invoker) { + std::mutex mutex; + std::condition_variable cv; + std::optional status; + invoker([&](NearbySharingService::StatusCodes callback_status) { + { + std::lock_guard lock(mutex); + status = callback_status; + } + cv.notify_one(); + }); + + std::unique_lock lock(mutex); + cv.wait(lock, [&] { return status.has_value(); }); + return *status; +} + +} // namespace + +DbusDictionary ShareTargetToDbus(const ShareTarget& share_target) { + DbusDictionary result; + result.emplace("id", sdbus::Variant(share_target.id)); + result.emplace("device_name", sdbus::Variant(share_target.device_name)); + result.emplace("type", + sdbus::Variant(static_cast(share_target.type))); + result.emplace("is_incoming", sdbus::Variant(share_target.is_incoming)); + result.emplace("is_known", sdbus::Variant(share_target.is_known)); + result.emplace("device_id", sdbus::Variant(share_target.device_id)); + result.emplace("for_self_share", sdbus::Variant(share_target.for_self_share)); + result.emplace("vendor_id", + sdbus::Variant(static_cast(share_target.vendor_id))); + result.emplace("receive_disabled", + sdbus::Variant(share_target.receive_disabled)); + return result; +} + +DbusDictionary TransferMetadataToDbus( + const TransferMetadata& transfer_metadata, + const AttachmentContainer& attachment_container) { + DbusDictionary result; + result.emplace("status", sdbus::Variant(TransferMetadata::StatusToString( + transfer_metadata.status()))); + result.emplace( + "progress", + sdbus::Variant(static_cast(transfer_metadata.progress()))); + result.emplace("transferred_bytes", + sdbus::Variant(static_cast( + transfer_metadata.transferred_bytes()))); + result.emplace( + "total_bytes", + sdbus::Variant(attachment_container.GetTotalAttachmentsSize())); + result.emplace( + "transfer_speed", + sdbus::Variant(static_cast(transfer_metadata.transfer_speed()))); + result.emplace("estimated_time_remaining", + sdbus::Variant(static_cast( + transfer_metadata.estimated_time_remaining()))); + result.emplace("total_attachments_count", + sdbus::Variant(transfer_metadata.total_attachments_count())); + result.emplace( + "transferred_attachments_count", + sdbus::Variant(transfer_metadata.transferred_attachments_count())); + result.emplace("is_final_status", + sdbus::Variant(transfer_metadata.is_final_status())); + result.emplace("is_self_share", + sdbus::Variant(transfer_metadata.is_self_share())); + result.emplace("binding_id", sdbus::Variant(transfer_metadata.binding_id())); + + if (transfer_metadata.token().has_value()) { + result.emplace("token", sdbus::Variant(*transfer_metadata.token())); + } + if (transfer_metadata.in_progress_attachment_id().has_value()) { + result.emplace( + "in_progress_attachment_id", + sdbus::Variant(*transfer_metadata.in_progress_attachment_id())); + } + if (transfer_metadata.in_progress_attachment_transferred_bytes() + .has_value()) { + result.emplace( + "in_progress_attachment_transferred_bytes", + sdbus::Variant(static_cast( + *transfer_metadata.in_progress_attachment_transferred_bytes()))); + } + if (transfer_metadata.in_progress_attachment_total_bytes().has_value()) { + result.emplace( + "in_progress_attachment_total_bytes", + sdbus::Variant(static_cast( + *transfer_metadata.in_progress_attachment_total_bytes()))); + } + return result; +} + +NearbySharingDbusService::TransferCallback::TransferCallback( + NearbySharingDbusService& service, bool receive_mode) + : service_(service), receive_mode_(receive_mode) {} + +void NearbySharingDbusService::TransferCallback::OnTransferUpdate( + const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) { + service_.OnTransferUpdate(receive_mode_, share_target, attachment_container, + transfer_metadata); +} + +NearbySharingDbusService::NearbySharingDbusService( + sdbus::IObject& object, NearbySharingService& service, + QuitCallback quit_callback) + : sharing_adaptor(object), + service_(service), + quit_callback_(std::move(quit_callback)), + send_transfer_callback_(*this, /*receive_mode=*/false), + receive_transfer_callback_(*this, /*receive_mode=*/true) { + registerAdaptor(); + service_.AddObserver(this); +} + +NearbySharingDbusService::~NearbySharingDbusService() { + service_.RemoveObserver(this); + ShutdownService(); +} + +void NearbySharingDbusService::EmitStatusChanged() { + emitStatusChanged(StatusToDbus()); +} + +void NearbySharingDbusService::ShutdownService() { + bool stop_receive = false; + bool stop_discovery = false; + { + absl::MutexLock lock(lock_); + if (shutdown_) { + return; + } + shutdown_ = true; + stop_receive = receive_registered_; + stop_discovery = discovery_registered_; + receive_registered_ = false; + discovery_registered_ = false; + targets_.clear(); + } + + if (stop_receive) { + WaitForStatus([&](auto callback) { + service_.UnregisterReceiveSurface(&receive_transfer_callback_, + std::move(callback)); + }); + } + if (stop_discovery) { + WaitForStatus([&](auto callback) { + service_.UnregisterSendSurface(&send_transfer_callback_, + std::move(callback)); + }); + } + WaitForStatus([&](auto callback) { service_.Shutdown(std::move(callback)); }); + EmitStatusChanged(); +} + +std::tuple NearbySharingDbusService::StartReceive() { + { + absl::MutexLock lock(lock_); + if (receive_registered_) { + return {true, "receive already started"}; + } + } + + auto result = InvokeStatusCommand([&](auto callback) { + service_.RegisterReceiveSurface( + &receive_transfer_callback_, + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, std::move(callback)); + }); + if (std::get<0>(result)) { + { + absl::MutexLock lock(lock_); + receive_registered_ = true; + } + EmitStatusChanged(); + } + return result; +} + +std::tuple NearbySharingDbusService::StopReceive() { + { + absl::MutexLock lock(lock_); + if (!receive_registered_) { + return {true, "receive already stopped"}; + } + } + + auto result = InvokeStatusCommand([&](auto callback) { + service_.UnregisterReceiveSurface(&receive_transfer_callback_, + std::move(callback)); + }); + if (std::get<0>(result)) { + { + absl::MutexLock lock(lock_); + receive_registered_ = false; + } + EmitStatusChanged(); + } + return result; +} + +std::tuple NearbySharingDbusService::StartDiscovery() { + { + absl::MutexLock lock(lock_); + if (discovery_registered_) { + return {true, "discovery already started"}; + } + } + + auto result = InvokeStatusCommand([&](auto callback) { + service_.RegisterSendSurface( + &send_transfer_callback_, this, + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + /*disable_wifi_hotspot=*/false, std::move(callback)); + }); + if (std::get<0>(result)) { + { + absl::MutexLock lock(lock_); + discovery_registered_ = true; + } + EmitStatusChanged(); + } + return result; +} + +std::tuple NearbySharingDbusService::StopDiscovery() { + { + absl::MutexLock lock(lock_); + if (!discovery_registered_) { + return {true, "discovery already stopped"}; + } + } + + auto result = InvokeStatusCommand([&](auto callback) { + service_.UnregisterSendSurface(&send_transfer_callback_, + std::move(callback)); + }); + if (std::get<0>(result)) { + { + absl::MutexLock lock(lock_); + discovery_registered_ = false; + targets_.clear(); + } + EmitStatusChanged(); + } + return result; +} + +std::tuple NearbySharingDbusService::SendFile( + const int64_t& share_target_id, const std::string& path) { + std::error_code file_error; + if (!std::filesystem::is_regular_file(path, file_error)) { + return {false, "path is not a regular file"}; + } + + { + absl::MutexLock lock(lock_); + if (targets_.find(share_target_id) == targets_.end()) { + return {false, "unknown share_target_id"}; + } + } + + auto attachments = CreateFileAttachments(path); + return InvokeStatusCommand([&](auto callback) { + service_.SendAttachments(share_target_id, std::move(attachments), + std::move(callback)); + }); +} + +std::tuple NearbySharingDbusService::Accept( + const int64_t& share_target_id) { + return InvokeStatusCommand([&](auto callback) { + service_.Accept(share_target_id, std::move(callback)); + }); +} + +std::tuple NearbySharingDbusService::Reject( + const int64_t& share_target_id) { + return InvokeStatusCommand([&](auto callback) { + service_.Reject(share_target_id, std::move(callback)); + }); +} + +std::tuple NearbySharingDbusService::Cancel( + const int64_t& share_target_id) { + return InvokeStatusCommand([&](auto callback) { + service_.Cancel(share_target_id, std::move(callback)); + }); +} + +std::tuple NearbySharingDbusService::Shutdown() { + ShutdownService(); + if (quit_callback_) { + quit_callback_(); + } + return {true, "daemon service shut down"}; +} + +std::tuple NearbySharingDbusService::InvokeStatusCommand( + std::function)> + invoker) { + return StatusResult(WaitForStatus(std::move(invoker))); +} + +DbusDictionary NearbySharingDbusService::StatusToDbus() const { + std::vector targets; + bool receive_registered = false; + bool discovery_registered = false; + { + absl::MutexLock lock(lock_); + receive_registered = receive_registered_; + discovery_registered = discovery_registered_; + targets.reserve(targets_.size()); + for (const auto& [id, target] : targets_) { + static_cast(id); + targets.push_back(ShareTargetToDbus(target)); + } + } + + DbusDictionary status; + status.emplace("receive_registered", sdbus::Variant(receive_registered)); + status.emplace("discovery_registered", sdbus::Variant(discovery_registered)); + status.emplace("is_transferring", sdbus::Variant(service_.IsTransferring())); + status.emplace("is_scanning", sdbus::Variant(service_.IsScanning())); + status.emplace("bluetooth_present", + sdbus::Variant(service_.IsBluetoothPresent())); + status.emplace("bluetooth_powered", + sdbus::Variant(service_.IsBluetoothPowered())); + status.emplace("lan_connected", sdbus::Variant(service_.IsLanConnected())); + status.emplace("targets", sdbus::Variant(targets)); + return status; +} + +void NearbySharingDbusService::OnTransferUpdate( + bool receive_mode, const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) { + const std::string direction = receive_mode ? "receive" : "send"; + const DbusDictionary target = ShareTargetToDbus(share_target); + const DbusDictionary transfer = + TransferMetadataToDbus(transfer_metadata, attachment_container); + + if (receive_mode && + transfer_metadata.status() == + TransferMetadata::Status::kAwaitingLocalConfirmation) { + emitIncomingTransfer(direction, target, transfer); + } else { + emitTransferUpdate(direction, target, transfer); + } + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnShareTargetDiscovered( + const ShareTarget& share_target) { + { + absl::MutexLock lock(lock_); + targets_[share_target.id] = share_target; + } + emitTargetDiscovered(ShareTargetToDbus(share_target)); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnShareTargetLost( + const ShareTarget& share_target) { + { + absl::MutexLock lock(lock_); + targets_.erase(share_target.id); + } + emitTargetLost(ShareTargetToDbus(share_target)); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnShareTargetUpdated( + const ShareTarget& share_target) { + { + absl::MutexLock lock(lock_); + targets_[share_target.id] = share_target; + } + emitTargetUpdated(ShareTargetToDbus(share_target)); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnHighVisibilityChanged( + bool in_high_visibility) { + static_cast(in_high_visibility); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnBluetoothStatusChanged(AdapterState state) { + static_cast(state); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnLanStatusChanged(AdapterState state) { + static_cast(state); + EmitStatusChanged(); +} + +void NearbySharingDbusService::OnIrrecoverableHardwareErrorReported() { + EmitStatusChanged(); +} + +} // namespace nearby::sharing::linux diff --git a/sharing/linux/daemon/nearby_sharing_dbus_service.h b/sharing/linux/daemon/nearby_sharing_dbus_service.h new file mode 100644 index 00000000..d7a4be77 --- /dev/null +++ b/sharing/linux/daemon/nearby_sharing_dbus_service.h @@ -0,0 +1,105 @@ +#ifndef SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_ +#define SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "absl/synchronization/mutex.h" +#include "sharing/attachment_container.h" +#include "sharing/linux/daemon/nearby_sharing_server.h" +#include "sharing/nearby_sharing_service.h" +#include "sharing/share_target.h" +#include "sharing/share_target_discovered_callback.h" +#include "sharing/transfer_metadata.h" +#include "sharing/transfer_update_callback.h" + +namespace nearby::sharing::linux { + +using DbusDictionary = std::map; + +DbusDictionary ShareTargetToDbus(const ShareTarget& share_target); +DbusDictionary TransferMetadataToDbus( + const TransferMetadata& transfer_metadata, + const AttachmentContainer& attachment_container); + +class NearbySharingDbusService final + : public com::google::nearby::sharing_adaptor, + public ShareTargetDiscoveredCallback, + public NearbySharingService::Observer { + public: + using QuitCallback = std::function; + + NearbySharingDbusService(sdbus::IObject& object, + NearbySharingService& service, + QuitCallback quit_callback); + ~NearbySharingDbusService() override; + + NearbySharingDbusService(const NearbySharingDbusService&) = delete; + NearbySharingDbusService& operator=(const NearbySharingDbusService&) = delete; + + void EmitStatusChanged(); + void ShutdownService(); + + void OnShareTargetDiscovered(const ShareTarget& share_target) override; + void OnShareTargetLost(const ShareTarget& share_target) override; + void OnShareTargetUpdated(const ShareTarget& share_target) override; + + void OnHighVisibilityChanged(bool in_high_visibility) override; + void OnBluetoothStatusChanged(AdapterState state) override; + void OnLanStatusChanged(AdapterState state) override; + void OnIrrecoverableHardwareErrorReported() override; + + private: + class TransferCallback final : public TransferUpdateCallback { + public: + TransferCallback(NearbySharingDbusService& service, bool receive_mode); + + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override; + + private: + NearbySharingDbusService& service_; + bool receive_mode_; + }; + + std::tuple StartReceive() override; + std::tuple StopReceive() override; + std::tuple StartDiscovery() override; + std::tuple StopDiscovery() override; + std::tuple SendFile(const int64_t& share_target_id, + const std::string& path) override; + std::tuple Accept(const int64_t& share_target_id) override; + std::tuple Reject(const int64_t& share_target_id) override; + std::tuple Cancel(const int64_t& share_target_id) override; + std::tuple Shutdown() override; + + std::tuple InvokeStatusCommand( + std::function< + void(std::function)> + invoker); + DbusDictionary StatusToDbus() const; + void OnTransferUpdate(bool receive_mode, const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata); + + NearbySharingService& service_; + QuitCallback quit_callback_; + TransferCallback send_transfer_callback_; + TransferCallback receive_transfer_callback_; + mutable absl::Mutex lock_; + std::unordered_map targets_; + bool receive_registered_ = false; + bool discovery_registered_ = false; + bool shutdown_ = false; +}; + +} // namespace nearby::sharing::linux + +#endif // SHARING_LINUX_DAEMON_NEARBY_SHARING_DBUS_SERVICE_H_ diff --git a/sharing/linux/daemon/nearby_sharing_dbus_service_test.cc b/sharing/linux/daemon/nearby_sharing_dbus_service_test.cc new file mode 100644 index 00000000..342e78b6 --- /dev/null +++ b/sharing/linux/daemon/nearby_sharing_dbus_service_test.cc @@ -0,0 +1,89 @@ +#include "sharing/linux/daemon/nearby_sharing_dbus_service.h" + +#include +#include + +#include + +#include "sharing/attachment_container.h" +#include "sharing/common/nearby_share_enums.h" +#include "sharing/share_target.h" +#include "sharing/transfer_metadata.h" +#include "sharing/transfer_metadata_builder.h" + +namespace nearby::sharing::linux { +namespace { + +ShareTarget MakeShareTarget() { + ShareTarget target; + target.id = 42; + target.device_name = "Pixel"; + target.type = ShareTargetType::kPhone; + target.is_incoming = true; + target.is_known = true; + target.device_id = "device-id"; + target.for_self_share = true; + target.vendor_id = 7; + target.receive_disabled = true; + return target; +} + +TEST(NearbySharingDbusServiceTest, ShareTargetToDbusMapsNearbyFields) { + DbusDictionary result = ShareTargetToDbus(MakeShareTarget()); + + EXPECT_EQ(result.at("id").get(), 42); + EXPECT_EQ(result.at("device_name").get(), "Pixel"); + EXPECT_EQ(result.at("type").get(), + static_cast(ShareTargetType::kPhone)); + EXPECT_TRUE(result.at("is_incoming").get()); + EXPECT_TRUE(result.at("is_known").get()); + EXPECT_EQ(result.at("device_id").get(), "device-id"); + EXPECT_TRUE(result.at("for_self_share").get()); + EXPECT_EQ(result.at("vendor_id").get(), 7); + EXPECT_TRUE(result.at("receive_disabled").get()); +} + +TEST(NearbySharingDbusServiceTest, TransferMetadataToDbusMapsNearbyFields) { + AttachmentContainer::Builder attachments_builder; + auto attachments = attachments_builder.Build(); + TransferMetadata metadata = + TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kInProgress) + .set_progress(25) + .set_token(std::string("1234")) + .set_is_self_share(true) + .set_transferred_bytes(1024) + .set_transfer_speed(256) + .set_estimated_time_remaining(4) + .set_total_attachments_count(2) + .set_transferred_attachments_count(1) + .set_in_progress_attachment_id(99) + .set_in_progress_attachment_transferred_bytes(512) + .set_in_progress_attachment_total_bytes(2048) + .set_binding_id("binding") + .build(); + + DbusDictionary result = TransferMetadataToDbus(metadata, *attachments); + + EXPECT_EQ(result.at("status").get(), "kInProgress"); + EXPECT_EQ(result.at("progress").get(), 25); + EXPECT_EQ(result.at("transferred_bytes").get(), 1024); + EXPECT_EQ(result.at("total_bytes").get(), 0); + EXPECT_EQ(result.at("transfer_speed").get(), 256); + EXPECT_EQ(result.at("estimated_time_remaining").get(), 4); + EXPECT_EQ(result.at("total_attachments_count").get(), 2); + EXPECT_EQ(result.at("transferred_attachments_count").get(), 1); + EXPECT_FALSE(result.at("is_final_status").get()); + EXPECT_TRUE(result.at("is_self_share").get()); + EXPECT_EQ(result.at("binding_id").get(), "binding"); + EXPECT_EQ(result.at("token").get(), "1234"); + EXPECT_EQ(result.at("in_progress_attachment_id").get(), 99); + EXPECT_EQ( + result.at("in_progress_attachment_transferred_bytes").get(), + 512); + EXPECT_EQ(result.at("in_progress_attachment_total_bytes").get(), + 2048); +} + +} // namespace +} // namespace nearby::sharing::linux diff --git a/sharing/linux/daemon/nearby_sharing_server.h b/sharing/linux/daemon/nearby_sharing_server.h index 391a4c31..cb32f0b8 100644 --- a/sharing/linux/daemon/nearby_sharing_server.h +++ b/sharing/linux/daemon/nearby_sharing_server.h @@ -3,8 +3,8 @@ * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! */ -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__ +#ifndef __sdbuscpp__sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__ +#define __sdbuscpp__sharing_linux_daemon_nearby_sharing_server_h__adaptor__H__ #include #include