Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
platform_macos.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(DART_HOST_OS_MACOS)
7
8#include "bin/platform.h"
10
11#include <CoreFoundation/CoreFoundation.h>
12
13#if !DART_HOST_OS_IOS
14#include <crt_externs.h>
15#endif // !DART_HOST_OS_IOS
16#include <dlfcn.h>
17#include <errno.h>
18#include <mach-o/dyld.h>
19#include <pthread.h>
20#include <signal.h>
21#include <sys/resource.h>
22#include <sys/sysctl.h>
23#include <sys/types.h>
24#include <sys/utsname.h>
25#include <unistd.h>
26
27#include <string>
28
29#include "bin/console.h"
30#include "bin/file.h"
32
33namespace dart {
34namespace bin {
35
36const char* Platform::executable_name_ = nullptr;
37int Platform::script_index_ = 1;
38char** Platform::argv_ = nullptr;
39
40static const char* strcode(int si_signo, int si_code) {
41#define CASE(signo, code) \
42 if (si_signo == signo && si_code == code) return #code;
43
44 CASE(SIGILL, ILL_ILLOPC);
45 CASE(SIGILL, ILL_ILLOPN);
46 CASE(SIGILL, ILL_ILLADR);
47 CASE(SIGILL, ILL_ILLTRP);
48 CASE(SIGILL, ILL_PRVOPC);
49 CASE(SIGILL, ILL_PRVREG);
50 CASE(SIGILL, ILL_COPROC);
51 CASE(SIGILL, ILL_BADSTK);
52 CASE(SIGSEGV, SEGV_MAPERR);
53 CASE(SIGSEGV, SEGV_ACCERR);
54 CASE(SIGBUS, BUS_ADRALN);
55 CASE(SIGBUS, BUS_ADRERR);
56 CASE(SIGBUS, BUS_OBJERR);
57 CASE(SIGTRAP, TRAP_BRKPT);
58 CASE(SIGTRAP, TRAP_TRACE);
59#undef CASE
60 return "?";
61}
62
63static void segv_handler(int signal, siginfo_t* siginfo, void* context) {
65 "\n===== CRASH =====\n"
66 "si_signo=%s(%d), si_code=%s(%d), si_addr=%p\n",
67 strsignal(siginfo->si_signo), siginfo->si_signo,
68 strcode(siginfo->si_signo, siginfo->si_code), siginfo->si_code,
69 siginfo->si_addr);
72 abort();
73}
74
76 // Turn off the signal handler for SIGPIPE as it causes the process
77 // to terminate on writing to a closed pipe. Without the signal
78 // handler error EPIPE is set instead.
79 struct sigaction act = {};
80 act.sa_handler = SIG_IGN;
81 if (sigaction(SIGPIPE, &act, nullptr) != 0) {
82 perror("Setting signal handler failed");
83 return false;
84 }
85
86 // tcsetattr raises SIGTTOU if we try to set console attributes when
87 // backgrounded, which suspends the process. Ignoring the signal prevents
88 // us from being suspended and lets us fail gracefully instead.
89 sigset_t signal_mask;
90 sigemptyset(&signal_mask);
91 sigaddset(&signal_mask, SIGTTOU);
92 if (sigprocmask(SIG_BLOCK, &signal_mask, nullptr) < 0) {
93 perror("Setting signal handler failed");
94 return false;
95 }
96
97 act.sa_flags = SA_SIGINFO;
98 act.sa_sigaction = &segv_handler;
99 if (sigemptyset(&act.sa_mask) != 0) {
100 perror("sigemptyset() failed.");
101 return false;
102 }
103 if (sigaddset(&act.sa_mask, SIGPROF) != 0) {
104 perror("sigaddset() failed");
105 return false;
106 }
107 if (sigaction(SIGSEGV, &act, nullptr) != 0) {
108 perror("sigaction() failed.");
109 return false;
110 }
111 if (sigaction(SIGBUS, &act, nullptr) != 0) {
112 perror("sigaction() failed.");
113 return false;
114 }
115 if (sigaction(SIGTRAP, &act, nullptr) != 0) {
116 perror("sigaction() failed.");
117 return false;
118 }
119 if (sigaction(SIGILL, &act, nullptr) != 0) {
120 perror("sigaction() failed.");
121 return false;
122 }
123 return true;
124}
125
127 int32_t cpus = -1;
128 size_t cpus_length = sizeof(cpus);
129 if (sysctlbyname("hw.logicalcpu", &cpus, &cpus_length, nullptr, 0) == 0) {
130 return cpus;
131 } else {
132 // Failed, fallback to using sysconf.
133 return sysconf(_SC_NPROCESSORS_ONLN);
134 }
135}
136
140}
141
142const char* Platform::LibraryPrefix() {
143 return "lib";
144}
145
146const char* Platform::LibraryExtension() {
147 return "dylib";
148}
149
150static const char* GetLocaleName() {
151 CFLocaleRef locale = CFLocaleCopyCurrent();
152 CFStringRef locale_string = CFLocaleGetIdentifier(locale);
153 CFIndex len = CFStringGetLength(locale_string);
154 CFIndex max_len =
155 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
156 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
157 ASSERT(result != nullptr);
158 bool success =
159 CFStringGetCString(locale_string, result, max_len, kCFStringEncodingUTF8);
160 CFRelease(locale);
161 if (!success) {
162 return nullptr;
163 }
164 return result;
165}
166
167static const char* GetPreferredLanguageName() {
168 CFArrayRef languages = CFLocaleCopyPreferredLanguages();
169 CFIndex languages_length = CFArrayGetCount(languages);
170 if (languages_length < 1) {
171 CFRelease(languages);
172 return nullptr;
173 }
174 CFTypeRef item =
175 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(languages, 0));
176 CFTypeID item_type = CFGetTypeID(item);
177 ASSERT(item_type == CFStringGetTypeID());
178 CFStringRef language = reinterpret_cast<CFStringRef>(item);
179 CFIndex len = CFStringGetLength(language);
180 CFIndex max_len =
181 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
182 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
183 ASSERT(result != nullptr);
184 bool success =
185 CFStringGetCString(language, result, max_len, kCFStringEncodingUTF8);
186 CFRelease(languages);
187 if (!success) {
188 return nullptr;
189 }
190 return result;
191}
192
193const char* Platform::LocaleName() {
194 // First see if there is a preferred language. If not, return the
195 // current locale name.
196 const char* preferred_language = GetPreferredLanguageName();
197 return (preferred_language != nullptr) ? preferred_language : GetLocaleName();
198}
199
200bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) {
201 return gethostname(buffer, buffer_length) == 0;
202}
203
204char** Platform::Environment(intptr_t* count) {
205#if DART_HOST_OS_IOS
206 // TODO(zra,chinmaygarde): On iOS, environment variables are seldom used. Wire
207 // this up if someone needs it. In the meantime, we return an empty array.
208 char** result;
209 result = reinterpret_cast<char**>(Dart_ScopeAllocate(1 * sizeof(*result)));
210 if (result == nullptr) {
211 return nullptr;
212 }
213 result[0] = nullptr;
214 *count = 0;
215 return result;
216#else
217 // Using environ directly is only safe as long as we do not
218 // provide access to modifying environment variables.
219 // On MacOS you have to do a bit of magic to get to the
220 // environment strings.
221 char** environ = *(_NSGetEnviron());
222 intptr_t i = 0;
223 char** tmp = environ;
224 while (*(tmp++) != nullptr) {
225 i++;
226 }
227 *count = i;
228 char** result;
229 result = reinterpret_cast<char**>(Dart_ScopeAllocate(i * sizeof(*result)));
230 for (intptr_t current = 0; current < i; current++) {
231 result[current] = environ[current];
232 }
233 return result;
234#endif
235}
236
237const char* Platform::GetExecutableName() {
238 return executable_name_;
239}
240
242 // Get the required length of the buffer.
243 uint32_t path_size = 0;
244 if (_NSGetExecutablePath(nullptr, &path_size) == 0) {
245 return nullptr;
246 }
247 // Allocate buffer and get executable path.
248 char* path = DartUtils::ScopedCString(path_size);
249 if (_NSGetExecutablePath(path, &path_size) != 0) {
250 return nullptr;
251 }
252 // Return the canonical path as the returned path might contain symlinks.
253 const char* canon_path = File::GetCanonicalPath(nullptr, path);
254 return canon_path;
255}
256
257intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
258 // Get the required length of the buffer.
259 uint32_t path_size = 0;
260 if (_NSGetExecutablePath(nullptr, &path_size) == 0) {
261 return -1;
262 }
263 if (path_size > result_size) {
264 return -1;
265 }
266 if (_NSGetExecutablePath(result, &path_size) != 0) {
267 return -1;
268 }
269 return path_size;
270}
271
272void Platform::SetProcessName(const char* name) {
273 pthread_setname_np(name);
274
275#if !defined(DART_HOST_OS_IOS)
276 // Attempt to set the name displayed in ActivityMonitor.
277 // https://codereview.chromium.org/659007
278
279 class ScopedDLHandle : public ValueObject {
280 public:
281 explicit ScopedDLHandle(void* handle) : handle_(handle) {}
282 ~ScopedDLHandle() {
283 if (handle_ != nullptr) dlclose(handle_);
284 }
285 void* get() { return handle_; }
286
287 private:
288 void* handle_;
289 DISALLOW_COPY_AND_ASSIGN(ScopedDLHandle);
290 };
291
292 class ScopedCFStringRef : public ValueObject {
293 public:
294 explicit ScopedCFStringRef(const char* s)
295 : ref_(CFStringCreateWithCString(nullptr, (s), kCFStringEncodingUTF8)) {
296 }
297 ~ScopedCFStringRef() {
298 if (ref_ != nullptr) CFRelease(ref_);
299 }
300 CFStringRef get() { return ref_; }
301
302 private:
303 CFStringRef ref_;
304 DISALLOW_COPY_AND_ASSIGN(ScopedCFStringRef);
305 };
306
307 ScopedDLHandle application_services_handle(
308 dlopen("/System/Library/Frameworks/ApplicationServices.framework/"
309 "Versions/A/ApplicationServices",
310 RTLD_LAZY | RTLD_LOCAL));
311 if (application_services_handle.get() == nullptr) return;
312
313 ScopedCFStringRef launch_services_bundle_name("com.apple.LaunchServices");
314 CFBundleRef launch_services_bundle =
315 CFBundleGetBundleWithIdentifier(launch_services_bundle_name.get());
316 if (launch_services_bundle == nullptr) return;
317
318#define GET_FUNC(name, cstr) \
319 ScopedCFStringRef name##_id(cstr); \
320 *reinterpret_cast<void**>(&name) = CFBundleGetFunctionPointerForName( \
321 launch_services_bundle, name##_id.get()); \
322 if (name == nullptr) return;
323
324#define GET_DATA(name, cstr) \
325 ScopedCFStringRef name##_id(cstr); \
326 *reinterpret_cast<void**>(&name) = \
327 CFBundleGetDataPointerForName(launch_services_bundle, name##_id.get()); \
328 if (name == nullptr) return;
329
330 CFTypeRef (*_LSGetCurrentApplicationASN)(void);
331 GET_FUNC(_LSGetCurrentApplicationASN, "_LSGetCurrentApplicationASN");
332
333 OSStatus (*_LSSetApplicationInformationItem)(int, CFTypeRef, CFStringRef,
334 CFStringRef, CFDictionaryRef*);
335 GET_FUNC(_LSSetApplicationInformationItem,
336 "_LSSetApplicationInformationItem");
337
338 CFDictionaryRef (*_LSApplicationCheckIn)(int, CFDictionaryRef);
339 GET_FUNC(_LSApplicationCheckIn, "_LSApplicationCheckIn");
340
341 void (*_LSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
342 void*);
343 GET_FUNC(_LSSetApplicationLaunchServicesServerConnectionStatus,
344 "_LSSetApplicationLaunchServicesServerConnectionStatus");
345
346 CFStringRef* _kLSDisplayNameKey;
347 GET_DATA(_kLSDisplayNameKey, "_kLSDisplayNameKey");
348 if (*_kLSDisplayNameKey == nullptr) return;
349
350 _LSSetApplicationLaunchServicesServerConnectionStatus(0, nullptr);
351
352 _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
353
354 CFTypeRef asn;
355 asn = _LSGetCurrentApplicationASN();
356 if (asn == nullptr) return;
357
358 ScopedCFStringRef cf_name(name);
359 _LSSetApplicationInformationItem(-2, asn, *_kLSDisplayNameKey, cf_name.get(),
360 nullptr);
361#undef GET_DATA
362#undef GET_FUNC
363#endif // !defined(DART_HOST_OS_IOS)
364}
365
366void Platform::Exit(int exit_code) {
369 exit(exit_code);
370}
371
372void Platform::_Exit(int exit_code) {
375 _exit(exit_code);
376}
377
379 rlimit limit = {static_cast<rlim_t>(value), static_cast<rlim_t>(value)};
380 setrlimit(RLIMIT_CORE, &limit);
381}
382
383} // namespace bin
384} // namespace dart
385
386#endif // defined(DART_HOST_OS_MACOS)
int count
Type::kYUV Type::kRGBA() int(0.7 *637)
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void RestoreConfig()
static char * ScopedCopyCString(const char *str)
Definition dartutils.h:232
static char * ScopedCString(intptr_t length)
Definition dartutils.h:224
static const char * GetCanonicalPath(Namespace *namespc, const char *path, char *dest=nullptr, int dest_size=0)
static bool LocalHostname(char *buffer, intptr_t buffer_length)
static const char * GetExecutableName()
static const char * LibraryPrefix()
static DART_NORETURN void _Exit(int exit_code)
static void SetProcessName(const char *name)
static const char * LocaleName()
static DART_NORETURN void Exit(int exit_code)
static bool Initialize()
static char ** Environment(intptr_t *count)
static const char * OperatingSystemVersion()
static intptr_t ResolveExecutablePathInto(char *result, size_t result_size)
static int NumberOfProcessors()
static const char * LibraryExtension()
static const char * ResolveExecutablePath()
static void SetCoreDumpResourceLimit(int value)
#define ASSERT(E)
struct MyStruct s
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
#define CASE(Arity, Mask, Name, Args, Result)
std::string NSProcessInfoOperatingSystemVersionString()
exit(kErrorExitCode)
DART_EXPORT void Dart_PrepareToAbort()
const char *const name
DART_EXPORT uint8_t * Dart_ScopeAllocate(intptr_t size)
DART_EXPORT void Dart_DumpNativeStackTrace(void *context)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
const myers::Point & get(const myers::Segment &)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
fuchsia::ui::composition::ParentViewportWatcherHandle handle_