xpcom/base/nsSystemInfo.cpp

changeset 0
6474c204b198
     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 +}

mercurial