Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Unified Diff: util/mac/mac_util.cc

Issue 473023002: Add mac_util, including MacOSXMinorVersion(), MacOSXVersion(), and MacModelAndBoard() (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Improve documentation Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « util/mac/mac_util.h ('k') | util/mac/mac_util_test.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/mac/mac_util.cc
diff --git a/util/mac/mac_util.cc b/util/mac/mac_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..da6930c7ec210059e2f7184b76617ddb40f7b168
--- /dev/null
+++ b/util/mac/mac_util.cc
@@ -0,0 +1,282 @@
+// Copyright 2014 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/mac/mac_util.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+
+extern "C" {
+// Private CoreFoundation internals. See 10.9.2 CF-855.14/CFPriv.h and
+// CF-855.14/CFUtilities.c. These are marked for weak import because they’re
+// private and subject to change.
+
+#define WEAK_IMPORT __attribute__((weak_import))
+
+// Don’t call these functions directly, call them through the
+// TryCFCopy*VersionDictionary() helpers to account for the possibility that
+// they may not be present at runtime.
+CFDictionaryRef _CFCopySystemVersionDictionary() WEAK_IMPORT;
+CFDictionaryRef _CFCopyServerVersionDictionary() WEAK_IMPORT;
+
+// Don’t use these constants with CFDictionaryGetValue() directly, use them with
+// the TryCFDictionaryGetValue() wrapper to account for the possibility that
+// they may not be present at runtime.
+extern const CFStringRef _kCFSystemVersionProductNameKey WEAK_IMPORT;
+extern const CFStringRef _kCFSystemVersionProductVersionKey WEAK_IMPORT;
+extern const CFStringRef _kCFSystemVersionProductVersionExtraKey WEAK_IMPORT;
+extern const CFStringRef _kCFSystemVersionBuildVersionKey WEAK_IMPORT;
+
+#undef WEAK_IMPORT
+
+} // extern "C"
+
+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().
+//
+// This is very similar to Chromium’s base/mac/mac_util.mm
+// DarwinMajorVersionInternal().
+int DarwinMajorVersion() {
+ // base::OperatingSystemVersionNumbers calls Gestalt(), which is a
+ // higher-level function 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.
+
+ utsname uname_info;
+ int rv = uname(&uname_info);
+ PCHECK(rv == 0) << "uname";
+
+ DCHECK_EQ(strcmp(uname_info.sysname, "Darwin"), 0) << "unexpected sysname "
+ << uname_info.sysname;
+
+ char* dot = strchr(uname_info.release, '.');
+ CHECK(dot);
+
+ int darwin_major_version = 0;
+ CHECK(base::StringToInt(
+ base::StringPiece(uname_info.release, dot - uname_info.release),
+ &darwin_major_version));
+
+ return darwin_major_version;
+}
+
+// Helpers for the weak-imported private CoreFoundation internals.
+
+CFDictionaryRef TryCFCopySystemVersionDictionary() {
+ if (_CFCopySystemVersionDictionary) {
+ return _CFCopySystemVersionDictionary();
+ }
+ return NULL;
+}
+
+CFDictionaryRef TryCFCopyServerVersionDictionary() {
+ if (_CFCopyServerVersionDictionary) {
+ return _CFCopyServerVersionDictionary();
+ }
+ return NULL;
+}
+
+const void* TryCFDictionaryGetValue(CFDictionaryRef dictionary,
+ const void* value) {
+ if (value) {
+ return CFDictionaryGetValue(dictionary, value);
+ }
+ return NULL;
+}
+
+// Converts |version| to a triplet of version numbers on behalf of
+// MacOSXVersion(). Returns true on success. If |version| does not have the
+// expected format, returns false. |version| must be in the form "10.9.2" or
+// just "10.9". In the latter case, |bugfix| will be set to 0.
+bool StringToVersionNumbers(const std::string& version,
+ int* major,
+ int* minor,
+ int* bugfix) {
+ size_t first_dot = version.find_first_of('.');
+ if (first_dot == 0 || first_dot == std::string::npos ||
+ first_dot == version.length() - 1) {
+ LOG(ERROR) << "version has unexpected format";
+ return false;
+ }
+ if (!base::StringToInt(base::StringPiece(&version[0], first_dot), major)) {
+ LOG(ERROR) << "version has unexpected format";
+ return false;
+ }
+
+ size_t second_dot = version.find_first_of('.', first_dot + 1);
+ if (second_dot == version.length() - 1) {
+ LOG(ERROR) << "version has unexpected format";
+ return false;
+ } else if (second_dot == std::string::npos) {
+ second_dot = version.length();
+ }
+
+ if (!base::StringToInt(base::StringPiece(&version[first_dot + 1],
+ second_dot - first_dot - 1),
+ minor)) {
+ LOG(ERROR) << "version has unexpected format";
+ return false;
+ }
+
+ if (second_dot == version.length()) {
+ *bugfix = 0;
+ } else if (!base::StringToInt(
+ base::StringPiece(&version[second_dot + 1],
+ version.length() - second_dot - 1),
+ bugfix)) {
+ LOG(ERROR) << "version has unexpected format";
+ return false;
+ }
+
+ return true;
+}
+
+std::string IORegistryEntryDataPropertyAsString(io_registry_entry_t entry,
+ CFStringRef key) {
+ base::ScopedCFTypeRef<CFTypeRef> property(
+ IORegistryEntryCreateCFProperty(entry, key, kCFAllocatorDefault, 0));
+ CFDataRef data = base::mac::CFCast<CFDataRef>(property);
+ if (data && CFDataGetLength(data) > 0) {
+ return reinterpret_cast<const char*>(CFDataGetBytePtr(data));
+ }
+
+ return std::string();
+}
+
+} // namespace
+
+namespace crashpad {
+
+int MacOSXMinorVersion() {
+ // 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.
+ static int mac_os_x_minor_version = DarwinMajorVersion() - 4;
+ DCHECK(mac_os_x_minor_version >= 2);
+ return mac_os_x_minor_version;
+}
+
+bool MacOSXVersion(int* major,
+ int* minor,
+ int* bugfix,
+ std::string* build,
+ bool* server,
+ std::string* version_string) {
+ base::ScopedCFTypeRef<CFDictionaryRef> dictionary(
+ TryCFCopyServerVersionDictionary());
+ if (dictionary) {
+ *server = true;
+ } else {
+ dictionary.reset(TryCFCopySystemVersionDictionary());
+ if (!dictionary) {
+ LOG(ERROR) << "_CFCopySystemVersionDictionary failed";
+ return false;
+ }
+ *server = false;
+ }
+
+ bool success = true;
+
+ CFStringRef version_cf = base::mac::CFCast<CFStringRef>(
+ TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductVersionKey));
+ std::string version;
+ if (!version_cf) {
+ LOG(ERROR) << "version_cf not found";
+ success = false;
+ } else {
+ version = base::SysCFStringRefToUTF8(version_cf);
+ success &= StringToVersionNumbers(version, major, minor, bugfix);
+ }
+
+ CFStringRef build_cf = base::mac::CFCast<CFStringRef>(
+ TryCFDictionaryGetValue(dictionary, _kCFSystemVersionBuildVersionKey));
+ if (!build_cf) {
+ LOG(ERROR) << "build_cf not found";
+ success = false;
+ } else {
+ build->assign(base::SysCFStringRefToUTF8(build_cf));
+ }
+
+ CFStringRef product_cf = base::mac::CFCast<CFStringRef>(
+ TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductNameKey));
+ std::string product;
+ if (!product_cf) {
+ LOG(ERROR) << "product_cf not found";
+ success = false;
+ } else {
+ product = base::SysCFStringRefToUTF8(product_cf);
+ }
+
+ // This key is not required, and in fact is normally not present.
+ CFStringRef extra_cf = base::mac::CFCast<CFStringRef>(TryCFDictionaryGetValue(
+ dictionary, _kCFSystemVersionProductVersionExtraKey));
+ std::string extra;
+ if (extra_cf) {
+ extra = base::SysCFStringRefToUTF8(extra_cf);
+ }
+
+ if (!product.empty() || !version.empty() || !build->empty()) {
+ if (!extra.empty()) {
+ version_string->assign(base::StringPrintf("%s %s %s (%s)",
+ product.c_str(),
+ version.c_str(),
+ extra.c_str(),
+ build->c_str()));
+ } else {
+ version_string->assign(base::StringPrintf(
+ "%s %s (%s)", product.c_str(), version.c_str(), build->c_str()));
+ }
+ }
+
+ return success;
+}
+
+void MacModelAndBoard(std::string* model, std::string* board_id) {
+ base::mac::ScopedIOObject<io_service_t> platform_expert(
+ IOServiceGetMatchingService(kIOMasterPortDefault,
+ IOServiceMatching("IOPlatformExpertDevice")));
+ if (platform_expert) {
+ model->assign(
+ IORegistryEntryDataPropertyAsString(platform_expert, CFSTR("model")));
+ board_id->assign(IORegistryEntryDataPropertyAsString(platform_expert,
+ CFSTR("board-id")));
+ } else {
+ model->clear();
+ board_id->clear();
+ }
+}
+
+} // namespace crashpad
« no previous file with comments | « util/mac/mac_util.h ('k') | util/mac/mac_util_test.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698