/src/mozilla-central/xpcom/base/nsSystemInfo.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | SimpleParseKeyValuePairs(const std::string& aFilename, |
86 | | std::map<nsCString, nsCString>& aKeyValuePairs) |
87 | 0 | { |
88 | 0 | std::ifstream input(aFilename.c_str()); |
89 | 0 | for (std::string line; std::getline(input, line); ) { |
90 | 0 | nsAutoCString key, value; |
91 | 0 |
|
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 | 0 | } |
98 | 0 | // We want the value even if there was just one token, to cover the |
99 | 0 | // case where we had the key, and the value was blank (seems to be |
100 | 0 | // a valid scenario some files.) |
101 | 0 | aKeyValuePairs[key] = value; |
102 | 0 | } |
103 | 0 | } |
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 | | nsSystemInfo::nsSystemInfo() |
373 | 0 | { |
374 | 0 | } |
375 | | |
376 | | nsSystemInfo::~nsSystemInfo() |
377 | 0 | { |
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 | | nsSystemInfo::Init() |
467 | 0 | { |
468 | 0 | // This uses the observer service on Windows, so for simplicity |
469 | 0 | // check that it is called from the main thread on all platforms. |
470 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
471 | 0 |
|
472 | 0 | nsresult rv; |
473 | 0 |
|
474 | 0 | static const struct |
475 | 0 | { |
476 | 0 | PRSysInfo cmd; |
477 | 0 | const char* name; |
478 | 0 | } items[] = { |
479 | 0 | { PR_SI_SYSNAME, "name" }, |
480 | 0 | { PR_SI_ARCHITECTURE, "arch" }, |
481 | 0 | { PR_SI_RELEASE, "version" } |
482 | 0 | }; |
483 | 0 |
|
484 | 0 | for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) { |
485 | 0 | 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 | 0 | } |
492 | 0 | } else { |
493 | 0 | NS_WARNING("PR_GetSystemInfo failed"); |
494 | 0 | } |
495 | 0 | } |
496 | 0 |
|
497 | 0 | rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), |
498 | 0 | false); |
499 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
500 | 0 |
|
501 | 0 | // 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 | 0 |
|
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 | 0 |
|
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 | 0 | // from /proc/cpuinfo file |
634 | 0 | { |
635 | 0 | std::map<nsCString, nsCString> keyValuePairs; |
636 | 0 | SimpleParseKeyValuePairs("/proc/cpuinfo", keyValuePairs); |
637 | 0 |
|
638 | 0 | // cpuVendor from "vendor_id" |
639 | 0 | cpuVendor.Assign(keyValuePairs[NS_LITERAL_CSTRING("vendor_id")]); |
640 | 0 |
|
641 | 0 | { |
642 | 0 | // 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 | 0 | } |
649 | 0 | } |
650 | 0 |
|
651 | 0 | { |
652 | 0 | // 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 | 0 | } |
659 | 0 | } |
660 | 0 |
|
661 | 0 | { |
662 | 0 | // 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 | 0 | } |
669 | 0 | } |
670 | 0 |
|
671 | 0 | { |
672 | 0 | // 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 | 0 | } |
679 | 0 | } |
680 | 0 |
|
681 | 0 | { |
682 | 0 | // 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 | 0 | // If we get here, there was some text after the cache size value |
691 | 0 | // and that text was not KB. For now, just don't report the |
692 | 0 | // L3 cache. |
693 | 0 | cacheSizeL3 = -1; |
694 | 0 | } |
695 | 0 | } |
696 | 0 | } |
697 | 0 | } |
698 | 0 |
|
699 | 0 | { |
700 | 0 | // 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 | 0 | Tokenizer::Token t; |
705 | 0 | Tokenizer p(line.c_str()); |
706 | 0 | if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && |
707 | 0 | t.AsInteger() <= INT32_MAX) { |
708 | 0 | cpuSpeed = static_cast<int>(t.AsInteger()/1000); |
709 | 0 | } |
710 | 0 | } |
711 | 0 | } |
712 | 0 |
|
713 | 0 | { |
714 | 0 | // 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 | 0 | } |
724 | 0 | } |
725 | 0 | } |
726 | 0 |
|
727 | 0 | SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); |
728 | | #else |
729 | | SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); |
730 | | #endif |
731 | |
|
732 | 0 | 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 | 0 |
|
739 | 0 | if (logicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucount"), logicalCPUs); |
740 | 0 | if (physicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucores"), physicalCPUs); |
741 | 0 |
|
742 | 0 | if (cacheSizeL2 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel2"), cacheSizeL2); |
743 | 0 | if (cacheSizeL3 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel3"), cacheSizeL3); |
744 | 0 |
|
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 | 0 | return rv; |
750 | 0 | } |
751 | 0 | } |
752 | 0 |
|
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 | 0 | #if defined(MOZ_WIDGET_GTK) |
852 | 0 | // This must be done here because NSPR can only separate OS's when compiled, not libraries. |
853 | 0 | // 64 bytes is going to be well enough for "GTK " followed by 3 integers |
854 | 0 | // separated with dots. |
855 | 0 | char gtkver[64]; |
856 | 0 | ssize_t gtkver_len = 0; |
857 | 0 |
|
858 | 0 | if (gtkver_len <= 0) { |
859 | 0 | gtkver_len = SprintfLiteral(gtkver, "GTK %u.%u.%u", gtk_major_version, |
860 | 0 | gtk_minor_version, gtk_micro_version); |
861 | 0 | } |
862 | 0 |
|
863 | 0 | nsAutoCString secondaryLibrary; |
864 | 0 | if (gtkver_len > 0 && gtkver_len < int(sizeof(gtkver))) { |
865 | 0 | secondaryLibrary.Append(nsDependentCSubstring(gtkver, gtkver_len)); |
866 | 0 | } |
867 | 0 |
|
868 | 0 | void* libpulse = dlopen("libpulse.so.0", RTLD_LAZY); |
869 | 0 | const char* libpulseVersion = "not-available"; |
870 | 0 | if (libpulse) { |
871 | 0 | auto pa_get_library_version = reinterpret_cast<const char* (*)()> |
872 | 0 | (dlsym(libpulse, "pa_get_library_version")); |
873 | 0 |
|
874 | 0 | if (pa_get_library_version) { |
875 | 0 | libpulseVersion = pa_get_library_version(); |
876 | 0 | } |
877 | 0 | } |
878 | 0 |
|
879 | 0 | secondaryLibrary.AppendPrintf(",libpulse %s", libpulseVersion); |
880 | 0 |
|
881 | 0 | if (libpulse) { |
882 | 0 | dlclose(libpulse); |
883 | 0 | } |
884 | 0 |
|
885 | 0 | rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), |
886 | 0 | secondaryLibrary); |
887 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
888 | 0 | return rv; |
889 | 0 | } |
890 | 0 | #endif |
891 | 0 | |
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 | 0 | #if defined(XP_LINUX) && defined(MOZ_SANDBOX) |
907 | 0 | SandboxInfo sandInfo = SandboxInfo::Get(); |
908 | 0 |
|
909 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompBPF"), |
910 | 0 | sandInfo.Test(SandboxInfo::kHasSeccompBPF)); |
911 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompTSync"), |
912 | 0 | sandInfo.Test(SandboxInfo::kHasSeccompTSync)); |
913 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("hasUserNamespaces"), |
914 | 0 | sandInfo.Test(SandboxInfo::kHasUserNamespaces)); |
915 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("hasPrivilegedUserNamespaces"), |
916 | 0 | sandInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces)); |
917 | 0 |
|
918 | 0 | if (sandInfo.Test(SandboxInfo::kEnabledForContent)) { |
919 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("canSandboxContent"), |
920 | 0 | sandInfo.CanSandboxContent()); |
921 | 0 | } |
922 | 0 |
|
923 | 0 | if (sandInfo.Test(SandboxInfo::kEnabledForMedia)) { |
924 | 0 | SetPropertyAsBool(NS_LITERAL_STRING("canSandboxMedia"), |
925 | 0 | sandInfo.CanSandboxMedia()); |
926 | 0 | } |
927 | 0 | #endif // XP_LINUX && MOZ_SANDBOX |
928 | 0 |
|
929 | 0 | return NS_OK; |
930 | 0 | } |
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 | | nsSystemInfo::SetInt32Property(const nsAString& aPropertyName, |
1020 | | const int32_t aValue) |
1021 | 0 | { |
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 | | SetPropertyAsInt32(aPropertyName, aValue); |
1028 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property"); |
1029 | 0 | } |
1030 | 0 | } |
1031 | | |
1032 | | void |
1033 | | nsSystemInfo::SetUint32Property(const nsAString& aPropertyName, |
1034 | | const uint32_t aValue) |
1035 | 0 | { |
1036 | 0 | // Only one property is currently set via this function. |
1037 | 0 | // It may legitimately be zero. |
1038 | | #ifdef DEBUG |
1039 | | nsresult rv = |
1040 | | #endif |
1041 | | SetPropertyAsUint32(aPropertyName, aValue); |
1042 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property"); |
1043 | 0 | } |
1044 | | |
1045 | | void |
1046 | | nsSystemInfo::SetUint64Property(const nsAString& aPropertyName, |
1047 | | const uint64_t aValue) |
1048 | 0 | { |
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 | | SetPropertyAsUint64(aPropertyName, aValue); |
1055 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property"); |
1056 | 0 | } |
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 | | |