1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsSystemInfo.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,342 @@ 1.4 +/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include "nsSystemInfo.h" 1.12 +#include "prsystem.h" 1.13 +#include "prio.h" 1.14 +#include "prprf.h" 1.15 +#include "mozilla/SSE.h" 1.16 +#include "mozilla/arm.h" 1.17 + 1.18 +#ifdef XP_WIN 1.19 +#include <windows.h> 1.20 +#include <winioctl.h> 1.21 +#include "base/scoped_handle_win.h" 1.22 +#include "nsAppDirectoryServiceDefs.h" 1.23 +#include "nsDirectoryServiceDefs.h" 1.24 +#include "nsDirectoryServiceUtils.h" 1.25 +#endif 1.26 + 1.27 +#ifdef MOZ_WIDGET_GTK 1.28 +#include <gtk/gtk.h> 1.29 +#endif 1.30 + 1.31 +#ifdef MOZ_WIDGET_ANDROID 1.32 +#include "AndroidBridge.h" 1.33 +using namespace mozilla::widget::android; 1.34 +#endif 1.35 + 1.36 +#ifdef MOZ_WIDGET_GONK 1.37 +#include <sys/system_properties.h> 1.38 +#endif 1.39 + 1.40 +#ifdef ANDROID 1.41 +extern "C" { 1.42 +NS_EXPORT int android_sdk_version; 1.43 +} 1.44 +#endif 1.45 + 1.46 +// Slot for NS_InitXPCOM2 to pass information to nsSystemInfo::Init. 1.47 +// Only set to nonzero (potentially) if XP_UNIX. On such systems, the 1.48 +// system call to discover the appropriate value is not thread-safe, 1.49 +// so we must call it before going multithreaded, but nsSystemInfo::Init 1.50 +// only happens well after that point. 1.51 +uint32_t nsSystemInfo::gUserUmask = 0; 1.52 + 1.53 +#if defined(XP_WIN) 1.54 +namespace { 1.55 +nsresult GetHDDInfo(const char* aSpecialDirName, nsAutoCString& aModel, 1.56 + nsAutoCString& aRevision) 1.57 +{ 1.58 + aModel.Truncate(); 1.59 + aRevision.Truncate(); 1.60 + 1.61 + nsCOMPtr<nsIFile> profDir; 1.62 + nsresult rv = NS_GetSpecialDirectory(aSpecialDirName, 1.63 + getter_AddRefs(profDir)); 1.64 + NS_ENSURE_SUCCESS(rv, rv); 1.65 + nsAutoString profDirPath; 1.66 + rv = profDir->GetPath(profDirPath); 1.67 + NS_ENSURE_SUCCESS(rv, rv); 1.68 + wchar_t volumeMountPoint[MAX_PATH] = {L'\\', L'\\', L'.', L'\\'}; 1.69 + const size_t PREFIX_LEN = 4; 1.70 + if (!::GetVolumePathNameW(profDirPath.get(), volumeMountPoint + PREFIX_LEN, 1.71 + mozilla::ArrayLength(volumeMountPoint) - 1.72 + PREFIX_LEN)) { 1.73 + return NS_ERROR_UNEXPECTED; 1.74 + } 1.75 + size_t volumeMountPointLen = wcslen(volumeMountPoint); 1.76 + // Since we would like to open a drive and not a directory, we need to 1.77 + // remove any trailing backslash. A drive handle is valid for 1.78 + // DeviceIoControl calls, a directory handle is not. 1.79 + if (volumeMountPoint[volumeMountPointLen - 1] == L'\\') { 1.80 + volumeMountPoint[volumeMountPointLen - 1] = L'\0'; 1.81 + } 1.82 + ScopedHandle handle(::CreateFileW(volumeMountPoint, 0, 1.83 + FILE_SHARE_READ | FILE_SHARE_WRITE, 1.84 + nullptr, OPEN_EXISTING, 0, nullptr)); 1.85 + if (!handle.IsValid()) { 1.86 + return NS_ERROR_UNEXPECTED; 1.87 + } 1.88 + STORAGE_PROPERTY_QUERY queryParameters = {StorageDeviceProperty, 1.89 + PropertyStandardQuery}; 1.90 + STORAGE_DEVICE_DESCRIPTOR outputHeader = {sizeof(STORAGE_DEVICE_DESCRIPTOR)}; 1.91 + DWORD bytesRead = 0; 1.92 + if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, 1.93 + &queryParameters, sizeof(queryParameters), 1.94 + &outputHeader, sizeof(outputHeader), &bytesRead, 1.95 + nullptr)) { 1.96 + return NS_ERROR_FAILURE; 1.97 + } 1.98 + PSTORAGE_DEVICE_DESCRIPTOR deviceOutput = 1.99 + (PSTORAGE_DEVICE_DESCRIPTOR)malloc(outputHeader.Size); 1.100 + if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, 1.101 + &queryParameters, sizeof(queryParameters), 1.102 + deviceOutput, outputHeader.Size, &bytesRead, 1.103 + nullptr)) { 1.104 + free(deviceOutput); 1.105 + return NS_ERROR_FAILURE; 1.106 + } 1.107 + // Some HDDs are including product ID info in the vendor field. Since PNP 1.108 + // IDs include vendor info and product ID concatenated together, we'll do 1.109 + // that here and interpret the result as a unique ID for the HDD model. 1.110 + if (deviceOutput->VendorIdOffset) { 1.111 + aModel = reinterpret_cast<char*>(deviceOutput) + 1.112 + deviceOutput->VendorIdOffset; 1.113 + } 1.114 + if (deviceOutput->ProductIdOffset) { 1.115 + aModel += reinterpret_cast<char*>(deviceOutput) + 1.116 + deviceOutput->ProductIdOffset; 1.117 + } 1.118 + aModel.CompressWhitespace(); 1.119 + if (deviceOutput->ProductRevisionOffset) { 1.120 + aRevision = reinterpret_cast<char*>(deviceOutput) + 1.121 + deviceOutput->ProductRevisionOffset; 1.122 + aRevision.CompressWhitespace(); 1.123 + } 1.124 + free(deviceOutput); 1.125 + return NS_OK; 1.126 +} 1.127 +} // anonymous namespace 1.128 +#endif // defined(XP_WIN) 1.129 + 1.130 +using namespace mozilla; 1.131 + 1.132 +nsSystemInfo::nsSystemInfo() 1.133 +{ 1.134 +} 1.135 + 1.136 +nsSystemInfo::~nsSystemInfo() 1.137 +{ 1.138 +} 1.139 + 1.140 +// CPU-specific information. 1.141 +static const struct PropItems { 1.142 + const char *name; 1.143 + bool (*propfun)(void); 1.144 +} cpuPropItems[] = { 1.145 + // x86-specific bits. 1.146 + { "hasMMX", mozilla::supports_mmx }, 1.147 + { "hasSSE", mozilla::supports_sse }, 1.148 + { "hasSSE2", mozilla::supports_sse2 }, 1.149 + { "hasSSE3", mozilla::supports_sse3 }, 1.150 + { "hasSSSE3", mozilla::supports_ssse3 }, 1.151 + { "hasSSE4A", mozilla::supports_sse4a }, 1.152 + { "hasSSE4_1", mozilla::supports_sse4_1 }, 1.153 + { "hasSSE4_2", mozilla::supports_sse4_2 }, 1.154 + // ARM-specific bits. 1.155 + { "hasEDSP", mozilla::supports_edsp }, 1.156 + { "hasARMv6", mozilla::supports_armv6 }, 1.157 + { "hasARMv7", mozilla::supports_armv7 }, 1.158 + { "hasNEON", mozilla::supports_neon } 1.159 +}; 1.160 + 1.161 +nsresult 1.162 +nsSystemInfo::Init() 1.163 +{ 1.164 + nsresult rv; 1.165 + 1.166 + static const struct { 1.167 + PRSysInfo cmd; 1.168 + const char *name; 1.169 + } items[] = { 1.170 + { PR_SI_SYSNAME, "name" }, 1.171 + { PR_SI_HOSTNAME, "host" }, 1.172 + { PR_SI_ARCHITECTURE, "arch" }, 1.173 + { PR_SI_RELEASE, "version" } 1.174 + }; 1.175 + 1.176 + for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) { 1.177 + char buf[SYS_INFO_BUFFER_LENGTH]; 1.178 + if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) { 1.179 + rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name), 1.180 + nsDependentCString(buf)); 1.181 + if (NS_WARN_IF(NS_FAILED(rv))) 1.182 + return rv; 1.183 + } 1.184 + else { 1.185 + NS_WARNING("PR_GetSystemInfo failed"); 1.186 + } 1.187 + } 1.188 + 1.189 +#if defined(XP_WIN) && defined(MOZ_METRO) 1.190 + // Create "hasWindowsTouchInterface" property. 1.191 + nsAutoString version; 1.192 + rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), version); 1.193 + NS_ENSURE_SUCCESS(rv, rv); 1.194 + double versionDouble = version.ToDouble(&rv); 1.195 + NS_ENSURE_SUCCESS(rv, rv); 1.196 + 1.197 + rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), 1.198 + versionDouble >= 6.2); 1.199 + NS_ENSURE_SUCCESS(rv, rv); 1.200 +#else 1.201 + rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), false); 1.202 + NS_ENSURE_SUCCESS(rv, rv); 1.203 +#endif 1.204 + 1.205 + // Additional informations not available through PR_GetSystemInfo. 1.206 + SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize()); 1.207 + SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift()); 1.208 + SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment()); 1.209 + SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); 1.210 + SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize()); 1.211 + SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask); 1.212 + 1.213 + for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) { 1.214 + rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name), 1.215 + cpuPropItems[i].propfun()); 1.216 + if (NS_WARN_IF(NS_FAILED(rv))) 1.217 + return rv; 1.218 + } 1.219 + 1.220 +#ifdef XP_WIN 1.221 + BOOL isWow64; 1.222 + BOOL gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64); 1.223 + NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed"); 1.224 + if (gotWow64Value) { 1.225 + rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64); 1.226 + if (NS_WARN_IF(NS_FAILED(rv))) 1.227 + return rv; 1.228 + } 1.229 + nsAutoCString hddModel, hddRevision; 1.230 + if (NS_SUCCEEDED(GetHDDInfo(NS_APP_USER_PROFILE_50_DIR, hddModel, 1.231 + hddRevision))) { 1.232 + rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDModel"), hddModel); 1.233 + NS_ENSURE_SUCCESS(rv, rv); 1.234 + rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDRevision"), 1.235 + hddRevision); 1.236 + NS_ENSURE_SUCCESS(rv, rv); 1.237 + } 1.238 + if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR, hddModel, hddRevision))) { 1.239 + rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel); 1.240 + NS_ENSURE_SUCCESS(rv, rv); 1.241 + rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"), 1.242 + hddRevision); 1.243 + NS_ENSURE_SUCCESS(rv, rv); 1.244 + } 1.245 + if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR, hddModel, hddRevision))) { 1.246 + rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel); 1.247 + NS_ENSURE_SUCCESS(rv, rv); 1.248 + rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"), 1.249 + hddRevision); 1.250 + NS_ENSURE_SUCCESS(rv, rv); 1.251 + } 1.252 +#endif 1.253 + 1.254 +#if defined(MOZ_WIDGET_GTK) 1.255 + // This must be done here because NSPR can only separate OS's when compiled, not libraries. 1.256 + char* gtkver = PR_smprintf("GTK %u.%u.%u", gtk_major_version, gtk_minor_version, gtk_micro_version); 1.257 + if (gtkver) { 1.258 + rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), 1.259 + nsDependentCString(gtkver)); 1.260 + PR_smprintf_free(gtkver); 1.261 + if (NS_WARN_IF(NS_FAILED(rv))) 1.262 + return rv; 1.263 + } 1.264 +#endif 1.265 + 1.266 +#ifdef MOZ_WIDGET_ANDROID 1.267 + if (mozilla::AndroidBridge::Bridge()) { 1.268 + nsAutoString str; 1.269 + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", str)) 1.270 + SetPropertyAsAString(NS_LITERAL_STRING("device"), str); 1.271 + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", str)) 1.272 + SetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), str); 1.273 + if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", str)) 1.274 + SetPropertyAsAString(NS_LITERAL_STRING("release_version"), str); 1.275 + int32_t version; 1.276 + if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &version)) 1.277 + version = 0; 1.278 + android_sdk_version = version; 1.279 + if (version >= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str)) 1.280 + SetPropertyAsAString(NS_LITERAL_STRING("hardware"), str); 1.281 + bool isTablet = mozilla::widget::android::GeckoAppShell::IsTablet(); 1.282 + SetPropertyAsBool(NS_LITERAL_STRING("tablet"), isTablet); 1.283 + // NSPR "version" is the kernel version. For Android we want the Android version. 1.284 + // Rename SDK version to version and put the kernel version into kernel_version. 1.285 + rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str); 1.286 + if (NS_SUCCEEDED(rv)) { 1.287 + SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str); 1.288 + } 1.289 + SetPropertyAsInt32(NS_LITERAL_STRING("version"), android_sdk_version); 1.290 + } 1.291 +#endif 1.292 + 1.293 +#ifdef MOZ_WIDGET_GONK 1.294 + char sdk[PROP_VALUE_MAX], characteristics[PROP_VALUE_MAX]; 1.295 + if (__system_property_get("ro.build.version.sdk", sdk)) 1.296 + android_sdk_version = atoi(sdk); 1.297 + if (__system_property_get("ro.build.characteristics", characteristics)) { 1.298 + if (!strcmp(characteristics, "tablet")) 1.299 + SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true); 1.300 + } 1.301 +#endif 1.302 + 1.303 + return NS_OK; 1.304 +} 1.305 + 1.306 +void 1.307 +nsSystemInfo::SetInt32Property(const nsAString &aPropertyName, 1.308 + const int32_t aValue) 1.309 +{ 1.310 + NS_WARN_IF_FALSE(aValue > 0, "Unable to read system value"); 1.311 + if (aValue > 0) { 1.312 +#ifdef DEBUG 1.313 + nsresult rv = 1.314 +#endif 1.315 + SetPropertyAsInt32(aPropertyName, aValue); 1.316 + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property"); 1.317 + } 1.318 +} 1.319 + 1.320 +void 1.321 +nsSystemInfo::SetUint32Property(const nsAString &aPropertyName, 1.322 + const uint32_t aValue) 1.323 +{ 1.324 + // Only one property is currently set via this function. 1.325 + // It may legitimately be zero. 1.326 +#ifdef DEBUG 1.327 + nsresult rv = 1.328 +#endif 1.329 + SetPropertyAsUint32(aPropertyName, aValue); 1.330 + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property"); 1.331 +} 1.332 + 1.333 +void 1.334 +nsSystemInfo::SetUint64Property(const nsAString &aPropertyName, 1.335 + const uint64_t aValue) 1.336 +{ 1.337 + NS_WARN_IF_FALSE(aValue > 0, "Unable to read system value"); 1.338 + if (aValue > 0) { 1.339 +#ifdef DEBUG 1.340 + nsresult rv = 1.341 +#endif 1.342 + SetPropertyAsUint64(aPropertyName, aValue); 1.343 + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property"); 1.344 + } 1.345 +}