diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/mac/mac_util.h | 49 | ||||
-rw-r--r-- | base/mac/mac_util.mm | 126 | ||||
-rw-r--r-- | base/mac/mac_util_unittest.mm | 43 | ||||
-rw-r--r-- | base/process_util_mac.mm | 53 | ||||
-rw-r--r-- | base/sys_info.h | 5 |
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); |