system service: deliver initial AppContent entitlement updates through shared queue
This commit is contained in:
parent
210d4dcd99
commit
62643c3424
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/stringUtils.h"
|
||||
#include "libs/errno.h"
|
||||
#include "libs/libs.h"
|
||||
#include "libs/systemService.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
#include "loader/systemContent.h"
|
||||
|
||||
|
|
@ -96,6 +97,7 @@ int KYTY_SYSV_ABI AppContentInitialize(const AppContentInitParam* init_param,
|
|||
LOGF("\t TITLE_ID missing\n");
|
||||
}
|
||||
|
||||
SystemService::NotifyEntitlementUpdate();
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@
|
|||
#include "libs/dialog.h"
|
||||
#include "libs/errno.h"
|
||||
#include "libs/libs.h"
|
||||
#include "libs/systemService.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
namespace Libs {
|
||||
|
||||
|
|
@ -70,6 +73,14 @@ struct SystemServiceEvent {
|
|||
uint8_t data[8192];
|
||||
};
|
||||
|
||||
static std::mutex g_event_mutex;
|
||||
static std::deque<int32_t> g_events;
|
||||
|
||||
void NotifyEntitlementUpdate() {
|
||||
std::scoped_lock lock(g_event_mutex);
|
||||
g_events.push_back(0x10000003); // SCE_SYSTEM_SERVICE_EVENT_ENTITLEMENT_UPDATE
|
||||
}
|
||||
|
||||
struct SystemServiceDisplaySafeAreaInfo {
|
||||
float ratio;
|
||||
uint8_t reserved[128];
|
||||
|
|
@ -153,7 +164,14 @@ static int KYTY_SYSV_ABI SystemServiceReceiveEvent(SystemServiceEvent* event) {
|
|||
event->event_type = -1;
|
||||
std::memset(event->data, 0, sizeof(event->data));
|
||||
|
||||
return SYSTEM_SERVICE_ERROR_NO_EVENT;
|
||||
std::scoped_lock lock(g_event_mutex);
|
||||
if (g_events.empty()) {
|
||||
return SYSTEM_SERVICE_ERROR_NO_EVENT;
|
||||
}
|
||||
event->event_type = g_events.front();
|
||||
g_events.pop_front();
|
||||
LOGF("\t SystemService event = 0x%08x\n", static_cast<uint32_t>(event->event_type));
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI SystemServiceGetStatus(SystemServiceStatus* status) {
|
||||
|
|
@ -167,6 +185,10 @@ static int KYTY_SYSV_ABI SystemServiceGetStatus(SystemServiceStatus* status) {
|
|||
*status = SystemServiceStatus();
|
||||
status->is_system_ui_overlaid = dialog.active;
|
||||
status->is_in_background_execution = dialog.background;
|
||||
{
|
||||
std::scoped_lock lock(g_event_mutex);
|
||||
status->event_num = static_cast<int32_t>(g_events.size());
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef EMULATOR_LIBS_SYSTEMSERVICE_H_
|
||||
#define EMULATOR_LIBS_SYSTEMSERVICE_H_
|
||||
|
||||
namespace Libs::SystemService {
|
||||
|
||||
void NotifyEntitlementUpdate();
|
||||
|
||||
} // namespace Libs::SystemService
|
||||
|
||||
#endif
|
||||
|
|
@ -46,6 +46,8 @@ void InitLibKernel_1_Apr(Loader::SymbolDatabase *symbols);
|
|||
namespace Libs {
|
||||
void InitLibKernel_1(Loader::SymbolDatabase *symbols);
|
||||
void InitSysmodule_1(Loader::SymbolDatabase *symbols);
|
||||
void InitSystemService_1(Loader::SymbolDatabase *symbols);
|
||||
void InitAppContent_1(Loader::SymbolDatabase *symbols);
|
||||
}
|
||||
|
||||
namespace Libs::LibAmpr {
|
||||
|
|
@ -204,6 +206,56 @@ void TestSysmoduleReferences() {
|
|||
"internal and public module operations share load state");
|
||||
}
|
||||
|
||||
void TestSystemServiceEntitlementEvents() {
|
||||
Loader::SymbolDatabase symbols;
|
||||
Libs::InitSystemService_1(&symbols);
|
||||
Libs::InitAppContent_1(&symbols);
|
||||
const auto resolve = [&](const char* nid, const char* library, const char* module) {
|
||||
const auto* symbol = symbols.Find(
|
||||
{nid, library, 1, module, 1, 1, Loader::SymbolType::Func});
|
||||
Check(symbol != nullptr, "entitlement event export resolves");
|
||||
return symbol->vaddr;
|
||||
};
|
||||
const auto initialize = reinterpret_cast<int (KYTY_SYSV_ABI *)(const void*, void*)>(
|
||||
resolve("R9lA82OraNs", "AppContent", "AppContentUtil"));
|
||||
struct Status {
|
||||
int32_t event_num;
|
||||
bool overlay, background, vr;
|
||||
uint8_t reserved[127];
|
||||
};
|
||||
struct Event {
|
||||
int32_t type;
|
||||
uint8_t data[8192];
|
||||
};
|
||||
static_assert(sizeof(Status) == 136 && sizeof(Event) == 8196);
|
||||
const auto get_status = reinterpret_cast<int (KYTY_SYSV_ABI *)(Status*)>(
|
||||
resolve("rPo6tV8D9bM", "SystemService", "SystemService"));
|
||||
const auto receive = reinterpret_cast<int (KYTY_SYSV_ABI *)(Event*)>(
|
||||
resolve("656LMQSrg6U", "SystemService", "SystemService"));
|
||||
Status status {};
|
||||
Event event {};
|
||||
Check(get_status(&status) == OK && status.event_num == 0,
|
||||
"SystemService starts without pending events");
|
||||
std::array<uint8_t, 32> init {};
|
||||
std::array<uint8_t, 40> boot {};
|
||||
Check(initialize(init.data(), boot.data()) == OK,
|
||||
"AppContent initialization generates an entitlement notification");
|
||||
Check(get_status(&status) == OK && status.event_num == 1 &&
|
||||
get_status(&status) == OK && status.event_num == 1,
|
||||
"status queries preserve pending notifications");
|
||||
Check(receive(nullptr) == Libs::SystemService::SYSTEM_SERVICE_ERROR_PARAMETER &&
|
||||
get_status(&status) == OK && status.event_num == 1,
|
||||
"invalid event output does not consume a notification");
|
||||
std::memset(&event, 0xff, sizeof(event));
|
||||
Check(receive(&event) == OK && event.type == 0x10000003 &&
|
||||
std::all_of(std::begin(event.data), std::end(event.data),
|
||||
[](uint8_t byte) { return byte == 0; }) &&
|
||||
get_status(&status) == OK && status.event_num == 0,
|
||||
"receive delivers the entitlement event with cleared payload exactly once");
|
||||
Check(receive(&event) == Libs::SystemService::SYSTEM_SERVICE_ERROR_NO_EVENT,
|
||||
"empty event queue reports NO_EVENT");
|
||||
}
|
||||
|
||||
void TestSaveOpenVisibility() {
|
||||
constexpr char Path[] = "/savedata0/visible-save.dat";
|
||||
constexpr char Payload[] = "saved progress";
|
||||
|
|
@ -1573,6 +1625,7 @@ int main(int, char**) {
|
|||
TempDirectory temporary;
|
||||
FileSystem::Initialize();
|
||||
TestSysmoduleReferences();
|
||||
TestSystemServiceEntitlementEvents();
|
||||
TestRandomDevices();
|
||||
TestFileDescriptorFlags();
|
||||
CheckMountRoot(temporary.Path());
|
||||
|
|
|
|||
Loading…
Reference in New Issue