From acdd958b7c02be383bc2ef4290ba7a4fc0546bf9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:39:22 +0000 Subject: [PATCH 1/9] Document Process timing after exit Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.FreeBSD.cs | 6 ++++ .../src/System/Diagnostics/Process.Linux.cs | 6 ++++ .../src/System/Diagnostics/Process.OSX.cs | 6 ++++ .../src/System/Diagnostics/Process.OpenBSD.cs | 6 ++++ .../src/System/Diagnostics/Process.SunOS.cs | 6 ++++ .../src/System/Diagnostics/Process.Windows.cs | 6 ++++ .../src/System/Diagnostics/Process.cs | 14 +++++---- .../tests/ProcessTests.cs | 29 +++++++++++++++++++ 8 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs index 10171374d39c78..dfeff939d77637 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs @@ -27,6 +27,8 @@ internal DateTime StartTimeCore /// It is the sum of the and /// . /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -49,6 +51,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -69,6 +73,8 @@ public TimeSpan UserProcessorTime } /// Gets the amount of time the process has spent running code inside the operating system core. + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs index 4b22d5bbd8e088..9abc76a9bd3570 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs @@ -14,6 +14,8 @@ namespace System.Diagnostics public partial class Process : IDisposable { /// Gets the amount of time the process has spent running code inside the operating system core. + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -88,6 +90,8 @@ private static DateTime BootTime /// It is the sum of the and /// . /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -109,6 +113,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs index f3f236b3f93e5b..468a938bddcf1e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs @@ -15,6 +15,8 @@ public partial class Process private const int MicrosecondsToSecondsFactor = 1_000_000; /// Gets the amount of time the process has spent running code inside the operating system core. + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -62,6 +64,8 @@ internal static string GetPathToOpenFile() /// It is the sum of the and /// . /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -84,6 +88,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs index f3ccc9cb35b613..216cb7d7a934b7 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs @@ -27,6 +27,8 @@ internal DateTime StartTimeCore /// It is the sum of the and /// . /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -49,6 +51,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -69,6 +73,8 @@ public TimeSpan UserProcessorTime } /// Gets the amount of time the process has spent running code inside the operating system core. + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs index fb515db23e5ccb..f39fe398c7ca17 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs @@ -46,6 +46,8 @@ internal DateTime StartTimeCore /// It is the sum of the and /// . /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -65,6 +67,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -83,6 +87,8 @@ public TimeSpan UserProcessorTime /// Gets the amount of time the process has spent running code inside the operating /// system core. /// + /// The value is unavailable after the process exits. + /// No process is associated with this object, or the process has exited. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs index 8686f53aeb076d..af01af280e8c85 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs @@ -193,6 +193,8 @@ private DateTime ExitTimeCore } /// Gets the amount of time the process has spent running code inside the operating system core. + /// The value can be retrieved after the process exits. + /// No process is associated with this object. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -212,6 +214,8 @@ internal DateTime StartTimeCore /// It is the sum of the and /// . /// + /// The value can be retrieved after the process exits. + /// No process is associated with this object. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -224,6 +228,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// + /// The value can be retrieved after the process exits. + /// No process is associated with this object. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 7450c980e98069..885a9598708696 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -188,6 +188,13 @@ public bool HasExited } /// Gets the time the associated process was started. + /// + /// On Windows, this property can be read after the process exits. + /// On Unix, it can be read after exit only if it was accessed while the process was running. + /// + /// + /// No process is associated with this object, or the process exited on Unix before the property was accessed. + /// [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -203,11 +210,8 @@ public DateTime StartTime } } - /// - /// - /// Gets the time that the associated process exited. - /// - /// + /// Gets the time that the associated process exited. + /// The process has not exited. public DateTime ExitTime { get diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index a8f25b6f282d98..23ead40cfb9baf 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -751,6 +751,35 @@ public void TestExitTime() Assert.InRange(p.ExitTime.ToUniversalTime(), timeBeforeProcessStart, DateTime.MaxValue); } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Process timing information is not supported on iOS/tvOS")] + public void TimingProperties_AfterProcessExit() + { + Process process = CreateProcess(); + process.Start(); + Assert.True(process.WaitForExit(WaitInMS)); + + Assert.Equal(RemoteExecutor.SuccessExitCode, process.ExitCode); + Assert.NotEqual(default, process.ExitTime); + + if (OperatingSystem.IsWindows()) + { + // Windows process handles retain timing information after the process exits. + Assert.InRange(process.StartTime, DateTime.MinValue, process.ExitTime); + Assert.InRange(process.PrivilegedProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); + Assert.InRange(process.TotalProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); + Assert.InRange(process.UserProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); + } + else + { + // Unix reaps child processes after exit, so timing information that was not cached is unavailable. + Assert.Throws(() => process.StartTime); + Assert.Throws(() => process.PrivilegedProcessorTime); + Assert.Throws(() => process.TotalProcessorTime); + Assert.Throws(() => process.UserProcessorTime); + } + } + [Fact] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "libproc is not supported on iOS/tvOS")] public void StartTime_GetNotStarted_ThrowsInvalidOperationException() From d377590e19bc8db81e4e07b38b788d0a229630f2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:41:46 +0000 Subject: [PATCH 2/9] Clarify Unix StartTime caching Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 3 ++- src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 885a9598708696..a8152fce66cccb 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -190,7 +190,8 @@ public bool HasExited /// Gets the time the associated process was started. /// /// On Windows, this property can be read after the process exits. - /// On Unix, it can be read after exit only if it was accessed while the process was running. + /// On Unix, accessing this property caches its value. A cached value can be read after the process exits, + /// but the first access after exit throws . /// /// /// No process is associated with this object, or the process exited on Unix before the property was accessed. diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 23ead40cfb9baf..08dad1b8cc63e1 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -772,7 +772,7 @@ public void TimingProperties_AfterProcessExit() } else { - // Unix reaps child processes after exit, so timing information that was not cached is unavailable. + // Unix reaps child processes after exit. Processor times are unavailable, and StartTime was not cached. Assert.Throws(() => process.StartTime); Assert.Throws(() => process.PrivilegedProcessorTime); Assert.Throws(() => process.TotalProcessorTime); From 802d661fcb8c0505d8d52293a699ed481aea9ab4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:45:53 +0000 Subject: [PATCH 3/9] Clarify exited StartTime test Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 08dad1b8cc63e1..4675d321e73049 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -772,7 +772,8 @@ public void TimingProperties_AfterProcessExit() } else { - // Unix reaps child processes after exit. Processor times are unavailable, and StartTime was not cached. + // Unix reaps child processes after exit. Processor times are unavailable, and StartTime was not + // accessed before exit and therefore was not cached. Assert.Throws(() => process.StartTime); Assert.Throws(() => process.PrivilegedProcessorTime); Assert.Throws(() => process.TotalProcessorTime); From 2d17f3b3a8d17104719f59ff3591b8f32d0cd4de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Jul 2026 16:18:50 +0000 Subject: [PATCH 4/9] Address review feedback on Process timing docs and tests Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 11 +++++++---- .../System.Diagnostics.Process/tests/ProcessTests.cs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index a8152fce66cccb..dfd2a184e285aa 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -190,11 +190,11 @@ public bool HasExited /// Gets the time the associated process was started. /// /// On Windows, this property can be read after the process exits. - /// On Unix, accessing this property caches its value. A cached value can be read after the process exits, - /// but the first access after exit throws . + /// On Unix, this property caches its value on first access. A cached value can be read after the process exits, + /// but accessing an uncached value after the process has been reaped may throw . /// /// - /// No process is associated with this object, or the process exited on Unix before the property was accessed. + /// No process is associated with this object, or on Unix the value was not cached before the process was reaped. /// [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] @@ -212,7 +212,10 @@ public DateTime StartTime } /// Gets the time that the associated process exited. - /// The process has not exited. + /// + /// No process is associated with this object, the process has not exited, + /// or there is no process handle available. + /// public DateTime ExitTime { get diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 4675d321e73049..69b7212a4f70c6 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -765,7 +765,7 @@ public void TimingProperties_AfterProcessExit() if (OperatingSystem.IsWindows()) { // Windows process handles retain timing information after the process exits. - Assert.InRange(process.StartTime, DateTime.MinValue, process.ExitTime); + Assert.NotEqual(default, process.StartTime); Assert.InRange(process.PrivilegedProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); Assert.InRange(process.TotalProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); Assert.InRange(process.UserProcessorTime, TimeSpan.Zero, TimeSpan.MaxValue); From 8695dd14d635a8de3b048717392cc5cc997a3e7e Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 15 Jul 2026 18:33:18 +0200 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/System/Diagnostics/Process.Windows.cs | 12 ++++++------ .../src/System/Diagnostics/Process.cs | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs index af01af280e8c85..6661126f034a47 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs @@ -193,8 +193,8 @@ private DateTime ExitTimeCore } /// Gets the amount of time the process has spent running code inside the operating system core. - /// The value can be retrieved after the process exits. - /// No process is associated with this object. + /// If a handle to the process is available, the value can be retrieved after the process exits. + /// No process is associated with this object, or there is no process handle available. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -214,8 +214,8 @@ internal DateTime StartTimeCore /// It is the sum of the and /// . /// - /// The value can be retrieved after the process exits. - /// No process is associated with this object. + /// If a handle to the process is available, the value can be retrieved after the process exits. + /// No process is associated with this object, or there is no process handle available. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -228,8 +228,8 @@ public TimeSpan TotalProcessorTime /// Gets the amount of time the associated process has spent running code /// inside the application portion of the process (not the operating system core). /// - /// The value can be retrieved after the process exits. - /// No process is associated with this object. + /// If a handle to the process is available, the value can be retrieved after the process exits. + /// No process is associated with this object, or there is no process handle available. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index dfd2a184e285aa..059e8759faf2af 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -189,12 +189,13 @@ public bool HasExited /// Gets the time the associated process was started. /// - /// On Windows, this property can be read after the process exits. + /// On Windows, if a handle to the process is available, this property can be read after the process exits. /// On Unix, this property caches its value on first access. A cached value can be read after the process exits, /// but accessing an uncached value after the process has been reaped may throw . /// /// - /// No process is associated with this object, or on Unix the value was not cached before the process was reaped. + /// No process is associated with this object; on Windows, there is no process handle available; or on Unix, + /// the value was not cached before the process was reaped. /// [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] From 4002a1283551cf3aae50b71f4d2bf1ed81f259e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:04:16 +0000 Subject: [PATCH 6/9] Unify processor time XML docs using partial properties Move TotalProcessorTime, UserProcessorTime, and PrivilegedProcessorTime XML documentation to Process.cs (shared file) using partial property declarations. The unified docs describe both Windows (handle-based post-exit availability) and Unix (unavailable after exit) behavior. Platform-specific files now contain only the partial implementations without documentation, eliminating duplication and ensuring the official docs get a single unified description across all OSes. Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.FreeBSD.cs | 31 ++---------- .../src/System/Diagnostics/Process.Linux.cs | 31 ++---------- .../src/System/Diagnostics/Process.OSX.cs | 31 ++---------- .../src/System/Diagnostics/Process.OpenBSD.cs | 31 ++---------- .../src/System/Diagnostics/Process.SunOS.cs | 34 ++----------- .../src/System/Diagnostics/Process.Windows.cs | 31 ++---------- .../src/System/Diagnostics/Process.cs | 48 +++++++++++++++++++ 7 files changed, 66 insertions(+), 171 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs index dfeff939d77637..851db8f923bcd9 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.FreeBSD.cs @@ -22,17 +22,7 @@ internal DateTime StartTimeCore } } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { @@ -47,16 +37,7 @@ public TimeSpan TotalProcessorTime } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get { @@ -72,13 +53,7 @@ public TimeSpan UserProcessorTime } } - /// Gets the amount of time the process has spent running code inside the operating system core. - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs index 9abc76a9bd3570..ce1bd2180efe2e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs @@ -13,13 +13,7 @@ namespace System.Diagnostics { public partial class Process : IDisposable { - /// Gets the amount of time the process has spent running code inside the operating system core. - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get => IsCurrentProcess ? Environment.CpuUsage.PrivilegedTime : TicksToTimeSpan(GetStat().stime); } @@ -85,17 +79,7 @@ private static DateTime BootTime return null; } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { @@ -109,16 +93,7 @@ public TimeSpan TotalProcessorTime } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get => IsCurrentProcess ? Environment.CpuUsage.UserTime : TicksToTimeSpan(GetStat().utime); } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs index 468a938bddcf1e..629335c06e4705 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OSX.cs @@ -14,13 +14,7 @@ public partial class Process private const int MicrosecondsToSecondsFactor = 1_000_000; - /// Gets the amount of time the process has spent running code inside the operating system core. - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get { @@ -59,17 +53,7 @@ internal static string GetPathToOpenFile() return "/usr/bin/open"; } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { @@ -84,16 +68,7 @@ public TimeSpan TotalProcessorTime } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs index 216cb7d7a934b7..40c2953d90b101 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.OpenBSD.cs @@ -22,17 +22,7 @@ internal DateTime StartTimeCore } } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { @@ -47,16 +37,7 @@ public TimeSpan TotalProcessorTime } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get { @@ -72,13 +53,7 @@ public TimeSpan UserProcessorTime } } - /// Gets the amount of time the process has spent running code inside the operating system core. - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs index f39fe398c7ca17..cf0ba747869f0c 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.SunOS.cs @@ -41,17 +41,7 @@ internal DateTime StartTimeCore return ProcessUtils.FindProgramInPath("xdg-open"); } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { @@ -63,16 +53,7 @@ public TimeSpan TotalProcessorTime } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get { @@ -83,16 +64,7 @@ public TimeSpan UserProcessorTime } } - /// - /// Gets the amount of time the process has spent running code inside the operating - /// system core. - /// - /// The value is unavailable after the process exits. - /// No process is associated with this object, or the process has exited. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs index 6661126f034a47..489459e5c00483 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs @@ -192,13 +192,7 @@ private DateTime ExitTimeCore get { return GetProcessTimes().ExitTime; } } - /// Gets the amount of time the process has spent running code inside the operating system core. - /// If a handle to the process is available, the value can be retrieved after the process exits. - /// No process is associated with this object, or there is no process handle available. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get => IsCurrentProcess ? Environment.CpuUsage.PrivilegedTime : GetProcessTimes().PrivilegedProcessorTime; } @@ -209,31 +203,12 @@ internal DateTime StartTimeCore get { return GetProcessTimes().StartTime; } } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - /// If a handle to the process is available, the value can be retrieved after the process exits. - /// No process is associated with this object, or there is no process handle available. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get => IsCurrentProcess ? Environment.CpuUsage.TotalTime : GetProcessTimes().TotalProcessorTime; } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - /// If a handle to the process is available, the value can be retrieved after the process exits. - /// No process is associated with this object, or there is no process handle available. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get => IsCurrentProcess ? Environment.CpuUsage.UserTime : GetProcessTimes().UserProcessorTime; } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 059e8759faf2af..3284c7f79e5b99 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -231,6 +231,54 @@ public DateTime ExitTime } } + /// Gets the amount of time the process has spent running code inside the operating system core. + /// + /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits. + /// On Unix, the value is unavailable after the process exits. + /// + /// + /// No process is associated with this object. On Windows, there is no process handle available. + /// On Unix, the process has exited. + /// + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [SupportedOSPlatform("maccatalyst")] + public partial TimeSpan PrivilegedProcessorTime { get; } + + /// + /// Gets the amount of time the associated process has spent utilizing the CPU. + /// It is the sum of the and . + /// + /// + /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits. + /// On Unix, the value is unavailable after the process exits. + /// + /// + /// No process is associated with this object. On Windows, there is no process handle available. + /// On Unix, the process has exited. + /// + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [SupportedOSPlatform("maccatalyst")] + public partial TimeSpan TotalProcessorTime { get; } + + /// + /// Gets the amount of time the associated process has spent running code + /// inside the application portion of the process (not the operating system core). + /// + /// + /// On Windows, if a handle to the process is available, the value can be retrieved after the process exits. + /// On Unix, the value is unavailable after the process exits. + /// + /// + /// No process is associated with this object. On Windows, there is no process handle available. + /// On Unix, the process has exited. + /// + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [SupportedOSPlatform("maccatalyst")] + public partial TimeSpan UserProcessorTime { get; } + /// /// /// Gets From f217d8d781095394b21a0f3c73a99e9ea4d90d58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:04:47 +0000 Subject: [PATCH 7/9] Address Process timing doc and test feedback Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 3 +++ .../src/System/Diagnostics/Process.iOS.cs | 25 +++---------------- .../tests/ProcessTests.cs | 15 ++++++++++- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 3284c7f79e5b99..40e945cb08fc50 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -240,6 +240,7 @@ public DateTime ExitTime /// No process is associated with this object. On Windows, there is no process handle available. /// On Unix, the process has exited. /// + /// The operating system could not retrieve process timing information. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -257,6 +258,7 @@ public DateTime ExitTime /// No process is associated with this object. On Windows, there is no process handle available. /// On Unix, the process has exited. /// + /// The operating system could not retrieve process timing information. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] @@ -274,6 +276,7 @@ public DateTime ExitTime /// No process is associated with this object. On Windows, there is no process handle available. /// On Unix, the process has exited. /// + /// The operating system could not retrieve process timing information. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs index 2a5d3ddb785291..e2bd120e8e1cc8 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs @@ -18,11 +18,7 @@ public void Kill(bool entireProcessTree) throw new PlatformNotSupportedException(); } - /// Gets the amount of time the process has spent running code inside the operating system core. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan PrivilegedProcessorTime + public partial TimeSpan PrivilegedProcessorTime { get { throw new PlatformNotSupportedException(); } } @@ -35,27 +31,12 @@ internal static DateTime StartTimeCore get { throw new PlatformNotSupportedException(); } } - /// - /// Gets the amount of time the associated process has spent utilizing the CPU. - /// It is the sum of the and - /// . - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan TotalProcessorTime + public partial TimeSpan TotalProcessorTime { get { throw new PlatformNotSupportedException(); } } - /// - /// Gets the amount of time the associated process has spent running code - /// inside the application portion of the process (not the operating system core). - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public TimeSpan UserProcessorTime + public partial TimeSpan UserProcessorTime { get { throw new PlatformNotSupportedException(); } } diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 69b7212a4f70c6..38feb8ba871b11 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -755,7 +755,7 @@ public void TestExitTime() [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Process timing information is not supported on iOS/tvOS")] public void TimingProperties_AfterProcessExit() { - Process process = CreateProcess(); + using Process process = CreateProcess(static () => RemoteExecutor.SuccessExitCode); process.Start(); Assert.True(process.WaitForExit(WaitInMS)); @@ -781,6 +781,19 @@ public void TimingProperties_AfterProcessExit() } } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Process timing information is not supported on iOS/tvOS")] + public void StartTime_AfterProcessExit_WhenCachedBeforeExit_IsAvailable() + { + using Process process = CreateProcess(static () => RemoteExecutor.SuccessExitCode); + process.Start(); + DateTime startTime = process.StartTime; + Assert.True(process.WaitForExit(WaitInMS)); + + Assert.NotEqual(default, startTime); + Assert.Equal(startTime, process.StartTime); + } + [Fact] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "libproc is not supported on iOS/tvOS")] public void StartTime_GetNotStarted_ThrowsInvalidOperationException() From f2fcfcfe518ccfac06d0ccde8c11c53339db1d94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Jul 2026 17:39:08 +0000 Subject: [PATCH 8/9] test: stabilize Process StartTime after-exit caching test Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../System.Diagnostics.Process/tests/ProcessTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 38feb8ba871b11..d903ced342bc91 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -752,7 +752,6 @@ public void TestExitTime() } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Process timing information is not supported on iOS/tvOS")] public void TimingProperties_AfterProcessExit() { using Process process = CreateProcess(static () => RemoteExecutor.SuccessExitCode); @@ -782,12 +781,13 @@ public void TimingProperties_AfterProcessExit() } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Process timing information is not supported on iOS/tvOS")] public void StartTime_AfterProcessExit_WhenCachedBeforeExit_IsAvailable() { - using Process process = CreateProcess(static () => RemoteExecutor.SuccessExitCode); + using Process process = CreateProcessLong(); process.Start(); DateTime startTime = process.StartTime; + + process.Kill(); Assert.True(process.WaitForExit(WaitInMS)); Assert.NotEqual(default, startTime); From bc589644d374888a77107b4c1a29440321df7352 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:35:43 +0000 Subject: [PATCH 9/9] Use public terminology in StartTime XML docs Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 40e945cb08fc50..c088f4226902d8 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -191,11 +191,11 @@ public bool HasExited /// /// On Windows, if a handle to the process is available, this property can be read after the process exits. /// On Unix, this property caches its value on first access. A cached value can be read after the process exits, - /// but accessing an uncached value after the process has been reaped may throw . + /// but accessing an uncached value after the process exits may throw when the value is unavailable. /// /// /// No process is associated with this object; on Windows, there is no process handle available; or on Unix, - /// the value was not cached before the process was reaped. + /// the value was not cached and is unavailable after the process exited. /// [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")]