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