summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/pctl/parental_control_service.cpp441
-rw-r--r--src/core/hle/service/pctl/parental_control_service.h74
-rw-r--r--src/core/hle/service/pctl/pctl_module.cpp468
4 files changed, 518 insertions, 467 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9e913fb10..d0fdae8db 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -893,6 +893,8 @@ add_library(core STATIC
893 hle/service/os/mutex.h 893 hle/service/os/mutex.h
894 hle/service/pcie/pcie.cpp 894 hle/service/pcie/pcie.cpp
895 hle/service/pcie/pcie.h 895 hle/service/pcie/pcie.h
896 hle/service/pctl/parental_control_service.cpp
897 hle/service/pctl/parental_control_service.h
896 hle/service/pctl/pctl.cpp 898 hle/service/pctl/pctl.cpp
897 hle/service/pctl/pctl.h 899 hle/service/pctl/pctl.h
898 hle/service/pctl/pctl_module.cpp 900 hle/service/pctl/pctl_module.cpp
diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp
new file mode 100644
index 000000000..4248b0184
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.cpp
@@ -0,0 +1,441 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/file_sys/control_metadata.h"
6#include "core/file_sys/patch_manager.h"
7#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/pctl/parental_control_service.h"
9#include "core/hle/service/pctl/pctl_results.h"
10
11namespace Service::PCTL {
12
13IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
14 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
15 service_context{system_, "IParentalControlService"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {1, &IParentalControlService::Initialize, "Initialize"},
19 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
20 {1002, nullptr, "ConfirmLaunchApplicationPermission"},
21 {1003, nullptr, "ConfirmResumeApplicationPermission"},
22 {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
23 {1005, nullptr, "ConfirmSystemSettingsPermission"},
24 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
25 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
26 {1008, nullptr, "EnterRestrictedSystemSettings"},
27 {1009, nullptr, "LeaveRestrictedSystemSettings"},
28 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
29 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
30 {1012, nullptr, "GetRestrictedFeatures"},
31 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
32 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
33 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
34 {1016, nullptr, "ConfirmShowNewsPermission"},
35 {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
36 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
37 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
38 {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
39 {1033, nullptr, "SetSafetyLevel"},
40 {1034, nullptr, "GetSafetyLevelSettings"},
41 {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
42 {1036, nullptr, "SetCustomSafetyLevelSettings"},
43 {1037, nullptr, "GetDefaultRatingOrganization"},
44 {1038, nullptr, "SetDefaultRatingOrganization"},
45 {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
46 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
47 {1043, nullptr, "DeleteSettings"},
48 {1044, nullptr, "GetFreeCommunicationApplicationList"},
49 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
50 {1046, nullptr, "DisableFeaturesForReset"},
51 {1047, nullptr, "NotifyApplicationDownloadStarted"},
52 {1048, nullptr, "NotifyNetworkProfileCreated"},
53 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
54 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
55 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
56 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
57 {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
58 {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
59 {1201, nullptr, "UnlockRestrictionTemporarily"},
60 {1202, nullptr, "UnlockSystemSettingsRestriction"},
61 {1203, nullptr, "SetPinCode"},
62 {1204, nullptr, "GenerateInquiryCode"},
63 {1205, nullptr, "CheckMasterKey"},
64 {1206, nullptr, "GetPinCodeLength"},
65 {1207, nullptr, "GetPinCodeChangedEvent"},
66 {1208, nullptr, "GetPinCode"},
67 {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
68 {1406, nullptr, "GetSettingsLastUpdated"},
69 {1411, nullptr, "GetPairingAccountInfo"},
70 {1421, nullptr, "GetAccountNickname"},
71 {1424, nullptr, "GetAccountState"},
72 {1425, nullptr, "RequestPostEvents"},
73 {1426, nullptr, "GetPostEventInterval"},
74 {1427, nullptr, "SetPostEventInterval"},
75 {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
76 {1451, nullptr, "StartPlayTimer"},
77 {1452, nullptr, "StopPlayTimer"},
78 {1453, nullptr, "IsPlayTimerEnabled"},
79 {1454, nullptr, "GetPlayTimerRemainingTime"},
80 {1455, nullptr, "IsRestrictedByPlayTimer"},
81 {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
82 {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
83 {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
84 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
85 {1472, nullptr, "CancelNetworkRequest"},
86 {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
87 {1474, nullptr, "ClearUnlinkedEvent"},
88 {1601, nullptr, "DisableAllFeatures"},
89 {1602, nullptr, "PostEnableAllFeatures"},
90 {1603, nullptr, "IsAllFeaturesDisabled"},
91 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
92 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
93 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
94 {1904, nullptr, "GetExemptApplicationListForDebug"},
95 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
96 {1906, nullptr, "AddToExemptApplicationListForDebug"},
97 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
98 {1908, nullptr, "ClearExemptApplicationListForDebug"},
99 {1941, nullptr, "DeletePairing"},
100 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
101 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
102 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
103 {2001, nullptr, "RequestPairingAsync"},
104 {2002, nullptr, "FinishRequestPairing"},
105 {2003, nullptr, "AuthorizePairingAsync"},
106 {2004, nullptr, "FinishAuthorizePairing"},
107 {2005, nullptr, "RetrievePairingInfoAsync"},
108 {2006, nullptr, "FinishRetrievePairingInfo"},
109 {2007, nullptr, "UnlinkPairingAsync"},
110 {2008, nullptr, "FinishUnlinkPairing"},
111 {2009, nullptr, "GetAccountMiiImageAsync"},
112 {2010, nullptr, "FinishGetAccountMiiImage"},
113 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
114 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
115 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
116 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
117 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
118 {2016, nullptr, "RequestUpdateExemptionListAsync"},
119 };
120 // clang-format on
121 RegisterHandlers(functions);
122
123 synchronization_event =
124 service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
125 unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
126 request_suspension_event =
127 service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
128}
129
130IParentalControlService::~IParentalControlService() {
131 service_context.CloseEvent(synchronization_event);
132 service_context.CloseEvent(unlinked_event);
133 service_context.CloseEvent(request_suspension_event);
134}
135
136bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
137 if (states.temporary_unlocked) {
138 return true;
139 }
140 if ((states.application_info.parental_control_flag & 1) == 0) {
141 return true;
142 }
143 if (pin_code[0] == '\0') {
144 return true;
145 }
146 if (!settings.is_free_communication_default_on) {
147 return true;
148 }
149 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
150 // but as we don't have multiproceses support yet, we can just assume our application is
151 // valid for the time being
152 return true;
153}
154
155bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
156 if (states.temporary_unlocked) {
157 return true;
158 }
159 if (pin_code[0] == '\0') {
160 return true;
161 }
162 if (!settings.is_stero_vision_restricted) {
163 return false;
164 }
165 return true;
166}
167
168void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
169 if (settings.disabled) {
170 return;
171 }
172
173 if (pin_code[0] == '\0') {
174 return;
175 }
176 settings.is_stero_vision_restricted = is_restricted;
177}
178
179void IParentalControlService::Initialize(HLERequestContext& ctx) {
180 LOG_DEBUG(Service_PCTL, "called");
181 IPC::ResponseBuilder rb{ctx, 2};
182
183 if (False(capability & (Capability::Application | Capability::System))) {
184 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
185 return;
186 }
187
188 // TODO(ogniK): Recovery flag initialization for pctl:r
189
190 const auto tid = system.GetApplicationProcessProgramID();
191 if (tid != 0) {
192 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
193 system.GetContentProvider()};
194 const auto control = pm.GetControlMetadata();
195 if (control.first) {
196 states.tid_from_event = 0;
197 states.launch_time_valid = false;
198 states.is_suspended = false;
199 states.free_communication = false;
200 states.stereo_vision = false;
201 states.application_info = ApplicationInfo{
202 .application_id = tid,
203 .age_rating = control.first->GetRatingAge(),
204 .parental_control_flag = control.first->GetParentalControlFlag(),
205 .capability = capability,
206 };
207
208 if (False(capability & (Capability::System | Capability::Recovery))) {
209 // TODO(ogniK): Signal application launch event
210 }
211 }
212 }
213
214 rb.Push(ResultSuccess);
215}
216
217void IParentalControlService::CheckFreeCommunicationPermission(HLERequestContext& ctx) {
218 LOG_DEBUG(Service_PCTL, "called");
219
220 IPC::ResponseBuilder rb{ctx, 2};
221 if (!CheckFreeCommunicationPermissionImpl()) {
222 rb.Push(PCTL::ResultNoFreeCommunication);
223 } else {
224 rb.Push(ResultSuccess);
225 }
226
227 states.free_communication = true;
228}
229
230void IParentalControlService::ConfirmSnsPostPermission(HLERequestContext& ctx) {
231 LOG_WARNING(Service_PCTL, "(STUBBED) called");
232
233 IPC::ResponseBuilder rb{ctx, 2};
234 rb.Push(PCTL::ResultNoFreeCommunication);
235}
236
237void IParentalControlService::IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
238 const bool is_temporary_unlocked = false;
239
240 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}", is_temporary_unlocked);
241
242 IPC::ResponseBuilder rb{ctx, 3};
243 rb.Push(ResultSuccess);
244 rb.Push<u8>(is_temporary_unlocked);
245}
246
247void IParentalControlService::ConfirmStereoVisionPermission(HLERequestContext& ctx) {
248 LOG_DEBUG(Service_PCTL, "called");
249 states.stereo_vision = true;
250
251 IPC::ResponseBuilder rb{ctx, 2};
252 rb.Push(ResultSuccess);
253}
254
255void IParentalControlService::EndFreeCommunication(HLERequestContext& ctx) {
256 LOG_WARNING(Service_PCTL, "(STUBBED) called");
257
258 IPC::ResponseBuilder rb{ctx, 2};
259 rb.Push(ResultSuccess);
260}
261
262void IParentalControlService::IsFreeCommunicationAvailable(HLERequestContext& ctx) {
263 LOG_WARNING(Service_PCTL, "(STUBBED) called");
264
265 IPC::ResponseBuilder rb{ctx, 2};
266 if (!CheckFreeCommunicationPermissionImpl()) {
267 rb.Push(PCTL::ResultNoFreeCommunication);
268 } else {
269 rb.Push(ResultSuccess);
270 }
271}
272
273void IParentalControlService::IsRestrictionEnabled(HLERequestContext& ctx) {
274 LOG_DEBUG(Service_PCTL, "called");
275
276 IPC::ResponseBuilder rb{ctx, 3};
277 if (False(capability & (Capability::Status | Capability::Recovery))) {
278 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
279 rb.Push(PCTL::ResultNoCapability);
280 rb.Push(false);
281 return;
282 }
283
284 rb.Push(pin_code[0] != '\0');
285}
286
287void IParentalControlService::GetSafetyLevel(HLERequestContext& ctx) {
288 const u32 safety_level = 0;
289
290 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
291
292 IPC::ResponseBuilder rb{ctx, 3};
293 rb.Push(ResultSuccess);
294 rb.Push(safety_level);
295}
296
297void IParentalControlService::GetCurrentSettings(HLERequestContext& ctx) {
298 LOG_INFO(Service_PCTL, "called");
299
300 IPC::ResponseBuilder rb{ctx, 3};
301 rb.Push(ResultSuccess);
302 rb.PushRaw(restriction_settings);
303}
304
305void IParentalControlService::GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
306 const u32 count = 4;
307
308 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
309
310 IPC::ResponseBuilder rb{ctx, 3};
311 rb.Push(ResultSuccess);
312 rb.Push(count);
313}
314
315void IParentalControlService::ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
316 LOG_DEBUG(Service_PCTL, "called");
317
318 IPC::ResponseBuilder rb{ctx, 2};
319
320 if (False(capability & Capability::StereoVision)) {
321 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
322 rb.Push(PCTL::ResultNoCapability);
323 return;
324 }
325
326 if (pin_code[0] == '\0') {
327 rb.Push(PCTL::ResultNoRestrictionEnabled);
328 return;
329 }
330
331 rb.Push(ResultSuccess);
332}
333
334void IParentalControlService::IsStereoVisionPermitted(HLERequestContext& ctx) {
335 LOG_DEBUG(Service_PCTL, "called");
336
337 IPC::ResponseBuilder rb{ctx, 3};
338 if (!ConfirmStereoVisionPermissionImpl()) {
339 rb.Push(PCTL::ResultStereoVisionRestricted);
340 rb.Push(false);
341 } else {
342 rb.Push(ResultSuccess);
343 rb.Push(true);
344 }
345}
346
347void IParentalControlService::IsPairingActive(HLERequestContext& ctx) {
348 const bool is_pairing_active = false;
349
350 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
351
352 IPC::ResponseBuilder rb{ctx, 3};
353 rb.Push(ResultSuccess);
354 rb.Push<u8>(is_pairing_active);
355}
356
357void IParentalControlService::GetSynchronizationEvent(HLERequestContext& ctx) {
358 LOG_INFO(Service_PCTL, "called");
359
360 IPC::ResponseBuilder rb{ctx, 2, 1};
361 rb.Push(ResultSuccess);
362 rb.PushCopyObjects(synchronization_event->GetReadableEvent());
363}
364
365void IParentalControlService::GetPlayTimerSettings(HLERequestContext& ctx) {
366 LOG_WARNING(Service_PCTL, "(STUBBED) called");
367
368 const PlayTimerSettings timer_settings{};
369
370 IPC::ResponseBuilder rb{ctx, 15};
371 rb.Push(ResultSuccess);
372 rb.PushRaw(timer_settings);
373}
374
375void IParentalControlService::GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
376 LOG_INFO(Service_PCTL, "called");
377
378 IPC::ResponseBuilder rb{ctx, 2, 1};
379 rb.Push(ResultSuccess);
380 rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
381}
382
383void IParentalControlService::IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
384 const bool is_play_timer_alarm_disabled = false;
385
386 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}", is_play_timer_alarm_disabled);
387
388 IPC::ResponseBuilder rb{ctx, 3};
389 rb.Push(ResultSuccess);
390 rb.Push<u8>(is_play_timer_alarm_disabled);
391}
392
393void IParentalControlService::GetUnlinkedEvent(HLERequestContext& ctx) {
394 LOG_INFO(Service_PCTL, "called");
395
396 IPC::ResponseBuilder rb{ctx, 2, 1};
397 rb.Push(ResultSuccess);
398 rb.PushCopyObjects(unlinked_event->GetReadableEvent());
399}
400
401void IParentalControlService::SetStereoVisionRestriction(HLERequestContext& ctx) {
402 IPC::RequestParser rp{ctx};
403 const auto can_use = rp.Pop<bool>();
404 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
405
406 IPC::ResponseBuilder rb{ctx, 2};
407 if (False(capability & Capability::StereoVision)) {
408 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
409 rb.Push(PCTL::ResultNoCapability);
410 return;
411 }
412
413 SetStereoVisionRestrictionImpl(can_use);
414 rb.Push(ResultSuccess);
415}
416
417void IParentalControlService::GetStereoVisionRestriction(HLERequestContext& ctx) {
418 LOG_DEBUG(Service_PCTL, "called");
419
420 IPC::ResponseBuilder rb{ctx, 3};
421 if (False(capability & Capability::StereoVision)) {
422 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
423 rb.Push(PCTL::ResultNoCapability);
424 rb.Push(false);
425 return;
426 }
427
428 rb.Push(ResultSuccess);
429 rb.Push(settings.is_stero_vision_restricted);
430}
431
432void IParentalControlService::ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
433 LOG_DEBUG(Service_PCTL, "called");
434
435 states.stereo_vision = false;
436
437 IPC::ResponseBuilder rb{ctx, 2};
438 rb.Push(ResultSuccess);
439}
440
441} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h
new file mode 100644
index 000000000..dcc357f65
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.h
@@ -0,0 +1,74 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/pctl/pctl_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PCTL {
11
12class IParentalControlService final : public ServiceFramework<IParentalControlService> {
13public:
14 explicit IParentalControlService(Core::System& system_, Capability capability_);
15 ~IParentalControlService() override;
16
17private:
18 bool CheckFreeCommunicationPermissionImpl() const;
19 bool ConfirmStereoVisionPermissionImpl() const;
20 void SetStereoVisionRestrictionImpl(bool is_restricted);
21
22 void Initialize(HLERequestContext& ctx);
23 void CheckFreeCommunicationPermission(HLERequestContext& ctx);
24 void ConfirmSnsPostPermission(HLERequestContext& ctx);
25 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx);
26 void ConfirmStereoVisionPermission(HLERequestContext& ctx);
27 void EndFreeCommunication(HLERequestContext& ctx);
28 void IsFreeCommunicationAvailable(HLERequestContext& ctx);
29 void IsRestrictionEnabled(HLERequestContext& ctx);
30 void GetSafetyLevel(HLERequestContext& ctx);
31 void GetCurrentSettings(HLERequestContext& ctx);
32 void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx);
33 void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx);
34 void IsStereoVisionPermitted(HLERequestContext& ctx);
35 void IsPairingActive(HLERequestContext& ctx);
36 void GetSynchronizationEvent(HLERequestContext& ctx);
37 void GetPlayTimerSettings(HLERequestContext& ctx);
38 void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx);
39 void IsPlayTimerAlarmDisabled(HLERequestContext& ctx);
40 void GetUnlinkedEvent(HLERequestContext& ctx);
41 void SetStereoVisionRestriction(HLERequestContext& ctx);
42 void GetStereoVisionRestriction(HLERequestContext& ctx);
43 void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx);
44
45 struct States {
46 u64 current_tid{};
47 ApplicationInfo application_info{};
48 u64 tid_from_event{};
49 bool launch_time_valid{};
50 bool is_suspended{};
51 bool temporary_unlocked{};
52 bool free_communication{};
53 bool stereo_vision{};
54 };
55
56 struct ParentalControlSettings {
57 bool is_stero_vision_restricted{};
58 bool is_free_communication_default_on{};
59 bool disabled{};
60 };
61
62 States states{};
63 ParentalControlSettings settings{};
64 RestrictionSettings restriction_settings{};
65 std::array<char, 8> pin_code{};
66 Capability capability{};
67
68 Kernel::KEvent* synchronization_event;
69 Kernel::KEvent* unlinked_event;
70 Kernel::KEvent* request_suspension_event;
71 KernelHelpers::ServiceContext service_context;
72};
73
74} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
index dab37cdc4..118856574 100644
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ b/src/core/hle/service/pctl/pctl_module.cpp
@@ -2,481 +2,15 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/hle/service/ipc_helpers.h" 5#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h" 6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/pctl/parental_control_service.h"
10#include "core/hle/service/pctl/pctl.h" 8#include "core/hle/service/pctl/pctl.h"
11#include "core/hle/service/pctl/pctl_module.h" 9#include "core/hle/service/pctl/pctl_module.h"
12#include "core/hle/service/pctl/pctl_results.h"
13#include "core/hle/service/pctl/pctl_types.h"
14#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
15 11
16namespace Service::PCTL { 12namespace Service::PCTL {
17 13
18struct States {
19 u64 current_tid{};
20 ApplicationInfo application_info{};
21 u64 tid_from_event{};
22 bool launch_time_valid{};
23 bool is_suspended{};
24 bool temporary_unlocked{};
25 bool free_communication{};
26 bool stereo_vision{};
27};
28
29struct ParentalControlSettings {
30 bool is_stero_vision_restricted{};
31 bool is_free_communication_default_on{};
32 bool disabled{};
33};
34
35class IParentalControlService final : public ServiceFramework<IParentalControlService> {
36public:
37 explicit IParentalControlService(Core::System& system_, Capability capability_)
38 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
39 service_context{system_, "IParentalControlService"} {
40 // clang-format off
41 static const FunctionInfo functions[] = {
42 {1, &IParentalControlService::Initialize, "Initialize"},
43 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
44 {1002, nullptr, "ConfirmLaunchApplicationPermission"},
45 {1003, nullptr, "ConfirmResumeApplicationPermission"},
46 {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
47 {1005, nullptr, "ConfirmSystemSettingsPermission"},
48 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
49 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
50 {1008, nullptr, "EnterRestrictedSystemSettings"},
51 {1009, nullptr, "LeaveRestrictedSystemSettings"},
52 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
53 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
54 {1012, nullptr, "GetRestrictedFeatures"},
55 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
56 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
57 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
58 {1016, nullptr, "ConfirmShowNewsPermission"},
59 {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
60 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
61 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
62 {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
63 {1033, nullptr, "SetSafetyLevel"},
64 {1034, nullptr, "GetSafetyLevelSettings"},
65 {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
66 {1036, nullptr, "SetCustomSafetyLevelSettings"},
67 {1037, nullptr, "GetDefaultRatingOrganization"},
68 {1038, nullptr, "SetDefaultRatingOrganization"},
69 {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
70 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
71 {1043, nullptr, "DeleteSettings"},
72 {1044, nullptr, "GetFreeCommunicationApplicationList"},
73 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
74 {1046, nullptr, "DisableFeaturesForReset"},
75 {1047, nullptr, "NotifyApplicationDownloadStarted"},
76 {1048, nullptr, "NotifyNetworkProfileCreated"},
77 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
78 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
79 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
80 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
81 {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
82 {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
83 {1201, nullptr, "UnlockRestrictionTemporarily"},
84 {1202, nullptr, "UnlockSystemSettingsRestriction"},
85 {1203, nullptr, "SetPinCode"},
86 {1204, nullptr, "GenerateInquiryCode"},
87 {1205, nullptr, "CheckMasterKey"},
88 {1206, nullptr, "GetPinCodeLength"},
89 {1207, nullptr, "GetPinCodeChangedEvent"},
90 {1208, nullptr, "GetPinCode"},
91 {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
92 {1406, nullptr, "GetSettingsLastUpdated"},
93 {1411, nullptr, "GetPairingAccountInfo"},
94 {1421, nullptr, "GetAccountNickname"},
95 {1424, nullptr, "GetAccountState"},
96 {1425, nullptr, "RequestPostEvents"},
97 {1426, nullptr, "GetPostEventInterval"},
98 {1427, nullptr, "SetPostEventInterval"},
99 {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
100 {1451, nullptr, "StartPlayTimer"},
101 {1452, nullptr, "StopPlayTimer"},
102 {1453, nullptr, "IsPlayTimerEnabled"},
103 {1454, nullptr, "GetPlayTimerRemainingTime"},
104 {1455, nullptr, "IsRestrictedByPlayTimer"},
105 {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
106 {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
107 {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
108 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
109 {1472, nullptr, "CancelNetworkRequest"},
110 {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
111 {1474, nullptr, "ClearUnlinkedEvent"},
112 {1601, nullptr, "DisableAllFeatures"},
113 {1602, nullptr, "PostEnableAllFeatures"},
114 {1603, nullptr, "IsAllFeaturesDisabled"},
115 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
116 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
117 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
118 {1904, nullptr, "GetExemptApplicationListForDebug"},
119 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
120 {1906, nullptr, "AddToExemptApplicationListForDebug"},
121 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
122 {1908, nullptr, "ClearExemptApplicationListForDebug"},
123 {1941, nullptr, "DeletePairing"},
124 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
125 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
126 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
127 {2001, nullptr, "RequestPairingAsync"},
128 {2002, nullptr, "FinishRequestPairing"},
129 {2003, nullptr, "AuthorizePairingAsync"},
130 {2004, nullptr, "FinishAuthorizePairing"},
131 {2005, nullptr, "RetrievePairingInfoAsync"},
132 {2006, nullptr, "FinishRetrievePairingInfo"},
133 {2007, nullptr, "UnlinkPairingAsync"},
134 {2008, nullptr, "FinishUnlinkPairing"},
135 {2009, nullptr, "GetAccountMiiImageAsync"},
136 {2010, nullptr, "FinishGetAccountMiiImage"},
137 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
138 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
139 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
140 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
141 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
142 {2016, nullptr, "RequestUpdateExemptionListAsync"},
143 };
144 // clang-format on
145 RegisterHandlers(functions);
146
147 synchronization_event =
148 service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
149 unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
150 request_suspension_event =
151 service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
152 }
153
154 ~IParentalControlService() {
155 service_context.CloseEvent(synchronization_event);
156 service_context.CloseEvent(unlinked_event);
157 service_context.CloseEvent(request_suspension_event);
158 };
159
160private:
161 bool CheckFreeCommunicationPermissionImpl() const {
162 if (states.temporary_unlocked) {
163 return true;
164 }
165 if ((states.application_info.parental_control_flag & 1) == 0) {
166 return true;
167 }
168 if (pin_code[0] == '\0') {
169 return true;
170 }
171 if (!settings.is_free_communication_default_on) {
172 return true;
173 }
174 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
175 // but as we don't have multiproceses support yet, we can just assume our application is
176 // valid for the time being
177 return true;
178 }
179
180 bool ConfirmStereoVisionPermissionImpl() const {
181 if (states.temporary_unlocked) {
182 return true;
183 }
184 if (pin_code[0] == '\0') {
185 return true;
186 }
187 if (!settings.is_stero_vision_restricted) {
188 return false;
189 }
190 return true;
191 }
192
193 void SetStereoVisionRestrictionImpl(bool is_restricted) {
194 if (settings.disabled) {
195 return;
196 }
197
198 if (pin_code[0] == '\0') {
199 return;
200 }
201 settings.is_stero_vision_restricted = is_restricted;
202 }
203
204 void Initialize(HLERequestContext& ctx) {
205 LOG_DEBUG(Service_PCTL, "called");
206 IPC::ResponseBuilder rb{ctx, 2};
207
208 if (False(capability & (Capability::Application | Capability::System))) {
209 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
210 return;
211 }
212
213 // TODO(ogniK): Recovery flag initialization for pctl:r
214
215 const auto tid = system.GetApplicationProcessProgramID();
216 if (tid != 0) {
217 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
218 system.GetContentProvider()};
219 const auto control = pm.GetControlMetadata();
220 if (control.first) {
221 states.tid_from_event = 0;
222 states.launch_time_valid = false;
223 states.is_suspended = false;
224 states.free_communication = false;
225 states.stereo_vision = false;
226 states.application_info = ApplicationInfo{
227 .application_id = tid,
228 .age_rating = control.first->GetRatingAge(),
229 .parental_control_flag = control.first->GetParentalControlFlag(),
230 .capability = capability,
231 };
232
233 if (False(capability & (Capability::System | Capability::Recovery))) {
234 // TODO(ogniK): Signal application launch event
235 }
236 }
237 }
238
239 rb.Push(ResultSuccess);
240 }
241
242 void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
243 LOG_DEBUG(Service_PCTL, "called");
244
245 IPC::ResponseBuilder rb{ctx, 2};
246 if (!CheckFreeCommunicationPermissionImpl()) {
247 rb.Push(ResultNoFreeCommunication);
248 } else {
249 rb.Push(ResultSuccess);
250 }
251
252 states.free_communication = true;
253 }
254
255 void ConfirmSnsPostPermission(HLERequestContext& ctx) {
256 LOG_WARNING(Service_PCTL, "(STUBBED) called");
257
258 IPC::ResponseBuilder rb{ctx, 2};
259 rb.Push(ResultNoFreeCommunication);
260 }
261
262 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
263 const bool is_temporary_unlocked = false;
264
265 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
266 is_temporary_unlocked);
267
268 IPC::ResponseBuilder rb{ctx, 3};
269 rb.Push(ResultSuccess);
270 rb.Push<u8>(is_temporary_unlocked);
271 }
272
273 void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
274 LOG_DEBUG(Service_PCTL, "called");
275 states.stereo_vision = true;
276
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(ResultSuccess);
279 }
280
281 void EndFreeCommunication(HLERequestContext& ctx) {
282 LOG_WARNING(Service_PCTL, "(STUBBED) called");
283
284 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(ResultSuccess);
286 }
287
288 void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
289 LOG_WARNING(Service_PCTL, "(STUBBED) called");
290
291 IPC::ResponseBuilder rb{ctx, 2};
292 if (!CheckFreeCommunicationPermissionImpl()) {
293 rb.Push(ResultNoFreeCommunication);
294 } else {
295 rb.Push(ResultSuccess);
296 }
297 }
298
299 void IsRestrictionEnabled(HLERequestContext& ctx) {
300 LOG_DEBUG(Service_PCTL, "called");
301
302 IPC::ResponseBuilder rb{ctx, 3};
303 if (False(capability & (Capability::Status | Capability::Recovery))) {
304 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
305 rb.Push(ResultNoCapability);
306 rb.Push(false);
307 return;
308 }
309
310 rb.Push(pin_code[0] != '\0');
311 }
312
313 void GetSafetyLevel(HLERequestContext& ctx) {
314 const u32 safety_level = 0;
315
316 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
317
318 IPC::ResponseBuilder rb{ctx, 3};
319 rb.Push(ResultSuccess);
320 rb.Push(safety_level);
321 }
322
323 void GetCurrentSettings(HLERequestContext& ctx) {
324 LOG_INFO(Service_PCTL, "called");
325
326 IPC::ResponseBuilder rb{ctx, 3};
327 rb.Push(ResultSuccess);
328 rb.PushRaw(restriction_settings);
329 }
330
331 void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
332 const u32 count = 4;
333
334 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
335
336 IPC::ResponseBuilder rb{ctx, 3};
337 rb.Push(ResultSuccess);
338 rb.Push(count);
339 }
340
341 void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
342 LOG_DEBUG(Service_PCTL, "called");
343
344 IPC::ResponseBuilder rb{ctx, 2};
345
346 if (False(capability & Capability::StereoVision)) {
347 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
348 rb.Push(ResultNoCapability);
349 return;
350 }
351
352 if (pin_code[0] == '\0') {
353 rb.Push(ResultNoRestrictionEnabled);
354 return;
355 }
356
357 rb.Push(ResultSuccess);
358 }
359
360 void IsStereoVisionPermitted(HLERequestContext& ctx) {
361 LOG_DEBUG(Service_PCTL, "called");
362
363 IPC::ResponseBuilder rb{ctx, 3};
364 if (!ConfirmStereoVisionPermissionImpl()) {
365 rb.Push(ResultStereoVisionRestricted);
366 rb.Push(false);
367 } else {
368 rb.Push(ResultSuccess);
369 rb.Push(true);
370 }
371 }
372
373 void IsPairingActive(HLERequestContext& ctx) {
374 const bool is_pairing_active = false;
375
376 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
377
378 IPC::ResponseBuilder rb{ctx, 3};
379 rb.Push(ResultSuccess);
380 rb.Push<u8>(is_pairing_active);
381 }
382
383 void GetSynchronizationEvent(HLERequestContext& ctx) {
384 LOG_INFO(Service_PCTL, "called");
385
386 IPC::ResponseBuilder rb{ctx, 2, 1};
387 rb.Push(ResultSuccess);
388 rb.PushCopyObjects(synchronization_event->GetReadableEvent());
389 }
390
391 void GetPlayTimerSettings(HLERequestContext& ctx) {
392 LOG_WARNING(Service_PCTL, "(STUBBED) called");
393
394 const PlayTimerSettings timer_settings{};
395
396 IPC::ResponseBuilder rb{ctx, 15};
397 rb.Push(ResultSuccess);
398 rb.PushRaw(timer_settings);
399 }
400
401 void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
402 LOG_INFO(Service_PCTL, "called");
403
404 IPC::ResponseBuilder rb{ctx, 2, 1};
405 rb.Push(ResultSuccess);
406 rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
407 }
408
409 void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
410 const bool is_play_timer_alarm_disabled = false;
411
412 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
413 is_play_timer_alarm_disabled);
414
415 IPC::ResponseBuilder rb{ctx, 3};
416 rb.Push(ResultSuccess);
417 rb.Push<u8>(is_play_timer_alarm_disabled);
418 }
419
420 void GetUnlinkedEvent(HLERequestContext& ctx) {
421 LOG_INFO(Service_PCTL, "called");
422
423 IPC::ResponseBuilder rb{ctx, 2, 1};
424 rb.Push(ResultSuccess);
425 rb.PushCopyObjects(unlinked_event->GetReadableEvent());
426 }
427
428 void SetStereoVisionRestriction(HLERequestContext& ctx) {
429 IPC::RequestParser rp{ctx};
430 const auto can_use = rp.Pop<bool>();
431 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
432
433 IPC::ResponseBuilder rb{ctx, 2};
434 if (False(capability & Capability::StereoVision)) {
435 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
436 rb.Push(ResultNoCapability);
437 return;
438 }
439
440 SetStereoVisionRestrictionImpl(can_use);
441 rb.Push(ResultSuccess);
442 }
443
444 void GetStereoVisionRestriction(HLERequestContext& ctx) {
445 LOG_DEBUG(Service_PCTL, "called");
446
447 IPC::ResponseBuilder rb{ctx, 3};
448 if (False(capability & Capability::StereoVision)) {
449 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
450 rb.Push(ResultNoCapability);
451 rb.Push(false);
452 return;
453 }
454
455 rb.Push(ResultSuccess);
456 rb.Push(settings.is_stero_vision_restricted);
457 }
458
459 void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
460 LOG_DEBUG(Service_PCTL, "called");
461
462 states.stereo_vision = false;
463
464 IPC::ResponseBuilder rb{ctx, 2};
465 rb.Push(ResultSuccess);
466 }
467
468 States states{};
469 ParentalControlSettings settings{};
470 RestrictionSettings restriction_settings{};
471 std::array<char, 8> pin_code{};
472 Capability capability{};
473
474 Kernel::KEvent* synchronization_event;
475 Kernel::KEvent* unlinked_event;
476 Kernel::KEvent* request_suspension_event;
477 KernelHelpers::ServiceContext service_context;
478};
479
480void Module::Interface::CreateService(HLERequestContext& ctx) { 14void Module::Interface::CreateService(HLERequestContext& ctx) {
481 LOG_DEBUG(Service_PCTL, "called"); 15 LOG_DEBUG(Service_PCTL, "called");
482 16