14f7622ef4
Android is based on Linux, so most of the files were identical sans some subtle discrepancies caused by drift over time. This discrepancies were making code base harder to maintain and in fact were hiding bugs. For example, on Android eventhandler's implementation of timers which relied on passing timeout to `epoll_wait` contained a bug which was not present on Linux which used `timerfd` instead. TEST=ci and manual testing of Flutter app on Android device Fixes https://github.com/dart-lang/sdk/issues/54868 Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-android-product-arm-try,vm-ffi-android-product-arm64c-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64c-try Bug: b/311165013 Change-Id: Ia166f69c14177ec34160805a0983eafee8ea65f6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350923 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Slava Egorov <vegorov@google.com>
218 lines
5.8 KiB
C++
218 lines
5.8 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "platform/globals.h"
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
|
|
#include "bin/platform.h"
|
|
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/resource.h>
|
|
#if defined(DART_HOST_OS_ANDROID)
|
|
#include <sys/system_properties.h>
|
|
#endif
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
|
|
#include "bin/console.h"
|
|
#include "bin/file.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
const char* Platform::executable_name_ = nullptr;
|
|
int Platform::script_index_ = 1;
|
|
char** Platform::argv_ = nullptr;
|
|
|
|
static const char* strcode(int si_signo, int si_code) {
|
|
#define CASE(signo, code) \
|
|
if (si_signo == signo && si_code == code) return #code;
|
|
|
|
CASE(SIGILL, ILL_ILLOPC);
|
|
CASE(SIGILL, ILL_ILLOPN);
|
|
CASE(SIGILL, ILL_ILLADR);
|
|
CASE(SIGILL, ILL_ILLTRP);
|
|
CASE(SIGILL, ILL_PRVOPC);
|
|
CASE(SIGILL, ILL_PRVREG);
|
|
CASE(SIGILL, ILL_COPROC);
|
|
CASE(SIGILL, ILL_BADSTK);
|
|
CASE(SIGSEGV, SEGV_MAPERR);
|
|
CASE(SIGSEGV, SEGV_ACCERR);
|
|
CASE(SIGBUS, BUS_ADRALN);
|
|
CASE(SIGBUS, BUS_ADRERR);
|
|
CASE(SIGBUS, BUS_OBJERR);
|
|
CASE(SIGBUS, BUS_MCEERR_AR);
|
|
CASE(SIGBUS, BUS_MCEERR_AO);
|
|
CASE(SIGTRAP, TRAP_BRKPT);
|
|
CASE(SIGTRAP, TRAP_TRACE);
|
|
#undef CASE
|
|
return "?";
|
|
}
|
|
|
|
static void segv_handler(int signal, siginfo_t* siginfo, void* context) {
|
|
Syslog::PrintErr(
|
|
"\n===== CRASH =====\n"
|
|
"si_signo=%s(%d), si_code=%s(%d), si_addr=%p\n",
|
|
strsignal(siginfo->si_signo), siginfo->si_signo,
|
|
strcode(siginfo->si_signo, siginfo->si_code), siginfo->si_code,
|
|
siginfo->si_addr);
|
|
Dart_DumpNativeStackTrace(context);
|
|
Dart_PrepareToAbort();
|
|
abort();
|
|
}
|
|
|
|
bool Platform::Initialize() {
|
|
// Turn off the signal handler for SIGPIPE as it causes the process
|
|
// to terminate on writing to a closed pipe. Without the signal
|
|
// handler error EPIPE is set instead.
|
|
struct sigaction act = {};
|
|
act.sa_handler = SIG_IGN;
|
|
if (sigaction(SIGPIPE, &act, nullptr) != 0) {
|
|
perror("Setting signal handler failed");
|
|
return false;
|
|
}
|
|
|
|
// tcsetattr raises SIGTTOU if we try to set console attributes when
|
|
// backgrounded, which suspends the process. Ignoring the signal prevents
|
|
// us from being suspended and lets us fail gracefully instead.
|
|
sigset_t signal_mask;
|
|
sigemptyset(&signal_mask);
|
|
sigaddset(&signal_mask, SIGTTOU);
|
|
if (sigprocmask(SIG_BLOCK, &signal_mask, nullptr) < 0) {
|
|
perror("Setting signal handler failed");
|
|
return false;
|
|
}
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
act.sa_sigaction = &segv_handler;
|
|
if (sigemptyset(&act.sa_mask) != 0) {
|
|
perror("sigemptyset() failed.");
|
|
return false;
|
|
}
|
|
if (sigaddset(&act.sa_mask, SIGPROF) != 0) {
|
|
perror("sigaddset() failed");
|
|
return false;
|
|
}
|
|
if (sigaction(SIGSEGV, &act, nullptr) != 0) {
|
|
perror("sigaction() failed.");
|
|
return false;
|
|
}
|
|
if (sigaction(SIGBUS, &act, nullptr) != 0) {
|
|
perror("sigaction() failed.");
|
|
return false;
|
|
}
|
|
if (sigaction(SIGTRAP, &act, nullptr) != 0) {
|
|
perror("sigaction() failed.");
|
|
return false;
|
|
}
|
|
if (sigaction(SIGILL, &act, nullptr) != 0) {
|
|
perror("sigaction() failed.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int Platform::NumberOfProcessors() {
|
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
|
}
|
|
|
|
const char* Platform::OperatingSystemVersion() {
|
|
#if defined(DART_HOST_OS_ANDROID)
|
|
char os_version[PROP_VALUE_MAX + 1];
|
|
int os_version_length =
|
|
__system_property_get("ro.build.display.id", os_version);
|
|
if (os_version_length == 0) {
|
|
return nullptr;
|
|
}
|
|
os_version[Utils::Minimum(os_version_length, PROP_VALUE_MAX)] = '\0';
|
|
return DartUtils::ScopedCopyCString(os_version);
|
|
#else
|
|
struct utsname info;
|
|
int ret = uname(&info);
|
|
if (ret != 0) {
|
|
return nullptr;
|
|
}
|
|
return DartUtils::ScopedCStringFormatted("%s %s %s", info.sysname,
|
|
info.release, info.version);
|
|
#endif
|
|
}
|
|
|
|
const char* Platform::LibraryPrefix() {
|
|
return "lib";
|
|
}
|
|
|
|
const char* Platform::LibraryExtension() {
|
|
return "so";
|
|
}
|
|
|
|
const char* Platform::LocaleName() {
|
|
char* lang = getenv("LANG");
|
|
if (lang == nullptr) {
|
|
return "en_US";
|
|
}
|
|
return lang;
|
|
}
|
|
|
|
bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) {
|
|
return gethostname(buffer, buffer_length) == 0;
|
|
}
|
|
|
|
char** Platform::Environment(intptr_t* count) {
|
|
// Using environ directly is only safe as long as we do not
|
|
// provide access to modifying environment variables.
|
|
intptr_t i = 0;
|
|
char** tmp = environ;
|
|
while (*(tmp++) != nullptr) {
|
|
i++;
|
|
}
|
|
*count = i;
|
|
char** result;
|
|
result = reinterpret_cast<char**>(Dart_ScopeAllocate(i * sizeof(*result)));
|
|
for (intptr_t current = 0; current < i; current++) {
|
|
result[current] = environ[current];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const char* Platform::GetExecutableName() {
|
|
return executable_name_;
|
|
}
|
|
|
|
const char* Platform::ResolveExecutablePath() {
|
|
return File::ReadLink("/proc/self/exe");
|
|
}
|
|
|
|
intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
|
|
return File::ReadLinkInto("/proc/self/exe", result, result_size);
|
|
}
|
|
|
|
void Platform::SetProcessName(const char* name) {
|
|
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name), 0, 0, 0); // NOLINT
|
|
}
|
|
|
|
void Platform::Exit(int exit_code) {
|
|
Console::RestoreConfig();
|
|
Dart_PrepareToAbort();
|
|
exit(exit_code);
|
|
}
|
|
|
|
void Platform::_Exit(int exit_code) {
|
|
Console::RestoreConfig();
|
|
Dart_PrepareToAbort();
|
|
_exit(exit_code);
|
|
}
|
|
|
|
void Platform::SetCoreDumpResourceLimit(int value) {
|
|
rlimit limit = {static_cast<rlim_t>(value), static_cast<rlim_t>(value)};
|
|
setrlimit(RLIMIT_CORE, &limit);
|
|
}
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|
|
|
|
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|