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/. */
6 #include "mozilla/ArrayUtils.h"
8 #include "nsSystemInfo.h"
12 #include "mozilla/SSE.h"
13 #include "mozilla/arm.h"
18 #include "base/scoped_handle_win.h"
19 #include "nsAppDirectoryServiceDefs.h"
20 #include "nsDirectoryServiceDefs.h"
21 #include "nsDirectoryServiceUtils.h"
28 #ifdef MOZ_WIDGET_ANDROID
29 #include "AndroidBridge.h"
30 using namespace mozilla::widget::android
;
33 #ifdef MOZ_WIDGET_GONK
34 #include <sys/system_properties.h>
39 NS_EXPORT
int android_sdk_version
;
45 nsresult
GetHDDInfo(const char* aSpecialDirName
, nsAutoCString
& aModel
,
46 nsAutoCString
& aRevision
)
51 nsCOMPtr
<nsIFile
> profDir
;
52 nsresult rv
= NS_GetSpecialDirectory(aSpecialDirName
,
53 getter_AddRefs(profDir
));
54 NS_ENSURE_SUCCESS(rv
, rv
);
55 nsAutoString profDirPath
;
56 rv
= profDir
->GetPath(profDirPath
);
57 NS_ENSURE_SUCCESS(rv
, rv
);
58 wchar_t volumeMountPoint
[MAX_PATH
] = {L
'\\', L
'\\', L
'.', L
'\\'};
59 const size_t PREFIX_LEN
= 4;
60 if (!::GetVolumePathNameW(profDirPath
.get(), volumeMountPoint
+ PREFIX_LEN
,
61 mozilla::ArrayLength(volumeMountPoint
) -
63 return NS_ERROR_UNEXPECTED
;
65 size_t volumeMountPointLen
= wcslen(volumeMountPoint
);
66 // Since we would like to open a drive and not a directory, we need to
67 // remove any trailing backslash. A drive handle is valid for
68 // DeviceIoControl calls, a directory handle is not.
69 if (volumeMountPoint
[volumeMountPointLen
- 1] == L
'\\') {
70 volumeMountPoint
[volumeMountPointLen
- 1] = L
'\0';
72 ScopedHandle
handle(::CreateFileW(volumeMountPoint
, 0,
73 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
74 nullptr, OPEN_EXISTING
, 0, nullptr));
75 if (!handle
.IsValid()) {
76 return NS_ERROR_UNEXPECTED
;
78 STORAGE_PROPERTY_QUERY queryParameters
= {StorageDeviceProperty
,
79 PropertyStandardQuery
};
80 STORAGE_DEVICE_DESCRIPTOR outputHeader
= {sizeof(STORAGE_DEVICE_DESCRIPTOR
)};
82 if (!::DeviceIoControl(handle
, IOCTL_STORAGE_QUERY_PROPERTY
,
83 &queryParameters
, sizeof(queryParameters
),
84 &outputHeader
, sizeof(outputHeader
), &bytesRead
,
86 return NS_ERROR_FAILURE
;
88 PSTORAGE_DEVICE_DESCRIPTOR deviceOutput
=
89 (PSTORAGE_DEVICE_DESCRIPTOR
)malloc(outputHeader
.Size
);
90 if (!::DeviceIoControl(handle
, IOCTL_STORAGE_QUERY_PROPERTY
,
91 &queryParameters
, sizeof(queryParameters
),
92 deviceOutput
, outputHeader
.Size
, &bytesRead
,
95 return NS_ERROR_FAILURE
;
97 // Some HDDs are including product ID info in the vendor field. Since PNP
98 // IDs include vendor info and product ID concatenated together, we'll do
99 // that here and interpret the result as a unique ID for the HDD model.
100 if (deviceOutput
->VendorIdOffset
) {
101 aModel
= reinterpret_cast<char*>(deviceOutput
) +
102 deviceOutput
->VendorIdOffset
;
104 if (deviceOutput
->ProductIdOffset
) {
105 aModel
+= reinterpret_cast<char*>(deviceOutput
) +
106 deviceOutput
->ProductIdOffset
;
108 aModel
.CompressWhitespace();
109 if (deviceOutput
->ProductRevisionOffset
) {
110 aRevision
= reinterpret_cast<char*>(deviceOutput
) +
111 deviceOutput
->ProductRevisionOffset
;
112 aRevision
.CompressWhitespace();
117 } // anonymous namespace
118 #endif // defined(XP_WIN)
120 using namespace mozilla
;
122 nsSystemInfo::nsSystemInfo()
126 nsSystemInfo::~nsSystemInfo()
130 // CPU-specific information.
131 static const struct PropItems
{
133 bool (*propfun
)(void);
135 // x86-specific bits.
136 { "hasMMX", mozilla::supports_mmx
},
137 { "hasSSE", mozilla::supports_sse
},
138 { "hasSSE2", mozilla::supports_sse2
},
139 { "hasSSE3", mozilla::supports_sse3
},
140 { "hasSSSE3", mozilla::supports_ssse3
},
141 { "hasSSE4A", mozilla::supports_sse4a
},
142 { "hasSSE4_1", mozilla::supports_sse4_1
},
143 { "hasSSE4_2", mozilla::supports_sse4_2
},
144 // ARM-specific bits.
145 { "hasEDSP", mozilla::supports_edsp
},
146 { "hasARMv6", mozilla::supports_armv6
},
147 { "hasARMv7", mozilla::supports_armv7
},
148 { "hasNEON", mozilla::supports_neon
}
156 static const struct {
160 { PR_SI_SYSNAME
, "name" },
161 { PR_SI_HOSTNAME
, "host" },
162 { PR_SI_ARCHITECTURE
, "arch" },
163 { PR_SI_RELEASE
, "version" }
166 for (uint32_t i
= 0; i
< (sizeof(items
) / sizeof(items
[0])); i
++) {
167 char buf
[SYS_INFO_BUFFER_LENGTH
];
168 if (PR_GetSystemInfo(items
[i
].cmd
, buf
, sizeof(buf
)) == PR_SUCCESS
) {
169 rv
= SetPropertyAsACString(NS_ConvertASCIItoUTF16(items
[i
].name
),
170 nsDependentCString(buf
));
171 if (NS_WARN_IF(NS_FAILED(rv
)))
175 NS_WARNING("PR_GetSystemInfo failed");
179 #if defined(XP_WIN) && defined(MOZ_METRO)
180 // Create "hasWindowsTouchInterface" property.
181 nsAutoString version
;
182 rv
= GetPropertyAsAString(NS_LITERAL_STRING("version"), version
);
183 NS_ENSURE_SUCCESS(rv
, rv
);
184 double versionDouble
= version
.ToDouble(&rv
);
185 NS_ENSURE_SUCCESS(rv
, rv
);
187 rv
= SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"),
188 versionDouble
>= 6.2);
189 NS_ENSURE_SUCCESS(rv
, rv
);
191 rv
= SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), false);
192 NS_ENSURE_SUCCESS(rv
, rv
);
195 // Additional informations not available through PR_GetSystemInfo.
196 SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize());
197 SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift());
198 SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment());
199 SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
200 SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize());
202 for (uint32_t i
= 0; i
< ArrayLength(cpuPropItems
); i
++) {
203 rv
= SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems
[i
].name
),
204 cpuPropItems
[i
].propfun());
205 if (NS_WARN_IF(NS_FAILED(rv
)))
211 BOOL gotWow64Value
= IsWow64Process(GetCurrentProcess(), &isWow64
);
212 NS_WARN_IF_FALSE(gotWow64Value
, "IsWow64Process failed");
214 rv
= SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64
);
215 if (NS_WARN_IF(NS_FAILED(rv
)))
218 nsAutoCString hddModel
, hddRevision
;
219 if (NS_SUCCEEDED(GetHDDInfo(NS_APP_USER_PROFILE_50_DIR
, hddModel
,
221 rv
= SetPropertyAsACString(NS_LITERAL_STRING("profileHDDModel"), hddModel
);
222 NS_ENSURE_SUCCESS(rv
, rv
);
223 rv
= SetPropertyAsACString(NS_LITERAL_STRING("profileHDDRevision"),
225 NS_ENSURE_SUCCESS(rv
, rv
);
227 if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR
, hddModel
, hddRevision
))) {
228 rv
= SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel
);
229 NS_ENSURE_SUCCESS(rv
, rv
);
230 rv
= SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"),
232 NS_ENSURE_SUCCESS(rv
, rv
);
234 if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR
, hddModel
, hddRevision
))) {
235 rv
= SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel
);
236 NS_ENSURE_SUCCESS(rv
, rv
);
237 rv
= SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"),
239 NS_ENSURE_SUCCESS(rv
, rv
);
243 #if defined(MOZ_WIDGET_GTK)
244 // This must be done here because NSPR can only separate OS's when compiled, not libraries.
245 char* gtkver
= PR_smprintf("GTK %u.%u.%u", gtk_major_version
, gtk_minor_version
, gtk_micro_version
);
247 rv
= SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"),
248 nsDependentCString(gtkver
));
249 PR_smprintf_free(gtkver
);
250 if (NS_WARN_IF(NS_FAILED(rv
)))
255 #ifdef MOZ_WIDGET_ANDROID
256 if (mozilla::AndroidBridge::Bridge()) {
258 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", str
))
259 SetPropertyAsAString(NS_LITERAL_STRING("device"), str
);
260 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", str
))
261 SetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), str
);
262 if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", str
))
263 SetPropertyAsAString(NS_LITERAL_STRING("release_version"), str
);
265 if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &version
))
267 android_sdk_version
= version
;
268 if (version
>= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str
))
269 SetPropertyAsAString(NS_LITERAL_STRING("hardware"), str
);
270 bool isTablet
= GeckoAppShell::IsTablet();
271 SetPropertyAsBool(NS_LITERAL_STRING("tablet"), isTablet
);
272 // NSPR "version" is the kernel version. For Android we want the Android version.
273 // Rename SDK version to version and put the kernel version into kernel_version.
274 rv
= GetPropertyAsAString(NS_LITERAL_STRING("version"), str
);
275 if (NS_SUCCEEDED(rv
)) {
276 SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str
);
278 SetPropertyAsInt32(NS_LITERAL_STRING("version"), android_sdk_version
);
282 #ifdef MOZ_WIDGET_GONK
283 char sdk
[PROP_VALUE_MAX
], characteristics
[PROP_VALUE_MAX
];
284 if (__system_property_get("ro.build.version.sdk", sdk
))
285 android_sdk_version
= atoi(sdk
);
286 if (__system_property_get("ro.build.characteristics", characteristics
)) {
287 if (!strcmp(characteristics
, "tablet"))
288 SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true);
296 nsSystemInfo::SetInt32Property(const nsAString
&aPropertyName
,
297 const int32_t aValue
)
299 NS_WARN_IF_FALSE(aValue
> 0, "Unable to read system value");
304 SetPropertyAsInt32(aPropertyName
, aValue
);
305 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv
), "Unable to set property");
310 nsSystemInfo::SetUint64Property(const nsAString
&aPropertyName
,
311 const uint64_t aValue
)
313 NS_WARN_IF_FALSE(aValue
> 0, "Unable to read system value");
318 SetPropertyAsUint64(aPropertyName
, aValue
);
319 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv
), "Unable to set property");