/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Host/SystemInfo.hpp" #include "Base/Logger.hpp" #include "IosDeviceNameDecoder.hpp" #include #include #include #include #import #import #import #import namespace OpenVulkano { Event<> SystemInfo::OnLowPowerModeChanged; Event<> SystemInfo::OnBatteryStateChanged; Event<> SystemInfo::OnBatteryLevelChanged; Event<> SystemInfo::OnDeviceOrientationChanged; size_t SystemInfo::GetSystemRam() { static const size_t ram = [NSProcessInfo processInfo].physicalMemory; return ram; } size_t SystemInfo::GetSystemRamAvailable() { return os_proc_available_memory(); } size_t SystemInfo::GetAppRamMax() { return GetAppRamAvailable() + GetAppRamUsed(); } size_t SystemInfo::GetAppVirtualMemoryMax() { return INT64_MAX; } size_t SystemInfo::GetAppRamAvailable() { return os_proc_available_memory(); } size_t SystemInfo::GetAppRamUsed() { struct task_basic_info info; mach_msg_type_number_t size = sizeof(info); kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); if( kerr == KERN_SUCCESS ) { return info.resident_size; } Logger::PERF->error("Failed to read memory consumption: {}", mach_error_string(kerr)); return 0; } const std::string& SystemInfo::GetUserName() { static const std::string userName = ""; return userName; } const std::string& SystemInfo::GetHostName() { static const std::string hostName = [[NSProcessInfo processInfo].hostName UTF8String]; return hostName; } const std::string& SystemInfo::GetDeviceName() { static const std::string devName = [[[UIDevice currentDevice] name] UTF8String]; return devName; } const std::string& SystemInfo::GetDeviceVendorName() { static const std::string vendorName = "Apple"; return vendorName; } const std::string& SystemInfo::GetDeviceModelName() { static std::string modelName; if (modelName.empty()) { struct utsname systemInfo; uname(&systemInfo); modelName = DecodeModelString(systemInfo.machine); if (modelName.empty()) modelName = [[[UIDevice currentDevice] model] UTF8String]; } return modelName; } const std::string& SystemInfo::GetOsName() { static const std::string osName = [[[UIDevice currentDevice] systemName] UTF8String]; return osName; } OsVersion SystemInfo::GetOsVersion() { static OsVersion osv = {}; if (osv.major == 0 && osv.minor == 0) { NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; osv = { static_cast(osVersion.majorVersion), static_cast(osVersion.minorVersion), static_cast(osVersion.patchVersion), 0 }; } return osv; } const std::string& SystemInfo::GetOsNameHumanReadable() { static std::string hrName; if (hrName.empty()) { OsVersion osVersion = GetOsVersion(); hrName = fmt::format("{} {}.{}", GetOsName(), osVersion.major, osVersion.minor); } return hrName; } DeviceType SystemInfo::GetDeviceType() { static DeviceType devType = DeviceType::Unknown; if (devType == DeviceType::Unknown) { switch ([UIDevice currentDevice].userInterfaceIdiom) { case UIUserInterfaceIdiomPhone: devType = DeviceType::Phone; case UIUserInterfaceIdiomPad: devType = DeviceType::Tablet; case UIUserInterfaceIdiomTV: devType = DeviceType::TV; case UIUserInterfaceIdiomMac: devType = DeviceType::PC; case UIUserInterfaceIdiomVision: devType = DeviceType::VR; default: break; } } return devType; } size_t SystemInfo::GetCpuCoreCount() { static const size_t coreCount = [NSProcessInfo processInfo].processorCount; return coreCount; } size_t SystemInfo::GetCpuThreadCount() { static const size_t threadCount = [NSProcessInfo processInfo].activeProcessorCount; return threadCount; } int32_t SystemInfo::GetCpuTemperature() { switch([NSProcessInfo processInfo].thermalState) { case NSProcessInfoThermalStateNominal: return 20; case NSProcessInfoThermalStateFair: return 50; case NSProcessInfoThermalStateSerious: return 80; case NSProcessInfoThermalStateCritical: return 100; } return -1; } CpuThermalState SystemInfo::GetCpuThermalState() { switch([NSProcessInfo processInfo].thermalState) { case NSProcessInfoThermalStateNominal: return CpuThermalState::Normal; case NSProcessInfoThermalStateFair: return CpuThermalState::Fair; case NSProcessInfoThermalStateSerious: return CpuThermalState::Serious; case NSProcessInfoThermalStateCritical: return CpuThermalState::Critical; } return CpuThermalState::Normal; } bool SystemInfo::IsDeviceInLowPowerMode() { return [NSProcessInfo processInfo].lowPowerModeEnabled; } void SystemInfo::EnableEnergyEvents() { [[NSNotificationCenter defaultCenter] addObserverForName:NSProcessInfoPowerStateDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { SystemInfo::OnLowPowerModeChanged.NotifyAll(); }]; [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceBatteryLevelDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { SystemInfo::OnBatteryLevelChanged.NotifyAll(); }]; [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceBatteryStateDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { SystemInfo::OnBatteryStateChanged.NotifyAll(); }]; } BatteryState SystemInfo::GetDeviceBatteryState() { switch([UIDevice currentDevice].batteryState) { case UIDeviceBatteryStateUnplugged: return BatteryState::Unplugged; case UIDeviceBatteryStateCharging: return BatteryState::Charging; case UIDeviceBatteryStateFull: return BatteryState::ChargingFull; default: break; } return BatteryState::Unavailable; } float SystemInfo::GetDeviceBatteryLevel() { return [UIDevice currentDevice].batteryLevel; } bool SystemInfo::IsMultitaskingSupported() { return [UIDevice currentDevice].multitaskingSupported; } DeviceOrientation SystemInfo::GetDeviceOrientation() { switch([UIDevice currentDevice].orientation) { case UIDeviceOrientationPortrait: return DeviceOrientation::Portrait; case UIDeviceOrientationPortraitUpsideDown: return DeviceOrientation::PortraitUpsideDown; case UIDeviceOrientationLandscapeLeft: return DeviceOrientation::LandscapeLeft; case UIDeviceOrientationLandscapeRight: return DeviceOrientation::LandscapeRight; case UIDeviceOrientationFaceUp: return DeviceOrientation::FaceUp; case UIDeviceOrientationFaceDown: return DeviceOrientation::FaceDown; default: break; } return DeviceOrientation::Unknown; } void SystemInfo::EnableDeviceOrientationEvents() { [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { SystemInfo::OnDeviceOrientationChanged.NotifyAll(); }]; [[UIDevice currentDevice]beginGeneratingDeviceOrientationNotifications]; } InterfaceOrientation SystemInfo::GetInterfaceOrientation() { if (@available(iOS 15.0, *)) { //TODO support multi scene at some point UIInterfaceOrientation interfaceOrientation; for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { if ([scene isKindOfClass:[UIWindowScene class]]) { interfaceOrientation = ((UIWindowScene *)scene).interfaceOrientation; break; } } switch(interfaceOrientation) { case UIInterfaceOrientationPortrait: return InterfaceOrientation::Portrait; case UIInterfaceOrientationPortraitUpsideDown: return InterfaceOrientation::PortraitUpsideDown; case UIInterfaceOrientationLandscapeLeft: return InterfaceOrientation::LandscapeLeft; case UIInterfaceOrientationLandscapeRight: return InterfaceOrientation::LandscapeRight; default: break; } } else { switch(GetDeviceOrientation()) { case DeviceOrientation::Portrait: return InterfaceOrientation::Portrait; case DeviceOrientation::PortraitUpsideDown: return InterfaceOrientation::PortraitUpsideDown; case DeviceOrientation::LandscapeLeft: return InterfaceOrientation::LandscapeRight; case DeviceOrientation::LandscapeRight: return InterfaceOrientation::LandscapeLeft; default: break; } } return InterfaceOrientation::Landscape; } }