xpcom/base/nsSystemInfo.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7
michael@0 8 #include "nsSystemInfo.h"
michael@0 9 #include "prsystem.h"
michael@0 10 #include "prio.h"
michael@0 11 #include "prprf.h"
michael@0 12 #include "mozilla/SSE.h"
michael@0 13 #include "mozilla/arm.h"
michael@0 14
michael@0 15 #ifdef XP_WIN
michael@0 16 #include <windows.h>
michael@0 17 #include <winioctl.h>
michael@0 18 #include "base/scoped_handle_win.h"
michael@0 19 #include "nsAppDirectoryServiceDefs.h"
michael@0 20 #include "nsDirectoryServiceDefs.h"
michael@0 21 #include "nsDirectoryServiceUtils.h"
michael@0 22 #endif
michael@0 23
michael@0 24 #ifdef MOZ_WIDGET_GTK
michael@0 25 #include <gtk/gtk.h>
michael@0 26 #endif
michael@0 27
michael@0 28 #ifdef MOZ_WIDGET_ANDROID
michael@0 29 #include "AndroidBridge.h"
michael@0 30 using namespace mozilla::widget::android;
michael@0 31 #endif
michael@0 32
michael@0 33 #ifdef MOZ_WIDGET_GONK
michael@0 34 #include <sys/system_properties.h>
michael@0 35 #endif
michael@0 36
michael@0 37 #ifdef ANDROID
michael@0 38 extern "C" {
michael@0 39 NS_EXPORT int android_sdk_version;
michael@0 40 }
michael@0 41 #endif
michael@0 42
michael@0 43 // Slot for NS_InitXPCOM2 to pass information to nsSystemInfo::Init.
michael@0 44 // Only set to nonzero (potentially) if XP_UNIX. On such systems, the
michael@0 45 // system call to discover the appropriate value is not thread-safe,
michael@0 46 // so we must call it before going multithreaded, but nsSystemInfo::Init
michael@0 47 // only happens well after that point.
michael@0 48 uint32_t nsSystemInfo::gUserUmask = 0;
michael@0 49
michael@0 50 #if defined(XP_WIN)
michael@0 51 namespace {
michael@0 52 nsresult GetHDDInfo(const char* aSpecialDirName, nsAutoCString& aModel,
michael@0 53 nsAutoCString& aRevision)
michael@0 54 {
michael@0 55 aModel.Truncate();
michael@0 56 aRevision.Truncate();
michael@0 57
michael@0 58 nsCOMPtr<nsIFile> profDir;
michael@0 59 nsresult rv = NS_GetSpecialDirectory(aSpecialDirName,
michael@0 60 getter_AddRefs(profDir));
michael@0 61 NS_ENSURE_SUCCESS(rv, rv);
michael@0 62 nsAutoString profDirPath;
michael@0 63 rv = profDir->GetPath(profDirPath);
michael@0 64 NS_ENSURE_SUCCESS(rv, rv);
michael@0 65 wchar_t volumeMountPoint[MAX_PATH] = {L'\\', L'\\', L'.', L'\\'};
michael@0 66 const size_t PREFIX_LEN = 4;
michael@0 67 if (!::GetVolumePathNameW(profDirPath.get(), volumeMountPoint + PREFIX_LEN,
michael@0 68 mozilla::ArrayLength(volumeMountPoint) -
michael@0 69 PREFIX_LEN)) {
michael@0 70 return NS_ERROR_UNEXPECTED;
michael@0 71 }
michael@0 72 size_t volumeMountPointLen = wcslen(volumeMountPoint);
michael@0 73 // Since we would like to open a drive and not a directory, we need to
michael@0 74 // remove any trailing backslash. A drive handle is valid for
michael@0 75 // DeviceIoControl calls, a directory handle is not.
michael@0 76 if (volumeMountPoint[volumeMountPointLen - 1] == L'\\') {
michael@0 77 volumeMountPoint[volumeMountPointLen - 1] = L'\0';
michael@0 78 }
michael@0 79 ScopedHandle handle(::CreateFileW(volumeMountPoint, 0,
michael@0 80 FILE_SHARE_READ | FILE_SHARE_WRITE,
michael@0 81 nullptr, OPEN_EXISTING, 0, nullptr));
michael@0 82 if (!handle.IsValid()) {
michael@0 83 return NS_ERROR_UNEXPECTED;
michael@0 84 }
michael@0 85 STORAGE_PROPERTY_QUERY queryParameters = {StorageDeviceProperty,
michael@0 86 PropertyStandardQuery};
michael@0 87 STORAGE_DEVICE_DESCRIPTOR outputHeader = {sizeof(STORAGE_DEVICE_DESCRIPTOR)};
michael@0 88 DWORD bytesRead = 0;
michael@0 89 if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY,
michael@0 90 &queryParameters, sizeof(queryParameters),
michael@0 91 &outputHeader, sizeof(outputHeader), &bytesRead,
michael@0 92 nullptr)) {
michael@0 93 return NS_ERROR_FAILURE;
michael@0 94 }
michael@0 95 PSTORAGE_DEVICE_DESCRIPTOR deviceOutput =
michael@0 96 (PSTORAGE_DEVICE_DESCRIPTOR)malloc(outputHeader.Size);
michael@0 97 if (!::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY,
michael@0 98 &queryParameters, sizeof(queryParameters),
michael@0 99 deviceOutput, outputHeader.Size, &bytesRead,
michael@0 100 nullptr)) {
michael@0 101 free(deviceOutput);
michael@0 102 return NS_ERROR_FAILURE;
michael@0 103 }
michael@0 104 // Some HDDs are including product ID info in the vendor field. Since PNP
michael@0 105 // IDs include vendor info and product ID concatenated together, we'll do
michael@0 106 // that here and interpret the result as a unique ID for the HDD model.
michael@0 107 if (deviceOutput->VendorIdOffset) {
michael@0 108 aModel = reinterpret_cast<char*>(deviceOutput) +
michael@0 109 deviceOutput->VendorIdOffset;
michael@0 110 }
michael@0 111 if (deviceOutput->ProductIdOffset) {
michael@0 112 aModel += reinterpret_cast<char*>(deviceOutput) +
michael@0 113 deviceOutput->ProductIdOffset;
michael@0 114 }
michael@0 115 aModel.CompressWhitespace();
michael@0 116 if (deviceOutput->ProductRevisionOffset) {
michael@0 117 aRevision = reinterpret_cast<char*>(deviceOutput) +
michael@0 118 deviceOutput->ProductRevisionOffset;
michael@0 119 aRevision.CompressWhitespace();
michael@0 120 }
michael@0 121 free(deviceOutput);
michael@0 122 return NS_OK;
michael@0 123 }
michael@0 124 } // anonymous namespace
michael@0 125 #endif // defined(XP_WIN)
michael@0 126
michael@0 127 using namespace mozilla;
michael@0 128
michael@0 129 nsSystemInfo::nsSystemInfo()
michael@0 130 {
michael@0 131 }
michael@0 132
michael@0 133 nsSystemInfo::~nsSystemInfo()
michael@0 134 {
michael@0 135 }
michael@0 136
michael@0 137 // CPU-specific information.
michael@0 138 static const struct PropItems {
michael@0 139 const char *name;
michael@0 140 bool (*propfun)(void);
michael@0 141 } cpuPropItems[] = {
michael@0 142 // x86-specific bits.
michael@0 143 { "hasMMX", mozilla::supports_mmx },
michael@0 144 { "hasSSE", mozilla::supports_sse },
michael@0 145 { "hasSSE2", mozilla::supports_sse2 },
michael@0 146 { "hasSSE3", mozilla::supports_sse3 },
michael@0 147 { "hasSSSE3", mozilla::supports_ssse3 },
michael@0 148 { "hasSSE4A", mozilla::supports_sse4a },
michael@0 149 { "hasSSE4_1", mozilla::supports_sse4_1 },
michael@0 150 { "hasSSE4_2", mozilla::supports_sse4_2 },
michael@0 151 // ARM-specific bits.
michael@0 152 { "hasEDSP", mozilla::supports_edsp },
michael@0 153 { "hasARMv6", mozilla::supports_armv6 },
michael@0 154 { "hasARMv7", mozilla::supports_armv7 },
michael@0 155 { "hasNEON", mozilla::supports_neon }
michael@0 156 };
michael@0 157
michael@0 158 nsresult
michael@0 159 nsSystemInfo::Init()
michael@0 160 {
michael@0 161 nsresult rv;
michael@0 162
michael@0 163 static const struct {
michael@0 164 PRSysInfo cmd;
michael@0 165 const char *name;
michael@0 166 } items[] = {
michael@0 167 { PR_SI_SYSNAME, "name" },
michael@0 168 { PR_SI_HOSTNAME, "host" },
michael@0 169 { PR_SI_ARCHITECTURE, "arch" },
michael@0 170 { PR_SI_RELEASE, "version" }
michael@0 171 };
michael@0 172
michael@0 173 for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) {
michael@0 174 char buf[SYS_INFO_BUFFER_LENGTH];
michael@0 175 if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) {
michael@0 176 rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name),
michael@0 177 nsDependentCString(buf));
michael@0 178 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 179 return rv;
michael@0 180 }
michael@0 181 else {
michael@0 182 NS_WARNING("PR_GetSystemInfo failed");
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 #if defined(XP_WIN) && defined(MOZ_METRO)
michael@0 187 // Create "hasWindowsTouchInterface" property.
michael@0 188 nsAutoString version;
michael@0 189 rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), version);
michael@0 190 NS_ENSURE_SUCCESS(rv, rv);
michael@0 191 double versionDouble = version.ToDouble(&rv);
michael@0 192 NS_ENSURE_SUCCESS(rv, rv);
michael@0 193
michael@0 194 rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"),
michael@0 195 versionDouble >= 6.2);
michael@0 196 NS_ENSURE_SUCCESS(rv, rv);
michael@0 197 #else
michael@0 198 rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), false);
michael@0 199 NS_ENSURE_SUCCESS(rv, rv);
michael@0 200 #endif
michael@0 201
michael@0 202 // Additional informations not available through PR_GetSystemInfo.
michael@0 203 SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize());
michael@0 204 SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift());
michael@0 205 SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment());
michael@0 206 SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
michael@0 207 SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize());
michael@0 208 SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask);
michael@0 209
michael@0 210 for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) {
michael@0 211 rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name),
michael@0 212 cpuPropItems[i].propfun());
michael@0 213 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 214 return rv;
michael@0 215 }
michael@0 216
michael@0 217 #ifdef XP_WIN
michael@0 218 BOOL isWow64;
michael@0 219 BOOL gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64);
michael@0 220 NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed");
michael@0 221 if (gotWow64Value) {
michael@0 222 rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64);
michael@0 223 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 224 return rv;
michael@0 225 }
michael@0 226 nsAutoCString hddModel, hddRevision;
michael@0 227 if (NS_SUCCEEDED(GetHDDInfo(NS_APP_USER_PROFILE_50_DIR, hddModel,
michael@0 228 hddRevision))) {
michael@0 229 rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDModel"), hddModel);
michael@0 230 NS_ENSURE_SUCCESS(rv, rv);
michael@0 231 rv = SetPropertyAsACString(NS_LITERAL_STRING("profileHDDRevision"),
michael@0 232 hddRevision);
michael@0 233 NS_ENSURE_SUCCESS(rv, rv);
michael@0 234 }
michael@0 235 if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR, hddModel, hddRevision))) {
michael@0 236 rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel);
michael@0 237 NS_ENSURE_SUCCESS(rv, rv);
michael@0 238 rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"),
michael@0 239 hddRevision);
michael@0 240 NS_ENSURE_SUCCESS(rv, rv);
michael@0 241 }
michael@0 242 if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR, hddModel, hddRevision))) {
michael@0 243 rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel);
michael@0 244 NS_ENSURE_SUCCESS(rv, rv);
michael@0 245 rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"),
michael@0 246 hddRevision);
michael@0 247 NS_ENSURE_SUCCESS(rv, rv);
michael@0 248 }
michael@0 249 #endif
michael@0 250
michael@0 251 #if defined(MOZ_WIDGET_GTK)
michael@0 252 // This must be done here because NSPR can only separate OS's when compiled, not libraries.
michael@0 253 char* gtkver = PR_smprintf("GTK %u.%u.%u", gtk_major_version, gtk_minor_version, gtk_micro_version);
michael@0 254 if (gtkver) {
michael@0 255 rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"),
michael@0 256 nsDependentCString(gtkver));
michael@0 257 PR_smprintf_free(gtkver);
michael@0 258 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 259 return rv;
michael@0 260 }
michael@0 261 #endif
michael@0 262
michael@0 263 #ifdef MOZ_WIDGET_ANDROID
michael@0 264 if (mozilla::AndroidBridge::Bridge()) {
michael@0 265 nsAutoString str;
michael@0 266 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", str))
michael@0 267 SetPropertyAsAString(NS_LITERAL_STRING("device"), str);
michael@0 268 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", str))
michael@0 269 SetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), str);
michael@0 270 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", str))
michael@0 271 SetPropertyAsAString(NS_LITERAL_STRING("release_version"), str);
michael@0 272 int32_t version;
michael@0 273 if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &version))
michael@0 274 version = 0;
michael@0 275 android_sdk_version = version;
michael@0 276 if (version >= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str))
michael@0 277 SetPropertyAsAString(NS_LITERAL_STRING("hardware"), str);
michael@0 278 bool isTablet = mozilla::widget::android::GeckoAppShell::IsTablet();
michael@0 279 SetPropertyAsBool(NS_LITERAL_STRING("tablet"), isTablet);
michael@0 280 // NSPR "version" is the kernel version. For Android we want the Android version.
michael@0 281 // Rename SDK version to version and put the kernel version into kernel_version.
michael@0 282 rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str);
michael@0 283 if (NS_SUCCEEDED(rv)) {
michael@0 284 SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str);
michael@0 285 }
michael@0 286 SetPropertyAsInt32(NS_LITERAL_STRING("version"), android_sdk_version);
michael@0 287 }
michael@0 288 #endif
michael@0 289
michael@0 290 #ifdef MOZ_WIDGET_GONK
michael@0 291 char sdk[PROP_VALUE_MAX], characteristics[PROP_VALUE_MAX];
michael@0 292 if (__system_property_get("ro.build.version.sdk", sdk))
michael@0 293 android_sdk_version = atoi(sdk);
michael@0 294 if (__system_property_get("ro.build.characteristics", characteristics)) {
michael@0 295 if (!strcmp(characteristics, "tablet"))
michael@0 296 SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true);
michael@0 297 }
michael@0 298 #endif
michael@0 299
michael@0 300 return NS_OK;
michael@0 301 }
michael@0 302
michael@0 303 void
michael@0 304 nsSystemInfo::SetInt32Property(const nsAString &aPropertyName,
michael@0 305 const int32_t aValue)
michael@0 306 {
michael@0 307 NS_WARN_IF_FALSE(aValue > 0, "Unable to read system value");
michael@0 308 if (aValue > 0) {
michael@0 309 #ifdef DEBUG
michael@0 310 nsresult rv =
michael@0 311 #endif
michael@0 312 SetPropertyAsInt32(aPropertyName, aValue);
michael@0 313 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property");
michael@0 314 }
michael@0 315 }
michael@0 316
michael@0 317 void
michael@0 318 nsSystemInfo::SetUint32Property(const nsAString &aPropertyName,
michael@0 319 const uint32_t aValue)
michael@0 320 {
michael@0 321 // Only one property is currently set via this function.
michael@0 322 // It may legitimately be zero.
michael@0 323 #ifdef DEBUG
michael@0 324 nsresult rv =
michael@0 325 #endif
michael@0 326 SetPropertyAsUint32(aPropertyName, aValue);
michael@0 327 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property");
michael@0 328 }
michael@0 329
michael@0 330 void
michael@0 331 nsSystemInfo::SetUint64Property(const nsAString &aPropertyName,
michael@0 332 const uint64_t aValue)
michael@0 333 {
michael@0 334 NS_WARN_IF_FALSE(aValue > 0, "Unable to read system value");
michael@0 335 if (aValue > 0) {
michael@0 336 #ifdef DEBUG
michael@0 337 nsresult rv =
michael@0 338 #endif
michael@0 339 SetPropertyAsUint64(aPropertyName, aValue);
michael@0 340 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to set property");
michael@0 341 }
michael@0 342 }

mercurial