diff options
Diffstat (limited to 'xbmc/utils/SystemInfo.cpp')
-rw-r--r-- | xbmc/utils/SystemInfo.cpp | 1469 |
1 files changed, 1469 insertions, 0 deletions
diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp new file mode 100644 index 0000000..e85c415 --- /dev/null +++ b/xbmc/utils/SystemInfo.cpp @@ -0,0 +1,1469 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include <limits.h> + +#include "SystemInfo.h" +#ifndef TARGET_POSIX +#include <conio.h> +#else +#include <sys/utsname.h> +#endif +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/CurlFile.h" +#include "filesystem/File.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/guiinfo/GUIInfoLabels.h" +#include "network/Network.h" +#include "platform/Filesystem.h" +#include "rendering/RenderSystem.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/CPUInfo.h" +#include "utils/log.h" + +#ifdef TARGET_WINDOWS +#include <dwmapi.h> +#include "utils/CharsetConverter.h" +#include <VersionHelpers.h> + +#ifdef TARGET_WINDOWS_STORE +#include <winrt/Windows.Security.ExchangeActiveSyncProvisioning.h> +#include <winrt/Windows.System.Profile.h> + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::Security::ExchangeActiveSyncProvisioning; +using namespace winrt::Windows::System; +using namespace winrt::Windows::System::Profile; +#endif +#include <wincrypt.h> +#include "platform/win32/CharsetConverter.h" +#endif +#if defined(TARGET_DARWIN) +#include "platform/darwin/DarwinUtils.h" +#endif +#include "powermanagement/PowerManager.h" +#include "utils/StringUtils.h" +#include "utils/XMLUtils.h" +#if defined(TARGET_ANDROID) +#include <androidjni/Build.h> +#include <androidjni/Context.h> +#include <androidjni/PackageManager.h> +#endif + +/* Platform identification */ +#if defined(TARGET_DARWIN) +#include <Availability.h> +#include <mach-o/arch.h> +#include <sys/sysctl.h> +#elif defined(TARGET_ANDROID) +#include <android/api-level.h> +#include <sys/system_properties.h> +#elif defined(TARGET_FREEBSD) +#include <sys/param.h> +#elif defined(TARGET_LINUX) +#include "platform/linux/SysfsPath.h" + +#include <linux/version.h> +#endif + +#include <system_error> + +/* Expand macro before stringify */ +#define STR_MACRO(x) #x +#define XSTR_MACRO(x) STR_MACRO(x) + +namespace +{ +auto startTime = std::chrono::steady_clock::now(); +} + +using namespace XFILE; + +#ifdef TARGET_WINDOWS_DESKTOP +static bool sysGetVersionExWByRef(OSVERSIONINFOEXW& osVerInfo) +{ + osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo); + + typedef NTSTATUS(__stdcall *RtlGetVersionPtr)(RTL_OSVERSIONINFOEXW* pOsInfo); + static HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll"); + if (hNtDll != NULL) + { + static RtlGetVersionPtr RtlGetVer = (RtlGetVersionPtr) GetProcAddress(hNtDll, "RtlGetVersion"); + if (RtlGetVer && RtlGetVer(&osVerInfo) == 0) + return true; + } + // failed to get OS information directly from ntdll.dll + // use GetVersionExW() as fallback + // note: starting from Windows 8.1 GetVersionExW() may return unfaithful information + if (GetVersionExW((OSVERSIONINFOW*) &osVerInfo) != 0) + return true; + + ZeroMemory(&osVerInfo, sizeof(osVerInfo)); + return false; +} + +static bool appendWindows10NameVersion(std::string& osNameVer) +{ + wchar_t versionW[32] = {}; + DWORD len = sizeof(versionW); + bool obtained = false; + if (ERROR_SUCCESS == RegGetValueW(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, L"DisplayVersion", + RRF_RT_REG_SZ, nullptr, &versionW, &len)) + { + obtained = true; + } + else if (ERROR_SUCCESS == RegGetValueW(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, L"ReleaseId", + RRF_RT_REG_SZ, nullptr, &versionW, &len)) + { + obtained = true; + } + if (obtained) + osNameVer.append(StringUtils::Format(" {}", KODI::PLATFORM::WINDOWS::FromW(versionW))); + + return obtained; +} +#endif // TARGET_WINDOWS_DESKTOP + +#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID) +static std::string getValueFromOs_release(std::string key) +{ + FILE* os_rel = fopen("/etc/os-release", "r"); + if (!os_rel) + return ""; + + char* buf = new char[10 * 1024]; // more than enough + size_t len = fread(buf, 1, 10 * 1024, os_rel); + fclose(os_rel); + if (len == 0) + { + delete[] buf; + return ""; + } + + std::string content(buf, len); + delete[] buf; + + // find begin of value string + size_t valStart = 0, seachPos; + key += '='; + if (content.compare(0, key.length(), key) == 0) + valStart = key.length(); + else + { + key = "\n" + key; + seachPos = 0; + do + { + seachPos = content.find(key, seachPos); + if (seachPos == std::string::npos) + return ""; + if (seachPos == 0 || content[seachPos - 1] != '\\') + valStart = seachPos + key.length(); + else + seachPos++; + } while (valStart == 0); + } + + if (content[valStart] == '\n') + return ""; + + // find end of value string + seachPos = valStart; + do + { + seachPos = content.find('\n', seachPos + 1); + } while (seachPos != std::string::npos && content[seachPos - 1] == '\\'); + size_t const valEnd = seachPos; + + std::string value(content, valStart, valEnd - valStart); + if (value.empty()) + return value; + + // remove quotes + if (value[0] == '\'' || value[0] == '"') + { + if (value.length() < 2) + return value; + size_t qEnd = value.rfind(value[0]); + if (qEnd != std::string::npos) + { + value.erase(qEnd); + value.erase(0, 1); + } + } + + // unescape characters + for (size_t slashPos = value.find('\\'); slashPos < value.length() - 1; slashPos = value.find('\\', slashPos)) + { + if (value[slashPos + 1] == '\n') + value.erase(slashPos, 2); + else + { + value.erase(slashPos, 1); + slashPos++; // skip unescaped character + } + } + + return value; +} + +enum lsb_rel_info_type +{ + lsb_rel_distributor, + lsb_rel_description, + lsb_rel_release, + lsb_rel_codename +}; + +static std::string getValueFromLsb_release(enum lsb_rel_info_type infoType) +{ + std::string key, command("unset PYTHONHOME; unset PYTHONPATH; lsb_release "); + switch (infoType) + { + case lsb_rel_distributor: + command += "-i"; + key = "Distributor ID:\t"; + break; + case lsb_rel_description: + command += "-d"; + key = "Description:\t"; + break; + case lsb_rel_release: + command += "-r"; + key = "Release:\t"; + break; + case lsb_rel_codename: + command += "-c"; + key = "Codename:\t"; + break; + default: + return ""; + } + command += " 2>/dev/null"; + FILE* lsb_rel = popen(command.c_str(), "r"); + if (lsb_rel == NULL) + return ""; + + char buf[300]; // more than enough + if (fgets(buf, 300, lsb_rel) == NULL) + { + pclose(lsb_rel); + return ""; + } + pclose(lsb_rel); + + std::string response(buf); + if (response.compare(0, key.length(), key) != 0) + return ""; + + return response.substr(key.length(), response.find('\n') - key.length()); +} +#endif // TARGET_LINUX && !TARGET_ANDROID + +CSysInfo g_sysinfo; + +CSysInfoJob::CSysInfoJob() = default; + +bool CSysInfoJob::DoWork() +{ + m_info.systemUptime = GetSystemUpTime(false); + m_info.systemTotalUptime = GetSystemUpTime(true); + m_info.internetState = GetInternetState(); + m_info.videoEncoder = GetVideoEncoder(); + m_info.cpuFrequency = + StringUtils::Format("{:4.0f} MHz", CServiceBroker::GetCPUInfo()->GetCPUFrequency()); + m_info.osVersionInfo = CSysInfo::GetOsPrettyNameWithVersion() + " (kernel: " + CSysInfo::GetKernelName() + " " + CSysInfo::GetKernelVersionFull() + ")"; + m_info.macAddress = GetMACAddress(); + m_info.batteryLevel = GetBatteryLevel(); + return true; +} + +const CSysData &CSysInfoJob::GetData() const +{ + return m_info; +} + +CSysData::INTERNET_STATE CSysInfoJob::GetInternetState() +{ + // Internet connection state! + XFILE::CCurlFile http; + if (http.IsInternet()) + return CSysData::CONNECTED; + return CSysData::DISCONNECTED; +} + +std::string CSysInfoJob::GetMACAddress() +{ + CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface(); + if (iface) + return iface->GetMacAddress(); + + return ""; +} + +std::string CSysInfoJob::GetVideoEncoder() +{ + return "GPU: " + CServiceBroker::GetRenderSystem()->GetRenderRenderer(); +} + +std::string CSysInfoJob::GetBatteryLevel() +{ + return StringUtils::Format("{}%", CServiceBroker::GetPowerManager().BatteryLevel()); +} + +bool CSysInfoJob::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays) +{ + iHours = 0; iDays = 0; + iMinutes = iInputMinutes; + if (iMinutes >= 60) // Hour's + { + iHours = iMinutes / 60; + iMinutes = iMinutes - (iHours *60); + } + if (iHours >= 24) // Days + { + iDays = iHours / 24; + iHours = iHours - (iDays * 24); + } + return true; +} + +std::string CSysInfoJob::GetSystemUpTime(bool bTotalUptime) +{ + std::string strSystemUptime; + int iInputMinutes, iMinutes,iHours,iDays; + + auto now = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast<std::chrono::minutes>(now - startTime); + + if(bTotalUptime) + { + //Total Uptime + iInputMinutes = g_sysinfo.GetTotalUptime() + duration.count(); + } + else + { + //Current UpTime + iInputMinutes = duration.count(); + } + + SystemUpTime(iInputMinutes,iMinutes, iHours, iDays); + if (iDays > 0) + { + strSystemUptime = + StringUtils::Format("{} {}, {} {}, {} {}", iDays, g_localizeStrings.Get(12393), iHours, + g_localizeStrings.Get(12392), iMinutes, g_localizeStrings.Get(12391)); + } + else if (iDays == 0 && iHours >= 1 ) + { + strSystemUptime = StringUtils::Format("{} {}, {} {}", iHours, g_localizeStrings.Get(12392), + iMinutes, g_localizeStrings.Get(12391)); + } + else if (iDays == 0 && iHours == 0 && iMinutes >= 0) + { + strSystemUptime = StringUtils::Format("{} {}", iMinutes, g_localizeStrings.Get(12391)); + } + return strSystemUptime; +} + +std::string CSysInfo::TranslateInfo(int info) const +{ + switch(info) + { + case SYSTEM_VIDEO_ENCODER_INFO: + return m_info.videoEncoder; + case NETWORK_MAC_ADDRESS: + return m_info.macAddress; + case SYSTEM_OS_VERSION_INFO: + return m_info.osVersionInfo; + case SYSTEM_CPUFREQUENCY: + return m_info.cpuFrequency; + case SYSTEM_UPTIME: + return m_info.systemUptime; + case SYSTEM_TOTALUPTIME: + return m_info.systemTotalUptime; + case SYSTEM_INTERNET_STATE: + if (m_info.internetState == CSysData::CONNECTED) + return g_localizeStrings.Get(13296); + else + return g_localizeStrings.Get(13297); + case SYSTEM_BATTERY_LEVEL: + return m_info.batteryLevel; + default: + return ""; + } +} + +void CSysInfo::Reset() +{ + m_info.Reset(); +} + +CSysInfo::CSysInfo(void) : CInfoLoader(15 * 1000) +{ + memset(MD5_Sign, 0, sizeof(MD5_Sign)); + m_iSystemTimeTotalUp = 0; +} + +CSysInfo::~CSysInfo() = default; + +bool CSysInfo::Load(const TiXmlNode *settings) +{ + if (settings == NULL) + return false; + + const TiXmlElement *pElement = settings->FirstChildElement("general"); + if (pElement) + XMLUtils::GetInt(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, INT_MAX); + + return true; +} + +bool CSysInfo::Save(TiXmlNode *settings) const +{ + if (settings == NULL) + return false; + + TiXmlNode *generalNode = settings->FirstChild("general"); + if (generalNode == NULL) + { + TiXmlElement generalNodeNew("general"); + generalNode = settings->InsertEndChild(generalNodeNew); + if (generalNode == NULL) + return false; + } + XMLUtils::SetInt(generalNode, "systemtotaluptime", m_iSystemTimeTotalUp); + + return true; +} + +const std::string& CSysInfo::GetAppName(void) +{ + assert(CCompileInfo::GetAppName() != NULL); + static const std::string appName(CCompileInfo::GetAppName()); + + return appName; +} + +bool CSysInfo::GetDiskSpace(std::string drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed) +{ + using namespace KODI::PLATFORM::FILESYSTEM; + + space_info total = {}; + std::error_code ec; + + // None of this makes sense but the idea of total space + // makes no sense on any system really. + // Return space for / or for C: as it's correct in a sense + // and not much worse than trying to count a total for different + // drives/mounts + if (drive.empty() || drive == "*") + { +#if defined(TARGET_WINDOWS) + drive = "C"; +#elif defined(TARGET_POSIX) + drive = "/"; +#endif + } + +#ifdef TARGET_WINDOWS_DESKTOP + using KODI::PLATFORM::WINDOWS::ToW; + UINT uidriveType = GetDriveType(ToW(drive + ":\\").c_str()); + if (uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR) + total = space(drive + ":\\", ec); +#elif defined(TARGET_POSIX) + total = space(drive, ec); +#endif + if (ec.value() != 0) + return false; + + iTotal = static_cast<int>(total.capacity / MB); + iTotalFree = static_cast<int>(total.free / MB); + iTotalUsed = iTotal - iTotalFree; + if (total.capacity > 0) + iPercentUsed = static_cast<int>(100.0f * (total.capacity - total.free) / total.capacity + 0.5f); + else + iPercentUsed = 0; + + iPercentFree = 100 - iPercentUsed; + + return true; +} + +std::string CSysInfo::GetKernelName(bool emptyIfUnknown /*= false*/) +{ + static std::string kernelName; + if (kernelName.empty()) + { +#if defined(TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi = {}; + if (sysGetVersionExWByRef(osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + kernelName = "Windows NT"; +#elif defined(TARGET_WINDOWS_STORE) + auto e = EasClientDeviceInformation(); + auto os = e.OperatingSystem(); + g_charsetConverter.wToUTF8(std::wstring(os.c_str()), kernelName); +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + kernelName.assign(un.sysname); +#endif // defined(TARGET_POSIX) + + if (kernelName.empty()) + kernelName = "Unknown kernel"; // can't detect + } + + if (emptyIfUnknown && kernelName == "Unknown kernel") + return ""; + + return kernelName; +} + +std::string CSysInfo::GetKernelVersionFull(void) +{ + static std::string kernelVersionFull; + if (!kernelVersionFull.empty()) + return kernelVersionFull; + +#if defined(TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi = {}; + DWORD dwBuildRevision = 0; + DWORD len = sizeof(DWORD); + + if (sysGetVersionExWByRef(osvi)) + kernelVersionFull = StringUtils::Format("{}.{}.{}", osvi.dwMajorVersion, osvi.dwMinorVersion, + osvi.dwBuildNumber); + // get UBR (updates build revision) + if (ERROR_SUCCESS == RegGetValueW(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, L"UBR", + RRF_RT_REG_DWORD, nullptr, &dwBuildRevision, &len)) + { + kernelVersionFull += StringUtils::Format(".{}", dwBuildRevision); + } + +#elif defined(TARGET_WINDOWS_STORE) + // get the system version number + auto sv = AnalyticsInfo::VersionInfo().DeviceFamilyVersion(); + wchar_t* end; + unsigned long long v = wcstoull(sv.c_str(), &end, 10); + unsigned long long v1 = (v & 0xFFFF000000000000L) >> 48; + unsigned long long v2 = (v & 0x0000FFFF00000000L) >> 32; + unsigned long long v3 = (v & 0x00000000FFFF0000L) >> 16; + unsigned long long v4 = (v & 0x000000000000FFFFL); + kernelVersionFull = StringUtils::Format("{}.{}.{}", v1, v2, v3); + if (v4) + kernelVersionFull += StringUtils::Format(".{}", v4); + +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + kernelVersionFull.assign(un.release); +#endif // defined(TARGET_POSIX) + + if (kernelVersionFull.empty()) + kernelVersionFull = "0.0.0"; // can't detect + + return kernelVersionFull; +} + +std::string CSysInfo::GetKernelVersion(void) +{ + static std::string kernelVersionClear; + if (kernelVersionClear.empty()) + { + kernelVersionClear = GetKernelVersionFull(); + const size_t erasePos = kernelVersionClear.find_first_not_of("0123456789."); + if (erasePos != std::string::npos) + kernelVersionClear.erase(erasePos); + } + + return kernelVersionClear; +} + +std::string CSysInfo::GetOsName(bool emptyIfUnknown /* = false*/) +{ + static std::string osName; + if (osName.empty()) + { +#if defined (TARGET_WINDOWS) + osName = GetKernelName() + "-based OS"; +#elif defined(TARGET_FREEBSD) + osName = GetKernelName(true); // FIXME: for FreeBSD OS name is a kernel name +#elif defined(TARGET_DARWIN_IOS) + osName = "iOS"; +#elif defined(TARGET_DARWIN_TVOS) + osName = "tvOS"; +#elif defined(TARGET_DARWIN_OSX) + osName = "macOS"; +#elif defined (TARGET_ANDROID) + if (CJNIContext::GetPackageManager().hasSystemFeature("android.software.leanback")) + osName = "Android TV"; + else + osName = "Android"; +#elif defined(TARGET_LINUX) + osName = getValueFromOs_release("NAME"); + if (osName.empty()) + osName = getValueFromLsb_release(lsb_rel_distributor); + if (osName.empty()) + osName = getValueFromOs_release("ID"); +#endif // defined(TARGET_LINUX) + + if (osName.empty()) + osName = "Unknown OS"; + } + + if (emptyIfUnknown && osName == "Unknown OS") + return ""; + + return osName; +} + +std::string CSysInfo::GetOsVersion(void) +{ + static std::string osVersion; + if (!osVersion.empty()) + return osVersion; + +#if defined(TARGET_WINDOWS) || defined(TARGET_FREEBSD) + osVersion = GetKernelVersion(); // FIXME: for Win32 and FreeBSD OS version is a kernel version +#elif defined(TARGET_DARWIN) + osVersion = CDarwinUtils::GetVersionString(); +#elif defined(TARGET_ANDROID) + char versionCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.build.version.release", versionCStr); + osVersion.assign(versionCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); + + if (osVersion.empty() || std::string("0123456789").find(versionCStr[0]) == std::string::npos) + osVersion.clear(); // can't correctly detect Android version + else + { + size_t pointPos = osVersion.find('.'); + if (pointPos == std::string::npos) + osVersion += ".0.0"; + else if (osVersion.find('.', pointPos + 1) == std::string::npos) + osVersion += ".0"; + } +#elif defined(TARGET_LINUX) + osVersion = getValueFromOs_release("VERSION_ID"); + if (osVersion.empty()) + osVersion = getValueFromLsb_release(lsb_rel_release); +#endif // defined(TARGET_LINUX) + + if (osVersion.empty()) + osVersion = "0.0"; + + return osVersion; +} + +std::string CSysInfo::GetOsPrettyNameWithVersion(void) +{ + static std::string osNameVer; + if (!osNameVer.empty()) + return osNameVer; + +#if defined (TARGET_WINDOWS_DESKTOP) + OSVERSIONINFOEXW osvi = {}; + + osNameVer = "Windows "; + if (sysGetVersionExWByRef(osvi)) + { + switch (GetWindowsVersion()) + { + case WindowsVersionWin7: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("7"); + else + osNameVer.append("Server 2008 R2"); + break; + case WindowsVersionWin8: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("8"); + else + osNameVer.append("Server 2012"); + break; + case WindowsVersionWin8_1: + if (osvi.wProductType == VER_NT_WORKSTATION) + osNameVer.append("8.1"); + else + osNameVer.append("Server 2012 R2"); + break; + case WindowsVersionWin10: + case WindowsVersionWin10_1709: + case WindowsVersionWin10_1803: + case WindowsVersionWin10_1809: + case WindowsVersionWin10_1903: + case WindowsVersionWin10_1909: + case WindowsVersionWin10_2004: + case WindowsVersionWin10_Future: + osNameVer.append("10"); + appendWindows10NameVersion(osNameVer); + break; + case WindowsVersionWin11: + osNameVer.append("11"); + appendWindows10NameVersion(osNameVer); + break; + case WindowsVersionFuture: + osNameVer.append("Unknown future version"); + break; + default: + osNameVer.append("Unknown version"); + break; + } + + // Append Service Pack version if any + if (osvi.wServicePackMajor > 0 || osvi.wServicePackMinor > 0) + { + osNameVer.append(StringUtils::Format(" SP{}", osvi.wServicePackMajor)); + if (osvi.wServicePackMinor > 0) + { + osNameVer.append(StringUtils::Format(".{}", osvi.wServicePackMinor)); + } + } + } + else + osNameVer.append(" unknown"); +#elif defined(TARGET_WINDOWS_STORE) + osNameVer = GetKernelName() + " " + GetOsVersion(); +#elif defined(TARGET_FREEBSD) + osNameVer = GetOsName() + " " + GetOsVersion(); +#elif defined(TARGET_DARWIN) + osNameVer = StringUtils::Format("{} {} ({})", GetOsName(), GetOsVersion(), + CDarwinUtils::GetOSVersionString()); +#elif defined(TARGET_ANDROID) + osNameVer = + GetOsName() + " " + GetOsVersion() + " API level " + std::to_string(CJNIBuild::SDK_INT); +#elif defined(TARGET_LINUX) + osNameVer = getValueFromOs_release("PRETTY_NAME"); + if (osNameVer.empty()) + { + osNameVer = getValueFromLsb_release(lsb_rel_description); + std::string osName(GetOsName(true)); + if (!osName.empty() && osNameVer.find(osName) == std::string::npos) + osNameVer = osName + osNameVer; + if (osNameVer.empty()) + osNameVer = "Unknown Linux Distribution"; + } + + if (osNameVer.find(GetOsVersion()) == std::string::npos) + osNameVer += " " + GetOsVersion(); +#endif // defined(TARGET_LINUX) + + if (osNameVer.empty()) + osNameVer = "Unknown OS Unknown version"; + + return osNameVer; + +} + +std::string CSysInfo::GetManufacturerName(void) +{ + static std::string manufName; + static bool inited = false; + if (!inited) + { +#if defined(TARGET_ANDROID) + char deviceCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.product.manufacturer", deviceCStr); + manufName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); +#elif defined(TARGET_DARWIN) + manufName = CDarwinUtils::GetManufacturer(); +#elif defined(TARGET_WINDOWS_STORE) + auto eas = EasClientDeviceInformation(); + auto manufacturer = eas.SystemManufacturer(); + g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), manufName); +#elif defined(TARGET_LINUX) + + auto cpuInfo = CServiceBroker::GetCPUInfo(); + manufName = cpuInfo->GetCPUSoC(); + +#elif defined(TARGET_WINDOWS) + // We just don't care, might be useful on embedded +#endif + inited = true; + } + + return manufName; +} + +std::string CSysInfo::GetModelName(void) +{ + static std::string modelName; + static bool inited = false; + if (!inited) + { +#if defined(TARGET_ANDROID) + char deviceCStr[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.product.model", deviceCStr); + modelName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0); +#elif defined(TARGET_DARWIN_EMBEDDED) + modelName = CDarwinUtils::getIosPlatformString(); +#elif defined(TARGET_DARWIN_OSX) + size_t nameLen = 0; // 'nameLen' should include terminating null + if (sysctlbyname("hw.model", NULL, &nameLen, NULL, 0) == 0 && nameLen > 1) + { + std::vector<char> buf(nameLen); + if (sysctlbyname("hw.model", buf.data(), &nameLen, NULL, 0) == 0 && nameLen == buf.size()) + modelName.assign(buf.data(), + nameLen - 1); // assign exactly 'nameLen-1' characters to 'modelName' + } +#elif defined(TARGET_WINDOWS_STORE) + auto eas = EasClientDeviceInformation(); + auto manufacturer = eas.SystemProductName(); + g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), modelName); +#elif defined(TARGET_LINUX) + auto cpuInfo = CServiceBroker::GetCPUInfo(); + modelName = cpuInfo->GetCPUHardware(); +#elif defined(TARGET_WINDOWS) + // We just don't care, might be useful on embedded +#endif + inited = true; + } + + return modelName; +} + +bool CSysInfo::IsAeroDisabled() +{ +#ifdef TARGET_WINDOWS_STORE + return true; // need to review https://msdn.microsoft.com/en-us/library/windows/desktop/aa969518(v=vs.85).aspx +#elif defined(TARGET_WINDOWS) + BOOL aeroEnabled = FALSE; + HRESULT res = DwmIsCompositionEnabled(&aeroEnabled); + if (SUCCEEDED(res)) + return !aeroEnabled; +#endif + return false; +} + +CSysInfo::WindowsVersion CSysInfo::m_WinVer = WindowsVersionUnknown; + +bool CSysInfo::IsWindowsVersion(WindowsVersion ver) +{ + if (ver == WindowsVersionUnknown) + return false; + return GetWindowsVersion() == ver; +} + +bool CSysInfo::IsWindowsVersionAtLeast(WindowsVersion ver) +{ + if (ver == WindowsVersionUnknown) + return false; + return GetWindowsVersion() >= ver; +} + +CSysInfo::WindowsVersion CSysInfo::GetWindowsVersion() +{ +#ifdef TARGET_WINDOWS_DESKTOP + if (m_WinVer == WindowsVersionUnknown) + { + OSVERSIONINFOEXW osvi = {}; + if (sysGetVersionExWByRef(osvi)) + { + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) + m_WinVer = WindowsVersionWin7; + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) + m_WinVer = WindowsVersionWin8; + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) + m_WinVer = WindowsVersionWin8_1; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < 16299) + m_WinVer = WindowsVersionWin10; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 16299) + m_WinVer = WindowsVersionWin10_1709; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 17134) + m_WinVer = WindowsVersionWin10_1803; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 17763) + m_WinVer = WindowsVersionWin10_1809; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 18362) + m_WinVer = WindowsVersionWin10_1903; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 18363) + m_WinVer = WindowsVersionWin10_1909; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber == 19041) + m_WinVer = WindowsVersionWin10_2004; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 22000) + m_WinVer = WindowsVersionWin11; + else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber > 19041) + m_WinVer = WindowsVersionWin10_Future; + /* Insert checks for new Windows versions here */ + else if ( (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 3) || osvi.dwMajorVersion > 10) + m_WinVer = WindowsVersionFuture; + } + } +#elif defined(TARGET_WINDOWS_STORE) + m_WinVer = WindowsVersionWin10; +#endif // TARGET_WINDOWS + return m_WinVer; +} + +int CSysInfo::GetKernelBitness(void) +{ + static int kernelBitness = -1; + if (kernelBitness == -1) + { +#ifdef TARGET_WINDOWS_STORE + Package package = Package::Current(); + auto arch = package.Id().Architecture(); + switch (arch) + { + case ProcessorArchitecture::X86: + kernelBitness = 32; + break; + case ProcessorArchitecture::X64: + kernelBitness = 64; + break; + case ProcessorArchitecture::Arm: + kernelBitness = 32; + break; + case ProcessorArchitecture::Unknown: // not sure what to do here. guess 32 for now + case ProcessorArchitecture::Neutral: + kernelBitness = 32; + break; + } +#elif defined(TARGET_WINDOWS_DESKTOP) + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + kernelBitness = 32; + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + kernelBitness = 64; + else + { + BOOL isWow64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) // fallback + kernelBitness = 64; + } +#elif defined(TARGET_DARWIN_EMBEDDED) + // Note: OS X return x86 CPU type without CPU_ARCH_ABI64 flag + const NXArchInfo* archInfo = NXGetLocalArchInfo(); + if (archInfo) + kernelBitness = ((archInfo->cputype & CPU_ARCH_ABI64) != 0) ? 64 : 32; +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + { + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || + machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" || + machine == "mips64" || machine == "s390x" || machine == "riscv64") + kernelBitness = 64; + else + kernelBitness = 32; + } +#endif + if (kernelBitness == -1) + kernelBitness = 0; // can't detect + } + + return kernelBitness; +} + +const std::string& CSysInfo::GetKernelCpuFamily(void) +{ + static std::string kernelCpuFamily; + if (kernelCpuFamily.empty()) + { +#ifdef TARGET_WINDOWS + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || + si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + kernelCpuFamily = "x86"; + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + kernelCpuFamily = "ARM"; +#elif defined(TARGET_DARWIN) + const NXArchInfo* archInfo = NXGetLocalArchInfo(); + if (archInfo) + { + const cpu_type_t cpuType = (archInfo->cputype & ~CPU_ARCH_ABI64); // get CPU family without 64-bit ABI flag + if (cpuType == CPU_TYPE_I386) + kernelCpuFamily = "x86"; + else if (cpuType == CPU_TYPE_ARM) + kernelCpuFamily = "ARM"; +#ifdef CPU_TYPE_MIPS + else if (cpuType == CPU_TYPE_MIPS) + kernelCpuFamily = "MIPS"; +#endif // CPU_TYPE_MIPS + } +#elif defined(TARGET_POSIX) + struct utsname un; + if (uname(&un) == 0) + { + std::string machine(un.machine); + if (machine.compare(0, 3, "arm", 3) == 0 || machine.compare(0, 7, "aarch64", 7) == 0) + kernelCpuFamily = "ARM"; + else if (machine.compare(0, 4, "mips", 4) == 0) + kernelCpuFamily = "MIPS"; + else if (machine.compare(0, 4, "i686", 4) == 0 || machine == "i386" || machine == "amd64" || machine.compare(0, 3, "x86", 3) == 0) + kernelCpuFamily = "x86"; + else if (machine.compare(0, 4, "s390", 4) == 0) + kernelCpuFamily = "s390"; + else if (machine.compare(0, 3, "ppc", 3) == 0 || machine.compare(0, 5, "power", 5) == 0) + kernelCpuFamily = "PowerPC"; + else if (machine.compare(0, 5, "riscv", 5) == 0) + kernelCpuFamily = "RISC-V"; + } +#endif + if (kernelCpuFamily.empty()) + kernelCpuFamily = "unknown CPU family"; + } + return kernelCpuFamily; +} + +int CSysInfo::GetXbmcBitness(void) +{ + return static_cast<int>(sizeof(void*) * 8); +} + +bool CSysInfo::HasInternet() +{ + if (m_info.internetState != CSysData::UNKNOWN) + return m_info.internetState == CSysData::CONNECTED; + return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED; +} + +std::string CSysInfo::GetHddSpaceInfo(int drive, bool shortText) +{ + int percent; + return GetHddSpaceInfo( percent, drive, shortText); +} + +std::string CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText) +{ + int total, totalFree, totalUsed, percentFree, percentused; + std::string strRet; + percent = 0; + if (g_sysinfo.GetDiskSpace("", total, totalFree, totalUsed, percentFree, percentused)) + { + if (shortText) + { + switch(drive) + { + case SYSTEM_FREE_SPACE: + percent = percentFree; + break; + case SYSTEM_USED_SPACE: + percent = percentused; + break; + } + } + else + { + switch(drive) + { + case SYSTEM_FREE_SPACE: + strRet = StringUtils::Format("{} MB {}", totalFree, g_localizeStrings.Get(160)); + break; + case SYSTEM_USED_SPACE: + strRet = StringUtils::Format("{} MB {}", totalUsed, g_localizeStrings.Get(20162)); + break; + case SYSTEM_TOTAL_SPACE: + strRet = StringUtils::Format("{} MB {}", total, g_localizeStrings.Get(20161)); + break; + case SYSTEM_FREE_SPACE_PERCENT: + strRet = StringUtils::Format("{} % {}", percentFree, g_localizeStrings.Get(160)); + break; + case SYSTEM_USED_SPACE_PERCENT: + strRet = StringUtils::Format("{} % {}", percentused, g_localizeStrings.Get(20162)); + break; + } + } + } + else + { + if (shortText) + strRet = g_localizeStrings.Get(10006); // N/A + else + strRet = g_localizeStrings.Get(10005); // Not available + } + return strRet; +} + +std::string CSysInfo::GetUserAgent() +{ + static std::string result; + if (!result.empty()) + return result; + + result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " ("; +#if defined(TARGET_WINDOWS) + result += GetKernelName() + " " + GetKernelVersion(); +#ifndef TARGET_WINDOWS_STORE + BOOL bIsWow = FALSE; + if (IsWow64Process(GetCurrentProcess(), &bIsWow) && bIsWow) + result.append("; WOW64"); + else +#endif + { + SYSTEM_INFO si = {}; + GetSystemInfo(&si); + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + result.append("; Win64; x64"); + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) + result.append("; Win64; IA64"); + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) + result.append("; ARM"); + } +#elif defined(TARGET_DARWIN) +#if defined(TARGET_DARWIN_EMBEDDED) + std::string iDevStr(GetModelName()); // device model name with number of model version + size_t iDevStrDigit = iDevStr.find_first_of("0123456789"); + std::string iDev(iDevStr, 0, iDevStrDigit); // device model name without number + if (iDevStrDigit == 0) + iDev = "unknown"; + result += iDev + "; "; + std::string iOSVersion(GetOsVersion()); + size_t lastDotPos = iOSVersion.rfind('.'); + if (lastDotPos != std::string::npos && iOSVersion.find('.') != lastDotPos + && iOSVersion.find_first_not_of('0', lastDotPos + 1) == std::string::npos) + iOSVersion.erase(lastDotPos); + StringUtils::Replace(iOSVersion, '.', '_'); + if (iDev == "AppleTV") + { + // check if it's ATV4 (AppleTV5,3) or later + auto modelMajorNumberEndPos = iDevStr.find_first_of(',', iDevStrDigit); + std::string s{iDevStr, iDevStrDigit, modelMajorNumberEndPos - iDevStrDigit}; + if (stoi(s) >= 5) + result += "CPU TVOS"; + else + result += "CPU OS"; + } + else if (iDev == "iPad") + result += "CPU OS"; + else + result += "CPU iPhone OS "; + result += iOSVersion + " like Mac OS X"; +#else + result += "Macintosh; "; + std::string cpuFam(GetBuildTargetCpuFamily()); + if (cpuFam == "x86") + result += "Intel "; + result += "Mac OS X "; + std::string OSXVersion(GetOsVersion()); + StringUtils::Replace(OSXVersion, '.', '_'); + result += OSXVersion; +#endif +#elif defined(TARGET_ANDROID) + result += "Linux; Android "; + std::string versionStr(GetOsVersion()); + const size_t verLen = versionStr.length(); + if (verLen >= 2 && versionStr.compare(verLen - 2, 2, ".0", 2) == 0) + versionStr.erase(verLen - 2); // remove last ".0" if any + result += versionStr; + std::string deviceInfo(GetModelName()); + + char buildId[PROP_VALUE_MAX]; + int propLen = __system_property_get("ro.build.id", buildId); + if (propLen > 0 && propLen <= PROP_VALUE_MAX) + { + if (!deviceInfo.empty()) + deviceInfo += " "; + deviceInfo += "Build/"; + deviceInfo.append(buildId, propLen); + } + + if (!deviceInfo.empty()) + result += "; " + deviceInfo; +#elif defined(TARGET_POSIX) + result += "X11; "; + struct utsname un; + if (uname(&un) == 0) + { + std::string cpuStr(un.machine); + if (cpuStr == "x86_64" && GetXbmcBitness() == 32) + cpuStr = "i686 on x86_64"; + result += un.sysname; + result += " "; + result += cpuStr; + } + else + result += "Unknown"; +#else + result += "Unknown"; +#endif + result += ")"; + + if (GetAppName() != "Kodi") + result += " Kodi_Fork_" + GetAppName() + "/1.0"; // default fork number is '1.0', replace it with actual number if necessary + +#ifdef TARGET_LINUX + // Add distribution name + std::string linuxOSName(GetOsName(true)); + if (!linuxOSName.empty()) + result += " " + linuxOSName + "/" + GetOsVersion(); +#endif + +#if defined(TARGET_DARWIN_IOS) + std::string iDevVer; + if (iDevStrDigit == std::string::npos) + iDevVer = "0.0"; + else + iDevVer.assign(iDevStr, iDevStrDigit, std::string::npos); + StringUtils::Replace(iDevVer, ',', '.'); + result += " HW_" + iDev + "/" + iDevVer; +#endif + // add more device IDs here if needed. + // keep only one device ID in result! Form: + // result += " HW_" + "deviceID" + "/" + "1.0"; // '1.0' if device has no version + +#if defined(TARGET_ANDROID) + // Android has no CPU string by default, so add it as additional parameter + struct utsname un1; + if (uname(&un1) == 0) + { + std::string cpuStr(un1.machine); + StringUtils::Replace(cpuStr, ' ', '_'); + result += " Sys_CPU/" + cpuStr; + } +#endif + + result += " App_Bitness/" + std::to_string(GetXbmcBitness()); + + std::string fullVer(CSysInfo::GetVersion()); + StringUtils::Replace(fullVer, ' ', '-'); + result += " Version/" + fullVer; + + return result; +} + +std::string CSysInfo::GetDeviceName() +{ + std::string friendlyName = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SERVICES_DEVICENAME); + if (StringUtils::EqualsNoCase(friendlyName, CCompileInfo::GetAppName())) + { + std::string hostname("[unknown]"); + CServiceBroker::GetNetwork().GetHostName(hostname); + return StringUtils::Format("{} ({})", friendlyName, hostname); + } + + return friendlyName; +} + +// Version string MUST NOT contain spaces. It is used +// in the HTTP request user agent. +std::string CSysInfo::GetVersionShort() +{ + if (strlen(CCompileInfo::GetSuffix()) == 0) + return StringUtils::Format("{}.{}", CCompileInfo::GetMajor(), CCompileInfo::GetMinor()); + else + return StringUtils::Format("{}.{}-{}", CCompileInfo::GetMajor(), CCompileInfo::GetMinor(), + CCompileInfo::GetSuffix()); +} + +std::string CSysInfo::GetVersion() +{ + return GetVersionShort() + " (" + CCompileInfo::GetVersionCode() + ")" + + " Git:" + CCompileInfo::GetSCMID(); +} + +std::string CSysInfo::GetVersionCode() +{ + return CCompileInfo::GetVersionCode(); +} + +std::string CSysInfo::GetVersionGit() +{ + return CCompileInfo::GetSCMID(); +} + +std::string CSysInfo::GetBuildDate() +{ + return CCompileInfo::GetBuildDate(); +} + +std::string CSysInfo::GetBuildTargetPlatformName(void) +{ +#if defined(TARGET_DARWIN_OSX) + return "macOS"; +#elif defined(TARGET_DARWIN_IOS) + return "iOS"; +#elif defined(TARGET_DARWIN_TVOS) + return "tvOS"; +#elif defined(TARGET_FREEBSD) + return "FreeBSD"; +#elif defined(TARGET_ANDROID) + return "Android"; +#elif defined(TARGET_LINUX) + return "Linux"; +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + return "Windows NT"; +#else // !NTDDI_VERSION + return "unknown Win32 platform"; +#endif // !NTDDI_VERSION +#else + return "unknown platform"; +#endif +} + +std::string CSysInfo::GetBuildTargetPlatformVersion(void) +{ +#if defined(TARGET_DARWIN_OSX) + return XSTR_MACRO(__MAC_OS_X_VERSION_MIN_REQUIRED); +#elif defined(TARGET_DARWIN_IOS) + return XSTR_MACRO(__IPHONE_OS_VERSION_MIN_REQUIRED); +#elif defined(TARGET_DARWIN_TVOS) + return XSTR_MACRO(__TV_OS_VERSION_MIN_REQUIRED); +#elif defined(TARGET_FREEBSD) + return XSTR_MACRO(__FreeBSD_version); +#elif defined(TARGET_ANDROID) + return "API level " XSTR_MACRO(__ANDROID_API__); +#elif defined(TARGET_LINUX) + return XSTR_MACRO(LINUX_VERSION_CODE); +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + return XSTR_MACRO(NTDDI_VERSION); +#else // !NTDDI_VERSION + return "(unknown Win32 platform)"; +#endif // !NTDDI_VERSION +#else + return "(unknown platform)"; +#endif +} + +std::string CSysInfo::GetBuildTargetPlatformVersionDecoded(void) +{ +#if defined(TARGET_DARWIN_OSX) + if (__MAC_OS_X_VERSION_MIN_REQUIRED % 100) + return StringUtils::Format("version {}.{}.{}", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000, + (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100, + __MAC_OS_X_VERSION_MIN_REQUIRED % 100); + else + return StringUtils::Format("version {}.{}", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000, + (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100); +#elif defined(TARGET_DARWIN_EMBEDDED) + std::string versionStr = GetBuildTargetPlatformVersion(); + static const int major = (std::stoi(versionStr) / 10000) % 100; + static const int minor = (std::stoi(versionStr) / 100) % 100; + static const int rev = std::stoi(versionStr) % 100; + return StringUtils::Format("version {}.{}.{}", major, minor, rev); +#elif defined(TARGET_FREEBSD) + // FIXME: should works well starting from FreeBSD 8.1 + static const int major = (__FreeBSD_version / 100000) % 100; + static const int minor = (__FreeBSD_version / 1000) % 100; + static const int Rxx = __FreeBSD_version % 1000; + if ((major < 9 && Rxx == 0)) + return StringUtils::Format("version {}.{}-RELEASE", major, minor); + if (Rxx >= 500) + return StringUtils::Format("version {}.{}-STABLE", major, minor); + + return StringUtils::Format("version {}.{}-CURRENT", major, minor); +#elif defined(TARGET_ANDROID) + return "API level " XSTR_MACRO(__ANDROID_API__); +#elif defined(TARGET_LINUX) + return StringUtils::Format("version {}.{}.{}", (LINUX_VERSION_CODE >> 16) & 0xFF, + (LINUX_VERSION_CODE >> 8) & 0xFF, LINUX_VERSION_CODE & 0xFF); +#elif defined(TARGET_WINDOWS) +#ifdef NTDDI_VERSION + std::string version(StringUtils::Format("version {}.{}", int(NTDDI_VERSION >> 24) & 0xFF, + int(NTDDI_VERSION >> 16) & 0xFF)); + if (SPVER(NTDDI_VERSION)) + version += StringUtils::Format(" SP{}", int(SPVER(NTDDI_VERSION))); + return version; +#else // !NTDDI_VERSION + return "(unknown Win32 platform)"; +#endif // !NTDDI_VERSION +#else + return "(unknown platform)"; +#endif +} + +std::string CSysInfo::GetBuildTargetCpuFamily(void) +{ +#if defined(__thumb__) || defined(_M_ARMT) + return "ARM (Thumb)"; +#elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + return "ARM"; +#elif defined(__mips__) || defined(mips) || defined(__mips) + return "MIPS"; +#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_) + return "x86"; +#elif defined(__s390x__) + return "s390"; +#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) + return "PowerPC"; +#elif defined(__riscv) + return "RISC-V"; +#else + return "unknown CPU family"; +#endif +} + +std::string CSysInfo::GetUsedCompilerNameAndVer(void) +{ +#if defined(__clang__) +#ifdef __clang_version__ + return "Clang " __clang_version__; +#else // ! __clang_version__ + return "Clang " XSTR_MACRO(__clang_major__) "." XSTR_MACRO(__clang_minor__) "." XSTR_MACRO(__clang_patchlevel__); +#endif //! __clang_version__ +#elif defined (__INTEL_COMPILER) + return "Intel Compiler " XSTR_MACRO(__INTEL_COMPILER); +#elif defined (__GNUC__) + std::string compilerStr; +#ifdef __llvm__ + /* Note: this will not detect GCC + DragonEgg */ + compilerStr = "llvm-gcc "; +#else // __llvm__ + compilerStr = "GCC "; +#endif // !__llvm__ + compilerStr += XSTR_MACRO(__GNUC__) "." XSTR_MACRO(__GNUC_MINOR__) "." XSTR_MACRO(__GNUC_PATCHLEVEL__); + return compilerStr; +#elif defined (_MSC_VER) + return "MSVC " XSTR_MACRO(_MSC_FULL_VER); +#else + return "unknown compiler"; +#endif +} + +std::string CSysInfo::GetPrivacyPolicy() +{ + if (m_privacyPolicy.empty()) + { + CFile file; + std::vector<uint8_t> buf; + if (file.LoadFile("special://xbmc/privacy-policy.txt", buf) > 0) + { + m_privacyPolicy = std::string(reinterpret_cast<char*>(buf.data()), buf.size()); + } + else + m_privacyPolicy = g_localizeStrings.Get(19055); + } + return m_privacyPolicy; +} + +CSysInfo::WindowsDeviceFamily CSysInfo::GetWindowsDeviceFamily() +{ +#ifdef TARGET_WINDOWS_STORE + auto familyName = AnalyticsInfo::VersionInfo().DeviceFamily(); + if (familyName == L"Windows.Desktop") + return WindowsDeviceFamily::Desktop; + else if (familyName == L"Windows.Mobile") + return WindowsDeviceFamily::Mobile; + else if (familyName == L"Windows.Universal") + return WindowsDeviceFamily::IoT; + else if (familyName == L"Windows.Team") + return WindowsDeviceFamily::Surface; + else if (familyName == L"Windows.Xbox") + return WindowsDeviceFamily::Xbox; + else + return WindowsDeviceFamily::Other; +#endif // TARGET_WINDOWS_STORE + return WindowsDeviceFamily::Desktop; +} + +CJob *CSysInfo::GetJob() const +{ + return new CSysInfoJob(); +} + +void CSysInfo::OnJobComplete(unsigned int jobID, bool success, CJob *job) +{ + m_info = static_cast<CSysInfoJob*>(job)->GetData(); + CInfoLoader::OnJobComplete(jobID, success, job); +} |