using System.Globalization;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace HarmonyPerf.Blog;
// Small protocol helpers. The application owns HDC, session recovery,
// incremental response parsing, sample recording and UI lifecycle.
public static class SmartPerfCommands
{
public static string CreateToken() =>
Convert.ToHexString(RandomNumberGenerator.GetBytes(16)).ToLowerInvariant();
public static string Init(string token, bool highPerformance,
int intervalMs = 500, string packageName = "")
{
token = ValidateToken(token);
if (intervalMs is < 500 or > 60_000)
throw new ArgumentOutOfRangeException(nameof(intervalMs));
var package = packageName.Trim();
if (package.Any(c => !char.IsAsciiLetterOrDigit(c) && c is not '.' and not '_' and not '-'))
throw new ArgumentException("Invalid package name.", nameof(packageName));
var app = package.Length == 0 ? "" : $" -PKG {package} -f";
var performance = highPerformance ? " -lockfreq" : "";
return $"init::{token} -SESSIONID 1 -INTERVAL {intervalMs.ToString(CultureInfo.InvariantCulture)}" +
$" -c -g -r -d -t -p -net{app}{performance}";
}
public static string Start(string token) => $"start::{ValidateToken(token)}";
public static string Keepalive(string token) => $"keepalive::{ValidateToken(token)}";
public static string Stop(string token) => $"stop::{ValidateToken(token)}";
private static string ValidateToken(string token)
{
ArgumentNullException.ThrowIfNull(token);
if (token.Length != 32 || token.Any(c => !Uri.IsHexDigit(c)))
throw new ArgumentException("Expected 32 hexadecimal characters.", nameof(token));
return token.ToLowerInvariant();
}
// Register an ACK waiter in the receiving loop BEFORE calling this method.
// A TCP ReadAsync completion is not a message boundary.
public static async Task SendSerializedAsync(NetworkStream stream,
SemaphoreSlim writeGate, string command, CancellationToken cancellationToken)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using var linked = CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken, timeout.Token);
var entered = false;
try
{
await writeGate.WaitAsync(linked.Token).ConfigureAwait(false);
entered = true;
// No newline is added by this daemon's command protocol.
await stream.WriteAsync(Encoding.UTF8.GetBytes(command), linked.Token).ConfigureAwait(false);
}
catch (OperationCanceledException) when (timeout.IsCancellationRequested &&
!cancellationToken.IsCancellationRequested)
{
throw new TimeoutException("SmartPerf command write timed out.");
}
finally
{
if (entered) writeGate.Release();
}
}
}
public sealed record ScreenState(int BaseTimeoutMs, int? OverrideTimeoutMs, string? PowerState)
{
public bool IsAwake => PowerState == "AWAKE";
}
public static class ScreenCommands
{
public const int FiniteTimeoutMs = 7_200_000;
public const string Read = "hidumper -s PowerManagerService -a '-s'";
public const string Wakeup = "power-shell wakeup";
private static readonly Regex TimeoutPattern = new(
@"^[ \t]*ScreenOffTime:[ \t]*Timeout=(?-?\d+)ms(?:[ \t]+OverrideTimeout=(?-?\d+)ms)?[ \t]*\r?$",
RegexOptions.Multiline | RegexOptions.CultureInvariant);
private static readonly Regex StatePattern = new(
@"^[ \t]*Current State:[ \t]*(?[A-Z_]+)(?:[ \t]+Reason:.*)?[ \t]*\r?$",
RegexOptions.Multiline | RegexOptions.CultureInvariant);
public static ScreenState Parse(string dump)
{
var matches = TimeoutPattern.Matches(dump);
if (matches.Count != 1) throw new FormatException("Expected one screen timeout record.");
var baseline = ParseTimeout(matches[0].Groups["base"].Value);
var temporary = matches[0].Groups["override"];
int? overridden = temporary.Success ? ParseTimeout(temporary.Value) : null;
var states = StatePattern.Matches(dump);
if (states.Count > 1) throw new FormatException("Ambiguous power state.");
return new(baseline, overridden, states.Count == 1 ? states[0].Groups["state"].Value : null);
}
public static string Override(int milliseconds)
{
if (milliseconds < -1) throw new ArgumentOutOfRangeException(nameof(milliseconds));
return $"power-shell timeout -o {milliseconds.ToString(CultureInfo.InvariantCulture)}";
}
// Persist original BEFORE any override. Before restore, cancel and join renewals.
public static string Restore(ScreenState original)
{
if (original.BaseTimeoutMs < -1 || original.OverrideTimeoutMs is < -1)
throw new ArgumentOutOfRangeException(nameof(original));
return original.OverrideTimeoutMs is int prior ? Override(prior) : "power-shell timeout -r";
}
public static bool InfiniteExplicitlyRejected(string output) =>
output.Trim() == "Override screen off time to -1 failed";
public static void RequireResponse(string output, string expected)
{
if (!string.Equals(output.Trim(), expected, StringComparison.Ordinal))
throw new InvalidOperationException("Device did not confirm the requested command.");
}
// A sleeping screen after a user's power-button action may still have a valid override.
public static bool SameTimeouts(ScreenState actual, ScreenState expected) =>
actual.BaseTimeoutMs == expected.BaseTimeoutMs && actual.OverrideTimeoutMs == expected.OverrideTimeoutMs;
private static int ParseTimeout(string text)
{
if (!int.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var value) || value < -1)
throw new FormatException("Invalid screen timeout value.");
return value;
}
}