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