Implement better platform identification and descriptions in preloader log

This commit is contained in:
Bepis committed 2022-01-24 18:05:22 +11:00
1 parent 7669b6dbec
commit a02c330295
3 files changed
+162 -8

No files matched your search

+2
View File
@@ -31,6 +31,8 @@ internal static class NetPreloaderRunner
internal static void OuterMain(string[] args, string filename)
{
PlatformUtils.SetPlatform();
Paths.SetExecutablePath(filename);
AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BepInEx.Logging;
using BepInEx.Shared;
using MonoMod.Utils;
@@ -25,10 +27,120 @@ public static class ChainloaderLogHelper
log.Log(LogLevel.Message, attribute.Info);
}
Logger.Log(LogLevel.Info, $"System platform: {PlatformHelper.Current}");
Logger.Log(LogLevel.Info, $"System platform: {GetPlatformString()}");
Logger.Log(LogLevel.Info, $"Process bitness: {(PlatformUtils.ProcessIs64Bit ? "64-bit (x64)" : "32-bit (x86)")}");
}
private static string GetPlatformString()
{
var builder = new StringBuilder();
var osVersion = Environment.OSVersion.Version;
// NOTE: this logic needs to be different for .NET 5.
// We don't use it and I don't think we will for a long time (possibly ever), but upgrading will break Environment.OSVersion
// https://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/environment-osversion-returns-correct-version#change-description
// Some additional notes
// On .NET Framework and .NET Core platforms before 5, Environment.OSVersion does not work as you would expect.
// On Windows, it returns at maximum 6.3 (Windows 8) if you don't specify that your application is specifically compatible with Windows 10, due to compatibility layer stuff.
// So we have to call RtlGetVersion which bypasses that and gets the values for us. This is done in PlatformUtils
// On macOS it returns the Darwin kernel version. I've included a mapping of most versions, but there's definitely some missing versions
// Not sure what it does on Linux. I think it returns the kernel version there too, but we already get the utsname structure from SetPlatform() regardless
if (PlatformHelper.Is(Platform.Windows))
{
osVersion = PlatformUtils.WindowsVersion;
builder.Append("Windows ");
// https://stackoverflow.com/a/2819962
if (osVersion.Major >= 10 && osVersion.Build >= 22000)
builder.Append("11");
else if (osVersion.Major >= 10)
builder.Append("10");
else if (osVersion.Major == 6 && osVersion.Minor == 3)
builder.Append("8.1");
else if (osVersion.Major == 6 && osVersion.Minor == 2)
builder.Append("8");
else if (osVersion.Major == 6 && osVersion.Minor == 1)
builder.Append("7");
else if (osVersion.Major == 6 && osVersion.Minor == 0)
builder.Append("Vista");
else if (osVersion.Major <= 5)
builder.Append("XP");
}
else if (PlatformHelper.Is(Platform.MacOS))
{
builder.Append("macOS ");
var osxVersion = osVersion.ToString(3);
if (MacOSVersions.TryGetValue(osxVersion, out var macOsVersion))
{
builder.Append(macOsVersion);
}
else
{
builder.AppendFormat("Unknown (kernel {0})", osVersion);
}
}
else if (PlatformHelper.Is(Platform.Linux))
{
builder.Append("Linux");
if (PlatformUtils.LinuxKernelVersion != null)
{
builder.AppendFormat(" (kernel {0})", PlatformUtils.LinuxKernelVersion);
}
}
builder.Append(PlatformHelper.Is(Platform.Bits64) ? " 64-bit" : " 32-bit");
if (PlatformHelper.Is(Platform.Android))
{
builder.Append(" Android");
}
if (PlatformHelper.Is(Platform.ARM))
{
builder.Append(" ARM");
if (PlatformHelper.Is(Platform.Bits64))
builder.Append("64");
}
return builder.ToString();
}
private static Dictionary<string, string> MacOSVersions { get; } = new()
{
// https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history
["16.0.0"] = "10.12",
["16.5.0"] = "10.12.4",
["16.6.0"] = "10.12.6",
["17.5.0"] = "10.13.4",
["17.6.0"] = "10.13.5",
["17.7.0"] = "10.13.6",
["18.2.0"] = "10.14.1",
["19.2.0"] = "10.15.2",
["19.3.0"] = "10.15.3",
["19.5.0"] = "10.15.5.1",
["20.1.0"] = "11.0",
["20.2.0"] = "11.1",
["20.3.0"] = "11.2",
["20.4.0"] = "11.3",
["20.5.0"] = "11.4",
["21.0.1"] = "12.0",
["21.1.0"] = "12.0.1",
["21.2.0"] = "12.1",
};
public static void RewritePreloaderLogs()
{
if (PreloaderConsoleListener.LogEvents == null || PreloaderConsoleListener.LogEvents.Count == 0)
+47 -7
View File
@@ -16,7 +16,19 @@ internal static class PlatformUtils
CharSet = CharSet.Ansi)]
private static extern IntPtr uname_osx(ref utsname_osx utsname);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern bool RtlGetVersion(ref WindowsOSVersionInfoExW versionInfo);
private static bool Is(this Platform current, Platform expected) => (current & expected) == expected;
public static readonly bool ProcessIs64Bit = IntPtr.Size >= 8;
public static Version WindowsVersion { get; set; }
public static string LinuxArchitecture { get; set; }
public static string LinuxKernelVersion { get; set; }
/// <summary>
/// Recreation of MonoMod's PlatformHelper.DeterminePlatform method, but with libc calls instead of creating processes.
@@ -40,13 +52,22 @@ internal static class PlatformUtils
current = Platform.Windows;
else if (platID.Contains("mac") || platID.Contains("osx"))
current = Platform.MacOS;
else if (platID.Contains("lin") || platID.Contains("unix")) current = Platform.Linux;
else if (platID.Contains("lin") || platID.Contains("unix"))
current = Platform.Linux;
if (Is(current, Platform.Linux) && Directory.Exists("/data") && File.Exists("/system/build.prop"))
if (current.Is(Platform.Linux) && Directory.Exists("/data") && File.Exists("/system/build.prop"))
current = Platform.Android;
else if (Is(current, Platform.Unix) && Directory.Exists("/System/Library/AccessibilityBundles"))
else if (current.Is(Platform.Unix) && Directory.Exists("/System/Library/AccessibilityBundles"))
current = Platform.iOS;
if (current.Is(Platform.Windows))
{
var windowsVersionInfo = new WindowsOSVersionInfoExW();
RtlGetVersion(ref windowsVersionInfo);
WindowsVersion = new Version((int)windowsVersionInfo.dwMajorVersion, (int)windowsVersionInfo.dwMinorVersion, 0, (int)windowsVersionInfo.dwBuildNumber);
}
// Is64BitOperatingSystem has been added in .NET Framework 4.0
var m_get_Is64BitOperatingSystem =
typeof(Environment).GetProperty("Is64BitOperatingSystem")?.GetGetMethod();
@@ -54,13 +75,13 @@ internal static class PlatformUtils
current |= (bool) m_get_Is64BitOperatingSystem.Invoke(null, new object[0]) ? Platform.Bits64 : 0;
else
current |= IntPtr.Size >= 8 ? Platform.Bits64 : 0;
if ((Is(current, Platform.MacOS) || Is(current, Platform.Linux)) && Type.GetType("Mono.Runtime") != null)
if ((current.Is(Platform.MacOS) || current.Is(Platform.Linux)) && Type.GetType("Mono.Runtime") != null)
{
string arch;
IntPtr result;
if (Is(current, Platform.MacOS))
if (current.Is(Platform.MacOS))
{
var utsname_osx = new utsname_osx();
result = uname_osx(ref utsname_osx);
@@ -72,6 +93,9 @@ internal static class PlatformUtils
var utsname_linux = new utsname_linux();
result = uname_linux(ref utsname_linux);
arch = utsname_linux.machine;
LinuxArchitecture = utsname_linux.machine;
LinuxKernelVersion = utsname_linux.version;
}
if (result == IntPtr.Zero && (arch.StartsWith("aarch") || arch.StartsWith("arm")))
@@ -88,7 +112,23 @@ internal static class PlatformUtils
PlatformHelper.Current = current;
}
private static bool Is(Platform current, Platform expected) => (current & expected) == expected;
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
public struct WindowsOSVersionInfoExW
{
private static uint size = (uint)Marshal.SizeOf(typeof(WindowsOSVersionInfoExW));
public uint dwOSVersionInfoSize = size;
public uint dwMajorVersion;
public uint dwMinorVersion;
public uint dwBuildNumber;
public uint dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCSDVersion;
public ushort wServicePackMajor;
public ushort wServicePackMinor;
public ushort wSuiteMask;
public byte wProductType;
public byte wReserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct utsname_osx