summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/mac/mac_util.h49
-rw-r--r--base/mac/mac_util.mm126
-rw-r--r--base/mac/mac_util_unittest.mm43
-rw-r--r--base/process_util_mac.mm53
-rw-r--r--base/sys_info.h5
5 files changed, 241 insertions, 35 deletions
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index 808716c..eed516e 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -6,6 +6,7 @@
#define BASE_MAC_MAC_UTIL_H_
#pragma once
+#include <AvailabilityMacros.h>
#include <Carbon/Carbon.h>
#include <string>
@@ -110,6 +111,54 @@ void RemoveFromLoginItems();
// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
bool WasLaunchedAsHiddenLoginItem();
+// Run-time OS version checks. Use these instead of
+// base::SysInfo::OperatingSystemVersionNumbers. Prefer the "OrEarlier" and
+// "OrLater" variants to those that check for a specific version, unless you
+// know for sure that you need to check for a specific version.
+
+// Leopard is Mac OS X 10.5, Darwin 9.
+bool IsOSLeopard();
+bool IsOSLeopardOrEarlier();
+
+// Snow Leopard is Mac OS X 10.6, Darwin 10.
+bool IsOSSnowLeopard();
+bool IsOSSnowLeopardOrEarlier();
+bool IsOSSnowLeopardOrLater();
+
+// Lion is Mac OS X 10.7, Darwin 11.
+bool IsOSLion();
+bool IsOSLionOrLater();
+
+// This should be infrequently used. It only makes sense to use this to avoid
+// codepaths that are very likely to break on future (unreleased, untested,
+// unborn) OS releases.
+bool IsOSLaterThanLion();
+
+// When the deployment target is set, the code produced cannot run on earlier
+// OS releases. That enables some of the IsOS* family to be implemented as
+// constant-value inline functions. The MAC_OS_X_VERSION_MIN_REQUIRED macro
+// contains the value of the deployment target.
+
+#if defined(MAC_OS_X_VERSION_10_6) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_6
+inline bool IsOSLeopardOrEarlier() { return false; }
+inline bool IsOSSnowLeopardOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7
+inline bool IsOSSnowLeopardOrEarlier() { return false; }
+inline bool IsOSLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7
+inline bool IsOSLaterThanLion() { return true; }
+#endif
+
} // namespace mac
} // namespace base
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index 16b3341..5a8cb4e 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -5,12 +5,15 @@
#include "base/mac/mac_util.h"
#import <Cocoa/Cocoa.h>
+#include <string.h>
+#include <sys/utsname.h>
#include "base/file_path.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_nsobject.h"
+#include "base/string_number_conversions.h"
#include "base/sys_string_conversions.h"
namespace base {
@@ -463,5 +466,128 @@ bool WasLaunchedAsHiddenLoginItem() {
return IsHiddenLoginItem(item);
}
+namespace {
+
+// Returns the running system's Darwin major version. Don't call this, it's
+// an implementation detail and its result is meant to be cached by
+// MacOSXMinorVersion.
+int DarwinMajorVersionInternal() {
+ // base::OperatingSystemVersionNumbers calls Gestalt, which is a
+ // higher-level operation than is needed. It might perform unnecessary
+ // operations. On 10.6, it was observed to be able to spawn threads (see
+ // http://crbug.com/53200). It might also read files or perform other
+ // blocking operations. Actually, nobody really knows for sure just what
+ // Gestalt might do, or what it might be taught to do in the future.
+ //
+ // uname, on the other hand, is implemented as a simple series of sysctl
+ // system calls to obtain the relevant data from the kernel. The data is
+ // compiled right into the kernel, so no threads or blocking or other
+ // funny business is necessary.
+
+ struct utsname uname_info;
+ if (uname(&uname_info) != 0) {
+ PLOG(ERROR) << "uname";
+ return 0;
+ }
+
+ if (strcmp(uname_info.sysname, "Darwin") != 0) {
+ LOG(ERROR) << "unexpected uname sysname " << uname_info.sysname;
+ return 0;
+ }
+
+ int darwin_major_version = 0;
+ char* dot = strchr(uname_info.release, '.');
+ if (dot) {
+ if (!base::StringToInt(uname_info.release, dot, &darwin_major_version)) {
+ dot = NULL;
+ }
+ }
+
+ if (!dot) {
+ LOG(ERROR) << "could not parse uname release " << uname_info.release;
+ return 0;
+ }
+
+ return darwin_major_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the
+// result is meant to be cached by MacOSXMinorVersion.
+int MacOSXMinorVersionInternal() {
+ int darwin_major_version = DarwinMajorVersionInternal();
+
+ // The Darwin major version is always 4 greater than the Mac OS X minor
+ // version for Darwin versions beginning with 6, corresponding to Mac OS X
+ // 10.2. Since this correspondence may change in the future, warn when
+ // encountering a version higher than anything seen before. Older Darwin
+ // versions, or versions that can't be determined, result in
+ // immediate death.
+ CHECK(darwin_major_version >= 6);
+ int mac_os_x_minor_version = darwin_major_version - 4;
+ LOG_IF(WARNING, darwin_major_version > 11) << "Assuming Darwin "
+ << base::IntToString(darwin_major_version) << " is Mac OS X 10."
+ << base::IntToString(mac_os_x_minor_version);
+
+ return mac_os_x_minor_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z.
+int MacOSXMinorVersion() {
+ static int mac_os_x_minor_version = MacOSXMinorVersionInternal();
+ return mac_os_x_minor_version;
+}
+
+enum {
+ LEOPARD_MINOR_VERSION = 5,
+ SNOW_LEOPARD_MINOR_VERSION = 6,
+ LION_MINOR_VERSION = 7
+};
+
+} // namespace
+
+bool IsOSLeopard() {
+ return MacOSXMinorVersion() == LEOPARD_MINOR_VERSION;
+}
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_6)
+bool IsOSLeopardOrEarlier() {
+ return MacOSXMinorVersion() <= LEOPARD_MINOR_VERSION;
+}
+#endif
+
+bool IsOSSnowLeopard() {
+ return MacOSXMinorVersion() == SNOW_LEOPARD_MINOR_VERSION;
+}
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSSnowLeopardOrEarlier() {
+ return MacOSXMinorVersion() <= SNOW_LEOPARD_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_6)
+bool IsOSSnowLeopardOrLater() {
+ return MacOSXMinorVersion() >= SNOW_LEOPARD_MINOR_VERSION;
+}
+#endif
+
+bool IsOSLion() {
+ return MacOSXMinorVersion() == LION_MINOR_VERSION;
+}
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSLionOrLater() {
+ return MacOSXMinorVersion() >= LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7)
+bool IsOSLaterThanLion() {
+ return MacOSXMinorVersion() > LION_MINOR_VERSION;
+}
+#endif
+
} // namespace mac
} // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index 92a6001..dd860a6 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -12,6 +12,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_nsobject.h"
#include "base/scoped_temp_dir.h"
+#include "base/sys_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -160,6 +161,48 @@ TEST_F(MacUtilTest, NSObjectRetainRelease) {
EXPECT_EQ(1U, [array retainCount]);
}
+TEST_F(MacUtilTest, IsOSEllipsis) {
+ int32 major, minor, bugfix;
+ base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+
+ if (major == 10) {
+ if (minor == 5) {
+ EXPECT_TRUE(IsOSLeopard());
+ EXPECT_TRUE(IsOSLeopardOrEarlier());
+ EXPECT_FALSE(IsOSSnowLeopard());
+ EXPECT_TRUE(IsOSSnowLeopardOrEarlier());
+ EXPECT_FALSE(IsOSSnowLeopardOrLater());
+ EXPECT_FALSE(IsOSLion());
+ EXPECT_FALSE(IsOSLionOrLater());
+ EXPECT_FALSE(IsOSLaterThanLion());
+ } else if (minor == 6) {
+ EXPECT_FALSE(IsOSLeopard());
+ EXPECT_FALSE(IsOSLeopardOrEarlier());
+ EXPECT_TRUE(IsOSSnowLeopard());
+ EXPECT_TRUE(IsOSSnowLeopardOrEarlier());
+ EXPECT_TRUE(IsOSSnowLeopardOrLater());
+ EXPECT_FALSE(IsOSLion());
+ EXPECT_FALSE(IsOSLionOrLater());
+ EXPECT_FALSE(IsOSLaterThanLion());
+ } else if (minor == 7) {
+ EXPECT_FALSE(IsOSLeopard());
+ EXPECT_FALSE(IsOSLeopardOrEarlier());
+ EXPECT_FALSE(IsOSSnowLeopard());
+ EXPECT_FALSE(IsOSSnowLeopardOrEarlier());
+ EXPECT_TRUE(IsOSSnowLeopardOrLater());
+ EXPECT_TRUE(IsOSLion());
+ EXPECT_TRUE(IsOSLionOrLater());
+ EXPECT_FALSE(IsOSLaterThanLion());
+ } else {
+ // Not five, six, or seven. Ah, ah, ah.
+ EXPECT_TRUE(false);
+ }
+ } else {
+ // Not ten. What you gonna do?
+ EXPECT_FALSE(true);
+ }
+}
+
} // namespace
} // namespace mac
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 5c81b2a..6e49d2c 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
#include "base/process_util.h"
#import <Cocoa/Cocoa.h>
@@ -19,7 +18,6 @@
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/types.h>
-#include <sys/utsname.h>
#include <sys/wait.h>
#include <new>
@@ -29,6 +27,7 @@
#include "base/eintr_wrapper.h"
#include "base/hash_tables.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/sys_string_conversions.h"
@@ -622,28 +621,25 @@ void oom_killer_new() {
// === Core Foundation CFAllocators ===
-bool CanGetContextForCFAllocator(long darwin_version) {
+bool CanGetContextForCFAllocator() {
// TODO(avi): remove at final release; http://crbug.com/74589
- if (darwin_version == 11) {
+ if (base::mac::IsOSLion()) {
NSLog(@"Unsure about the internals of CFAllocator but going to patch them "
"anyway. Watch out for crashes inside of CFAllocatorAllocate.");
}
- return darwin_version == 9 ||
- darwin_version == 10 ||
- darwin_version == 11;
+ return !base::mac::IsOSLaterThanLion();
}
-CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator,
- long darwin_version) {
- if (darwin_version == 9 || darwin_version == 10) {
- ChromeCFAllocator9and10* our_allocator =
- const_cast<ChromeCFAllocator9and10*>(
- reinterpret_cast<const ChromeCFAllocator9and10*>(allocator));
+CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
+ if (base::mac::IsOSLeopard() || base::mac::IsOSSnowLeopard()) {
+ ChromeCFAllocatorLeopards* our_allocator =
+ const_cast<ChromeCFAllocatorLeopards*>(
+ reinterpret_cast<const ChromeCFAllocatorLeopards*>(allocator));
return &our_allocator->_context;
- } else if (darwin_version == 11) {
- ChromeCFAllocator11* our_allocator =
- const_cast<ChromeCFAllocator11*>(
- reinterpret_cast<const ChromeCFAllocator11*>(allocator));
+ } else if (base::mac::IsOSLion()) {
+ ChromeCFAllocatorLion* our_allocator =
+ const_cast<ChromeCFAllocatorLion*>(
+ reinterpret_cast<const ChromeCFAllocatorLion*>(allocator));
return &our_allocator->_context;
} else {
return NULL;
@@ -714,18 +710,6 @@ void EnableTerminationOnOutOfMemory() {
g_oom_killer_enabled = true;
- // Not SysInfo::OperatingSystemVersionNumbers as that calls through to Gestalt
- // which ends up (on > 10.6) spawning threads.
- struct utsname machine_info;
- if (uname(&machine_info)) {
- return;
- }
-
- // The string machine_info.release is the xnu/Darwin version number, "9.xxx"
- // on Mac OS X 10.5, and "10.xxx" on Mac OS X 10.6. See
- // http://en.wikipedia.org/wiki/Darwin_(operating_system) .
- long darwin_version = strtol(machine_info.release, NULL, 10);
-
// === C malloc/calloc/valloc/realloc/posix_memalign ===
// This approach is not perfect, as requests for amounts of memory larger than
@@ -743,7 +727,7 @@ void EnableTerminationOnOutOfMemory() {
!g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
// See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac
- bool zone_allocators_protected = darwin_version > 10;
+ bool zone_allocators_protected = base::mac::IsOSLionOrLater();
ChromeMallocZone* default_zone =
reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
@@ -858,26 +842,25 @@ void EnableTerminationOnOutOfMemory() {
!g_old_cfallocator_malloc_zone)
<< "Old allocators unexpectedly non-null";
- bool cf_allocator_internals_known =
- CanGetContextForCFAllocator(darwin_version);
+ bool cf_allocator_internals_known = CanGetContextForCFAllocator();
if (cf_allocator_internals_known) {
CFAllocatorContext* context =
- ContextForCFAllocator(kCFAllocatorSystemDefault, darwin_version);
+ ContextForCFAllocator(kCFAllocatorSystemDefault);
CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
g_old_cfallocator_system_default = context->allocate;
CHECK(g_old_cfallocator_system_default)
<< "Failed to get kCFAllocatorSystemDefault allocation function.";
context->allocate = oom_killer_cfallocator_system_default;
- context = ContextForCFAllocator(kCFAllocatorMalloc, darwin_version);
+ context = ContextForCFAllocator(kCFAllocatorMalloc);
CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
g_old_cfallocator_malloc = context->allocate;
CHECK(g_old_cfallocator_malloc)
<< "Failed to get kCFAllocatorMalloc allocation function.";
context->allocate = oom_killer_cfallocator_malloc;
- context = ContextForCFAllocator(kCFAllocatorMallocZone, darwin_version);
+ context = ContextForCFAllocator(kCFAllocatorMallocZone);
CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
g_old_cfallocator_malloc_zone = context->allocate;
CHECK(g_old_cfallocator_malloc_zone)
diff --git a/base/sys_info.h b/base/sys_info.h
index 863e068..89bd193 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -41,6 +41,11 @@ class BASE_API SysInfo {
// Retrieves detailed numeric values for the OS version.
// TODO(port): Implement a Linux version of this method and enable the
// corresponding unit test.
+ // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
+ // for OS version-specific feature checks and workarounds. If you must use
+ // an OS version check instead of a feature check, use the base::mac::IsOS*
+ // family from base/mac/mac_util.h, or base::win::GetVersion from
+ // base/win/windows_version.h.
static void OperatingSystemVersionNumbers(int32* major_version,
int32* minor_version,
int32* bugfix_version);