Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/ArrayUtils.h"
8 :
9 : #include "nsSystemInfo.h"
10 : #include "prsystem.h"
11 : #include "prio.h"
12 : #include "mozilla/SSE.h"
13 : #include "mozilla/arm.h"
14 : #include "mozilla/Sprintf.h"
15 :
16 : #ifdef XP_WIN
17 : #include <time.h>
18 : #include <windows.h>
19 : #include <winioctl.h>
20 : #include "base/scoped_handle_win.h"
21 : #include "nsAppDirectoryServiceDefs.h"
22 : #include "nsDirectoryServiceDefs.h"
23 : #include "nsDirectoryServiceUtils.h"
24 : #include "nsIObserverService.h"
25 : #include "nsWindowsHelpers.h"
26 : #endif
27 :
28 : #ifdef XP_MACOSX
29 : #include "MacHelpers.h"
30 : #endif
31 :
32 : #ifdef MOZ_WIDGET_GTK
33 : #include <gtk/gtk.h>
34 : #include <dlfcn.h>
35 : #endif
36 :
37 : #if defined (XP_LINUX) && !defined (ANDROID)
38 : #include <unistd.h>
39 : #include <fstream>
40 : #include "mozilla/Tokenizer.h"
41 : #include "nsCharSeparatedTokenizer.h"
42 :
43 : #include <map>
44 : #include <string>
45 : #endif
46 :
47 : #ifdef MOZ_WIDGET_ANDROID
48 : #include "AndroidBridge.h"
49 : #include "mozilla/dom/ContentChild.h"
50 : #endif
51 :
52 : #ifdef MOZ_WIDGET_GONK
53 : #include <sys/system_properties.h>
54 : #include "mozilla/Preferences.h"
55 : #include "nsPrintfCString.h"
56 : #endif
57 :
58 : #ifdef ANDROID
59 : extern "C" {
60 : NS_EXPORT int android_sdk_version;
61 : }
62 : #endif
63 :
64 : #ifdef XP_MACOSX
65 : #include <sys/sysctl.h>
66 : #endif
67 :
68 : #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
69 : #include "mozilla/SandboxInfo.h"
70 : #endif
71 :
72 : // Slot for NS_InitXPCOM2 to pass information to nsSystemInfo::Init.
73 : // Only set to nonzero (potentially) if XP_UNIX. On such systems, the
74 : // system call to discover the appropriate value is not thread-safe,
75 : // so we must call it before going multithreaded, but nsSystemInfo::Init
76 : // only happens well after that point.
77 : uint32_t nsSystemInfo::gUserUmask = 0;
78 :
79 : using namespace mozilla::dom;
80 :
81 : #if defined (XP_LINUX) && !defined (ANDROID)
82 : static void
83 1 : SimpleParseKeyValuePairs(const std::string& aFilename,
84 : std::map<nsCString, nsCString>& aKeyValuePairs)
85 : {
86 2 : std::ifstream input(aFilename.c_str());
87 217 : for (std::string line; std::getline(input, line); ) {
88 432 : nsAutoCString key, value;
89 :
90 216 : nsCCharSeparatedTokenizer tokens(nsDependentCString(line.c_str()), ':');
91 216 : if (tokens.hasMoreTokens()) {
92 208 : key = tokens.nextToken();
93 208 : if (tokens.hasMoreTokens()) {
94 192 : value = tokens.nextToken();
95 : }
96 : // We want the value even if there was just one token, to cover the
97 : // case where we had the key, and the value was blank (seems to be
98 : // a valid scenario some files.)
99 208 : aKeyValuePairs[key] = value;
100 : }
101 : }
102 1 : }
103 : #endif
104 :
105 : #if defined(XP_WIN)
106 : namespace {
107 : nsresult
108 : GetHDDInfo(const char* aSpecialDirName, nsAutoCString& aModel,
109 : nsAutoCString& aRevision)
110 : {
111 : aModel.Truncate();
112 : aRevision.Truncate();
113 :
114 : nsCOMPtr<nsIFile> profDir;
115 : nsresult rv = NS_GetSpecialDirectory(aSpecialDirName,
116 : getter_AddRefs(profDir));
117 : NS_ENSURE_SUCCESS(rv, rv);
118 : nsAutoString profDirPath;
119 : rv = profDir->GetPath(profDirPath);
120 : NS_ENSURE_SUCCESS(rv, rv);
121 : wchar_t volumeMountPoint[MAX_PATH] = {L'\\', L'\\', L'.', L'\\'};
122 : const size_t PREFIX_LEN = 4;
123 : if (!::GetVolumePathNameW(profDirPath.get(), volumeMountPoint + PREFIX_LEN,
124 : mozilla::ArrayLength(volumeMountPoint) -
125 : PREFIX_LEN)) {
126 : return NS_ERROR_UNEXPECTED;
127 : }
128 : size_t volumeMountPointLen = wcslen(volumeMountPoint);
129 : // Since we would like to open a drive and not a directory, we need to
130 : // remove any trailing backslash. A drive handle is valid for
131 : // DeviceIoControl calls, a directory handle is not.
132 : if (volumeMountPoint[volumeMountPointLen - 1] == L'\\') {
133 : volumeMountPoint[volumeMountPointLen - 1] = L'\0';
134 : }
135 : ScopedHandle handle(::CreateFileW(volumeMountPoint, 0,
136 : FILE_SHARE_READ | FILE_SHARE_WRITE,
137 : nullptr, OPEN_EXISTING, 0, nullptr));
138 : if (!handle.IsValid()) {
139 : return NS_ERROR_UNEXPECTED;
140 : }
141 : STORAGE_PROPERTY_QUERY queryParameters = {
142 : StorageDeviceProperty, PropertyStandardQuery
143 : };
144 : STORAGE_DEVICE_DESCRIPTOR outputHeader = {sizeof(STORAGE_DEVICE_DESCRIPTOR)};
145 : DWORD bytesRead = 0;
146 : if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY,
147 : &queryParameters, sizeof(queryParameters),
148 : &outputHeader, sizeof(outputHeader), &bytesRead,
149 : nullptr)) {
150 : return NS_ERROR_FAILURE;
151 : }
152 : PSTORAGE_DEVICE_DESCRIPTOR deviceOutput =
153 : (PSTORAGE_DEVICE_DESCRIPTOR)malloc(outputHeader.Size);
154 : if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY,
155 : &queryParameters, sizeof(queryParameters),
156 : deviceOutput, outputHeader.Size, &bytesRead,
157 : nullptr)) {
158 : free(deviceOutput);
159 : return NS_ERROR_FAILURE;
160 : }
161 : // Some HDDs are including product ID info in the vendor field. Since PNP
162 : // IDs include vendor info and product ID concatenated together, we'll do
163 : // that here and interpret the result as a unique ID for the HDD model.
164 : if (deviceOutput->VendorIdOffset) {
165 : aModel = reinterpret_cast<char*>(deviceOutput) +
166 : deviceOutput->VendorIdOffset;
167 : }
168 : if (deviceOutput->ProductIdOffset) {
169 : aModel += reinterpret_cast<char*>(deviceOutput) +
170 : deviceOutput->ProductIdOffset;
171 : }
172 : aModel.CompressWhitespace();
173 : if (deviceOutput->ProductRevisionOffset) {
174 : aRevision = reinterpret_cast<char*>(deviceOutput) +
175 : deviceOutput->ProductRevisionOffset;
176 : aRevision.CompressWhitespace();
177 : }
178 : free(deviceOutput);
179 : return NS_OK;
180 : }
181 :
182 : nsresult GetInstallYear(uint32_t& aYear)
183 : {
184 : HKEY hKey;
185 : LONG status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
186 : L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
187 : 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
188 :
189 : if (status != ERROR_SUCCESS) {
190 : return NS_ERROR_UNEXPECTED;
191 : }
192 :
193 : nsAutoRegKey key(hKey);
194 :
195 : DWORD type = 0;
196 : time_t raw_time = 0;
197 : DWORD time_size = sizeof(time_t);
198 :
199 : status = RegQueryValueExW(hKey, L"InstallDate",
200 : nullptr, &type, (LPBYTE)&raw_time, &time_size);
201 :
202 : if (status != ERROR_SUCCESS) {
203 : return NS_ERROR_UNEXPECTED;
204 : }
205 :
206 : if (type != REG_DWORD) {
207 : return NS_ERROR_UNEXPECTED;
208 : }
209 :
210 : tm time;
211 : if (localtime_s(&time, &raw_time) != 0) {
212 : return NS_ERROR_UNEXPECTED;
213 : }
214 :
215 : aYear = 1900UL + time.tm_year;
216 : return NS_OK;
217 : }
218 :
219 : nsresult GetCountryCode(nsAString& aCountryCode)
220 : {
221 : GEOID geoid = GetUserGeoID(GEOCLASS_NATION);
222 : if (geoid == GEOID_NOT_AVAILABLE) {
223 : return NS_ERROR_NOT_AVAILABLE;
224 : }
225 : // Get required length
226 : int numChars = GetGeoInfoW(geoid, GEO_ISO2, nullptr, 0, 0);
227 : if (!numChars) {
228 : return NS_ERROR_FAILURE;
229 : }
230 : // Now get the string for real
231 : aCountryCode.SetLength(numChars);
232 : numChars = GetGeoInfoW(geoid, GEO_ISO2, char16ptr_t(aCountryCode.BeginWriting()),
233 : aCountryCode.Length(), 0);
234 : if (!numChars) {
235 : return NS_ERROR_FAILURE;
236 : }
237 :
238 : // numChars includes null terminator
239 : aCountryCode.Truncate(numChars - 1);
240 : return NS_OK;
241 : }
242 :
243 : } // namespace
244 : #endif // defined(XP_WIN)
245 :
246 : using namespace mozilla;
247 :
248 1 : nsSystemInfo::nsSystemInfo()
249 : {
250 1 : }
251 :
252 0 : nsSystemInfo::~nsSystemInfo()
253 : {
254 0 : }
255 :
256 : // CPU-specific information.
257 : static const struct PropItems
258 : {
259 : const char* name;
260 : bool (*propfun)(void);
261 : } cpuPropItems[] = {
262 : // x86-specific bits.
263 : { "hasMMX", mozilla::supports_mmx },
264 : { "hasSSE", mozilla::supports_sse },
265 : { "hasSSE2", mozilla::supports_sse2 },
266 : { "hasSSE3", mozilla::supports_sse3 },
267 : { "hasSSSE3", mozilla::supports_ssse3 },
268 : { "hasSSE4A", mozilla::supports_sse4a },
269 : { "hasSSE4_1", mozilla::supports_sse4_1 },
270 : { "hasSSE4_2", mozilla::supports_sse4_2 },
271 : { "hasAVX", mozilla::supports_avx },
272 : { "hasAVX2", mozilla::supports_avx2 },
273 : { "hasAES", mozilla::supports_aes },
274 : // ARM-specific bits.
275 : { "hasEDSP", mozilla::supports_edsp },
276 : { "hasARMv6", mozilla::supports_armv6 },
277 : { "hasARMv7", mozilla::supports_armv7 },
278 : { "hasNEON", mozilla::supports_neon }
279 : };
280 :
281 : #ifdef XP_WIN
282 : // Lifted from media/webrtc/trunk/webrtc/base/systeminfo.cc,
283 : // so keeping the _ instead of switching to camel case for now.
284 : typedef BOOL (WINAPI *LPFN_GLPI)(
285 : PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
286 : PDWORD);
287 : static void
288 : GetProcessorInformation(int* physical_cpus, int* cache_size_L2, int* cache_size_L3)
289 : {
290 : MOZ_ASSERT(physical_cpus && cache_size_L2 && cache_size_L3);
291 :
292 : *physical_cpus = 0;
293 : *cache_size_L2 = 0; // This will be in kbytes
294 : *cache_size_L3 = 0; // This will be in kbytes
295 :
296 : // GetLogicalProcessorInformation() is available on Windows XP SP3 and beyond.
297 : LPFN_GLPI glpi = reinterpret_cast<LPFN_GLPI>(GetProcAddress(
298 : GetModuleHandle(L"kernel32"),
299 : "GetLogicalProcessorInformation"));
300 : if (nullptr == glpi) {
301 : return;
302 : }
303 : // Determine buffer size, allocate and get processor information.
304 : // Size can change between calls (unlikely), so a loop is done.
305 : SYSTEM_LOGICAL_PROCESSOR_INFORMATION info_buffer[32];
306 : SYSTEM_LOGICAL_PROCESSOR_INFORMATION* infos = &info_buffer[0];
307 : DWORD return_length = sizeof(info_buffer);
308 : while (!glpi(infos, &return_length)) {
309 : if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && infos == &info_buffer[0]) {
310 : infos = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)];
311 : } else {
312 : return;
313 : }
314 : }
315 :
316 : for (size_t i = 0;
317 : i < return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) {
318 : if (infos[i].Relationship == RelationProcessorCore) {
319 : ++*physical_cpus;
320 : } else if (infos[i].Relationship == RelationCache) {
321 : // Only care about L2 and L3 cache
322 : switch (infos[i].Cache.Level) {
323 : case 2:
324 : *cache_size_L2 = static_cast<int>(infos[i].Cache.Size/1024);
325 : break;
326 : case 3:
327 : *cache_size_L3 = static_cast<int>(infos[i].Cache.Size/1024);
328 : break;
329 : default:
330 : break;
331 : }
332 : }
333 : }
334 : if (infos != &info_buffer[0]) {
335 : delete [] infos;
336 : }
337 : return;
338 : }
339 : #endif
340 :
341 : nsresult
342 1 : nsSystemInfo::Init()
343 : {
344 : // This uses the observer service on Windows, so for simplicity
345 : // check that it is called from the main thread on all platforms.
346 1 : MOZ_ASSERT(NS_IsMainThread());
347 :
348 : nsresult rv;
349 :
350 : static const struct
351 : {
352 : PRSysInfo cmd;
353 : const char* name;
354 : } items[] = {
355 : { PR_SI_SYSNAME, "name" },
356 : { PR_SI_ARCHITECTURE, "arch" },
357 : { PR_SI_RELEASE, "version" }
358 : };
359 :
360 4 : for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) {
361 : char buf[SYS_INFO_BUFFER_LENGTH];
362 3 : if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) {
363 9 : rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name),
364 9 : nsDependentCString(buf));
365 3 : if (NS_WARN_IF(NS_FAILED(rv))) {
366 0 : return rv;
367 : }
368 : } else {
369 0 : NS_WARNING("PR_GetSystemInfo failed");
370 : }
371 : }
372 :
373 3 : rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"),
374 2 : false);
375 1 : NS_ENSURE_SUCCESS(rv, rv);
376 :
377 : // Additional informations not available through PR_GetSystemInfo.
378 1 : SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize());
379 1 : SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift());
380 1 : SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment());
381 1 : SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize());
382 1 : SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask);
383 :
384 1 : uint64_t virtualMem = 0;
385 2 : nsAutoCString cpuVendor;
386 1 : int cpuSpeed = -1;
387 1 : int cpuFamily = -1;
388 1 : int cpuModel = -1;
389 1 : int cpuStepping = -1;
390 1 : int logicalCPUs = -1;
391 1 : int physicalCPUs = -1;
392 1 : int cacheSizeL2 = -1;
393 1 : int cacheSizeL3 = -1;
394 :
395 : #if defined (XP_WIN)
396 : // Virtual memory:
397 : MEMORYSTATUSEX memStat;
398 : memStat.dwLength = sizeof(memStat);
399 : if (GlobalMemoryStatusEx(&memStat)) {
400 : virtualMem = memStat.ullTotalVirtual;
401 : }
402 :
403 : // CPU speed
404 : HKEY key;
405 : static const WCHAR keyName[] =
406 : L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
407 :
408 : if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key)
409 : == ERROR_SUCCESS) {
410 : DWORD data, len, vtype;
411 : len = sizeof(data);
412 :
413 : if (RegQueryValueEx(key, L"~Mhz", 0, 0, reinterpret_cast<LPBYTE>(&data),
414 : &len) == ERROR_SUCCESS) {
415 : cpuSpeed = static_cast<int>(data);
416 : }
417 :
418 : // Limit to 64 double byte characters, should be plenty, but create
419 : // a buffer one larger as the result may not be null terminated. If
420 : // it is more than 64, we will not get the value.
421 : wchar_t cpuVendorStr[64+1];
422 : len = sizeof(cpuVendorStr)-2;
423 : if (RegQueryValueExW(key, L"VendorIdentifier",
424 : 0, &vtype,
425 : reinterpret_cast<LPBYTE>(cpuVendorStr),
426 : &len) == ERROR_SUCCESS &&
427 : vtype == REG_SZ && len % 2 == 0 && len > 1) {
428 : cpuVendorStr[len/2] = 0; // In case it isn't null terminated
429 : CopyUTF16toUTF8(nsDependentString(cpuVendorStr), cpuVendor);
430 : }
431 :
432 : RegCloseKey(key);
433 : }
434 :
435 : // Other CPU attributes:
436 : SYSTEM_INFO si;
437 : GetNativeSystemInfo(&si);
438 : logicalCPUs = si.dwNumberOfProcessors;
439 : GetProcessorInformation(&physicalCPUs, &cacheSizeL2, &cacheSizeL3);
440 : if (physicalCPUs <= 0) {
441 : physicalCPUs = logicalCPUs;
442 : }
443 : cpuFamily = si.wProcessorLevel;
444 : cpuModel = si.wProcessorRevision >> 8;
445 : cpuStepping = si.wProcessorRevision & 0xFF;
446 : #elif defined (XP_MACOSX)
447 : // CPU speed
448 : uint64_t sysctlValue64 = 0;
449 : uint32_t sysctlValue32 = 0;
450 : size_t len = 0;
451 : len = sizeof(sysctlValue64);
452 : if (!sysctlbyname("hw.cpufrequency_max", &sysctlValue64, &len, NULL, 0)) {
453 : cpuSpeed = static_cast<int>(sysctlValue64/1000000);
454 : }
455 : MOZ_ASSERT(sizeof(sysctlValue64) == len);
456 :
457 : len = sizeof(sysctlValue32);
458 : if (!sysctlbyname("hw.physicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
459 : physicalCPUs = static_cast<int>(sysctlValue32);
460 : }
461 : MOZ_ASSERT(sizeof(sysctlValue32) == len);
462 :
463 : len = sizeof(sysctlValue32);
464 : if (!sysctlbyname("hw.logicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
465 : logicalCPUs = static_cast<int>(sysctlValue32);
466 : }
467 : MOZ_ASSERT(sizeof(sysctlValue32) == len);
468 :
469 : len = sizeof(sysctlValue64);
470 : if (!sysctlbyname("hw.l2cachesize", &sysctlValue64, &len, NULL, 0)) {
471 : cacheSizeL2 = static_cast<int>(sysctlValue64/1024);
472 : }
473 : MOZ_ASSERT(sizeof(sysctlValue64) == len);
474 :
475 : len = sizeof(sysctlValue64);
476 : if (!sysctlbyname("hw.l3cachesize", &sysctlValue64, &len, NULL, 0)) {
477 : cacheSizeL3 = static_cast<int>(sysctlValue64/1024);
478 : }
479 : MOZ_ASSERT(sizeof(sysctlValue64) == len);
480 :
481 : if (!sysctlbyname("machdep.cpu.vendor", NULL, &len, NULL, 0)) {
482 : char* cpuVendorStr = new char[len];
483 : if (!sysctlbyname("machdep.cpu.vendor", cpuVendorStr, &len, NULL, 0)) {
484 : cpuVendor = cpuVendorStr;
485 : }
486 : delete [] cpuVendorStr;
487 : }
488 :
489 : len = sizeof(sysctlValue32);
490 : if (!sysctlbyname("machdep.cpu.family", &sysctlValue32, &len, NULL, 0)) {
491 : cpuFamily = static_cast<int>(sysctlValue32);
492 : }
493 : MOZ_ASSERT(sizeof(sysctlValue32) == len);
494 :
495 : len = sizeof(sysctlValue32);
496 : if (!sysctlbyname("machdep.cpu.model", &sysctlValue32, &len, NULL, 0)) {
497 : cpuModel = static_cast<int>(sysctlValue32);
498 : }
499 : MOZ_ASSERT(sizeof(sysctlValue32) == len);
500 :
501 : len = sizeof(sysctlValue32);
502 : if (!sysctlbyname("machdep.cpu.stepping", &sysctlValue32, &len, NULL, 0)) {
503 : cpuStepping = static_cast<int>(sysctlValue32);
504 : }
505 : MOZ_ASSERT(sizeof(sysctlValue32) == len);
506 :
507 : #elif defined (XP_LINUX) && !defined (ANDROID)
508 : // Get vendor, family, model, stepping, physical cores, L3 cache size
509 : // from /proc/cpuinfo file
510 : {
511 2 : std::map<nsCString, nsCString> keyValuePairs;
512 1 : SimpleParseKeyValuePairs("/proc/cpuinfo", keyValuePairs);
513 :
514 : // cpuVendor from "vendor_id"
515 1 : cpuVendor.Assign(keyValuePairs[NS_LITERAL_CSTRING("vendor_id")]);
516 :
517 : {
518 : // cpuFamily from "cpu family"
519 2 : Tokenizer::Token t;
520 2 : Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu family")]);
521 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
522 1 : t.AsInteger() <= INT32_MAX) {
523 1 : cpuFamily = static_cast<int>(t.AsInteger());
524 : }
525 : }
526 :
527 : {
528 : // cpuModel from "model"
529 2 : Tokenizer::Token t;
530 2 : Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("model")]);
531 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
532 1 : t.AsInteger() <= INT32_MAX) {
533 1 : cpuModel = static_cast<int>(t.AsInteger());
534 : }
535 : }
536 :
537 : {
538 : // cpuStepping from "stepping"
539 2 : Tokenizer::Token t;
540 2 : Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("stepping")]);
541 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
542 1 : t.AsInteger() <= INT32_MAX) {
543 1 : cpuStepping = static_cast<int>(t.AsInteger());
544 : }
545 : }
546 :
547 : {
548 : // physicalCPUs from "cpu cores"
549 2 : Tokenizer::Token t;
550 2 : Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu cores")]);
551 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
552 1 : t.AsInteger() <= INT32_MAX) {
553 1 : physicalCPUs = static_cast<int>(t.AsInteger());
554 : }
555 : }
556 :
557 : {
558 : // cacheSizeL3 from "cache size"
559 2 : Tokenizer::Token t;
560 2 : Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cache size")]);
561 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
562 1 : t.AsInteger() <= INT32_MAX) {
563 1 : cacheSizeL3 = static_cast<int>(t.AsInteger());
564 3 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_WORD &&
565 1 : t.AsString() != NS_LITERAL_CSTRING("KB")) {
566 : // If we get here, there was some text after the cache size value
567 : // and that text was not KB. For now, just don't report the
568 : // L3 cache.
569 0 : cacheSizeL3 = -1;
570 : }
571 : }
572 : }
573 : }
574 :
575 : {
576 : // Get cpuSpeed from another file.
577 2 : std::ifstream input("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
578 2 : std::string line;
579 1 : if (getline(input, line)) {
580 2 : Tokenizer::Token t;
581 2 : Tokenizer p(line.c_str());
582 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
583 1 : t.AsInteger() <= INT32_MAX) {
584 1 : cpuSpeed = static_cast<int>(t.AsInteger()/1000);
585 : }
586 : }
587 : }
588 :
589 : {
590 : // Get cacheSizeL2 from yet another file
591 2 : std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index2/size");
592 2 : std::string line;
593 1 : if (getline(input, line)) {
594 2 : Tokenizer::Token t;
595 2 : Tokenizer p(line.c_str(), nullptr, "K");
596 2 : if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
597 1 : t.AsInteger() <= INT32_MAX) {
598 1 : cacheSizeL2 = static_cast<int>(t.AsInteger());
599 : }
600 : }
601 : }
602 :
603 1 : SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
604 : #else
605 : SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
606 : #endif
607 :
608 1 : if (virtualMem) SetUint64Property(NS_LITERAL_STRING("virtualmemsize"), virtualMem);
609 1 : if (cpuSpeed >= 0) SetInt32Property(NS_LITERAL_STRING("cpuspeed"), cpuSpeed);
610 1 : if (!cpuVendor.IsEmpty()) SetPropertyAsACString(NS_LITERAL_STRING("cpuvendor"), cpuVendor);
611 1 : if (cpuFamily >= 0) SetInt32Property(NS_LITERAL_STRING("cpufamily"), cpuFamily);
612 1 : if (cpuModel >= 0) SetInt32Property(NS_LITERAL_STRING("cpumodel"), cpuModel);
613 1 : if (cpuStepping >= 0) SetInt32Property(NS_LITERAL_STRING("cpustepping"), cpuStepping);
614 :
615 1 : if (logicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucount"), logicalCPUs);
616 1 : if (physicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucores"), physicalCPUs);
617 :
618 1 : if (cacheSizeL2 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel2"), cacheSizeL2);
619 1 : if (cacheSizeL3 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel3"), cacheSizeL3);
620 :
621 16 : for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) {
622 45 : rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name),
623 30 : cpuPropItems[i].propfun());
624 15 : if (NS_WARN_IF(NS_FAILED(rv))) {
625 0 : return rv;
626 : }
627 : }
628 :
629 : #ifdef XP_WIN
630 : BOOL isWow64;
631 : BOOL gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64);
632 : NS_WARNING_ASSERTION(gotWow64Value, "IsWow64Process failed");
633 : if (gotWow64Value) {
634 : rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64);
635 : if (NS_WARN_IF(NS_FAILED(rv))) {
636 : return rv;
637 : }
638 : }
639 : if (NS_FAILED(GetProfileHDDInfo())) {
640 : // We might have been called before profile-do-change. We'll observe that
641 : // event so that we can fill this in later.
642 : nsCOMPtr<nsIObserverService> obsService =
643 : do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
644 : if (NS_WARN_IF(NS_FAILED(rv))) {
645 : return rv;
646 : }
647 : rv = obsService->AddObserver(this, "profile-do-change", false);
648 : if (NS_FAILED(rv)) {
649 : return rv;
650 : }
651 : }
652 : nsAutoCString hddModel, hddRevision;
653 : if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR, hddModel, hddRevision))) {
654 : rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel);
655 : NS_ENSURE_SUCCESS(rv, rv);
656 : rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"),
657 : hddRevision);
658 : NS_ENSURE_SUCCESS(rv, rv);
659 : }
660 : if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR, hddModel, hddRevision))) {
661 : rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel);
662 : NS_ENSURE_SUCCESS(rv, rv);
663 : rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"),
664 : hddRevision);
665 : NS_ENSURE_SUCCESS(rv, rv);
666 : }
667 :
668 : nsAutoString countryCode;
669 : if (NS_SUCCEEDED(GetCountryCode(countryCode))) {
670 : rv = SetPropertyAsAString(NS_LITERAL_STRING("countryCode"), countryCode);
671 : NS_ENSURE_SUCCESS(rv, rv);
672 : }
673 :
674 : uint32_t installYear = 0;
675 : if (NS_SUCCEEDED(GetInstallYear(installYear))) {
676 : rv = SetPropertyAsUint32(NS_LITERAL_STRING("installYear"), installYear);
677 : if (NS_WARN_IF(NS_FAILED(rv))) {
678 : return rv;
679 : }
680 : }
681 : #endif
682 :
683 : #if defined(XP_MACOSX)
684 : nsAutoString countryCode;
685 : if (NS_SUCCEEDED(GetSelectedCityInfo(countryCode))) {
686 : rv = SetPropertyAsAString(NS_LITERAL_STRING("countryCode"), countryCode);
687 : NS_ENSURE_SUCCESS(rv, rv);
688 : }
689 : #endif
690 :
691 : #if defined(MOZ_WIDGET_GTK)
692 : // This must be done here because NSPR can only separate OS's when compiled, not libraries.
693 : // 64 bytes is going to be well enough for "GTK " followed by 3 integers
694 : // separated with dots.
695 : char gtkver[64];
696 1 : ssize_t gtkver_len = 0;
697 :
698 : #if MOZ_WIDGET_GTK == 2
699 : extern int gtk_read_end_of_the_pipe;
700 :
701 : if (gtk_read_end_of_the_pipe != -1) {
702 : do {
703 : gtkver_len = read(gtk_read_end_of_the_pipe, >kver, sizeof(gtkver));
704 : } while (gtkver_len < 0 && errno == EINTR);
705 : close(gtk_read_end_of_the_pipe);
706 : }
707 : #endif
708 :
709 1 : if (gtkver_len <= 0) {
710 1 : gtkver_len = SprintfLiteral(gtkver, "GTK %u.%u.%u", gtk_major_version,
711 : gtk_minor_version, gtk_micro_version);
712 : }
713 :
714 2 : nsAutoCString secondaryLibrary;
715 1 : if (gtkver_len > 0) {
716 1 : secondaryLibrary.Append(nsDependentCSubstring(gtkver, gtkver_len));
717 : }
718 :
719 1 : void* libpulse = dlopen("libpulse.so.0", RTLD_LAZY);
720 1 : const char* libpulseVersion = "not-available";
721 1 : if (libpulse) {
722 : auto pa_get_library_version = reinterpret_cast<const char* (*)()>
723 1 : (dlsym(libpulse, "pa_get_library_version"));
724 :
725 1 : if (pa_get_library_version) {
726 1 : libpulseVersion = pa_get_library_version();
727 : }
728 : }
729 :
730 1 : secondaryLibrary.AppendPrintf(",libpulse %s", libpulseVersion);
731 :
732 1 : if (libpulse) {
733 1 : dlclose(libpulse);
734 : }
735 :
736 4 : rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"),
737 3 : secondaryLibrary);
738 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
739 0 : return rv;
740 : }
741 : #endif
742 :
743 : #ifdef MOZ_WIDGET_ANDROID
744 : AndroidSystemInfo info;
745 : if (XRE_IsContentProcess()) {
746 : dom::ContentChild* child = dom::ContentChild::GetSingleton();
747 : if (child) {
748 : child->SendGetAndroidSystemInfo(&info);
749 : SetupAndroidInfo(info);
750 : }
751 : } else {
752 : GetAndroidSystemInfo(&info);
753 : SetupAndroidInfo(info);
754 : }
755 : #endif
756 :
757 : #ifdef MOZ_WIDGET_GONK
758 : char sdk[PROP_VALUE_MAX];
759 : if (__system_property_get("ro.build.version.sdk", sdk)) {
760 : android_sdk_version = atoi(sdk);
761 : SetPropertyAsInt32(NS_LITERAL_STRING("sdk_version"), android_sdk_version);
762 :
763 : SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"),
764 : nsPrintfCString("SDK %u", android_sdk_version));
765 : }
766 :
767 : char characteristics[PROP_VALUE_MAX];
768 : if (__system_property_get("ro.build.characteristics", characteristics)) {
769 : if (!strcmp(characteristics, "tablet")) {
770 : SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true);
771 : } else if (!strcmp(characteristics, "tv")) {
772 : SetPropertyAsBool(NS_LITERAL_STRING("tv"), true);
773 : }
774 : }
775 :
776 : nsAutoString str;
777 : rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str);
778 : if (NS_SUCCEEDED(rv)) {
779 : SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str);
780 : }
781 :
782 : const nsAdoptingString& b2g_os_name =
783 : mozilla::Preferences::GetString("b2g.osName");
784 : if (b2g_os_name) {
785 : SetPropertyAsAString(NS_LITERAL_STRING("name"), b2g_os_name);
786 : }
787 :
788 : const nsAdoptingString& b2g_version =
789 : mozilla::Preferences::GetString("b2g.version");
790 : if (b2g_version) {
791 : SetPropertyAsAString(NS_LITERAL_STRING("version"), b2g_version);
792 : }
793 : #endif
794 :
795 : #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
796 : SandboxInfo sandInfo = SandboxInfo::Get();
797 :
798 : SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompBPF"),
799 : sandInfo.Test(SandboxInfo::kHasSeccompBPF));
800 : SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompTSync"),
801 : sandInfo.Test(SandboxInfo::kHasSeccompTSync));
802 : SetPropertyAsBool(NS_LITERAL_STRING("hasUserNamespaces"),
803 : sandInfo.Test(SandboxInfo::kHasUserNamespaces));
804 : SetPropertyAsBool(NS_LITERAL_STRING("hasPrivilegedUserNamespaces"),
805 : sandInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces));
806 :
807 : if (sandInfo.Test(SandboxInfo::kEnabledForContent)) {
808 : SetPropertyAsBool(NS_LITERAL_STRING("canSandboxContent"),
809 : sandInfo.CanSandboxContent());
810 : }
811 :
812 : if (sandInfo.Test(SandboxInfo::kEnabledForMedia)) {
813 : SetPropertyAsBool(NS_LITERAL_STRING("canSandboxMedia"),
814 : sandInfo.CanSandboxMedia());
815 : }
816 : #endif // XP_LINUX && MOZ_SANDBOX
817 :
818 1 : return NS_OK;
819 : }
820 :
821 : #ifdef MOZ_WIDGET_ANDROID
822 : // Prerelease versions of Android use a letter instead of version numbers.
823 : // Unfortunately this breaks websites due to the user agent.
824 : // Chrome works around this by hardcoding an Android version when a
825 : // numeric version can't be obtained. We're doing the same.
826 : // This version will need to be updated whenever there is a new official
827 : // Android release.
828 : // See: https://cs.chromium.org/chromium/src/base/sys_info_android.cc?l=61
829 : #define DEFAULT_ANDROID_VERSION "6.0.99"
830 :
831 : /* static */
832 : void
833 : nsSystemInfo::GetAndroidSystemInfo(AndroidSystemInfo* aInfo)
834 : {
835 : MOZ_ASSERT(XRE_IsParentProcess());
836 :
837 : if (!mozilla::AndroidBridge::Bridge()) {
838 : aInfo->sdk_version() = 0;
839 : return;
840 : }
841 :
842 : nsAutoString str;
843 : if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
844 : "android/os/Build", "MODEL", str)) {
845 : aInfo->device() = str;
846 : }
847 : if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
848 : "android/os/Build", "MANUFACTURER", str)) {
849 : aInfo->manufacturer() = str;
850 : }
851 : if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
852 : "android/os/Build$VERSION", "RELEASE", str)) {
853 : int major_version;
854 : int minor_version;
855 : int bugfix_version;
856 : int num_read = sscanf(NS_ConvertUTF16toUTF8(str).get(), "%d.%d.%d", &major_version, &minor_version, &bugfix_version);
857 : if (num_read == 0) {
858 : aInfo->release_version() = NS_LITERAL_STRING(DEFAULT_ANDROID_VERSION);
859 : } else {
860 : aInfo->release_version() = str;
861 : }
862 : }
863 : if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
864 : "android/os/Build", "HARDWARE", str)) {
865 : aInfo->hardware() = str;
866 : }
867 : int32_t sdk_version;
868 : if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField(
869 : "android/os/Build$VERSION", "SDK_INT", &sdk_version)) {
870 : sdk_version = 0;
871 : }
872 : aInfo->sdk_version() = sdk_version;
873 : aInfo->isTablet() = java::GeckoAppShell::IsTablet();
874 : }
875 :
876 : void
877 : nsSystemInfo::SetupAndroidInfo(const AndroidSystemInfo& aInfo)
878 : {
879 : if (!aInfo.device().IsEmpty()) {
880 : SetPropertyAsAString(NS_LITERAL_STRING("device"), aInfo.device());
881 : }
882 : if (!aInfo.manufacturer().IsEmpty()) {
883 : SetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), aInfo.manufacturer());
884 : }
885 : if (!aInfo.release_version().IsEmpty()) {
886 : SetPropertyAsAString(NS_LITERAL_STRING("release_version"), aInfo.release_version());
887 : }
888 : SetPropertyAsBool(NS_LITERAL_STRING("tablet"), aInfo.isTablet());
889 : // NSPR "version" is the kernel version. For Android we want the Android version.
890 : // Rename SDK version to version and put the kernel version into kernel_version.
891 : nsAutoString str;
892 : nsresult rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str);
893 : if (NS_SUCCEEDED(rv)) {
894 : SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str);
895 : }
896 : // When AndroidBridge is not available (eg. in xpcshell tests), sdk_version is 0.
897 : if (aInfo.sdk_version() != 0) {
898 : android_sdk_version = aInfo.sdk_version();
899 : if (android_sdk_version >= 8 && !aInfo.hardware().IsEmpty()) {
900 : SetPropertyAsAString(NS_LITERAL_STRING("hardware"), aInfo.hardware());
901 : }
902 : SetPropertyAsInt32(NS_LITERAL_STRING("version"), android_sdk_version);
903 : }
904 : }
905 : #endif // MOZ_WIDGET_ANDROID
906 :
907 : void
908 11 : nsSystemInfo::SetInt32Property(const nsAString& aPropertyName,
909 : const int32_t aValue)
910 : {
911 11 : NS_WARNING_ASSERTION(aValue > 0, "Unable to read system value");
912 11 : if (aValue > 0) {
913 : #ifdef DEBUG
914 : nsresult rv =
915 : #endif
916 11 : SetPropertyAsInt32(aPropertyName, aValue);
917 11 : NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
918 : }
919 11 : }
920 :
921 : void
922 1 : nsSystemInfo::SetUint32Property(const nsAString& aPropertyName,
923 : const uint32_t aValue)
924 : {
925 : // Only one property is currently set via this function.
926 : // It may legitimately be zero.
927 : #ifdef DEBUG
928 : nsresult rv =
929 : #endif
930 1 : SetPropertyAsUint32(aPropertyName, aValue);
931 1 : NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
932 1 : }
933 :
934 : void
935 1 : nsSystemInfo::SetUint64Property(const nsAString& aPropertyName,
936 : const uint64_t aValue)
937 : {
938 1 : NS_WARNING_ASSERTION(aValue > 0, "Unable to read system value");
939 1 : if (aValue > 0) {
940 : #ifdef DEBUG
941 : nsresult rv =
942 : #endif
943 1 : SetPropertyAsUint64(aPropertyName, aValue);
944 1 : NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
945 : }
946 1 : }
947 :
948 : #if defined(XP_WIN)
949 : NS_IMETHODIMP
950 : nsSystemInfo::Observe(nsISupports* aSubject, const char* aTopic,
951 : const char16_t* aData)
952 : {
953 : if (!strcmp(aTopic, "profile-do-change")) {
954 : nsresult rv;
955 : nsCOMPtr<nsIObserverService> obsService =
956 : do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
957 : if (NS_FAILED(rv)) {
958 : return rv;
959 : }
960 : rv = obsService->RemoveObserver(this, "profile-do-change");
961 : if (NS_FAILED(rv)) {
962 : return rv;
963 : }
964 : return GetProfileHDDInfo();
965 : }
966 : return NS_OK;
967 : }
968 :
969 : nsresult
970 : nsSystemInfo::GetProfileHDDInfo()
971 : {
972 : nsAutoCString hddModel, hddRevision;
973 : nsresult rv = GetHDDInfo(NS_APP_USER_PROFILE_50_DIR, hddModel, hddRevision);
974 : if (NS_FAILED(rv)) {
975 : return rv;
976 : }
977 : rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDModel"), hddModel);
978 : if (NS_FAILED(rv)) {
979 : return rv;
980 : }
981 : rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDRevision"),
982 : hddRevision);
983 : return rv;
984 : }
985 :
986 : NS_IMPL_ISUPPORTS_INHERITED(nsSystemInfo, nsHashPropertyBag, nsIObserver)
987 : #endif // defined(XP_WIN)
988 :
|