/xbmc/utils/SystemInfo.cpp

http://github.com/xbmc/xbmc · C++ · 1384 lines · 1257 code · 96 blank · 31 comment · 331 complexity · 3f049a32c8580c2130c0a8498aa1b66c MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2018 Team Kodi
  3. * This file is part of Kodi - https://kodi.tv
  4. *
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * See LICENSES/README.md for more information.
  7. */
  8. #include <limits.h>
  9. #include "threads/SystemClock.h"
  10. #include "SystemInfo.h"
  11. #ifndef TARGET_POSIX
  12. #include <conio.h>
  13. #else
  14. #include <sys/utsname.h>
  15. #endif
  16. #include "CompileInfo.h"
  17. #include "ServiceBroker.h"
  18. #include "filesystem/CurlFile.h"
  19. #include "filesystem/File.h"
  20. #include "guilib/LocalizeStrings.h"
  21. #include "guilib/guiinfo/GUIInfoLabels.h"
  22. #include "network/Network.h"
  23. #include "platform/Filesystem.h"
  24. #include "rendering/RenderSystem.h"
  25. #include "settings/Settings.h"
  26. #include "settings/SettingsComponent.h"
  27. #include "utils/CPUInfo.h"
  28. #include "utils/log.h"
  29. #ifdef TARGET_WINDOWS
  30. #include <dwmapi.h>
  31. #include "utils/CharsetConverter.h"
  32. #include <VersionHelpers.h>
  33. #ifdef TARGET_WINDOWS_STORE
  34. #include <winrt/Windows.Security.ExchangeActiveSyncProvisioning.h>
  35. #include <winrt/Windows.System.Profile.h>
  36. using namespace winrt::Windows::ApplicationModel;
  37. using namespace winrt::Windows::Security::ExchangeActiveSyncProvisioning;
  38. using namespace winrt::Windows::System;
  39. using namespace winrt::Windows::System::Profile;
  40. #endif
  41. #include <wincrypt.h>
  42. #include "platform/win32/CharsetConverter.h"
  43. #endif
  44. #if defined(TARGET_DARWIN)
  45. #include "platform/darwin/DarwinUtils.h"
  46. #endif
  47. #include "powermanagement/PowerManager.h"
  48. #include "utils/StringUtils.h"
  49. #include "utils/XMLUtils.h"
  50. #if defined(TARGET_ANDROID)
  51. #include <androidjni/Build.h>
  52. #endif
  53. /* Platform identification */
  54. #if defined(TARGET_DARWIN)
  55. #include <Availability.h>
  56. #include <mach-o/arch.h>
  57. #include <sys/sysctl.h>
  58. #include "utils/auto_buffer.h"
  59. #elif defined(TARGET_ANDROID)
  60. #include <android/api-level.h>
  61. #include <sys/system_properties.h>
  62. #elif defined(TARGET_FREEBSD)
  63. #include <sys/param.h>
  64. #elif defined(TARGET_LINUX)
  65. #include "platform/linux/SysfsPath.h"
  66. #include <linux/version.h>
  67. #endif
  68. #include <system_error>
  69. /* Expand macro before stringify */
  70. #define STR_MACRO(x) #x
  71. #define XSTR_MACRO(x) STR_MACRO(x)
  72. using namespace XFILE;
  73. #ifdef TARGET_WINDOWS_DESKTOP
  74. static bool sysGetVersionExWByRef(OSVERSIONINFOEXW& osVerInfo)
  75. {
  76. ZeroMemory(&osVerInfo, sizeof(osVerInfo));
  77. osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
  78. typedef NTSTATUS(__stdcall *RtlGetVersionPtr)(RTL_OSVERSIONINFOEXW* pOsInfo);
  79. static HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll");
  80. if (hNtDll != NULL)
  81. {
  82. static RtlGetVersionPtr RtlGetVer = (RtlGetVersionPtr) GetProcAddress(hNtDll, "RtlGetVersion");
  83. if (RtlGetVer && RtlGetVer(&osVerInfo) == 0)
  84. return true;
  85. }
  86. // failed to get OS information directly from ntdll.dll
  87. // use GetVersionExW() as fallback
  88. // note: starting from Windows 8.1 GetVersionExW() may return unfaithful information
  89. if (GetVersionExW((OSVERSIONINFOW*) &osVerInfo) != 0)
  90. return true;
  91. ZeroMemory(&osVerInfo, sizeof(osVerInfo));
  92. return false;
  93. }
  94. #endif // TARGET_WINDOWS_DESKTOP
  95. #if defined(TARGET_LINUX) && !defined(TARGET_ANDROID)
  96. static std::string getValueFromOs_release(std::string key)
  97. {
  98. FILE* os_rel = fopen("/etc/os-release", "r");
  99. if (!os_rel)
  100. return "";
  101. char* buf = new char[10 * 1024]; // more than enough
  102. size_t len = fread(buf, 1, 10 * 1024, os_rel);
  103. fclose(os_rel);
  104. if (len == 0)
  105. {
  106. delete[] buf;
  107. return "";
  108. }
  109. std::string content(buf, len);
  110. delete[] buf;
  111. // find begin of value string
  112. size_t valStart = 0, seachPos;
  113. key += '=';
  114. if (content.compare(0, key.length(), key) == 0)
  115. valStart = key.length();
  116. else
  117. {
  118. key = "\n" + key;
  119. seachPos = 0;
  120. do
  121. {
  122. seachPos = content.find(key, seachPos);
  123. if (seachPos == std::string::npos)
  124. return "";
  125. if (seachPos == 0 || content[seachPos - 1] != '\\')
  126. valStart = seachPos + key.length();
  127. else
  128. seachPos++;
  129. } while (valStart == 0);
  130. }
  131. if (content[valStart] == '\n')
  132. return "";
  133. // find end of value string
  134. seachPos = valStart;
  135. do
  136. {
  137. seachPos = content.find('\n', seachPos + 1);
  138. } while (seachPos != std::string::npos && content[seachPos - 1] == '\\');
  139. size_t const valEnd = seachPos;
  140. std::string value(content, valStart, valEnd - valStart);
  141. if (value.empty())
  142. return value;
  143. // remove quotes
  144. if (value[0] == '\'' || value[0] == '"')
  145. {
  146. if (value.length() < 2)
  147. return value;
  148. size_t qEnd = value.rfind(value[0]);
  149. if (qEnd != std::string::npos)
  150. {
  151. value.erase(qEnd);
  152. value.erase(0, 1);
  153. }
  154. }
  155. // unescape characters
  156. for (size_t slashPos = value.find('\\'); slashPos < value.length() - 1; slashPos = value.find('\\', slashPos))
  157. {
  158. if (value[slashPos + 1] == '\n')
  159. value.erase(slashPos, 2);
  160. else
  161. {
  162. value.erase(slashPos, 1);
  163. slashPos++; // skip unescaped character
  164. }
  165. }
  166. return value;
  167. }
  168. enum lsb_rel_info_type
  169. {
  170. lsb_rel_distributor,
  171. lsb_rel_description,
  172. lsb_rel_release,
  173. lsb_rel_codename
  174. };
  175. static std::string getValueFromLsb_release(enum lsb_rel_info_type infoType)
  176. {
  177. std::string key, command("unset PYTHONHOME; unset PYTHONPATH; lsb_release ");
  178. switch (infoType)
  179. {
  180. case lsb_rel_distributor:
  181. command += "-i";
  182. key = "Distributor ID:\t";
  183. break;
  184. case lsb_rel_description:
  185. command += "-d";
  186. key = "Description:\t";
  187. break;
  188. case lsb_rel_release:
  189. command += "-r";
  190. key = "Release:\t";
  191. break;
  192. case lsb_rel_codename:
  193. command += "-c";
  194. key = "Codename:\t";
  195. break;
  196. default:
  197. return "";
  198. }
  199. command += " 2>/dev/null";
  200. FILE* lsb_rel = popen(command.c_str(), "r");
  201. if (lsb_rel == NULL)
  202. return "";
  203. char buf[300]; // more than enough
  204. if (fgets(buf, 300, lsb_rel) == NULL)
  205. {
  206. pclose(lsb_rel);
  207. return "";
  208. }
  209. pclose(lsb_rel);
  210. std::string response(buf);
  211. if (response.compare(0, key.length(), key) != 0)
  212. return "";
  213. return response.substr(key.length(), response.find('\n') - key.length());
  214. }
  215. #endif // TARGET_LINUX && !TARGET_ANDROID
  216. CSysInfo g_sysinfo;
  217. CSysInfoJob::CSysInfoJob() = default;
  218. bool CSysInfoJob::DoWork()
  219. {
  220. m_info.systemUptime = GetSystemUpTime(false);
  221. m_info.systemTotalUptime = GetSystemUpTime(true);
  222. m_info.internetState = GetInternetState();
  223. m_info.videoEncoder = GetVideoEncoder();
  224. m_info.cpuFrequency =
  225. StringUtils::Format("%4.0f MHz", CServiceBroker::GetCPUInfo()->GetCPUFrequency());
  226. m_info.osVersionInfo = CSysInfo::GetOsPrettyNameWithVersion() + " (kernel: " + CSysInfo::GetKernelName() + " " + CSysInfo::GetKernelVersionFull() + ")";
  227. m_info.macAddress = GetMACAddress();
  228. m_info.batteryLevel = GetBatteryLevel();
  229. return true;
  230. }
  231. const CSysData &CSysInfoJob::GetData() const
  232. {
  233. return m_info;
  234. }
  235. CSysData::INTERNET_STATE CSysInfoJob::GetInternetState()
  236. {
  237. // Internet connection state!
  238. XFILE::CCurlFile http;
  239. if (http.IsInternet())
  240. return CSysData::CONNECTED;
  241. return CSysData::DISCONNECTED;
  242. }
  243. std::string CSysInfoJob::GetMACAddress()
  244. {
  245. CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
  246. if (iface)
  247. return iface->GetMacAddress();
  248. return "";
  249. }
  250. std::string CSysInfoJob::GetVideoEncoder()
  251. {
  252. return "GPU: " + CServiceBroker::GetRenderSystem()->GetRenderRenderer();
  253. }
  254. std::string CSysInfoJob::GetBatteryLevel()
  255. {
  256. return StringUtils::Format("%d%%", CServiceBroker::GetPowerManager().BatteryLevel());
  257. }
  258. bool CSysInfoJob::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays)
  259. {
  260. iHours = 0; iDays = 0;
  261. iMinutes = iInputMinutes;
  262. if (iMinutes >= 60) // Hour's
  263. {
  264. iHours = iMinutes / 60;
  265. iMinutes = iMinutes - (iHours *60);
  266. }
  267. if (iHours >= 24) // Days
  268. {
  269. iDays = iHours / 24;
  270. iHours = iHours - (iDays * 24);
  271. }
  272. return true;
  273. }
  274. std::string CSysInfoJob::GetSystemUpTime(bool bTotalUptime)
  275. {
  276. std::string strSystemUptime;
  277. int iInputMinutes, iMinutes,iHours,iDays;
  278. if(bTotalUptime)
  279. {
  280. //Total Uptime
  281. iInputMinutes = g_sysinfo.GetTotalUptime() + ((int)(XbmcThreads::SystemClockMillis() / 60000));
  282. }
  283. else
  284. {
  285. //Current UpTime
  286. iInputMinutes = (int)(XbmcThreads::SystemClockMillis() / 60000);
  287. }
  288. SystemUpTime(iInputMinutes,iMinutes, iHours, iDays);
  289. if (iDays > 0)
  290. {
  291. strSystemUptime = StringUtils::Format("%i %s, %i %s, %i %s",
  292. iDays, g_localizeStrings.Get(12393).c_str(),
  293. iHours, g_localizeStrings.Get(12392).c_str(),
  294. iMinutes, g_localizeStrings.Get(12391).c_str());
  295. }
  296. else if (iDays == 0 && iHours >= 1 )
  297. {
  298. strSystemUptime = StringUtils::Format("%i %s, %i %s",
  299. iHours, g_localizeStrings.Get(12392).c_str(),
  300. iMinutes, g_localizeStrings.Get(12391).c_str());
  301. }
  302. else if (iDays == 0 && iHours == 0 && iMinutes >= 0)
  303. {
  304. strSystemUptime = StringUtils::Format("%i %s",
  305. iMinutes, g_localizeStrings.Get(12391).c_str());
  306. }
  307. return strSystemUptime;
  308. }
  309. std::string CSysInfo::TranslateInfo(int info) const
  310. {
  311. switch(info)
  312. {
  313. case SYSTEM_VIDEO_ENCODER_INFO:
  314. return m_info.videoEncoder;
  315. case NETWORK_MAC_ADDRESS:
  316. return m_info.macAddress;
  317. case SYSTEM_OS_VERSION_INFO:
  318. return m_info.osVersionInfo;
  319. case SYSTEM_CPUFREQUENCY:
  320. return m_info.cpuFrequency;
  321. case SYSTEM_UPTIME:
  322. return m_info.systemUptime;
  323. case SYSTEM_TOTALUPTIME:
  324. return m_info.systemTotalUptime;
  325. case SYSTEM_INTERNET_STATE:
  326. if (m_info.internetState == CSysData::CONNECTED)
  327. return g_localizeStrings.Get(13296);
  328. else
  329. return g_localizeStrings.Get(13297);
  330. case SYSTEM_BATTERY_LEVEL:
  331. return m_info.batteryLevel;
  332. default:
  333. return "";
  334. }
  335. }
  336. void CSysInfo::Reset()
  337. {
  338. m_info.Reset();
  339. }
  340. CSysInfo::CSysInfo(void) : CInfoLoader(15 * 1000)
  341. {
  342. memset(MD5_Sign, 0, sizeof(MD5_Sign));
  343. m_iSystemTimeTotalUp = 0;
  344. }
  345. CSysInfo::~CSysInfo() = default;
  346. bool CSysInfo::Load(const TiXmlNode *settings)
  347. {
  348. if (settings == NULL)
  349. return false;
  350. const TiXmlElement *pElement = settings->FirstChildElement("general");
  351. if (pElement)
  352. XMLUtils::GetInt(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, INT_MAX);
  353. return true;
  354. }
  355. bool CSysInfo::Save(TiXmlNode *settings) const
  356. {
  357. if (settings == NULL)
  358. return false;
  359. TiXmlNode *generalNode = settings->FirstChild("general");
  360. if (generalNode == NULL)
  361. {
  362. TiXmlElement generalNodeNew("general");
  363. generalNode = settings->InsertEndChild(generalNodeNew);
  364. if (generalNode == NULL)
  365. return false;
  366. }
  367. XMLUtils::SetInt(generalNode, "systemtotaluptime", m_iSystemTimeTotalUp);
  368. return true;
  369. }
  370. const std::string& CSysInfo::GetAppName(void)
  371. {
  372. assert(CCompileInfo::GetAppName() != NULL);
  373. static const std::string appName(CCompileInfo::GetAppName());
  374. return appName;
  375. }
  376. bool CSysInfo::GetDiskSpace(std::string drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed)
  377. {
  378. using namespace KODI::PLATFORM::FILESYSTEM;
  379. space_info total = { 0 };
  380. std::error_code ec;
  381. // None of this makes sense but the idea of total space
  382. // makes no sense on any system really.
  383. // Return space for / or for C: as it's correct in a sense
  384. // and not much worse than trying to count a total for different
  385. // drives/mounts
  386. if (drive.empty() || drive == "*")
  387. {
  388. #if defined(TARGET_WINDOWS)
  389. drive = "C";
  390. #elif defined(TARGET_POSIX)
  391. drive = "/";
  392. #endif
  393. }
  394. #ifdef TARGET_WINDOWS_DESKTOP
  395. using KODI::PLATFORM::WINDOWS::ToW;
  396. UINT uidriveType = GetDriveType(ToW(drive + ":\\").c_str());
  397. if (uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR)
  398. total = space(drive + ":\\", ec);
  399. #elif defined(TARGET_POSIX)
  400. total = space(drive, ec);
  401. #endif
  402. if (ec.value() != 0)
  403. return false;
  404. iTotal = static_cast<int>(total.capacity / MB);
  405. iTotalFree = static_cast<int>(total.free / MB);
  406. iTotalUsed = iTotal - iTotalFree;
  407. if (total.capacity > 0)
  408. iPercentUsed = static_cast<int>(100.0f * (total.capacity - total.free) / total.capacity + 0.5f);
  409. else
  410. iPercentUsed = 0;
  411. iPercentFree = 100 - iPercentUsed;
  412. return true;
  413. }
  414. std::string CSysInfo::GetKernelName(bool emptyIfUnknown /*= false*/)
  415. {
  416. static std::string kernelName;
  417. if (kernelName.empty())
  418. {
  419. #if defined(TARGET_WINDOWS_DESKTOP)
  420. OSVERSIONINFOEXW osvi;
  421. if (sysGetVersionExWByRef(osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
  422. kernelName = "Windows NT";
  423. #elif defined(TARGET_WINDOWS_STORE)
  424. auto e = EasClientDeviceInformation();
  425. auto os = e.OperatingSystem();
  426. g_charsetConverter.wToUTF8(std::wstring(os.c_str()), kernelName);
  427. #elif defined(TARGET_POSIX)
  428. struct utsname un;
  429. if (uname(&un) == 0)
  430. kernelName.assign(un.sysname);
  431. #endif // defined(TARGET_POSIX)
  432. if (kernelName.empty())
  433. kernelName = "Unknown kernel"; // can't detect
  434. }
  435. if (emptyIfUnknown && kernelName == "Unknown kernel")
  436. return "";
  437. return kernelName;
  438. }
  439. std::string CSysInfo::GetKernelVersionFull(void)
  440. {
  441. static std::string kernelVersionFull;
  442. if (!kernelVersionFull.empty())
  443. return kernelVersionFull;
  444. #if defined(TARGET_WINDOWS_DESKTOP)
  445. OSVERSIONINFOEXW osvi;
  446. if (sysGetVersionExWByRef(osvi))
  447. kernelVersionFull = StringUtils::Format("%d.%d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
  448. #elif defined(TARGET_WINDOWS_STORE)
  449. // get the system version number
  450. auto sv = AnalyticsInfo::VersionInfo().DeviceFamilyVersion();
  451. wchar_t* end;
  452. unsigned long long v = wcstoull(sv.c_str(), &end, 10);
  453. unsigned long long v1 = (v & 0xFFFF000000000000L) >> 48;
  454. unsigned long long v2 = (v & 0x0000FFFF00000000L) >> 32;
  455. unsigned long long v3 = (v & 0x00000000FFFF0000L) >> 16;
  456. kernelVersionFull = StringUtils::Format("%lld.%lld.%lld", v1, v2, v3);
  457. #elif defined(TARGET_POSIX)
  458. struct utsname un;
  459. if (uname(&un) == 0)
  460. kernelVersionFull.assign(un.release);
  461. #endif // defined(TARGET_POSIX)
  462. if (kernelVersionFull.empty())
  463. kernelVersionFull = "0.0.0"; // can't detect
  464. return kernelVersionFull;
  465. }
  466. std::string CSysInfo::GetKernelVersion(void)
  467. {
  468. static std::string kernelVersionClear;
  469. if (kernelVersionClear.empty())
  470. {
  471. kernelVersionClear = GetKernelVersionFull();
  472. const size_t erasePos = kernelVersionClear.find_first_not_of("0123456789.");
  473. if (erasePos != std::string::npos)
  474. kernelVersionClear.erase(erasePos);
  475. }
  476. return kernelVersionClear;
  477. }
  478. std::string CSysInfo::GetOsName(bool emptyIfUnknown /* = false*/)
  479. {
  480. static std::string osName;
  481. if (osName.empty())
  482. {
  483. #if defined (TARGET_WINDOWS)
  484. osName = GetKernelName() + "-based OS";
  485. #elif defined(TARGET_FREEBSD)
  486. osName = GetKernelName(true); // FIXME: for FreeBSD OS name is a kernel name
  487. #elif defined(TARGET_DARWIN_IOS)
  488. osName = "iOS";
  489. #elif defined(TARGET_DARWIN_TVOS)
  490. osName = "tvOS";
  491. #elif defined(TARGET_DARWIN_OSX)
  492. osName = "OS X";
  493. #elif defined (TARGET_ANDROID)
  494. osName = "Android";
  495. #elif defined(TARGET_LINUX)
  496. osName = getValueFromOs_release("NAME");
  497. if (osName.empty())
  498. osName = getValueFromLsb_release(lsb_rel_distributor);
  499. if (osName.empty())
  500. osName = getValueFromOs_release("ID");
  501. #endif // defined(TARGET_LINUX)
  502. if (osName.empty())
  503. osName = "Unknown OS";
  504. }
  505. if (emptyIfUnknown && osName == "Unknown OS")
  506. return "";
  507. return osName;
  508. }
  509. std::string CSysInfo::GetOsVersion(void)
  510. {
  511. static std::string osVersion;
  512. if (!osVersion.empty())
  513. return osVersion;
  514. #if defined(TARGET_WINDOWS) || defined(TARGET_FREEBSD)
  515. osVersion = GetKernelVersion(); // FIXME: for Win32 and FreeBSD OS version is a kernel version
  516. #elif defined(TARGET_DARWIN)
  517. osVersion = CDarwinUtils::GetVersionString();
  518. #elif defined(TARGET_ANDROID)
  519. char versionCStr[PROP_VALUE_MAX];
  520. int propLen = __system_property_get("ro.build.version.release", versionCStr);
  521. osVersion.assign(versionCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0);
  522. if (osVersion.empty() || std::string("0123456789").find(versionCStr[0]) == std::string::npos)
  523. osVersion.clear(); // can't correctly detect Android version
  524. else
  525. {
  526. size_t pointPos = osVersion.find('.');
  527. if (pointPos == std::string::npos)
  528. osVersion += ".0.0";
  529. else if (osVersion.find('.', pointPos + 1) == std::string::npos)
  530. osVersion += ".0";
  531. }
  532. #elif defined(TARGET_LINUX)
  533. osVersion = getValueFromOs_release("VERSION_ID");
  534. if (osVersion.empty())
  535. osVersion = getValueFromLsb_release(lsb_rel_release);
  536. #endif // defined(TARGET_LINUX)
  537. if (osVersion.empty())
  538. osVersion = "0.0";
  539. return osVersion;
  540. }
  541. std::string CSysInfo::GetOsPrettyNameWithVersion(void)
  542. {
  543. static std::string osNameVer;
  544. if (!osNameVer.empty())
  545. return osNameVer;
  546. #if defined (TARGET_WINDOWS_DESKTOP)
  547. OSVERSIONINFOEXW osvi = {};
  548. osNameVer = "Windows ";
  549. if (sysGetVersionExWByRef(osvi))
  550. {
  551. switch (GetWindowsVersion())
  552. {
  553. case WindowsVersionWin7:
  554. if (osvi.wProductType == VER_NT_WORKSTATION)
  555. osNameVer.append("7");
  556. else
  557. osNameVer.append("Server 2008 R2");
  558. break;
  559. case WindowsVersionWin8:
  560. if (osvi.wProductType == VER_NT_WORKSTATION)
  561. osNameVer.append("8");
  562. else
  563. osNameVer.append("Server 2012");
  564. break;
  565. case WindowsVersionWin8_1:
  566. if (osvi.wProductType == VER_NT_WORKSTATION)
  567. osNameVer.append("8.1");
  568. else
  569. osNameVer.append("Server 2012 R2");
  570. break;
  571. case WindowsVersionWin10:
  572. case WindowsVersionWin10_FCU:
  573. if (osvi.wProductType == VER_NT_WORKSTATION)
  574. osNameVer.append("10");
  575. else
  576. osNameVer.append("Unknown future server version");
  577. break;
  578. case WindowsVersionFuture:
  579. osNameVer.append("Unknown future version");
  580. break;
  581. default:
  582. osNameVer.append("Unknown version");
  583. break;
  584. }
  585. // Append Service Pack version if any
  586. if (osvi.wServicePackMajor > 0 || osvi.wServicePackMinor > 0)
  587. {
  588. osNameVer.append(StringUtils::Format(" SP%d", osvi.wServicePackMajor));
  589. if (osvi.wServicePackMinor > 0)
  590. {
  591. osNameVer.append(StringUtils::Format(".%d", osvi.wServicePackMinor));
  592. }
  593. }
  594. }
  595. else
  596. osNameVer.append(" unknown");
  597. #elif defined(TARGET_WINDOWS_STORE)
  598. osNameVer = GetKernelName() + " " + GetOsVersion();
  599. #elif defined(TARGET_FREEBSD) || defined(TARGET_DARWIN)
  600. osNameVer = GetOsName() + " " + GetOsVersion();
  601. #elif defined(TARGET_ANDROID)
  602. osNameVer = GetOsName() + " " + GetOsVersion() + " API level " + StringUtils::Format("%d", CJNIBuild::SDK_INT);
  603. #elif defined(TARGET_LINUX)
  604. osNameVer = getValueFromOs_release("PRETTY_NAME");
  605. if (osNameVer.empty())
  606. {
  607. osNameVer = getValueFromLsb_release(lsb_rel_description);
  608. std::string osName(GetOsName(true));
  609. if (!osName.empty() && osNameVer.find(osName) == std::string::npos)
  610. osNameVer = osName + osNameVer;
  611. if (osNameVer.empty())
  612. osNameVer = "Unknown Linux Distribution";
  613. }
  614. if (osNameVer.find(GetOsVersion()) == std::string::npos)
  615. osNameVer += " " + GetOsVersion();
  616. #endif // defined(TARGET_LINUX)
  617. if (osNameVer.empty())
  618. osNameVer = "Unknown OS Unknown version";
  619. return osNameVer;
  620. }
  621. std::string CSysInfo::GetManufacturerName(void)
  622. {
  623. static std::string manufName;
  624. static bool inited = false;
  625. if (!inited)
  626. {
  627. #if defined(TARGET_ANDROID)
  628. char deviceCStr[PROP_VALUE_MAX];
  629. int propLen = __system_property_get("ro.product.manufacturer", deviceCStr);
  630. manufName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0);
  631. #elif defined(TARGET_DARWIN)
  632. manufName = CDarwinUtils::GetManufacturer();
  633. #elif defined(TARGET_WINDOWS_STORE)
  634. auto eas = EasClientDeviceInformation();
  635. auto manufacturer = eas.SystemManufacturer();
  636. g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), manufName);
  637. #elif defined(TARGET_LINUX)
  638. auto cpuInfo = CServiceBroker::GetCPUInfo();
  639. manufName = cpuInfo->GetCPUSoC();
  640. #elif defined(TARGET_WINDOWS)
  641. // We just don't care, might be useful on embedded
  642. #endif
  643. inited = true;
  644. }
  645. return manufName;
  646. }
  647. std::string CSysInfo::GetModelName(void)
  648. {
  649. static std::string modelName;
  650. static bool inited = false;
  651. if (!inited)
  652. {
  653. #if defined(TARGET_ANDROID)
  654. char deviceCStr[PROP_VALUE_MAX];
  655. int propLen = __system_property_get("ro.product.model", deviceCStr);
  656. modelName.assign(deviceCStr, (propLen > 0 && propLen <= PROP_VALUE_MAX) ? propLen : 0);
  657. #elif defined(TARGET_DARWIN_EMBEDDED)
  658. modelName = CDarwinUtils::getIosPlatformString();
  659. #elif defined(TARGET_DARWIN_OSX)
  660. size_t nameLen = 0; // 'nameLen' should include terminating null
  661. if (sysctlbyname("hw.model", NULL, &nameLen, NULL, 0) == 0 && nameLen > 1)
  662. {
  663. XUTILS::auto_buffer buf(nameLen);
  664. if (sysctlbyname("hw.model", buf.get(), &nameLen, NULL, 0) == 0 && nameLen == buf.size())
  665. modelName.assign(buf.get(), nameLen - 1); // assign exactly 'nameLen-1' characters to 'modelName'
  666. }
  667. #elif defined(TARGET_WINDOWS_STORE)
  668. auto eas = EasClientDeviceInformation();
  669. auto manufacturer = eas.SystemProductName();
  670. g_charsetConverter.wToUTF8(std::wstring(manufacturer.c_str()), modelName);
  671. #elif defined(TARGET_LINUX)
  672. auto cpuInfo = CServiceBroker::GetCPUInfo();
  673. modelName = cpuInfo->GetCPUHardware();
  674. #elif defined(TARGET_WINDOWS)
  675. // We just don't care, might be useful on embedded
  676. #endif
  677. inited = true;
  678. }
  679. return modelName;
  680. }
  681. bool CSysInfo::IsAeroDisabled()
  682. {
  683. #ifdef TARGET_WINDOWS_STORE
  684. return true; // need to review https://msdn.microsoft.com/en-us/library/windows/desktop/aa969518(v=vs.85).aspx
  685. #elif defined(TARGET_WINDOWS)
  686. BOOL aeroEnabled = FALSE;
  687. HRESULT res = DwmIsCompositionEnabled(&aeroEnabled);
  688. if (SUCCEEDED(res))
  689. return !aeroEnabled;
  690. #endif
  691. return false;
  692. }
  693. CSysInfo::WindowsVersion CSysInfo::m_WinVer = WindowsVersionUnknown;
  694. bool CSysInfo::IsWindowsVersion(WindowsVersion ver)
  695. {
  696. if (ver == WindowsVersionUnknown)
  697. return false;
  698. return GetWindowsVersion() == ver;
  699. }
  700. bool CSysInfo::IsWindowsVersionAtLeast(WindowsVersion ver)
  701. {
  702. if (ver == WindowsVersionUnknown)
  703. return false;
  704. return GetWindowsVersion() >= ver;
  705. }
  706. CSysInfo::WindowsVersion CSysInfo::GetWindowsVersion()
  707. {
  708. #ifdef TARGET_WINDOWS_DESKTOP
  709. if (m_WinVer == WindowsVersionUnknown)
  710. {
  711. OSVERSIONINFOEXW osvi = {};
  712. if (sysGetVersionExWByRef(osvi))
  713. {
  714. if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
  715. m_WinVer = WindowsVersionWin7;
  716. else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
  717. m_WinVer = WindowsVersionWin8;
  718. else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3)
  719. m_WinVer = WindowsVersionWin8_1;
  720. else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber < 16299)
  721. m_WinVer = WindowsVersionWin10;
  722. else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= 16299)
  723. m_WinVer = WindowsVersionWin10_FCU;
  724. /* Insert checks for new Windows versions here */
  725. else if ( (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 3) || osvi.dwMajorVersion > 10)
  726. m_WinVer = WindowsVersionFuture;
  727. }
  728. }
  729. #elif defined(TARGET_WINDOWS_STORE)
  730. m_WinVer = WindowsVersionWin10;
  731. #endif // TARGET_WINDOWS
  732. return m_WinVer;
  733. }
  734. int CSysInfo::GetKernelBitness(void)
  735. {
  736. static int kernelBitness = -1;
  737. if (kernelBitness == -1)
  738. {
  739. #ifdef TARGET_WINDOWS_STORE
  740. Package package = Package::Current();
  741. auto arch = package.Id().Architecture();
  742. switch (arch)
  743. {
  744. case ProcessorArchitecture::X86:
  745. kernelBitness = 32;
  746. break;
  747. case ProcessorArchitecture::X64:
  748. kernelBitness = 64;
  749. break;
  750. case ProcessorArchitecture::Arm:
  751. kernelBitness = 32;
  752. break;
  753. case ProcessorArchitecture::Unknown: // not sure what to do here. guess 32 for now
  754. case ProcessorArchitecture::Neutral:
  755. kernelBitness = 32;
  756. break;
  757. }
  758. #elif defined(TARGET_WINDOWS_DESKTOP)
  759. SYSTEM_INFO si;
  760. GetNativeSystemInfo(&si);
  761. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
  762. kernelBitness = 32;
  763. else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  764. kernelBitness = 64;
  765. else
  766. {
  767. BOOL isWow64 = FALSE;
  768. if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) // fallback
  769. kernelBitness = 64;
  770. }
  771. #elif defined(TARGET_DARWIN_EMBEDDED)
  772. // Note: OS X return x86 CPU type without CPU_ARCH_ABI64 flag
  773. const NXArchInfo* archInfo = NXGetLocalArchInfo();
  774. if (archInfo)
  775. kernelBitness = ((archInfo->cputype & CPU_ARCH_ABI64) != 0) ? 64 : 32;
  776. #elif defined(TARGET_POSIX)
  777. struct utsname un;
  778. if (uname(&un) == 0)
  779. {
  780. std::string machine(un.machine);
  781. if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || machine == "ppc64" ||
  782. machine == "ia64" || machine == "mips64" || machine == "s390x")
  783. kernelBitness = 64;
  784. else
  785. kernelBitness = 32;
  786. }
  787. #endif
  788. if (kernelBitness == -1)
  789. kernelBitness = 0; // can't detect
  790. }
  791. return kernelBitness;
  792. }
  793. const std::string& CSysInfo::GetKernelCpuFamily(void)
  794. {
  795. static std::string kernelCpuFamily;
  796. if (kernelCpuFamily.empty())
  797. {
  798. #ifdef TARGET_WINDOWS
  799. SYSTEM_INFO si;
  800. GetNativeSystemInfo(&si);
  801. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ||
  802. si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  803. kernelCpuFamily = "x86";
  804. else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
  805. kernelCpuFamily = "ARM";
  806. #elif defined(TARGET_DARWIN)
  807. const NXArchInfo* archInfo = NXGetLocalArchInfo();
  808. if (archInfo)
  809. {
  810. const cpu_type_t cpuType = (archInfo->cputype & ~CPU_ARCH_ABI64); // get CPU family without 64-bit ABI flag
  811. if (cpuType == CPU_TYPE_I386)
  812. kernelCpuFamily = "x86";
  813. else if (cpuType == CPU_TYPE_ARM)
  814. kernelCpuFamily = "ARM";
  815. #ifdef CPU_TYPE_MIPS
  816. else if (cpuType == CPU_TYPE_MIPS)
  817. kernelCpuFamily = "MIPS";
  818. #endif // CPU_TYPE_MIPS
  819. }
  820. #elif defined(TARGET_POSIX)
  821. struct utsname un;
  822. if (uname(&un) == 0)
  823. {
  824. std::string machine(un.machine);
  825. if (machine.compare(0, 3, "arm", 3) == 0 || machine.compare(0, 7, "aarch64", 7) == 0)
  826. kernelCpuFamily = "ARM";
  827. else if (machine.compare(0, 4, "mips", 4) == 0)
  828. kernelCpuFamily = "MIPS";
  829. else if (machine.compare(0, 4, "i686", 4) == 0 || machine == "i386" || machine == "amd64" || machine.compare(0, 3, "x86", 3) == 0)
  830. kernelCpuFamily = "x86";
  831. else if (machine.compare(0, 4, "s390", 4) == 0)
  832. kernelCpuFamily = "s390";
  833. else if (machine.compare(0, 3, "ppc", 3) == 0 || machine.compare(0, 5, "power", 5) == 0)
  834. kernelCpuFamily = "PowerPC";
  835. }
  836. #endif
  837. if (kernelCpuFamily.empty())
  838. kernelCpuFamily = "unknown CPU family";
  839. }
  840. return kernelCpuFamily;
  841. }
  842. int CSysInfo::GetXbmcBitness(void)
  843. {
  844. return static_cast<int>(sizeof(void*) * 8);
  845. }
  846. bool CSysInfo::HasInternet()
  847. {
  848. if (m_info.internetState != CSysData::UNKNOWN)
  849. return m_info.internetState == CSysData::CONNECTED;
  850. return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED;
  851. }
  852. std::string CSysInfo::GetHddSpaceInfo(int drive, bool shortText)
  853. {
  854. int percent;
  855. return GetHddSpaceInfo( percent, drive, shortText);
  856. }
  857. std::string CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText)
  858. {
  859. int total, totalFree, totalUsed, percentFree, percentused;
  860. std::string strRet;
  861. percent = 0;
  862. if (g_sysinfo.GetDiskSpace("", total, totalFree, totalUsed, percentFree, percentused))
  863. {
  864. if (shortText)
  865. {
  866. switch(drive)
  867. {
  868. case SYSTEM_FREE_SPACE:
  869. percent = percentFree;
  870. break;
  871. case SYSTEM_USED_SPACE:
  872. percent = percentused;
  873. break;
  874. }
  875. }
  876. else
  877. {
  878. switch(drive)
  879. {
  880. case SYSTEM_FREE_SPACE:
  881. strRet = StringUtils::Format("%i MB %s", totalFree, g_localizeStrings.Get(160).c_str());
  882. break;
  883. case SYSTEM_USED_SPACE:
  884. strRet = StringUtils::Format("%i MB %s", totalUsed, g_localizeStrings.Get(20162).c_str());
  885. break;
  886. case SYSTEM_TOTAL_SPACE:
  887. strRet = StringUtils::Format("%i MB %s", total, g_localizeStrings.Get(20161).c_str());
  888. break;
  889. case SYSTEM_FREE_SPACE_PERCENT:
  890. strRet = StringUtils::Format("%i %% %s", percentFree, g_localizeStrings.Get(160).c_str());
  891. break;
  892. case SYSTEM_USED_SPACE_PERCENT:
  893. strRet = StringUtils::Format("%i %% %s", percentused, g_localizeStrings.Get(20162).c_str());
  894. break;
  895. }
  896. }
  897. }
  898. else
  899. {
  900. if (shortText)
  901. strRet = g_localizeStrings.Get(10006); // N/A
  902. else
  903. strRet = g_localizeStrings.Get(10005); // Not available
  904. }
  905. return strRet;
  906. }
  907. std::string CSysInfo::GetUserAgent()
  908. {
  909. static std::string result;
  910. if (!result.empty())
  911. return result;
  912. result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " (";
  913. #if defined(TARGET_WINDOWS)
  914. result += GetKernelName() + " " + GetKernelVersion();
  915. #ifndef TARGET_WINDOWS_STORE
  916. BOOL bIsWow = FALSE;
  917. if (IsWow64Process(GetCurrentProcess(), &bIsWow) && bIsWow)
  918. result.append("; WOW64");
  919. else
  920. #endif
  921. {
  922. SYSTEM_INFO si = {};
  923. GetSystemInfo(&si);
  924. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  925. result.append("; Win64; x64");
  926. else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
  927. result.append("; Win64; IA64");
  928. else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
  929. result.append("; ARM");
  930. }
  931. #elif defined(TARGET_DARWIN)
  932. #if defined(TARGET_DARWIN_EMBEDDED)
  933. std::string iDevStr(GetModelName()); // device model name with number of model version
  934. size_t iDevStrDigit = iDevStr.find_first_of("0123456789");
  935. std::string iDev(iDevStr, 0, iDevStrDigit); // device model name without number
  936. if (iDevStrDigit == 0)
  937. iDev = "unknown";
  938. result += iDev + "; ";
  939. std::string iOSVersion(GetOsVersion());
  940. size_t lastDotPos = iOSVersion.rfind('.');
  941. if (lastDotPos != std::string::npos && iOSVersion.find('.') != lastDotPos
  942. && iOSVersion.find_first_not_of('0', lastDotPos + 1) == std::string::npos)
  943. iOSVersion.erase(lastDotPos);
  944. StringUtils::Replace(iOSVersion, '.', '_');
  945. if (iDev == "AppleTV")
  946. {
  947. // check if it's ATV4 (AppleTV5,3) or later
  948. auto modelMajorNumberEndPos = iDevStr.find_first_of(',', iDevStrDigit);
  949. std::string s{iDevStr, iDevStrDigit, modelMajorNumberEndPos - iDevStrDigit};
  950. if (stoi(s) >= 5)
  951. result += "CPU TVOS";
  952. else
  953. result += "CPU OS";
  954. }
  955. else if (iDev == "iPad")
  956. result += "CPU OS";
  957. else
  958. result += "CPU iPhone OS ";
  959. result += iOSVersion + " like Mac OS X";
  960. #else
  961. result += "Macintosh; ";
  962. std::string cpuFam(GetBuildTargetCpuFamily());
  963. if (cpuFam == "x86")
  964. result += "Intel ";
  965. result += "Mac OS X ";
  966. std::string OSXVersion(GetOsVersion());
  967. StringUtils::Replace(OSXVersion, '.', '_');
  968. result += OSXVersion;
  969. #endif
  970. #elif defined(TARGET_ANDROID)
  971. result += "Linux; Android ";
  972. std::string versionStr(GetOsVersion());
  973. const size_t verLen = versionStr.length();
  974. if (verLen >= 2 && versionStr.compare(verLen - 2, 2, ".0", 2) == 0)
  975. versionStr.erase(verLen - 2); // remove last ".0" if any
  976. result += versionStr;
  977. std::string deviceInfo(GetModelName());
  978. char buildId[PROP_VALUE_MAX];
  979. int propLen = __system_property_get("ro.build.id", buildId);
  980. if (propLen > 0 && propLen <= PROP_VALUE_MAX)
  981. {
  982. if (!deviceInfo.empty())
  983. deviceInfo += " ";
  984. deviceInfo += "Build/";
  985. deviceInfo.append(buildId, propLen);
  986. }
  987. if (!deviceInfo.empty())
  988. result += "; " + deviceInfo;
  989. #elif defined(TARGET_POSIX)
  990. result += "X11; ";
  991. struct utsname un;
  992. if (uname(&un) == 0)
  993. {
  994. std::string cpuStr(un.machine);
  995. if (cpuStr == "x86_64" && GetXbmcBitness() == 32)
  996. cpuStr = "i686 (x86_64)";
  997. result += un.sysname;
  998. result += " ";
  999. result += cpuStr;
  1000. }
  1001. else
  1002. result += "Unknown";
  1003. #else
  1004. result += "Unknown";
  1005. #endif
  1006. result += ")";
  1007. if (GetAppName() != "Kodi")
  1008. result += " Kodi_Fork_" + GetAppName() + "/1.0"; // default fork number is '1.0', replace it with actual number if necessary
  1009. #ifdef TARGET_LINUX
  1010. // Add distribution name
  1011. std::string linuxOSName(GetOsName(true));
  1012. if (!linuxOSName.empty())
  1013. result += " " + linuxOSName + "/" + GetOsVersion();
  1014. #endif
  1015. #ifdef TARGET_RASPBERRY_PI
  1016. result += " HW_RaspberryPi/1.0";
  1017. #elif defined (TARGET_DARWIN_EMBEDDED)
  1018. std::string iDevVer;
  1019. if (iDevStrDigit == std::string::npos)
  1020. iDevVer = "0.0";
  1021. else
  1022. iDevVer.assign(iDevStr, iDevStrDigit, std::string::npos);
  1023. StringUtils::Replace(iDevVer, ',', '.');
  1024. result += " HW_" + iDev + "/" + iDevVer;
  1025. #endif
  1026. // add more device IDs here if needed.
  1027. // keep only one device ID in result! Form:
  1028. // result += " HW_" + "deviceID" + "/" + "1.0"; // '1.0' if device has no version
  1029. #if defined(TARGET_ANDROID)
  1030. // Android has no CPU string by default, so add it as additional parameter
  1031. struct utsname un1;
  1032. if (uname(&un1) == 0)
  1033. {
  1034. std::string cpuStr(un1.machine);
  1035. StringUtils::Replace(cpuStr, ' ', '_');
  1036. result += " Sys_CPU/" + cpuStr;
  1037. }
  1038. #endif
  1039. result += " App_Bitness/" + StringUtils::Format("%d", GetXbmcBitness());
  1040. std::string fullVer(CSysInfo::GetVersion());
  1041. StringUtils::Replace(fullVer, ' ', '-');
  1042. result += " Version/" + fullVer;
  1043. return result;
  1044. }
  1045. std::string CSysInfo::GetDeviceName()
  1046. {
  1047. std::string friendlyName = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SERVICES_DEVICENAME);
  1048. if (StringUtils::EqualsNoCase(friendlyName, CCompileInfo::GetAppName()))
  1049. {
  1050. std::string hostname("[unknown]");
  1051. CServiceBroker::GetNetwork().GetHostName(hostname);
  1052. return StringUtils::Format("%s (%s)", friendlyName.c_str(), hostname.c_str());
  1053. }
  1054. return friendlyName;
  1055. }
  1056. // Version string MUST NOT contain spaces. It is used
  1057. // in the HTTP request user agent.
  1058. std::string CSysInfo::GetVersionShort()
  1059. {
  1060. if (strlen(CCompileInfo::GetSuffix()) == 0)
  1061. return StringUtils::Format("%d.%d", CCompileInfo::GetMajor(), CCompileInfo::GetMinor());
  1062. else
  1063. return StringUtils::Format("%d.%d-%s", CCompileInfo::GetMajor(), CCompileInfo::GetMinor(), CCompileInfo::GetSuffix());
  1064. }
  1065. std::string CSysInfo::GetVersion()
  1066. {
  1067. return GetVersionShort() + " Git:" + CCompileInfo::GetSCMID();
  1068. }
  1069. std::string CSysInfo::GetBuildDate()
  1070. {
  1071. return CCompileInfo::GetBuildDate();
  1072. }
  1073. std::string CSysInfo::GetBuildTargetPlatformName(void)
  1074. {
  1075. #if defined(TARGET_DARWIN_OSX)
  1076. return "OS X";
  1077. #elif defined(TARGET_DARWIN_IOS)
  1078. return "iOS";
  1079. #elif defined(TARGET_DARWIN_TVOS)
  1080. return "tvOS";
  1081. #elif defined(TARGET_FREEBSD)
  1082. return "FreeBSD";
  1083. #elif defined(TARGET_ANDROID)
  1084. return "Android";
  1085. #elif defined(TARGET_LINUX)
  1086. return "Linux";
  1087. #elif defined(TARGET_WINDOWS)
  1088. #ifdef NTDDI_VERSION
  1089. return "Windows NT";
  1090. #else // !NTDDI_VERSION
  1091. return "unknown Win32 platform";
  1092. #endif // !NTDDI_VERSION
  1093. #else
  1094. return "unknown platform";
  1095. #endif
  1096. }
  1097. std::string CSysInfo::GetBuildTargetPlatformVersion(void)
  1098. {
  1099. #if defined(TARGET_DARWIN_OSX)
  1100. return XSTR_MACRO(__MAC_OS_X_VERSION_MIN_REQUIRED);
  1101. #elif defined(TARGET_DARWIN_IOS)
  1102. return XSTR_MACRO(__IPHONE_OS_VERSION_MIN_REQUIRED);
  1103. #elif defined(TARGET_DARWIN_TVOS)
  1104. return XSTR_MACRO(__TV_OS_VERSION_MIN_REQUIRED);
  1105. #elif defined(TARGET_FREEBSD)
  1106. return XSTR_MACRO(__FreeBSD_version);
  1107. #elif defined(TARGET_ANDROID)
  1108. return "API level " XSTR_MACRO(__ANDROID_API__);
  1109. #elif defined(TARGET_LINUX)
  1110. return XSTR_MACRO(LINUX_VERSION_CODE);
  1111. #elif defined(TARGET_WINDOWS)
  1112. #ifdef NTDDI_VERSION
  1113. return XSTR_MACRO(NTDDI_VERSION);
  1114. #else // !NTDDI_VERSION
  1115. return "(unknown Win32 platform)";
  1116. #endif // !NTDDI_VERSION
  1117. #else
  1118. return "(unknown platform)";
  1119. #endif
  1120. }
  1121. std::string CSysInfo::GetBuildTargetPlatformVersionDecoded(void)
  1122. {
  1123. #if defined(TARGET_DARWIN_OSX)
  1124. if (__MAC_OS_X_VERSION_MIN_REQUIRED % 100)
  1125. return StringUtils::Format("version %d.%d.%d", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000,
  1126. (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100,
  1127. __MAC_OS_X_VERSION_MIN_REQUIRED % 100);
  1128. else
  1129. return StringUtils::Format("version %d.%d", __MAC_OS_X_VERSION_MIN_REQUIRED / 10000,
  1130. (__MAC_OS_X_VERSION_MIN_REQUIRED / 100) % 100);
  1131. #elif defined(TARGET_DARWIN_EMBEDDED)
  1132. std::string versionStr = GetBuildTargetPlatformVersion();
  1133. static const int major = (std::stoi(versionStr) / 10000) % 100;
  1134. static const int minor = (std::stoi(versionStr) / 100) % 100;
  1135. static const int rev = std::stoi(versionStr) % 100;
  1136. return StringUtils::Format("version %d.%d.%d", major, minor, rev);
  1137. #elif defined(TARGET_FREEBSD)
  1138. // FIXME: should works well starting from FreeBSD 8.1
  1139. static const int major = (__FreeBSD_version / 100000) % 100;
  1140. static const int minor = (__FreeBSD_version / 1000) % 100;
  1141. static const int Rxx = __FreeBSD_version % 1000;
  1142. if ((major < 9 && Rxx == 0))
  1143. return StringUtils::Format("version %d.%d-RELEASE", major, minor);
  1144. if (Rxx >= 500)
  1145. return StringUtils::Format("version %d.%d-STABLE", major, minor);
  1146. return StringUtils::Format("version %d.%d-CURRENT", major, minor);
  1147. #elif defined(TARGET_ANDROID)
  1148. return "API level " XSTR_MACRO(__ANDROID_API__);
  1149. #elif defined(TARGET_LINUX)
  1150. return StringUtils::Format("version %d.%d.%d", (LINUX_VERSION_CODE >> 16) & 0xFF , (LINUX_VERSION_CODE >> 8) & 0xFF, LINUX_VERSION_CODE & 0xFF);
  1151. #elif defined(TARGET_WINDOWS)
  1152. #ifdef NTDDI_VERSION
  1153. std::string version(StringUtils::Format("version %d.%d", int(NTDDI_VERSION >> 24) & 0xFF, int(NTDDI_VERSION >> 16) & 0xFF));
  1154. if (SPVER(NTDDI_VERSION))
  1155. version += StringUtils::Format(" SP%d", int(SPVER(NTDDI_VERSION)));
  1156. return version;
  1157. #else // !NTDDI_VERSION
  1158. return "(unknown Win32 platform)";
  1159. #endif // !NTDDI_VERSION
  1160. #else
  1161. return "(unknown platform)";
  1162. #endif
  1163. }
  1164. std::string CSysInfo::GetBuildTargetCpuFamily(void)
  1165. {
  1166. #if defined(__thumb__) || defined(_M_ARMT)
  1167. return "ARM (Thumb)";
  1168. #elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__)
  1169. return "ARM";
  1170. #elif defined(__mips__) || defined(mips) || defined(__mips)
  1171. return "MIPS";
  1172. #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \
  1173. defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(_X86_)
  1174. return "x86";
  1175. #elif defined(__s390x__)
  1176. return "s390";
  1177. #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC)
  1178. return "PowerPC";
  1179. #else
  1180. return "unknown CPU family";
  1181. #endif
  1182. }
  1183. std::string CSysInfo::GetUsedCompilerNameAndVer(void)
  1184. {
  1185. #if defined(__clang__)
  1186. #ifdef __clang_version__
  1187. return "Clang " __clang_version__;
  1188. #else // ! __clang_version__
  1189. return "Clang " XSTR_MACRO(__clang_major__) "." XSTR_MACRO(__clang_minor__) "." XSTR_MACRO(__clang_patchlevel__);
  1190. #endif //! __clang_version__
  1191. #elif defined (__INTEL_COMPILER)
  1192. return "Intel Compiler " XSTR_MACRO(__INTEL_COMPILER);
  1193. #elif defined (__GNUC__)
  1194. std::string compilerStr;
  1195. #ifdef __llvm__
  1196. /* Note: this will not detect GCC + DragonEgg */
  1197. compilerStr = "llvm-gcc ";
  1198. #else // __llvm__
  1199. compilerStr = "GCC ";
  1200. #endif // !__llvm__
  1201. compilerStr += XSTR_MACRO(__GNUC__) "." XSTR_MACRO(__GNUC_MINOR__) "." XSTR_MACRO(__GNUC_PATCHLEVEL__);
  1202. return compilerStr;
  1203. #elif defined (_MSC_VER)
  1204. return "MSVC " XSTR_MACRO(_MSC_FULL_VER);
  1205. #else
  1206. return "unknown compiler";
  1207. #endif
  1208. }
  1209. std::string CSysInfo::GetPrivacyPolicy()
  1210. {
  1211. if (m_privacyPolicy.empty())
  1212. {
  1213. CFile file;
  1214. XFILE::auto_buffer buf;
  1215. if (file.LoadFile("special://xbmc/privacy-policy.txt", buf) > 0)
  1216. {
  1217. std::string strBuf(buf.get(), buf.length());
  1218. m_privacyPolicy = strBuf;
  1219. }
  1220. else
  1221. m_privacyPolicy = g_localizeStrings.Get(19055);
  1222. }
  1223. return m_privacyPolicy;
  1224. }
  1225. CSysInfo::WindowsDeviceFamily CSysInfo::GetWindowsDeviceFamily()
  1226. {
  1227. #ifdef TARGET_WINDOWS_STORE
  1228. auto familyName = AnalyticsInfo::VersionInfo().DeviceFamily();
  1229. if (familyName == L"Windows.Desktop")
  1230. return WindowsDeviceFamily::Desktop;
  1231. else if (familyName == L"Windows.Mobile")
  1232. return WindowsDeviceFamily::Mobile;
  1233. else if (familyName == L"Windows.Universal")
  1234. return WindowsDeviceFamily::IoT;
  1235. else if (familyName == L"Windows.Team")
  1236. return WindowsDeviceFamily::Surface;
  1237. else if (familyName == L"Windows.Xbox")
  1238. return WindowsDeviceFamily::Xbox;
  1239. else
  1240. return WindowsDeviceFamily::Other;
  1241. #endif // TARGET_WINDOWS_STORE
  1242. return WindowsDeviceFamily::Desktop;
  1243. }
  1244. CJob *CSysInfo::GetJob() const
  1245. {
  1246. return new CSysInfoJob();
  1247. }
  1248. void CSysInfo::OnJobComplete(unsigned int jobID, bool success, CJob *job)
  1249. {
  1250. m_info = static_cast<CSysInfoJob*>(job)->GetData();
  1251. CInfoLoader::OnJobComplete(jobID, success, job);
  1252. }