summaryrefslogtreecommitdiffstats
path: root/base/mac
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 18:18:38 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 18:18:38 +0000
commitba64e2bae9b1d00777a81231148e0f69909a840c (patch)
tree8d8168983abb8635bfd5e9471169febbc397d3f4 /base/mac
parent7bf10b0e47e51d9c6d0a5f39a9d0bfad1d78eef4 (diff)
downloadchromium_src-ba64e2bae9b1d00777a81231148e0f69909a840c.zip
chromium_src-ba64e2bae9b1d00777a81231148e0f69909a840c.tar.gz
chromium_src-ba64e2bae9b1d00777a81231148e0f69909a840c.tar.bz2
Improve and unify Mac OS X run-time version checks.
Don't use base::SysInfo::OperatingSystemVersionNumbers, because it calls Gestalt, which has a few bad properties. Introduce new functions that perform specific version checks. BUG=85972 TEST=base_unittests MacUtilTest.IsOSEllipsis Review URL: http://codereview.chromium.org/7144007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89028 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/mac')
-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
3 files changed, 218 insertions, 0 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