From 7f7ba1780254cc0eee43487484b38b397f33a89c Mon Sep 17 00:00:00 2001
From: yellows8 <yellows8@users.noreply.github.com>
Date: Sat, 29 Jun 2019 20:44:03 -0400
Subject: [PATCH] Fixed appletQueryApplicationPlayStatistics and added
 appletQueryApplicationPlayStatisticsByUid. Renamed
 AppletApplicationPlayStatistics to PdmApplicationPlayStatistics, updated it,
 and moved it to new file pdm.h.

---
 nx/include/switch.h                 |  1 +
 nx/include/switch/services/applet.h | 25 ++++++++-----
 nx/include/switch/services/pdm.h    | 16 +++++++++
 nx/source/services/applet.c         | 56 ++++++++++++++++++++++++++---
 4 files changed, 84 insertions(+), 14 deletions(-)
 create mode 100644 nx/include/switch/services/pdm.h

diff --git a/nx/include/switch.h b/nx/include/switch.h
index 467736f8..e9fbd656 100644
--- a/nx/include/switch.h
+++ b/nx/include/switch.h
@@ -90,6 +90,7 @@ extern "C" {
 #include "switch/services/nfc.h"
 #include "switch/services/wlaninf.h"
 #include "switch/services/pctl.h"
+#include "switch/services/pdm.h"
 
 #include "switch/display/binder.h"
 #include "switch/display/parcel.h"
diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h
index 53f6a7d8..7daad349 100644
--- a/nx/include/switch/services/applet.h
+++ b/nx/include/switch/services/applet.h
@@ -9,6 +9,7 @@
 #include "../types.h"
 #include "../services/sm.h"
 #include "../services/apm.h"
+#include "../services/pdm.h"
 #include "../kernel/tmem.h"
 #include "../kernel/event.h"
 
@@ -135,11 +136,6 @@ typedef struct {
     LibAppletExitReason exitreason;    ///< Set by \ref appletHolderJoin using the output from cmd GetResult, see \ref LibAppletExitReason.
 } AppletHolder;
 
-/// 'pdm' ApplicationPlayStatistics
-typedef struct {
-    u8 unk_x0[0x8];
-} AppletApplicationPlayStatistics;
-
 /// Attributes for launching applications for Quest.
 typedef struct {
     u32 unk_x0;
@@ -226,13 +222,24 @@ Result appletEndBlockingHomeButton(void);
 /**
  * @brief Gets ApplicationPlayStatistics.
  * @note Only available with AppletType_*Application on 5.0.0+.
- * @note This may return no output in some cases.
- * @param stats Output \ref AppletApplicationPlayStatistics array.
+ * @note The input titleIDs must be allowed via control.nacp with the current host title. The minimum allowed titleID is the titleID for the current-process.
+ * @param stats Output \ref PdmApplicationPlayStatistics array.
  * @param titleIDs Input titleIDs array.
  * @param count Total entries in the input/output arrays.
- * @param out Output s32.
+ * @param total_out Total output entries.
  */
-Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *out);
+Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out);
+
+/**
+ * @brief Same as \ref appletQueryApplicationPlayStatistics except this gets playstats specific to the input userID.
+ * @note Only available with AppletType_*Application on 6.0.0+.
+ * @param userID userID
+ * @param stats Output \ref PdmApplicationPlayStatistics array.
+ * @param titleIDs Input titleIDs array.
+ * @param count Total entries in the input/output arrays.
+ * @param total_out Total output entries.
+ */
+Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out);
 
 /**
  * @brief Delay exiting until \ref appletUnlockExit is called, with a 15 second timeout once exit is requested.
diff --git a/nx/include/switch/services/pdm.h b/nx/include/switch/services/pdm.h
new file mode 100644
index 00000000..d66c4270
--- /dev/null
+++ b/nx/include/switch/services/pdm.h
@@ -0,0 +1,16 @@
+/**
+ * @file pdm.h
+ * @brief PDM (pdm:*) service IPC wrapper.
+ * @author yellows8
+ * @copyright libnx Authors
+ */
+#pragma once
+#include "../types.h"
+#include "../services/sm.h"
+
+/// ApplicationPlayStatistics
+typedef struct {
+    u64 titleID;                      ///< titleID
+    u8 unk_x8[0x10];                  ///< Unknown
+} PdmApplicationPlayStatistics;
+
diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c
index 0ee932b8..d270f4c7 100644
--- a/nx/source/services/applet.c
+++ b/nx/source/services/applet.c
@@ -1445,8 +1445,8 @@ Result appletInitializeGamePlayRecording(void) {
     return rc;
 }
 
-//Official sw has this under 'pdm'.
-Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *out) {
+//Official sw has these under 'pdm'.
+Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out) {
     IpcCommand c;
     ipcInitialize(&c);
 
@@ -1456,8 +1456,8 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta
     if (hosversionBefore(5,0,0))
         return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
 
-    ipcAddRecvBuffer(&c, stats, count*sizeof(AppletApplicationPlayStatistics), BufferType_Normal);
     ipcAddSendBuffer(&c, titleIDs, count*sizeof(u64), BufferType_Normal);
+    ipcAddRecvBuffer(&c, stats, count*sizeof(PdmApplicationPlayStatistics), BufferType_Normal);
 
     struct {
         u64 magic;
@@ -1476,7 +1476,7 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta
         struct {
             u64 magic;
             u64 result;
-            s32 out;
+            s32 total_out;
         } *resp;
 
         serviceIpcParse(&g_appletIFunctions, &r, sizeof(*resp));
@@ -1484,7 +1484,53 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta
 
         rc = resp->result;
 
-        if (R_SUCCEEDED(rc) && out) *out = resp->out;
+        if (R_SUCCEEDED(rc) && total_out) *total_out = resp->total_out;
+    }
+
+    return rc;
+}
+
+Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out) {
+    IpcCommand c;
+    ipcInitialize(&c);
+
+    if (!serviceIsActive(&g_appletSrv) || !_appletIsRegularApplication())
+        return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
+
+    if (hosversionBefore(6,0,0))
+        return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
+
+    ipcAddSendBuffer(&c, titleIDs, count*sizeof(u64), BufferType_Normal);
+    ipcAddRecvBuffer(&c, stats, count*sizeof(PdmApplicationPlayStatistics), BufferType_Normal);
+
+    struct {
+        u64 magic;
+        u64 cmd_id;
+        u128 userID;
+    } *raw;
+
+    raw = serviceIpcPrepareHeader(&g_appletIFunctions, &c, sizeof(*raw));
+
+    raw->magic = SFCI_MAGIC;
+    raw->cmd_id = 111;
+    raw->userID = userID;
+
+    Result rc = serviceIpcDispatch(&g_appletIFunctions);
+
+    if (R_SUCCEEDED(rc)) {
+        IpcParsedCommand r;
+        struct {
+            u64 magic;
+            u64 result;
+            s32 total_out;
+        } *resp;
+
+        serviceIpcParse(&g_appletIFunctions, &r, sizeof(*resp));
+        resp = r.Raw;
+
+        rc = resp->result;
+
+        if (R_SUCCEEDED(rc) && total_out) *total_out = resp->total_out;
     }
 
     return rc;