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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mac/mac_util.h"
16
17 #include <CoreFoundation/CoreFoundation.h>
18 #include <IOKit/IOKitLib.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
22
23 #include "base/logging.h"
24 #include "base/mac/foundation_util.h"
25 #include "base/mac/scoped_cftyperef.h"
26 #include "base/mac/scoped_ioobject.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_piece.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/sys_string_conversions.h"
31
32 extern "C" {
33 // Private CoreFoundation internals. See 10.9.2 CF-855.14/CFPriv.h and
34 // CF-855.14/CFUtilities.c. These are marked for weak import because they’re
35 // private and subject to change.
36
37 #define WEAK_IMPORT __attribute__((weak_import))
38
39 // Don’t call these functions directly, call them through the
40 // TryCFCopy*VersionDictionary() helpers to account for the possibility that
41 // they may not be present at runtime.
42 CFDictionaryRef _CFCopySystemVersionDictionary() WEAK_IMPORT;
43 CFDictionaryRef _CFCopyServerVersionDictionary() WEAK_IMPORT;
44
45 // Don’t use these constants with CFDictionaryGetValue() directly, use them with
46 // the TryCFDictionaryGetValue() wrapper to account for the possibility that
47 // they may not be present at runtime.
48 extern const CFStringRef _kCFSystemVersionProductNameKey WEAK_IMPORT;
49 extern const CFStringRef _kCFSystemVersionProductVersionKey WEAK_IMPORT;
50 extern const CFStringRef _kCFSystemVersionProductVersionExtraKey WEAK_IMPORT;
51 extern const CFStringRef _kCFSystemVersionBuildVersionKey WEAK_IMPORT;
52
53 #undef WEAK_IMPORT
54
55 } // extern "C"
56
57 namespace {
58
59 // Returns the running system’s Darwin major version. Don’t call this, it’s an
60 // implementation detail and its result is meant to be cached by
61 // MacOSXMinorVersion().
62 //
63 // This is very similar to Chromium’s base/mac/mac_util.mm
64 // DarwinMajorVersionInternal().
65 int DarwinMajorVersion() {
66 // base::OperatingSystemVersionNumbers calls Gestalt(), which is a
67 // higher-level function than is needed. It might perform unnecessary
68 // operations. On 10.6, it was observed to be able to spawn threads (see
69 // http://crbug.com/53200). It might also read files or perform other blocking
70 // operations. Actually, nobody really knows for sure just what Gestalt()
71 // might do, or what it might be taught to do in the future.
72 //
73 // uname(), on the other hand, is implemented as a simple series of sysctl()
74 // system calls to obtain the relevant data from the kernel. The data is
75 // compiled right into the kernel, so no threads or blocking or other funny
76 // business is necessary.
77
78 utsname uname_info;
79 int rv = uname(&uname_info);
80 PCHECK(rv == 0) << "uname";
81
82 DCHECK_EQ(strcmp(uname_info.sysname, "Darwin"), 0) << "unexpected sysname "
83 << uname_info.sysname;
84
85 char* dot = strchr(uname_info.release, '.');
86 CHECK(dot);
87
88 int darwin_major_version = 0;
89 CHECK(base::StringToInt(
90 base::StringPiece(uname_info.release, dot - uname_info.release),
91 &darwin_major_version));
92
93 return darwin_major_version;
94 }
95
96 // Helpers for the weak-imported private CoreFoundation internals.
97
98 CFDictionaryRef TryCFCopySystemVersionDictionary() {
99 if (_CFCopySystemVersionDictionary) {
100 return _CFCopySystemVersionDictionary();
101 }
102 return NULL;
103 }
104
105 CFDictionaryRef TryCFCopyServerVersionDictionary() {
106 if (_CFCopyServerVersionDictionary) {
107 return _CFCopyServerVersionDictionary();
108 }
109 return NULL;
110 }
111
112 const void* TryCFDictionaryGetValue(CFDictionaryRef dictionary,
113 const void* value) {
114 if (value) {
115 return CFDictionaryGetValue(dictionary, value);
116 }
117 return NULL;
118 }
119
120 // Converts |version| to a triplet of version numbers on behalf of
121 // MacOSXVersion(). Returns true on success. If |version| does not have the
122 // expected format, returns false. |version| must be in the form "10.9.2" or
123 // just "10.9". In the latter case, |bugfix| will be set to 0.
124 bool StringToVersionNumbers(const std::string& version,
125 int* major,
126 int* minor,
127 int* bugfix) {
128 size_t first_dot = version.find_first_of('.');
129 if (first_dot == 0 || first_dot == std::string::npos ||
130 first_dot == version.length() - 1) {
131 LOG(ERROR) << "version has unexpected format";
132 return false;
133 }
134 if (!base::StringToInt(base::StringPiece(&version[0], first_dot), major)) {
135 LOG(ERROR) << "version has unexpected format";
136 return false;
137 }
138
139 size_t second_dot = version.find_first_of('.', first_dot + 1);
140 if (second_dot == version.length() - 1) {
141 LOG(ERROR) << "version has unexpected format";
142 return false;
143 } else if (second_dot == std::string::npos) {
144 second_dot = version.length();
145 }
146
147 if (!base::StringToInt(base::StringPiece(&version[first_dot + 1],
148 second_dot - first_dot - 1),
149 minor)) {
150 LOG(ERROR) << "version has unexpected format";
151 return false;
152 }
153
154 if (second_dot == version.length()) {
155 *bugfix = 0;
156 } else if (!base::StringToInt(
157 base::StringPiece(&version[second_dot + 1],
158 version.length() - second_dot - 1),
159 bugfix)) {
160 LOG(ERROR) << "version has unexpected format";
161 return false;
162 }
163
164 return true;
165 }
166
167 std::string IORegistryEntryDataPropertyAsString(io_registry_entry_t entry,
168 CFStringRef key) {
169 base::ScopedCFTypeRef<CFTypeRef> property(
170 IORegistryEntryCreateCFProperty(entry, key, kCFAllocatorDefault, 0));
171 CFDataRef data = base::mac::CFCast<CFDataRef>(property);
172 if (data && CFDataGetLength(data) > 0) {
173 return reinterpret_cast<const char*>(CFDataGetBytePtr(data));
174 }
175
176 return std::string();
177 }
178
179 } // namespace
180
181 namespace crashpad {
182
183 int MacOSXMinorVersion() {
184 // The Darwin major version is always 4 greater than the Mac OS X minor
185 // version for Darwin versions beginning with 6, corresponding to Mac OS X
186 // 10.2.
187 static int mac_os_x_minor_version = DarwinMajorVersion() - 4;
188 DCHECK(mac_os_x_minor_version >= 2);
189 return mac_os_x_minor_version;
190 }
191
192 bool MacOSXVersion(int* major,
193 int* minor,
194 int* bugfix,
195 std::string* build,
196 bool* server,
197 std::string* version_string) {
198 base::ScopedCFTypeRef<CFDictionaryRef> dictionary(
199 TryCFCopyServerVersionDictionary());
200 if (dictionary) {
201 *server = true;
202 } else {
203 dictionary.reset(TryCFCopySystemVersionDictionary());
204 if (!dictionary) {
205 LOG(ERROR) << "_CFCopySystemVersionDictionary failed";
206 return false;
207 }
208 *server = false;
209 }
210
211 bool success = true;
212
213 CFStringRef version_cf = base::mac::CFCast<CFStringRef>(
214 TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductVersionKey));
215 std::string version;
216 if (!version_cf) {
217 LOG(ERROR) << "version_cf not found";
218 success = false;
219 } else {
220 version = base::SysCFStringRefToUTF8(version_cf);
221 success &= StringToVersionNumbers(version, major, minor, bugfix);
222 }
223
224 CFStringRef build_cf = base::mac::CFCast<CFStringRef>(
225 TryCFDictionaryGetValue(dictionary, _kCFSystemVersionBuildVersionKey));
226 if (!build_cf) {
227 LOG(ERROR) << "build_cf not found";
228 success = false;
229 } else {
230 build->assign(base::SysCFStringRefToUTF8(build_cf));
231 }
232
233 CFStringRef product_cf = base::mac::CFCast<CFStringRef>(
234 TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductNameKey));
235 std::string product;
236 if (!product_cf) {
237 LOG(ERROR) << "product_cf not found";
238 success = false;
239 } else {
240 product = base::SysCFStringRefToUTF8(product_cf);
241 }
242
243 // This key is not required, and in fact is normally not present.
244 CFStringRef extra_cf = base::mac::CFCast<CFStringRef>(TryCFDictionaryGetValue(
245 dictionary, _kCFSystemVersionProductVersionExtraKey));
246 std::string extra;
247 if (extra_cf) {
248 extra = base::SysCFStringRefToUTF8(extra_cf);
249 }
250
251 if (!product.empty() || !version.empty() || !build->empty()) {
252 if (!extra.empty()) {
253 version_string->assign(base::StringPrintf("%s %s %s (%s)",
254 product.c_str(),
255 version.c_str(),
256 extra.c_str(),
257 build->c_str()));
258 } else {
259 version_string->assign(base::StringPrintf(
260 "%s %s (%s)", product.c_str(), version.c_str(), build->c_str()));
261 }
262 }
263
264 return success;
265 }
266
267 void MacModelAndBoard(std::string* model, std::string* board_id) {
268 base::mac::ScopedIOObject<io_service_t> platform_expert(
269 IOServiceGetMatchingService(kIOMasterPortDefault,
270 IOServiceMatching("IOPlatformExpertDevice")));
271 if (platform_expert) {
272 model->assign(
273 IORegistryEntryDataPropertyAsString(platform_expert, CFSTR("model")));
274 board_id->assign(IORegistryEntryDataPropertyAsString(platform_expert,
275 CFSTR("board-id")));
276 } else {
277 model->clear();
278 board_id->clear();
279 }
280 }
281
282 } // namespace crashpad
OLDNEW
« 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