From eeaa63aa28877002cde8087ceceb95944f88bfd3 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Thu, 15 Aug 2019 21:34:42 -0400 Subject: [PATCH] Added appletPushContext/appletPopContext. Added appletHolderJump. Added appletGetAppletInfo. Added libappletSetJumpFlag. Added structs AppletProcessLaunchReason and AppletInfo. --- nx/include/switch/applets/libapplet.h | 8 +- nx/include/switch/services/applet.h | 43 +++++++ nx/source/applets/libapplet.c | 9 ++ nx/source/services/applet.c | 175 +++++++++++++++++++++++++- 4 files changed, 229 insertions(+), 6 deletions(-) diff --git a/nx/include/switch/applets/libapplet.h b/nx/include/switch/applets/libapplet.h index 4c090a67..d9f66b11 100644 --- a/nx/include/switch/applets/libapplet.h +++ b/nx/include/switch/applets/libapplet.h @@ -82,7 +82,13 @@ Result libappletPushInData(AppletHolder *h, const void* buffer, size_t size); Result libappletPopOutData(AppletHolder *h, void* buffer, size_t size, size_t *transfer_size); /** - * @brief Starts the applet and waits for it to finish, then checks the \ref LibAppletExitReason. + * @brief Sets whether \ref libappletStart uses \ref appletHolderJump. + * @param flag Flag. Value true should not be used unless running as AppletType_LibraryApplet. + */ +void libappletSetJumpFlag(bool flag); + +/** + * @brief If the flag from \ref libappletSetJumpFlag is set, this just uses \ref appletHolderJump. Otherwise, starts the applet and waits for it to finish, then checks the \ref LibAppletExitReason. * @note Uses \ref appletHolderStart and \ref appletHolderJoin. * @param h AppletHolder object. */ diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 6d4c3b4b..7e5c02ce 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -223,6 +223,19 @@ typedef struct { LibAppletMode mode; ///< \ref LibAppletMode } LibAppletInfo; +/// AppletProcessLaunchReason, from GetLaunchReason. +typedef struct { + u8 flag; ///< When non-zero, indicates that OpenCallingLibraryApplet should be used. + u8 unk_x1[3]; ///< Always zero. +} AppletProcessLaunchReason; + +/// Cached info for the current LibraryApplet, from \ref appletGetAppletInfo. +typedef struct { + LibAppletInfo info; ///< Output from \ref appletGetLibraryAppletInfo. + bool caller_flag; ///< Loaded from AppletProcessLaunchReason::flag, indicates that the below AppletHolder is initialized. + AppletHolder caller; ///< \ref AppletHolder for the CallingLibraryApplet, automatically closed by \ref appletExit when needed. +} AppletInfo; + /// IdentityInfo typedef struct { AppletId appletId; ///< \ref AppletId @@ -823,6 +836,23 @@ Result appletReleaseCallerAppletCaptureSharedBuffer(void); */ Result appletTakeScreenShotOfOwnLayerEx(bool flag0, bool immediately, AppletCaptureSharedBuffer captureBuf); +// IProcessWindingController + +/** + * @brief Pushes a storage to the ContextStack. Normally this should only be used when AppletInfo::caller_flag is true. + * @note Only available with AppletType_LibraryApplet. + * @note This uses \ref appletStorageClose automatically. + * @param[in] s Storage object. + */ +Result appletPushContext(AppletStorage *s); + +/** + * @brief Pops a storage from the ContextStack. Normally this should only be used when AppletInfo::caller_flag is true. + * @note Only available with AppletType_LibraryApplet. + * @param[out] s Storage object. + */ +Result appletPopContext(AppletStorage *s); + // LockAccessor /** @@ -890,6 +920,13 @@ Result appletHolderGetIndirectLayerConsumerHandle(AppletHolder *h, u64 *out); */ Result appletHolderStart(AppletHolder *h); +/** + * @brief Jumps to the LibraryApplet, with the current-LibraryApplet being terminated. This will enter an infinite-sleep-loop on success. + * @note Only available with AppletType_LibraryApplet. + * @param h AppletHolder object. + */ +Result appletHolderJump(AppletHolder *h); + /** * @brief Requests the LibraryApplet to exit. The command is only used if \ref appletHolderCheckFinished returns false. * @param h AppletHolder object. @@ -1652,6 +1689,12 @@ Result appletGetHomeButtonDoubleClickEnabled(bool *out); // State / other +/** + * @brief Gets the cached \ref AppletInfo loaded during \ref appletInitialize. This will return NULL when the info is not initialized, due to not running as AppletType_LibraryApplet, or when any of the used cmds fail. + * @note Only available with AppletType_LibraryApplet. + */ +AppletInfo *appletGetAppletInfo(void); + /** * @brief Gets a notification message. */ diff --git a/nx/source/applets/libapplet.c b/nx/source/applets/libapplet.c index c7e5773e..b319447e 100644 --- a/nx/source/applets/libapplet.c +++ b/nx/source/applets/libapplet.c @@ -5,6 +5,8 @@ #include "services/applet.h" #include "applets/libapplet.h" +static bool g_libappletJumpFlag; + void libappletArgsCreate(LibAppletArgs* a, u32 version) { memset(a, 0, sizeof(LibAppletArgs)); @@ -117,9 +119,16 @@ Result libappletPopOutData(AppletHolder *h, void* buffer, size_t size, size_t *t return rc; } +void libappletSetJumpFlag(bool flag) { + g_libappletJumpFlag = flag; +} + Result libappletStart(AppletHolder *h) { Result rc=0; + if (g_libappletJumpFlag) + return appletHolderJump(h); + rc = appletHolderStart(h); if (R_SUCCEEDED(rc)) { diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 73a22ccf..d1b884c5 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -80,6 +80,9 @@ static AppletThemeColorType g_appletThemeColorType = AppletThemeColorType_Defaul static ApmCpuBoostMode g_appletCpuBoostMode = ApmCpuBoostMode_Disabled; +static AppletInfo g_appletInfo; +static bool g_appletInfoInitialized; + static Result _appletGetHandle(Service* srv, Handle* handle_out, u64 cmd_id); static Result _appletGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool autoclear); static Result _appletGetSession(Service* srv, Service* srv_out, u64 cmd_id); @@ -107,6 +110,11 @@ static Result _appletExitProcessAndReturn(void); static Result _appletGetAccumulatedSuspendedTickValue(u64 *tick); static Result _appletGetAccumulatedSuspendedTickChangedEvent(Event *out_event); +static Result _appletGetLaunchReason(AppletProcessLaunchReason *reason); +static Result _appletOpenCallingLibraryApplet(AppletHolder *h); + +static Result _appletHolderCreateState(AppletHolder *h, LibAppletMode mode, bool creating_self); + Result appletInitialize(void) { AppletAttribute *attr = NULL; @@ -129,6 +137,9 @@ Result appletInitialize(void) g_appletExitProcessFlag = 0; g_appletRecordingInitialized = 0; + g_appletInfoInitialized = 0; + memset(&g_appletInfo, 0, sizeof(g_appletInfo)); + switch (__nx_applet_type) { case AppletType_Default: __nx_applet_type = AppletType_Application; @@ -310,6 +321,21 @@ Result appletInitialize(void) } } + if (R_SUCCEEDED(rc) && __nx_applet_type == AppletType_LibraryApplet) { + AppletProcessLaunchReason launchreason={0}; + + Result rc2 = appletGetLibraryAppletInfo(&g_appletInfo.info); + + if (R_SUCCEEDED(rc2)) rc2 = _appletGetLaunchReason(&launchreason); + + if (R_SUCCEEDED(rc2)) { + g_appletInfo.caller_flag = launchreason.flag!=0; + if (g_appletInfo.caller_flag) rc2 = _appletOpenCallingLibraryApplet(&g_appletInfo.caller); + } + + if (R_SUCCEEDED(rc2)) g_appletInfoInitialized = true; + } + if (R_FAILED(rc)) appletExit(); @@ -365,6 +391,12 @@ void appletExit(void) } } + if (g_appletInfoInitialized) { + if (g_appletInfo.caller_flag) appletHolderClose(&g_appletInfo.caller); + g_appletInfoInitialized = 0; + memset(&g_appletInfo, 0, sizeof(g_appletInfo)); + } + eventClose(&g_appletLibraryAppletLaunchableEvent); eventClose(&g_appletMessageEvent); @@ -2512,6 +2544,103 @@ Result appletTakeScreenShotOfOwnLayerEx(bool flag0, bool immediately, AppletCapt return rc; } +// IProcessWindingController + +static Result _appletGetLaunchReason(AppletProcessLaunchReason *reason) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_appletIProcessWindingController, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + + Result rc = serviceIpcDispatch(&g_appletIProcessWindingController); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + AppletProcessLaunchReason reason; + } *resp; + + serviceIpcParse(&g_appletIProcessWindingController, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && reason) *reason = resp->reason; + } + + return rc; +} + +static Result _appletOpenCallingLibraryApplet(AppletHolder *h) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + Result rc=0; + LibAppletInfo info={0}; + + memset(h, 0, sizeof(AppletHolder)); + + rc = _appletGetSession(&g_appletIProcessWindingController, &h->s, 11); + + if (R_SUCCEEDED(rc)) rc = appletHolderGetLibraryAppletInfo(h, &info); + + if (R_SUCCEEDED(rc)) rc = _appletHolderCreateState(h, info.mode, false); + + if (R_FAILED(rc)) appletHolderClose(h); + + return rc; +} + +Result appletPushContext(AppletStorage *s) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdInStorage(&g_appletIProcessWindingController, s, 21); +} + +Result appletPopContext(AppletStorage *s) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdNoInOutStorage(&g_appletIProcessWindingController, s, 22); +} + +static Result _appletWindAndDoReserved(void) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdNoIO(&g_appletIProcessWindingController, 30); +} + +static Result _appletReserveToStartAndWaitAndUnwindThis(AppletHolder *h) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdInSession(&g_appletIProcessWindingController, &h->s, 40); +} + +static Result _appletReserveToStartAndWait(AppletHolder *h) { + if (__nx_applet_type != AppletType_LibraryApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdInSession(&g_appletIProcessWindingController, &h->s, 41); +} + // LockAccessor void appletLockAccessorClose(AppletLockAccessor *a) { eventClose(&a->event); @@ -2679,20 +2808,29 @@ static Result _appletGetIndirectLayerConsumerHandle(Service* srv, u64 *out) { return rc; } +static Result _appletHolderCreateState(AppletHolder *h, LibAppletMode mode, bool creating_self) { + Result rc=0; + + h->mode = mode; + h->creating_self = creating_self; + + if (R_SUCCEEDED(rc)) rc = _appletGetEvent(&h->s, &h->StateChangedEvent, 0, false);//GetAppletStateChangedEvent + + if (R_SUCCEEDED(rc) && hosversionAtLeast(2,0,0) && h->mode == LibAppletMode_BackgroundIndirect) rc = _appletGetIndirectLayerConsumerHandle(&h->s, &h->layer_handle); + + return rc; +} + static Result _appletHolderCreate(AppletHolder *h, AppletId id, LibAppletMode mode, bool creating_self) { Result rc=0; memset(h, 0, sizeof(AppletHolder)); - h->mode = mode; - h->creating_self = creating_self; if (!h->creating_self) rc = _appletWaitLibraryAppletLaunchableEvent(); if (R_SUCCEEDED(rc)) rc = _appletCreateLibraryApplet(&h->s, id, mode); - if (R_SUCCEEDED(rc)) rc = _appletGetEvent(&h->s, &h->StateChangedEvent, 0, false);//GetAppletStateChangedEvent - - if (R_SUCCEEDED(rc) && hosversionAtLeast(2,0,0) && h->mode == LibAppletMode_BackgroundIndirect) rc = _appletGetIndirectLayerConsumerHandle(&h->s, &h->layer_handle); + if (R_SUCCEEDED(rc)) rc = _appletHolderCreateState(h, mode, creating_self); return rc; } @@ -2743,6 +2881,28 @@ Result appletHolderStart(AppletHolder *h) { return rc; } +Result appletHolderJump(AppletHolder *h) { + Result rc=0; + + if (!serviceIsActive(&h->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (!h->creating_self) rc = _appletWaitLibraryAppletLaunchableEvent(); + + if (hosversionBefore(4,0,0)) + rc = _appletReserveToStartAndWaitAndUnwindThis(h); + else + rc = _appletReserveToStartAndWait(h); + + if (R_SUCCEEDED(rc)) rc = _appletWindAndDoReserved(); + + if (R_FAILED(rc)) return rc; + + while(1)svcSleepThread(86400000000000ULL); + + return rc; +} + Result appletHolderRequestExit(AppletHolder *h) { Result rc=0; @@ -4619,6 +4779,11 @@ AppletFocusState appletGetFocusState(void) { return (AppletFocusState)g_appletFocusState; } +AppletInfo *appletGetAppletInfo(void) { + if (!g_appletInfoInitialized) return NULL; + return &g_appletInfo; +} + Result appletGetMessage(u32 *msg) { Result rc=0; if (msg==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);