/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef XP_WIN # include <comutil.h> # include <time.h> # ifndef __MINGW32__ # include <iwscapi.h> # endif // __MINGW32__ # include <windows.h> # include <winioctl.h> # ifndef __MINGW32__ # include <wrl.h> # include <wscapi.h> # endif // __MINGW32__ # include "base/scoped_handle_win.h" # include "mozilla/DynamicallyLinkedFunctionPtr.h" # include "mozilla/WindowsVersion.h" # include "nsAppDirectoryServiceDefs.h" # include "nsDirectoryServiceDefs.h" # include "nsDirectoryServiceUtils.h" # include "nsWindowsHelpers.h" # include "WinUtils.h" # include "mozilla/NotNull.h"
#endif
#ifdef XP_MACOSX # include "MacHelpers.h" #endif
#ifdef MOZ_WIDGET_GTK # include <gtk/gtk.h> # include <dlfcn.h> # include "mozilla/WidgetUtilsGtk.h" #endif
#ifdefined(XP_LINUX) # include <unistd.h> # include <fstream> # include "mozilla/Tokenizer.h" # include "mozilla/widget/LSBUtils.h" # include "nsCharSeparatedTokenizer.h"
# include <map> # include <string> #endif
#ifdef MOZ_WIDGET_ANDROID # include "AndroidBuild.h" # include "mozilla/java/GeckoAppShellWrappers.h" # include "mozilla/jni/Utils.h" #endif
#ifdef XP_MACOSX # include <sys/sysctl.h> #endif
#ifdefined(XP_LINUX) && defined(MOZ_SANDBOX) # include "mozilla/SandboxInfo.h" #endif
// Slot for NS_InitXPCOM to pass information to nsSystemInfo::Init. // Only set to nonzero (potentially) if XP_UNIX. On such systems, the // system call to discover the appropriate value is not thread-safe, // so we must call it before going multithreaded, but nsSystemInfo::Init // only happens well after that point.
uint32_t nsSystemInfo::gUserUmask = 0;
nsCCharSeparatedTokenizer tokens(nsDependentCString(line.c_str()), ':'); if (tokens.hasMoreTokens()) {
key = tokens.nextToken(); if (tokens.hasMoreTokens()) {
value = tokens.nextToken();
} // We want the value even if there was just one token, to cover the // case where we had the key, and the value was blank (seems to be // a valid scenario some files.)
aKeyValuePairs[key] = value;
}
}
} #endif
#ifdef XP_WIN // Lifted from media/webrtc/trunk/webrtc/base/systeminfo.cc, // so keeping the _ instead of switching to camel case for now. staticvoid GetProcessorInformation(int* physical_cpus, int* cache_size_L2, int* cache_size_L3) {
MOZ_ASSERT(physical_cpus && cache_size_L2 && cache_size_L3);
*physical_cpus = 0;
*cache_size_L2 = 0; // This will be in kbytes
*cache_size_L3 = 0; // This will be in kbytes
// Determine buffer size, allocate and get processor information. // Size can change between calls (unlikely), so a loop is done.
SYSTEM_LOGICAL_PROCESSOR_INFORMATION info_buffer[32];
SYSTEM_LOGICAL_PROCESSOR_INFORMATION* infos = &info_buffer[0];
DWORD return_length = sizeof(info_buffer); while (!::GetLogicalProcessorInformation(infos, &return_length)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
infos == &info_buffer[0]) {
infos = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION
[return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)];
} else { return;
}
}
for (size_t i = 0;
i < return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) { if (infos[i].Relationship == RelationProcessorCore) {
++*physical_cpus;
} elseif (infos[i].Relationship == RelationCache) { // Only care about L2 and L3 cache switch (infos[i].Cache.Level) { case 2:
*cache_size_L2 = static_cast<int>(infos[i].Cache.Size / 1024); break; case 3:
*cache_size_L3 = static_cast<int>(infos[i].Cache.Size / 1024); break; default: break;
}
}
} if (infos != &info_buffer[0]) { delete[] infos;
} return;
} #endif
if (isSSD) { // Get Seek Penalty
queryParameters.PropertyId = StorageDeviceSeekPenaltyProperty;
bytesRead = 0;
DEVICE_SEEK_PENALTY_DESCRIPTOR seekPenaltyDescriptor = { sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR)}; if (::DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY,
&queryParameters, sizeof(queryParameters),
&seekPenaltyDescriptor, sizeof(seekPenaltyDescriptor),
&bytesRead, nullptr)) { // It is possible that the disk has TrimEnabled, but also // IncursSeekPenalty; In this case, this is an HDD if (seekPenaltyDescriptor.IncursSeekPenalty) {
isSSD = false;
}
}
}
// Some HDDs are including product ID info in the vendor field. Since PNP // IDs include vendor info and product ID concatenated together, we'll do // that here and interpret the result as a unique ID for the HDD model. if (deviceOutput->VendorIdOffset) {
info.model = reinterpret_cast<char*>(deviceOutput) + deviceOutput->VendorIdOffset;
} if (deviceOutput->ProductIdOffset) {
info.model += reinterpret_cast<char*>(deviceOutput) + deviceOutput->ProductIdOffset;
}
info.model.CompressWhitespace(); if (deviceOutput->ProductRevisionOffset) {
info.revision = reinterpret_cast<char*>(deviceOutput) +
deviceOutput->ProductRevisionOffset;
info.revision.CompressWhitespace();
}
info.isSSD = isSSD;
free(deviceOutput); return NS_OK;
}
// Superfetch was introduced in Windows Vista as a service with the name // SysMain. The service display name was also renamed to SysMain after Windows // 10 build 1809.
nsAutoServiceHandle hService(OpenService(scm, L"SysMain", GENERIC_READ));
if (hService) {
SERVICE_STATUS superfetchStatus;
LPSERVICE_STATUS pSuperfetchStatus = &superfetchStatus;
if (!QueryServiceStatus(hService, pSuperfetchStatus)) { return NS_ERROR_UNEXPECTED;
}
// If the SysMain (Superfetch) service is available, but not configured using // the defaults, then it's disabled for our purposes, since it's not going to // be operating as expected. bool superfetchUsingDefaultParams = true; bool prefetchUsingDefaultParams = true;
// If the EnableSuperfetch registry key doesn't exist, then it's using the // default configuration. if (superfetchParamStatus == ERROR_SUCCESS &&
superfetchValue != SUPERFETCH_DEFAULT_PARAM) {
superfetchUsingDefaultParams = false;
}
DWORD prefetchValue = 0;
LONG prefetchParamStatus = RegQueryValueExW(
prefetchParamsHKey, L"EnablePrefetcher", nullptr, &type, reinterpret_cast<LPBYTE>(&prefetchValue), &valueSize);
// If the EnablePrefetcher registry key doesn't exist, then we interpret // that as the Prefetcher being disabled (since Prefetch behaviour when // the key is not available appears to be undefined). if (prefetchParamStatus != ERROR_SUCCESS ||
prefetchValue != PREFETCH_DEFAULT_PARAM) {
prefetchUsingDefaultParams = false;
}
}
// We only care about products that are active if (state == WSC_SECURITY_PRODUCT_STATE_OFF ||
state == WSC_SECURITY_PRODUCT_STATE_SNOOZED) { continue;
}
// NB: A separate instance of IWSCProductList is needed for each distinct // security provider type; MSDN says that we cannot reuse the same object // and call Initialize() to pave over the previous data.
static nsresult ProcessIsRosettaTranslated(bool& isRosetta) { # ifdefined(__aarch64__) // There is no need to call sysctlbyname() if we are running as arm64.
isRosetta = false; # else int ret = 0;
size_t size = sizeof(ret); if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) { if (errno != ENOENT) {
fprintf(stderr, "Failed to check for translation environment\n");
}
isRosetta = false;
} else {
isRosetta = (ret == 1);
} # endif return NS_OK;
} #endif
nsresult CollectProcessInfo(ProcessInfo& info) {
nsAutoCString cpuVendor;
nsAutoCString cpuName; int cpuSpeed = -1; int cpuFamily = -1; int cpuModel = -1; int cpuStepping = -1; int logicalCPUs = -1; int physicalCPUs = -1; int cacheSizeL2 = -1; int cacheSizeL3 = -1;
#ifdefined(XP_WIN) // IsWow64Process2 is only available on Windows 10+, so we have to dynamically // check for its existence. typedefBOOL(WINAPI * LPFN_IWP2)(HANDLE, USHORT*, USHORT*);
LPFN_IWP2 iwp2 = reinterpret_cast<LPFN_IWP2>(
GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process2")); BOOL isWow64 = FALSE;
USHORT processMachine = IMAGE_FILE_MACHINE_UNKNOWN;
USHORT nativeMachine = IMAGE_FILE_MACHINE_UNKNOWN; BOOL gotWow64Value; if (iwp2) {
gotWow64Value = iwp2(GetCurrentProcess(), &processMachine, &nativeMachine); if (gotWow64Value) {
isWow64 = (processMachine != IMAGE_FILE_MACHINE_UNKNOWN);
}
} else {
gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64); // The function only indicates a WOW64 environment if it's 32-bit x86 // running on x86-64, so emulate what IsWow64Process2 would have given. if (gotWow64Value && isWow64) {
processMachine = IMAGE_FILE_MACHINE_I386;
nativeMachine = IMAGE_FILE_MACHINE_AMD64;
}
}
NS_WARNING_ASSERTION(gotWow64Value, "IsWow64Process failed"); if (gotWow64Value) { // Set this always, even for the x86-on-arm64 case.
info.isWow64 = !!isWow64; // Additional information if we're running x86-on-arm64
info.isWowARM64 = (processMachine == IMAGE_FILE_MACHINE_I386 &&
nativeMachine == IMAGE_FILE_MACHINE_ARM64);
}
// S Mode
# ifndef __MINGW32__ // WindowsIntegrityPolicy is only available on newer versions // of Windows 10, so there's no point in trying to check this // on earlier versions. We know GetActivationFactory crashes on // Windows 7 when trying to retrieve this class, and may also // crash on very old versions of Windows 10. if (IsWin10Sep2018UpdateOrLater()) {
ComPtr<IWindowsIntegrityPolicyStatics> wip;
HRESULT hr = GetActivationFactory(
HStringReference(
RuntimeClass_Windows_System_Profile_WindowsIntegrityPolicy)
.Get(),
&wip); if (SUCCEEDED(hr)) { // info.isWindowsSMode ends up true if Windows is in S mode, otherwise // false // https://docs.microsoft.com/en-us/uwp/api/windows.system.profile.windowsintegritypolicy.isenabled?view=winrt-22000
hr = wip->get_IsEnabled(&info.isWindowsSMode);
NS_WARNING_ASSERTION(SUCCEEDED(hr), "WindowsIntegrityPolicy.IsEnabled failed");
}
} # endif // __MINGW32__
// CPU speed
HKEY key; staticconst WCHAR keyName[] =
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &key) ==
ERROR_SUCCESS) {
DWORD data, len, vtype;
len = sizeof(data);
// Limit to 64 double byte characters, should be plenty, but create // a buffer one larger as the result may not be null terminated. If // it is more than 64, we will not get the value. wchar_t cpuVendorStr[64 + 1];
len = sizeof(cpuVendorStr) - 2; if (RegQueryValueExW(key, L"VendorIdentifier", 0, &vtype, reinterpret_cast<LPBYTE>(cpuVendorStr),
&len) == ERROR_SUCCESS &&
vtype == REG_SZ && len % 2 == 0 && len > 1) {
cpuVendorStr[len / 2] = 0; // In case it isn't null terminated
CopyUTF16toUTF8(nsDependentString(cpuVendorStr), cpuVendor);
}
// Limit to 64 double byte characters, should be plenty, but create // a buffer one larger as the result may not be null terminated. If // it is more than 64, we will not get the value. // The expected string size is 48 characters or less. wchar_t cpuNameStr[64 + 1];
len = sizeof(cpuNameStr) - 2; if (RegQueryValueExW(key, L"ProcessorNameString", 0, &vtype, reinterpret_cast<LPBYTE>(cpuNameStr),
&len) == ERROR_SUCCESS &&
vtype == REG_SZ && len % 2 == 0 && len > 1) {
cpuNameStr[len / 2] = 0; // In case it isn't null terminated
CopyUTF16toUTF8(nsDependentString(cpuNameStr), cpuName);
}
RegCloseKey(key);
}
// Other CPU attributes:
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
logicalCPUs = si.dwNumberOfProcessors;
GetProcessorInformation(&physicalCPUs, &cacheSizeL2, &cacheSizeL3); if (physicalCPUs <= 0) {
physicalCPUs = logicalCPUs;
}
cpuFamily = si.wProcessorLevel;
cpuModel = si.wProcessorRevision >> 8;
cpuStepping = si.wProcessorRevision & 0xFF; #elifdefined(XP_MACOSX) // CPU speed
uint64_t sysctlValue64 = 0;
uint32_t sysctlValue32 = 0;
size_t len = 0;
len = sizeof(sysctlValue64); if (!sysctlbyname("hw.cpufrequency_max", &sysctlValue64, &len, NULL, 0)) {
cpuSpeed = static_cast<int>(sysctlValue64 / 1000000);
}
MOZ_ASSERT(sizeof(sysctlValue64) == len);
len = sizeof(sysctlValue32); if (!sysctlbyname("hw.physicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
physicalCPUs = static_cast<int>(sysctlValue32);
}
MOZ_ASSERT(sizeof(sysctlValue32) == len);
len = sizeof(sysctlValue32); if (!sysctlbyname("hw.logicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
logicalCPUs = static_cast<int>(sysctlValue32);
}
MOZ_ASSERT(sizeof(sysctlValue32) == len);
len = sizeof(sysctlValue64); if (!sysctlbyname("hw.l2cachesize", &sysctlValue64, &len, NULL, 0)) {
cacheSizeL2 = static_cast<int>(sysctlValue64 / 1024);
}
MOZ_ASSERT(sizeof(sysctlValue64) == len);
len = sizeof(sysctlValue64); if (!sysctlbyname("hw.l3cachesize", &sysctlValue64, &len, NULL, 0)) {
cacheSizeL3 = static_cast<int>(sysctlValue64 / 1024);
}
MOZ_ASSERT(sizeof(sysctlValue64) == len);
staticconststruct id_part hisi_part[] = {
{ 0xd01, "TaiShan-v110" }, /* used in Kunpeng-920 SoC */
{ 0xd02, "TaiShan-v120" }, /* used in Kirin 990A and 9000S SoCs */
{ 0xd40, "Cortex-A76" }, /* HiSilicon uses this ID though advertises A76 */
{ 0xd41, "Cortex-A77" }, /* HiSilicon uses this ID though advertises A77 */
{ -1, "unknown" },
};
// cpuFamily from "CPU implementer". Technically, this is only the vendor, // but this is the closed to a family we can get.
(void)Tokenizer(keyValuePairs["CPU implementer"_ns])
.ReadHexadecimal(&cpuFamily);
// cpuModel from "CPU part". Not exactly a model number, but close enough, // and that's what lscpu uses.
(void)Tokenizer(keyValuePairs["CPU part"_ns]).ReadHexadecimal(&cpuModel);
// cpuStepping from "CPU variant" (that's what lscpu uses).
(void)Tokenizer(keyValuePairs["CPU variant"_ns])
.ReadHexadecimal(&cpuStepping);
for (auto& hw_impl : hw_implementer) { if (hw_impl.id == (int)cpuFamily) {
info.cpuVendor.Assign(hw_impl.name); for (auto* p = &hw_impl.parts[0]; p->id != -1; ++p) { if (p->id == (int)cpuModel) {
info.cpuName.Assign(p->name);
}
}
}
} # else // cpuVendor from "vendor_id"
info.cpuVendor.Assign(keyValuePairs["vendor_id"_ns]);
// cpuName from "model name"
info.cpuName.Assign(keyValuePairs["model name"_ns]);
// cpuFamily from "cpu family"
(void)Tokenizer(keyValuePairs["cpu family"_ns]).ReadInteger(&cpuFamily);
// cpuModel from "model"
(void)Tokenizer(keyValuePairs["model"_ns]).ReadInteger(&cpuModel);
// cpuStepping from "stepping"
(void)Tokenizer(keyValuePairs["stepping"_ns]).ReadInteger(&cpuStepping); # endif
}
{ // Get cpuSpeed from another file.
std::ifstream input( "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
std::string line; if (getline(input, line)) {
(void)Tokenizer(line.c_str()).ReadInteger(&cpuSpeed);
cpuSpeed /= 1000;
}
}
{ // Get cacheSizeL2 from yet another file
std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index2/size");
std::string line; if (getline(input, line)) {
(void)Tokenizer(line.c_str(), nullptr, "K").ReadInteger(&cacheSizeL2);
}
}
{ // Get cacheSizeL3 from yet another file
std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index3/size");
std::string line; if (getline(input, line)) {
(void)Tokenizer(line.c_str(), nullptr, "K").ReadInteger(&cacheSizeL3);
}
}
info.cpuCount = PR_GetNumberOfProcessors(); int max_cpu_bits = [&] { // PR_GetNumberOfProcessors gets the value from // /sys/devices/system/cpu/present, but the number of bits in the CPU masks // we're going to read below can be larger (for instance, on the 32-core // 64-threads Threadripper 3970X, PR_GetNumberOfProcessors returns 64, but // the number of bits in the CPU masks is 128). That number of bits is // correlated with the number of CPUs possible (which is different from the // number of CPUs present).
std::ifstream input("/sys/devices/system/cpu/possible");
std::string line; if (getline(input, line)) { int num;
Tokenizer p(line.c_str()); // The expected format is `0-n` where n is the number of CPUs possible // - 1. if (p.ReadInteger(&num) && num == 0 && p.CheckChar('-') &&
p.ReadInteger(&num) && p.CheckEOF()) { return num + 1;
}
} // If we weren't able to get the value from /sys/devices/system/cpu/possible // from some reason, fallback to cpuCount, it might work. return info.cpuCount;
}();
// /proc/cpuinfo doesn't have a cross-architecture way of counting physical // cores. On x86, one could look at the number of unique combinations of // `physical id` and `core id` or `cpu cores`, but those are not present on // e.g. aarch64. (and that might not even be enough for NUMA nodes, but // realistically, there probably aren't a lot of people running this code // on such machines) // As a shortcut on x86, you'd think you could just multiply the last // physical id + 1 with the last core id + 1, but at least core ids are not // even necessarily adjacent. (notably, on 13th or 14th generation Intel // CPUs, they go in increments of 4 for performance cores, and then 1 after // hitting the first efficiency core) // /sys/devices/system/cpu/cpu*/topology/core_cpus does show which logical // cores are associated together, such that running the command: // sort -u /sys/devices/system/cpu/cpu*/topology/core_cpus | wc -l // gives a count of physical cores. // There are cpuCount /sys/devices/system/cpu/cpu* directories, and they // are monotonically increasing. // We're going to kind of do that, but reading the actual bitmasks contained // in those files.
constexpr int mask_bits = sizeof(uint32_t) * 8;
Vector<uint32_t> cpumasks;
physicalCPUs = [&] { int cores = 0; if (!cpumasks.appendN(0, (max_cpu_bits + mask_bits - 1) / mask_bits)) { return -1;
} for (int32_t cpu = 0; cpu < info.cpuCount; ++cpu) {
nsPrintfCString core_cpus( "/sys/devices/system/cpu/cpu%d/topology/core_cpus", cpu);
std::ifstream input(core_cpus.Data()); // Kernel versions before 5.3 didn't have core_cpus, they had // thread_siblings instead, with the same content. As of writing, kernel // version 6.9 still has both, but thread_siblings has been deprecated // since the introduction of core_cpus. if (input.fail()) {
core_cpus.Truncate(core_cpus.Length() - sizeof("core_cpus") + 1);
core_cpus.AppendLiteral("thread_siblings");
input.open(core_cpus.Data());
}
std::string line; if (!getline(input, line)) { return -1;
}
Tokenizer p(line.c_str()); bool unknown_core = false; // The format of the file is `bitmask0,bitmask1,..,bitmaskn` // where each bitmask is 32-bits wide, and there are as many as // necessary to print max_cpu_bits bits. for (auto& mask : cpumasks) {
uint32_t m; if (NS_WARN_IF(!p.ReadHexadecimal(&m, /* aPrefixed = */ false))) { return -1;
} if (!p.CheckEOF() && !p.CheckChar(',')) { return -1;
} // We're keeping track of all the CPU bits we've seen so far. // If we're now seeing one that has never been set, it means // we're seeing a new physical core (as opposed to a logical // core). We don't want to end the loop now, though, because // we also want to track all the bits we're seeing, in case // subsequent masks have new bits as well. if ((mask & m) != m) {
unknown_core = true;
}
mask |= m;
} if (unknown_core) {
cores++;
}
} return cores;
}();
#ifdefined(MOZ_WIDGET_GTK) // This must be done here because NSPR can only separate OS's when compiled, // not libraries. 64 bytes is going to be well enough for "GTK " followed by 3 // integers separated with dots. char gtkver[64];
ssize_t gtkver_len = 0;
# ifndef MOZ_TSAN // With TSan, avoid loading libpulse here because we cannot unload it // afterwards due to restrictions from TSan about unloading libraries // matched by the suppression list. void* libpulse = dlopen("libpulse.so.0", RTLD_LAZY); constchar* libpulseVersion = "not-available"; if (libpulse) { auto pa_get_library_version = reinterpret_cast<constchar* (*)()>(
dlsym(libpulse, "pa_get_library_version"));
if (pa_get_library_version) {
libpulseVersion = pa_get_library_version();
}
}
if (sandInfo.Test(SandboxInfo::kEnabledForContent)) {
SetPropertyAsBool(u"canSandboxContent"_ns, sandInfo.CanSandboxContent());
}
if (sandInfo.Test(SandboxInfo::kEnabledForMedia)) {
SetPropertyAsBool(u"canSandboxMedia"_ns, sandInfo.CanSandboxMedia());
} #endif// XP_LINUX && MOZ_SANDBOX
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID // Prerelease versions of Android use a letter instead of version numbers. // Unfortunately this breaks websites due to the user agent. // Chrome works around this by hardcoding an Android version when a // numeric version can't be obtained. We're doing the same. // This version will need to be updated whenever there is a new official // Android release. Search for "kDefaultAndroidMajorVersion" in: // https://source.chromium.org/chromium/chromium/src/+/master:base/system/sys_info_android.cc # define DEFAULT_ANDROID_VERSION u"10.0.99"
/* static */ void nsSystemInfo::GetAndroidSystemInfo(AndroidSystemInfo* aInfo) { if (!jni::IsAvailable()) { // called from xpcshell etc.
aInfo->sdk_version() = 0; return;
}
jni::String::LocalRef model = java::sdk::Build::MODEL();
aInfo->device() = model->ToString();
void nsSystemInfo::SetupAndroidInfo(const AndroidSystemInfo& aInfo) { if (!aInfo.device().IsEmpty()) {
SetPropertyAsAString(u"device"_ns, aInfo.device());
} if (!aInfo.manufacturer().IsEmpty()) {
SetPropertyAsAString(u"manufacturer"_ns, aInfo.manufacturer());
} if (!aInfo.release_version().IsEmpty()) {
SetPropertyAsAString(u"release_version"_ns, aInfo.release_version());
}
SetPropertyAsBool(u"tablet"_ns, aInfo.isTablet()); // NSPR "version" is the kernel version. For Android we want the Android // version. Rename SDK version to version and put the kernel version into // kernel_version.
nsAutoString str;
nsresult rv = GetPropertyAsAString(u"version"_ns, str); if (NS_SUCCEEDED(rv)) {
SetPropertyAsAString(u"kernel_version"_ns, str);
} // When JNI is not available (eg. in xpcshell tests), sdk_version is 0. if (aInfo.sdk_version() != 0) { if (!aInfo.hardware().IsEmpty()) {
SetPropertyAsAString(u"hardware"_ns, aInfo.hardware());
}
SetPropertyAsInt32(u"version"_ns, aInfo.sdk_version());
}
} #endif// MOZ_WIDGET_ANDROID
void nsSystemInfo::SetInt32Property(const nsAString& aPropertyName, const int32_t aValue) {
NS_WARNING_ASSERTION(aValue > 0, "Unable to read system value"); if (aValue > 0) { #ifdef DEBUG
nsresult rv = #endif
SetPropertyAsInt32(aPropertyName, aValue);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
}
}
void nsSystemInfo::SetUint32Property(const nsAString& aPropertyName, const uint32_t aValue) { // Only one property is currently set via this function. // It may legitimately be zero. #ifdef DEBUG
nsresult rv = #endif
SetPropertyAsUint32(aPropertyName, aValue);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
}
void nsSystemInfo::SetUint64Property(const nsAString& aPropertyName, const uint64_t aValue) {
NS_WARNING_ASSERTION(aValue > 0, "Unable to read system value"); if (aValue > 0) { #ifdef DEBUG
nsresult rv = #endif
SetPropertyAsUint64(aPropertyName, aValue);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Unable to set property");
}
}
// Chain the new promise to the extant mozpromise
RefPtr<Promise> capturedPromise = promise;
mOSInfoPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[capturedPromise](const OSInfo& info) {
AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(capturedPromise->GetGlobalObject()))) {
capturedPromise->MaybeReject(NS_ERROR_UNEXPECTED); return;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> val(
cx, JS::ObjectValue(*GetJSObjForOSInfo(cx, info)));
capturedPromise->MaybeResolve(val);
},
[capturedPromise](const nsresult rv) { // Resolve with null when installYear is not available from the system
capturedPromise->MaybeResolve(JS::NullHandleValue);
});
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.