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