1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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 // This file makes some assumptions about the versions of macOS.
7 // We are assuming that the major, minor and bugfix versions are each less than
9 // There are MOZ_ASSERTs for that.
11 // The formula for the version integer is (major << 16) + (minor << 8) + bugfix.
13 #define MACOS_VERSION_MASK 0x00FFFFFF
14 #define MACOS_MAJOR_VERSION_MASK 0x00FFFFFF
15 #define MACOS_MINOR_VERSION_MASK 0x00FFFFFF
16 #define MACOS_BUGFIX_VERSION_MASK 0x00FFFFFF
17 #define MACOS_VERSION_10_0_HEX 0x000A0000
18 #define MACOS_VERSION_10_9_HEX 0x000A0900
19 #define MACOS_VERSION_10_10_HEX 0x000A0A00
20 #define MACOS_VERSION_10_11_HEX 0x000A0B00
21 #define MACOS_VERSION_10_12_HEX 0x000A0C00
22 #define MACOS_VERSION_10_13_HEX 0x000A0D00
23 #define MACOS_VERSION_10_14_HEX 0x000A0E00
24 #define MACOS_VERSION_10_15_HEX 0x000A0F00
25 #define MACOS_VERSION_10_16_HEX 0x000A1000
26 #define MACOS_VERSION_11_0_HEX 0x000B0000
28 #include "nsCocoaFeatures.h"
29 #include "nsCocoaUtils.h"
31 #include "nsObjCExceptions.h"
33 #import <Cocoa/Cocoa.h>
34 #include <sys/sysctl.h>
36 /*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
38 // This should not be called with unchecked aMajor, which should be >= 10.
39 inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
40 MOZ_ASSERT(aMajor >= 10);
41 return (aMajor << 16) + (aMinor << 8) + aBugFix;
44 int32_t nsCocoaFeatures::ExtractMajorVersion(int32_t aVersion) {
45 MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
46 return (aVersion & 0xFF0000) >> 16;
49 int32_t nsCocoaFeatures::ExtractMinorVersion(int32_t aVersion) {
50 MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
51 return (aVersion & 0xFF00) >> 8;
54 int32_t nsCocoaFeatures::ExtractBugFixVersion(int32_t aVersion) {
55 MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
56 return aVersion & 0xFF;
59 static int intAtStringIndex(NSArray* array, int index) {
60 return [(NSString*)[array objectAtIndex:index] integerValue];
63 void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
64 major = minor = bugfix = 0;
66 NSString* versionString = [[NSDictionary
67 dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
68 objectForKey:@"ProductVersion"];
70 NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist to determine macOS "
74 NSArray* versions = [versionString componentsSeparatedByString:@"."];
75 NSUInteger count = [versions count];
77 major = intAtStringIndex(versions, 0);
79 minor = intAtStringIndex(versions, 1);
81 bugfix = intAtStringIndex(versions, 2);
87 int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
91 NS_ERROR("Couldn't determine macOS version, assuming 10.9");
92 macOSVersion = MACOS_VERSION_10_9_HEX;
93 } else if (aMajor == 10 && aMinor < 9) {
95 NS_ERROR("macOS version too old, assuming 10.9");
96 macOSVersion = MACOS_VERSION_10_9_HEX;
98 MOZ_ASSERT(aMajor >= 10);
99 MOZ_ASSERT(aMajor < 256);
100 MOZ_ASSERT(aMinor >= 0);
101 MOZ_ASSERT(aMinor < 256);
102 MOZ_ASSERT(aBugFix >= 0);
103 MOZ_ASSERT(aBugFix < 256);
104 macOSVersion = AssembleVersion(aMajor, aMinor, aBugFix);
106 MOZ_ASSERT(aMajor == ExtractMajorVersion(macOSVersion));
107 MOZ_ASSERT(aMinor == ExtractMinorVersion(macOSVersion));
108 MOZ_ASSERT(aBugFix == ExtractBugFixVersion(macOSVersion));
112 /*static*/ void nsCocoaFeatures::InitializeVersionNumbers() {
113 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
115 // Provide an autorelease pool to avoid leaking Cocoa objects,
116 // as this gets called before the main autorelease pool is in place.
117 nsAutoreleasePool localPool;
119 int major, minor, bugfix;
120 GetSystemVersion(major, minor, bugfix);
121 mOSVersion = GetVersion(major, minor, bugfix);
123 NS_OBJC_END_TRY_ABORT_BLOCK;
126 /* static */ int32_t nsCocoaFeatures::macOSVersion() {
127 // Don't let this be called while we're first setting the value...
128 MOZ_ASSERT((mOSVersion & MACOS_VERSION_MASK) >= 0);
131 InitializeVersionNumbers();
136 /* static */ int32_t nsCocoaFeatures::macOSVersionMajor() {
137 return ExtractMajorVersion(macOSVersion());
140 /* static */ int32_t nsCocoaFeatures::macOSVersionMinor() {
141 return ExtractMinorVersion(macOSVersion());
144 /* static */ int32_t nsCocoaFeatures::macOSVersionBugFix() {
145 return ExtractBugFixVersion(macOSVersion());
148 /* static */ bool nsCocoaFeatures::OnSierraExactly() {
149 return (macOSVersion() >= MACOS_VERSION_10_12_HEX) && (macOSVersion() < MACOS_VERSION_10_13_HEX);
152 /* Version of OnSierraExactly as global function callable from cairo & skia */
153 bool Gecko_OnSierraExactly() { return nsCocoaFeatures::OnSierraExactly(); }
155 /* static */ bool nsCocoaFeatures::OnHighSierraOrLater() {
156 return (macOSVersion() >= MACOS_VERSION_10_13_HEX);
159 /* static */ bool nsCocoaFeatures::OnMojaveOrLater() {
160 return (macOSVersion() >= MACOS_VERSION_10_14_HEX);
163 /* static */ bool nsCocoaFeatures::OnCatalinaOrLater() {
164 return (macOSVersion() >= MACOS_VERSION_10_15_HEX);
167 /* static */ bool nsCocoaFeatures::OnBigSurOrLater() {
168 // Account for the version being 10.16 (which occurs when the
169 // application is linked with an older SDK) or 11.0 on Big Sur.
170 return ((macOSVersion() >= MACOS_VERSION_10_16_HEX) ||
171 (macOSVersion() >= MACOS_VERSION_11_0_HEX));
174 /* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor,
176 return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
180 * Returns true if the process is running under Rosetta translation. Returns
181 * false if running natively or if an error was encountered. We use the
182 * `sysctl.proc_translated` sysctl which is documented by Apple to be used
183 * for this purpose. Note: using this in a sandboxed process requires allowing
184 * the sysctl in the sandbox policy.
186 /* static */ bool nsCocoaFeatures::ProcessIsRosettaTranslated() {
188 size_t size = sizeof(ret);
189 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
190 if (errno != ENOENT) {
191 fprintf(stderr, "Failed to check for translation environment\n");