LCOV - code coverage report
Current view: top level - xpcom/base - nsSystemInfo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 134 141 95.0 %
Date: 2017-07-14 16:53:18 Functions: 6 8 75.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13