diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index 77c879b8..3268fdcb 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -12,6 +12,7 @@ #include "../services/async.h" #include "../services/acc.h" #include "../services/fs.h" +#include "../applets/error.h" #include "../kernel/event.h" #include "../kernel/tmem.h" @@ -82,6 +83,53 @@ typedef struct { u8 unk_x11[7]; ///< Unknown. } NsApplicationRecord; +/// ApplicationViewDeprecated. The below comments are for the \ref NsApplicationView to NsApplicationViewDeprecated conversion done by \ref nsGetApplicationViewDeprecated on newer system-versions. +typedef struct { + u64 application_id; ///< Same as NsApplicationView::application_id. + u8 unk_x8[0x4]; ///< Same as NsApplicationView::unk_x8. + u32 flags; ///< Same as NsApplicationView::flags. + u8 unk_x10[0x10]; ///< Same as NsApplicationView::unk_x10. + u32 unk_x20; ///< Same as NsApplicationView::unk_x20. + u16 unk_x24; ///< Same as NsApplicationView::unk_x24. + u8 unk_x26[0x2]; ///< Cleared to zero. + u8 unk_x28[0x10]; ///< Same as NsApplicationView::unk_x30. + u32 unk_x38; ///< Same as NsApplicationView::unk_x40. + u8 unk_x3c; ///< Same as NsApplicationView::unk_x44. + u8 unk_x3d[3]; ///< Cleared to zero. +} NsApplicationViewDeprecated; + +/// ApplicationView +typedef struct { + u64 application_id; ///< ApplicationId. + u8 unk_x8[0x4]; ///< Unknown. + u32 flags; ///< Flags. + u8 unk_x10[0x10]; ///< Unknown. + u32 unk_x20; ///< Unknown. + u16 unk_x24; ///< Unknown. + u8 unk_x26[0x2]; ///< Unknown. + u8 unk_x28[0x8]; ///< Unknown. + u8 unk_x30[0x10]; ///< Unknown. + u32 unk_x40; ///< Unknown. + u8 unk_x44; ///< Unknown. + u8 unk_x45[0xb]; ///< Unknown. +} NsApplicationView; + +/// NsPromotionInfo +typedef struct { + u64 start_timestamp; ///< POSIX timestamp for the promotion start. + u64 end_timestamp; ///< POSIX timestamp for the promotion end. + s64 remaining_time; ///< Remaining time until the promotion ends, in nanoseconds ({end_timestamp - current_time} converted to nanoseconds). + u8 unk_x18[0x4]; ///< Not set, left at zero. + u8 flags; ///< Flags. Bit0: whether the PromotionInfo is valid (including bit1). Bit1 clear: remaining_time is set. + u8 pad[3]; ///< Padding. +} NsPromotionInfo; + +/// NsApplicationViewWithPromotionInfo +typedef struct { + NsApplicationView view; ///< \ref NsApplicationView + NsPromotionInfo promotion; ///< \ref NsPromotionInfo +} NsApplicationViewWithPromotionInfo; + /// LaunchProperties typedef struct { u64 program_id; ///< program_id. @@ -186,6 +234,15 @@ Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entr */ Result nsGetApplicationRecordUpdateSystemEvent(Event* out_event); +/** + * @brief GetApplicationViewDeprecated + * @note On [3.0.0+] you should generally use \ref nsGetApplicationView instead. + * @param[out] out Output array of \ref NsApplicationViewDeprecated. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationViewDeprecated(NsApplicationViewDeprecated *views, const u64 *application_ids, s32 count); + /** * @brief DeleteApplicationEntity * @param[in] application_id ApplicationId. @@ -550,6 +607,32 @@ Result nsNeedsSystemUpdateToFormatSdCard(bool *out); */ Result nsGetLastSdCardFormatUnexpectedResult(void); +/** + * @brief GetApplicationView + * @note Only available on [3.0.0+], on prior system-versions use \ref nsGetApplicationViewDeprecated instead. + * @param[out] out Output array of \ref NsApplicationView. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationView(NsApplicationView *views, const u64 *application_ids, s32 count); + +/** + * @brief GetApplicationViewDownloadErrorContext + * @note Only available on [4.0.0+]. + * @param[in] application_id ApplicationId + * @param[out] context \ref ErrorContext + */ +Result nsGetApplicationViewDownloadErrorContext(u64 application_id, ErrorContext *context); + +/** + * @brief GetApplicationViewWithPromotionInfo + * @note Only available on [8.0.0+]. + * @param[out] out Output array of \ref NsApplicationViewWithPromotionInfo. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the input/output arrays in entries. + */ +Result nsGetApplicationViewWithPromotionInfo(NsApplicationViewWithPromotionInfo *out, const u64 *application_ids, s32 count); + /** * @brief RequestDownloadApplicationPrepurchasedRights * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. @@ -776,6 +859,15 @@ Result nsRequestNoDownloadRightsErrorResolution(AsyncValue *a, u64 application_i */ Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id); +/** + * @brief GetPromotionInfo + * @note Only available on [8.0.0+]. + * @param[out] promotion \ref NsPromotionInfo + * @param application_id ApplicationId. + * @param[in] uid \ref AccountUid + */ +Result nsGetPromotionInfo(NsPromotionInfo *promotion, u64 application_id, AccountUid uid); + ///@} ///@name IRequestServerStopper diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index 35ac9c4f..abc2ca6b 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -245,6 +245,19 @@ Result nsGetApplicationRecordUpdateSystemEvent(Event* out_event) { return _nsCmdGetEvent(&g_nsAppManSrv, out_event, true, 2); } +Result nsGetApplicationViewDeprecated(NsApplicationViewDeprecated *views, const u64 *application_ids, s32 count) { + return serviceDispatch(&g_nsAppManSrv, 3, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { views, count*sizeof(NsApplicationViewDeprecated) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + Result nsDeleteApplicationEntity(u64 application_id) { return _nsCmdInU64(&g_nsAppManSrv, application_id, 4); } @@ -652,6 +665,48 @@ Result nsGetLastSdCardFormatUnexpectedResult(void) { return _nsCmdNoIO(&g_nsAppManSrv, 1502); } +Result nsGetApplicationView(NsApplicationView *views, const u64 *application_ids, s32 count) { + if (hosversionBefore(3,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_nsAppManSrv, 1701, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { views, count*sizeof(NsApplicationView) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + +Result nsGetApplicationViewDownloadErrorContext(u64 application_id, ErrorContext *context) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchIn(&g_nsAppManSrv, 1703, application_id, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { context, sizeof(*context) } }, + ); +} + +Result nsGetApplicationViewWithPromotionInfo(NsApplicationViewWithPromotionInfo *out, const u64 *application_ids, s32 count) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatch(&g_nsAppManSrv, 1704, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { out, count*sizeof(NsApplicationViewWithPromotionInfo) }, + { application_ids, count*sizeof(u64) }, + }, + ); +} + Result nsRequestDownloadApplicationPrepurchasedRights(AsyncResult *a, u64 application_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -977,6 +1032,26 @@ Result nsRequestResolveNoDownloadRightsError(AsyncValue *a, u64 application_id) return _nsCmdInU64OutAsyncValue(&g_nsAppManSrv, a, application_id, 2352); } +Result nsGetPromotionInfo(NsPromotionInfo *promotion, u64 application_id, AccountUid uid) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + // These are arrays, but official sw uses hard-coded value 1 for array-count. + + return serviceDispatch(&g_nsAppManSrv, 2400, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { promotion, sizeof(NsPromotionInfo) }, + { &application_id, sizeof(u64) }, + { &uid, sizeof(AccountUid) }, + }, + ); +} + // IRequestServerStopper void nsRequestServerStopperClose(NsRequestServerStopper *r) {