xpcom/base/nsSystemInfo.cpp

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

mercurial