1 // Copyright 2018 yuzu emulator team
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <cstring>
6 #include "common/assert.h"
7 #include "core/core.h"
8 #include "core/frontend/applets/controller.h"
9 #include "core/frontend/applets/error.h"
10 #include "core/frontend/applets/general_frontend.h"
11 #include "core/frontend/applets/profile_select.h"
12 #include "core/frontend/applets/software_keyboard.h"
13 #include "core/frontend/applets/web_browser.h"
14 #include "core/hle/kernel/readable_event.h"
15 #include "core/hle/kernel/server_session.h"
16 #include "core/hle/kernel/writable_event.h"
17 #include "core/hle/service/am/am.h"
18 #include "core/hle/service/am/applets/applets.h"
19 #include "core/hle/service/am/applets/controller.h"
20 #include "core/hle/service/am/applets/error.h"
21 #include "core/hle/service/am/applets/general_backend.h"
22 #include "core/hle/service/am/applets/profile_select.h"
23 #include "core/hle/service/am/applets/software_keyboard.h"
24 #include "core/hle/service/am/applets/web_browser.h"
25
26 namespace Service::AM::Applets {
27
AppletDataBroker(Kernel::KernelCore & kernel)28 AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
29 state_changed_event =
30 Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:StateChangedEvent");
31 pop_out_data_event =
32 Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:PopDataOutEvent");
33 pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
34 kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
35 }
36
37 AppletDataBroker::~AppletDataBroker() = default;
38
PeekDataToAppletForDebug() const39 AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
40 std::vector<std::vector<u8>> out_normal;
41
42 for (const auto& storage : in_channel) {
43 out_normal.push_back(storage->GetData());
44 }
45
46 std::vector<std::vector<u8>> out_interactive;
47
48 for (const auto& storage : in_interactive_channel) {
49 out_interactive.push_back(storage->GetData());
50 }
51
52 return {std::move(out_normal), std::move(out_interactive)};
53 }
54
PopNormalDataToGame()55 std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
56 if (out_channel.empty())
57 return nullptr;
58
59 auto out = std::move(out_channel.front());
60 out_channel.pop_front();
61 pop_out_data_event.writable->Clear();
62 return out;
63 }
64
PopNormalDataToApplet()65 std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
66 if (in_channel.empty())
67 return nullptr;
68
69 auto out = std::move(in_channel.front());
70 in_channel.pop_front();
71 return out;
72 }
73
PopInteractiveDataToGame()74 std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
75 if (out_interactive_channel.empty())
76 return nullptr;
77
78 auto out = std::move(out_interactive_channel.front());
79 out_interactive_channel.pop_front();
80 pop_interactive_out_data_event.writable->Clear();
81 return out;
82 }
83
PopInteractiveDataToApplet()84 std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
85 if (in_interactive_channel.empty())
86 return nullptr;
87
88 auto out = std::move(in_interactive_channel.front());
89 in_interactive_channel.pop_front();
90 return out;
91 }
92
PushNormalDataFromGame(std::shared_ptr<IStorage> && storage)93 void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
94 in_channel.emplace_back(std::move(storage));
95 }
96
PushNormalDataFromApplet(std::shared_ptr<IStorage> && storage)97 void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
98 out_channel.emplace_back(std::move(storage));
99 pop_out_data_event.writable->Signal();
100 }
101
PushInteractiveDataFromGame(std::shared_ptr<IStorage> && storage)102 void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
103 in_interactive_channel.emplace_back(std::move(storage));
104 }
105
PushInteractiveDataFromApplet(std::shared_ptr<IStorage> && storage)106 void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
107 out_interactive_channel.emplace_back(std::move(storage));
108 pop_interactive_out_data_event.writable->Signal();
109 }
110
SignalStateChanged() const111 void AppletDataBroker::SignalStateChanged() const {
112 state_changed_event.writable->Signal();
113 }
114
GetNormalDataEvent() const115 std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
116 return pop_out_data_event.readable;
117 }
118
GetInteractiveDataEvent() const119 std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
120 return pop_interactive_out_data_event.readable;
121 }
122
GetStateChangedEvent() const123 std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
124 return state_changed_event.readable;
125 }
126
Applet(Kernel::KernelCore & kernel_)127 Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {}
128
129 Applet::~Applet() = default;
130
Initialize()131 void Applet::Initialize() {
132 const auto common = broker.PopNormalDataToApplet();
133 ASSERT(common != nullptr);
134
135 const auto common_data = common->GetData();
136
137 ASSERT(common_data.size() >= sizeof(CommonArguments));
138 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
139
140 initialized = true;
141 }
142
143 AppletFrontendSet::AppletFrontendSet() = default;
144
AppletFrontendSet(ControllerApplet controller,ECommerceApplet e_commerce,ErrorApplet error,ParentalControlsApplet parental_controls,PhotoViewer photo_viewer,ProfileSelect profile_select,SoftwareKeyboard software_keyboard,WebBrowser web_browser)145 AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
146 ErrorApplet error, ParentalControlsApplet parental_controls,
147 PhotoViewer photo_viewer, ProfileSelect profile_select,
148 SoftwareKeyboard software_keyboard, WebBrowser web_browser)
149 : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
150 parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
151 profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
152 web_browser{std::move(web_browser)} {}
153
154 AppletFrontendSet::~AppletFrontendSet() = default;
155
156 AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
157
158 AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
159
AppletManager(Core::System & system_)160 AppletManager::AppletManager(Core::System& system_) : system{system_} {}
161
162 AppletManager::~AppletManager() = default;
163
GetAppletFrontendSet() const164 const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
165 return frontend;
166 }
167
SetAppletFrontendSet(AppletFrontendSet set)168 void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
169 if (set.controller != nullptr) {
170 frontend.controller = std::move(set.controller);
171 }
172
173 if (set.e_commerce != nullptr) {
174 frontend.e_commerce = std::move(set.e_commerce);
175 }
176
177 if (set.error != nullptr) {
178 frontend.error = std::move(set.error);
179 }
180
181 if (set.parental_controls != nullptr) {
182 frontend.parental_controls = std::move(set.parental_controls);
183 }
184
185 if (set.photo_viewer != nullptr) {
186 frontend.photo_viewer = std::move(set.photo_viewer);
187 }
188
189 if (set.profile_select != nullptr) {
190 frontend.profile_select = std::move(set.profile_select);
191 }
192
193 if (set.software_keyboard != nullptr) {
194 frontend.software_keyboard = std::move(set.software_keyboard);
195 }
196
197 if (set.web_browser != nullptr) {
198 frontend.web_browser = std::move(set.web_browser);
199 }
200 }
201
SetDefaultAppletFrontendSet()202 void AppletManager::SetDefaultAppletFrontendSet() {
203 ClearAll();
204 SetDefaultAppletsIfMissing();
205 }
206
SetDefaultAppletsIfMissing()207 void AppletManager::SetDefaultAppletsIfMissing() {
208 if (frontend.controller == nullptr) {
209 frontend.controller =
210 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
211 }
212
213 if (frontend.e_commerce == nullptr) {
214 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
215 }
216
217 if (frontend.error == nullptr) {
218 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
219 }
220
221 if (frontend.parental_controls == nullptr) {
222 frontend.parental_controls =
223 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
224 }
225
226 if (frontend.photo_viewer == nullptr) {
227 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
228 }
229
230 if (frontend.profile_select == nullptr) {
231 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
232 }
233
234 if (frontend.software_keyboard == nullptr) {
235 frontend.software_keyboard =
236 std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
237 }
238
239 if (frontend.web_browser == nullptr) {
240 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
241 }
242 }
243
ClearAll()244 void AppletManager::ClearAll() {
245 frontend = {};
246 }
247
GetApplet(AppletId id) const248 std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
249 switch (id) {
250 case AppletId::Auth:
251 return std::make_shared<Auth>(system, *frontend.parental_controls);
252 case AppletId::Controller:
253 return std::make_shared<Controller>(system, *frontend.controller);
254 case AppletId::Error:
255 return std::make_shared<Error>(system, *frontend.error);
256 case AppletId::ProfileSelect:
257 return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
258 case AppletId::SoftwareKeyboard:
259 return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
260 case AppletId::PhotoViewer:
261 return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
262 case AppletId::LibAppletShop:
263 return std::make_shared<WebBrowser>(system, *frontend.web_browser,
264 frontend.e_commerce.get());
265 case AppletId::LibAppletOff:
266 return std::make_shared<WebBrowser>(system, *frontend.web_browser);
267 default:
268 UNIMPLEMENTED_MSG(
269 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
270 static_cast<u8>(id));
271 return std::make_shared<StubApplet>(system, id);
272 }
273 }
274
275 } // namespace Service::AM::Applets
276