From e49ae3bf92fdc3f925ceaff03c4f2b9e90f94448 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Mon, 24 Jun 2019 12:26:45 +1000 Subject: [PATCH 1/5] Implemented INotificationService --- src/core/CMakeLists.txt | 1 + src/core/hle/service/friend/errors.h | 12 +++ src/core/hle/service/friend/friend.cpp | 112 ++++++++++++++++++++++ src/core/hle/service/friend/friend.h | 1 + src/core/hle/service/friend/interface.cpp | 2 +- 5 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/core/hle/service/friend/errors.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cdb3bf6ab..2ccd4a779 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -272,6 +272,7 @@ add_library(core STATIC hle/service/filesystem/fsp_srv.h hle/service/fgm/fgm.cpp hle/service/fgm/fgm.h + hle/service/friend/errors.h hle/service/friend/friend.cpp hle/service/friend/friend.h hle/service/friend/interface.cpp diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h new file mode 100644 index 000000000..72d96b555 --- /dev/null +++ b/src/core/hle/service/friend/errors.h @@ -0,0 +1,12 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::Friend { + +constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15}; +} diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 5100e376c..9752f1a8d 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -2,8 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/logging/log.h" +#include "common/uuid.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" +#include "core/hle/service/friend/errors.h" #include "core/hle/service/friend/friend.h" #include "core/hle/service/friend/interface.h" @@ -109,6 +114,103 @@ private: } }; +class INotificationService final : public ServiceFramework { +public: + INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &INotificationService::GetEvent, "GetEvent"}, + {1, &INotificationService::Clear, "Clear"}, + {2, &INotificationService::Pop, "Pop"} + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ACC, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + + if (is_event_created) { + rb.PushCopyObjects(notification_event.readable); + } else { + auto& kernel = Core::System::GetInstance().Kernel(); + notification_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); + is_event_created = true; + rb.PushCopyObjects(notification_event.readable); + } + } + + void Clear(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ACC, "called"); + while (!notifications.empty()) { + notifications.pop(); + } + states.has_recieved_friend_request = false; + states.has_updated_friends = false; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Pop(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ACC, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + + if (notifications.empty()) { + LOG_ERROR(Service_ACC, "No notifications in queue!"); + rb.Push(ERR_NO_NOTIFICATIONS); + return; + } + + auto notification = notifications.front(); + notifications.pop(); + + switch (notification.notification_type) { + case NotificationTypes::HasUpdatedFriendsList: + states.has_updated_friends = false; + break; + case NotificationTypes::HasRecievedFriendRequest: + states.has_recieved_friend_request = false; + break; + default: + // HOS seems not have an error case for an unknown notification + LOG_WARNING(Service_ACC, "Unknown notification {:08X}", + static_cast(notification.notification_type)); + break; + } + rb.Push(RESULT_SUCCESS); + } + + enum class NotificationTypes : u32_le { + HasUpdatedFriendsList = 0x65, + HasRecievedFriendRequest = 0x1 + }; + + struct SizedNotificationInfo { + NotificationTypes notification_type; + INSERT_PADDING_WORDS( + 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now + Common::UUID user_uuid; + }; + + struct States { + bool has_updated_friends; + bool has_recieved_friend_request; + }; + + Common::UUID uuid{}; + bool is_event_created = false; + Kernel::EventPair notification_event; + std::queue notifications{}; + States states{}; +}; + void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -116,6 +218,16 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); } +void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto uuid = rp.PopRaw(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(uuid); + LOG_DEBUG(Service_ACC, "called"); +} + Module::Interface::Interface(std::shared_ptr module, const char* name) : ServiceFramework(name), module(std::move(module)) {} diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index e762840cb..38d05fa8e 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -16,6 +16,7 @@ public: ~Interface() override; void CreateFriendService(Kernel::HLERequestContext& ctx); + void CreateNotificationService(Kernel::HLERequestContext& ctx); protected: std::shared_ptr module; diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 5a6840af5..5b384f733 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -10,7 +10,7 @@ Friend::Friend(std::shared_ptr module, const char* name) : Interface(std::move(module), name) { static const FunctionInfo functions[] = { {0, &Friend::CreateFriendService, "CreateFriendService"}, - {1, nullptr, "CreateNotificationService"}, + {1, &Friend::CreateNotificationService, "CreateNotificationService"}, {2, nullptr, "CreateDaemonSuspendSessionService"}, }; RegisterHandlers(functions); From 5d005b87a3494e2d488ef611783a4e177fcfcee9 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Tue, 25 Jun 2019 11:23:23 +1000 Subject: [PATCH 2/5] fixed spelling errors and fixed issue with Pop not returning the SizedNotificationInfo --- src/core/hle/service/friend/friend.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 9752f1a8d..a00d7dce7 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -151,7 +151,7 @@ private: while (!notifications.empty()) { notifications.pop(); } - states.has_recieved_friend_request = false; + states.has_received_friend_request = false; states.has_updated_friends = false; IPC::ResponseBuilder rb{ctx, 2}; @@ -160,13 +160,14 @@ private: void Pop(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); - IPC::ResponseBuilder rb{ctx, 2}; if (notifications.empty()) { LOG_ERROR(Service_ACC, "No notifications in queue!"); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_NO_NOTIFICATIONS); return; } + IPC::ResponseBuilder rb{ctx, 6}; auto notification = notifications.front(); notifications.pop(); @@ -175,8 +176,8 @@ private: case NotificationTypes::HasUpdatedFriendsList: states.has_updated_friends = false; break; - case NotificationTypes::HasRecievedFriendRequest: - states.has_recieved_friend_request = false; + case NotificationTypes::HasReceivedFriendRequest: + states.has_received_friend_request = false; break; default: // HOS seems not have an error case for an unknown notification @@ -185,11 +186,12 @@ private: break; } rb.Push(RESULT_SUCCESS); + rb.PushRaw(notification); } enum class NotificationTypes : u32_le { HasUpdatedFriendsList = 0x65, - HasRecievedFriendRequest = 0x1 + HasReceivedFriendRequest = 0x1 }; struct SizedNotificationInfo { @@ -201,7 +203,7 @@ private: struct States { bool has_updated_friends; - bool has_recieved_friend_request; + bool has_received_friend_request; }; Common::UUID uuid{}; From 192f1f7ebe65e492fcdc0ac81d39b4277a7d5f6c Mon Sep 17 00:00:00 2001 From: David Marcec Date: Tue, 25 Jun 2019 15:19:37 +1000 Subject: [PATCH 3/5] SizedNotificationInfo should be 0x10 bytes, user_uuid is incorrect, this should be the users account id --- src/core/hle/service/friend/friend.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index a00d7dce7..296babc7c 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -198,8 +198,10 @@ private: NotificationTypes notification_type; INSERT_PADDING_WORDS( 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now - Common::UUID user_uuid; + u64_le account_id; }; + static_assert(sizeof(SizedNotificationInfo) == 0x10, + "SizedNotificationInfo is an incorrect size"); struct States { bool has_updated_friends; From c2146c4eefdb67e64a9cb572d52391dfbb5b0f80 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Fri, 28 Jun 2019 15:29:38 +1000 Subject: [PATCH 4/5] Addressed issues --- src/core/hle/service/friend/errors.h | 3 ++- src/core/hle/service/friend/friend.cpp | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h index 72d96b555..b8314eb3f 100644 --- a/src/core/hle/service/friend/errors.h +++ b/src/core/hle/service/friend/errors.h @@ -1,4 +1,4 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,4 +9,5 @@ namespace Service::Friend { constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15}; + } diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 296babc7c..dec541f2e 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -135,15 +135,13 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - if (is_event_created) { - rb.PushCopyObjects(notification_event.readable); - } else { + if (!is_event_created) { auto& kernel = Core::System::GetInstance().Kernel(); notification_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); is_event_created = true; - rb.PushCopyObjects(notification_event.readable); } + rb.PushCopyObjects(notification_event.readable); } void Clear(Kernel::HLERequestContext& ctx) { @@ -151,8 +149,7 @@ private: while (!notifications.empty()) { notifications.pop(); } - states.has_received_friend_request = false; - states.has_updated_friends = false; + std::memset(&states, 0, sizeof(States)); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -167,9 +164,8 @@ private: rb.Push(ERR_NO_NOTIFICATIONS); return; } - IPC::ResponseBuilder rb{ctx, 6}; - auto notification = notifications.front(); + const auto notification = notifications.front(); notifications.pop(); switch (notification.notification_type) { @@ -185,11 +181,13 @@ private: static_cast(notification.notification_type)); break; } + + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); rb.PushRaw(notification); } - enum class NotificationTypes : u32_le { + enum class NotificationTypes : u32 { HasUpdatedFriendsList = 0x65, HasReceivedFriendRequest = 0x1 }; @@ -208,10 +206,10 @@ private: bool has_received_friend_request; }; - Common::UUID uuid{}; + Common::UUID uuid; bool is_event_created = false; Kernel::EventPair notification_event; - std::queue notifications{}; + std::queue notifications; States states{}; }; @@ -226,10 +224,11 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx IPC::RequestParser rp{ctx}; auto uuid = rp.PopRaw(); + LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format()); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(uuid); - LOG_DEBUG(Service_ACC, "called"); } Module::Interface::Interface(std::shared_ptr module, const char* name) From dfe4b3f7238af2d91327a956d3a52f299ee7d26f Mon Sep 17 00:00:00 2001 From: David Marcec Date: Fri, 28 Jun 2019 22:08:50 +1000 Subject: [PATCH 5/5] Attemp clang format fix? Seems to be an issue with clang format --- src/core/hle/service/friend/errors.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h index b8314eb3f..b3996e275 100644 --- a/src/core/hle/service/friend/errors.h +++ b/src/core/hle/service/friend/errors.h @@ -9,5 +9,4 @@ namespace Service::Friend { constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15}; - }